From bb3048f8f8bda02ac4fe9d5bb6140a3689a774a4 Mon Sep 17 00:00:00 2001 From: Sean Corfield Date: Fri, 8 Nov 2019 11:12:17 -0800 Subject: [PATCH] More documentation improvements --- CHANGELOG.md | 3 +++ doc/datafy-nav-and-schema.md | 12 +++++++++--- doc/friendly-sql-functions.md | 2 +- doc/migration-from-clojure-java-jdbc.md | 4 +++- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e171e66..e83eb95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ The following changes have been committed to the **master** branch since the 1.0 * Fix link to **All The Options** in **Migration from `clojure.java.jdbc`**. PR #71 (@laurio). * Address #70 by adding **CLOB & BLOB SQL Types** to the **Tips & Tricks** section of **Friendly SQL Functions** and by adding `next.jdbc.result-set/clob-column-reader` and `next.jdbc.result-set/clob->string` helper to make it easier to deal with `CLOB` column data. * Clarify what `execute!` and `execute-one!` produce when the result set is empty (`[]` and `nil` respectively, and there are now tests for this). Similarly for `find-by-keys` and `get-by-id`. +* Clarify that **Friendly SQL Functions** are deliberately simple (hint: they will not be enhanced or expanded -- use `plan`, `execute!`, and `execute-one!` instead, with a DSL library if you want!). +* Improve migration docs: explicitly recommend the use of a datasource for code that needs to work with both `clojure.java.jdbc` and `next.jdbc`; add caveat about column name conflicts. +* Improve `datafy`/`nav` documentation around `:schema`. * Update `org.clojure/java.data` to `"0.1.4"` (0.1.2 fixes a number of reflection warnings). ## Stable Builds diff --git a/doc/datafy-nav-and-schema.md b/doc/datafy-nav-and-schema.md index c4ec5a5..13d8279 100644 --- a/doc/datafy-nav-and-schema.md +++ b/doc/datafy-nav-and-schema.md @@ -25,14 +25,20 @@ You can override this default behavior for any column in any table by providing The default behavior in the example above is equivalent to this `:schema` value: ```clojure -{:contact/addressid :address/id} ; a one-to-one or many-to-one relationship +(jdbc/execute! ds + ["select * from contact where city = ?" "San Francisco"] + ;; a one-to-one or many-to-one relationship + {:schema {:contact/addressid :address/id}}) ``` If you had a table to track the valid/bouncing status of email addresses over time, `:deliverability`, where `email` is the non-unique key, you could provide automatic navigation into that using: ```clojure -{:contact/addressid :address/id - :address/email [:deliverability/email]} ; one-to-many or many-to-many +(jdbc/execute! ds + ["select * from contact where city = ?" "San Francisco"] + ;; one-to-many or many-to-many + {:schema {:contact/addressid :address/id + :address/email [:deliverability/email]}}) ``` When you indicate a `*-to-many` relationship, by wrapping the foreign table/key in a vector, `next.jdbc`'s implementation of `nav` will fetch a multi-row result set from the target table. diff --git a/doc/friendly-sql-functions.md b/doc/friendly-sql-functions.md index c802911..657487a 100644 --- a/doc/friendly-sql-functions.md +++ b/doc/friendly-sql-functions.md @@ -16,7 +16,7 @@ as well as these more specific "read" operations: * `find-by-keys` -- a query on one or more column values, specified as a hash map or `WHERE` clause, * `get-by-id` -- a query to return a single row, based on a single column value, usually the primary key. -These functions are described in more detail below. They are deliberately simple and intended to cover only the most common, basic SQL operations. If you need more expressiveness, consider one of the following libraries to build SQL/parameter vectors, or run queries: +These functions are described in more detail below. They are deliberately simple and intended to cover only the most common, basic SQL operations. The primary API (`plan`, `execute!`, `execute-one!`) is the recommended approach for everything beyond that. If you need more expressiveness, consider one of the following libraries to build SQL/parameter vectors, or run queries: * [HoneySQL](https://github.com/jkk/honeysql) -- a composable DSL for creating SQL/parameter vectors from Clojure data structures * [seql](https://github.com/exoscale/seql) -- a simplified EQL-inspired query language, built on `next.jdbc` (as of release 0.1.6) diff --git a/doc/migration-from-clojure-java-jdbc.md b/doc/migration-from-clojure-java-jdbc.md index 0565bb1..aa07ac4 100644 --- a/doc/migration-from-clojure-java-jdbc.md +++ b/doc/migration-from-clojure-java-jdbc.md @@ -12,6 +12,8 @@ This page attempts to list all of the differences between [clojure.java.jdbc](ht `clojure.java.jdbc` returned result sets (and generated keys) as hash maps with simple, lower-case keys by default. `next.jdbc` returns result sets (and generated keys) as hash maps with qualified, as-is keys by default: each key is qualified by the name of table from which it is drawn, if known. The as-is default is chosen to a) improve performance and b) not mess with the data. Using a `:builder-fn` option of `next.jdbc.result-set/as-unqualified-maps` will produce simple, as-is keys. Using a `:builder-fn` option of `next.jdbc.result-set/as-unqualified-lower-maps` will produce simple, lower-case keys -- the most compatible with `clojure.java.jdbc`'s default behavior. +*Note: `clojure.java.jdbc` would make column names unique by appending numeric suffices, for example in a `JOIN` that produced columns `id` from multiple tables. `next.jdbc` does not do this: if you use _qualified_ column names -- the default -- then you would get `:sometable/id` and `:othertable/id`, but with _unqualified_ column names you would just get one `:id` in each row. It was always poor practice to rely on `clojure.java.jdbc`'s renaming behavior and it added quite an overhead to result set building, which is why `next.jdbc` does not support it -- use explicit column aliasing in your SQL instead if you want _unqualified_ column names!* + If you used `:as-arrays? true`, you will most likely want to use a `:builder-fn` option of `next.jdbc.result-set/as-unqualified-lower-arrays`. *Note: When `next.jdbc` cannot obtain a `ResultSet` object and returns `{:next.jdbc/count N}` instead, these builder functions are not applied -- the `:builder-fn` option is not used in that situation.* @@ -57,7 +59,7 @@ The `next.jdbc.sql` namespace contains several functions with similarities to `c If you are using `:identifiers`, you will need to change to the appropriate `:builder-fn` option with one of `next.jdbc.result-set`'s `as-*` functions. -`clojure.java.jdbc`'s default is the equivalent of `as-unqualified-lower-maps`. If you specified `:identifiers identity`, you can use `as-unqualified-maps`. If you provided your own string transformation function, you probably want `as-unqualified-modified-maps` and also pass your transformation function as the `:label-fn` option. +`clojure.java.jdbc`'s default is the equivalent of `as-unqualified-lower-maps` (with the caveat that conflicting column names are not made unique -- see the note above in **Rows and Result Sets**). If you specified `:identifiers identity`, you can use `as-unqualified-maps`. If you provided your own string transformation function, you probably want `as-unqualified-modified-maps` and also pass your transformation function as the `:label-fn` option. If you used `:qualifier`, you may be able to get the same effect with `as-maps`, `as-lower-maps`, or `as-modified-maps`. Otherwise, you may need to specify the fixed qualifier via the `:label-fn #(str "my_qualifier/" %)`. You might think you could use `:qualifier-fn (constantly "my_qualifier")` for this but it is only called when the column has a known table name so it wouldn't be applied for derived values (and some databases don't provide the table name, so it wouldn't be applied at all for those databases).