From 3008aa2c6800066b7cc6ddd0b233522036224fd5 Mon Sep 17 00:00:00 2001 From: Sean Corfield Date: Mon, 12 Sep 2022 12:16:49 -0700 Subject: [PATCH] fix #224 by clarify CSK usage (I hope!) --- CHANGELOG.md | 5 ++++- doc/friendly-sql-functions.md | 9 ++++++++- doc/getting-started.md | 3 +++ doc/result-set-builders.md | 6 ++++-- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c378d57..3b9f341 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ Only accretive/fixative changes will be made from now on. +* 1.3.next in progress + * Address [#224](https://github.com/seancorfield/next-jdbc/issues/224) by attempting to clarify how to use the snake/kebab options and builders. + * 1.3.828 -- 2022-09-11 * Fix [#222](https://github.com/seancorfield/next-jdbc/issues/222) by correcting implementation of `.cons` on a row. * Address [#221](https://github.com/seancorfield/next-jdbc/issues/221) by supporting `:column-fn` a top-level option in `plan`-related functions to transform keys used in reducing function contexts. Also corrects handling of column names in schema `nav`igation (which previously only supported `:table-fn` and incorrectly applied it to columns as well). @@ -119,7 +122,7 @@ Only accretive/fixative changes will be made from now on. * Fix #130 by implementing `clojure.lang.ILookup` on the three builder adapters. * Fix #129 by adding `with-column-value` to `RowBuilder` and a more generic `builder-adapter`. * Fix #128 by adding a test for the "not found" arity of lookup on mapified result sets. - * Fix #121 by conditionally adding `next.jdbc/snake-kebab-opts`, `next.jdbc/unqualified-snake-kebab-opts`, `next.jdbc.result-set/as-kebab-maps`, and `next.jdbc.result-set/as-unqualified-kebab-maps` (which are present only if `camel-snake-kebab` is on your classpath). + * Fix #121 by conditionally adding `next.jdbc/snake-kebab-opts`, `next.jdbc/unqualified-snake-kebab-opts`, `next.jdbc.result-set/as-kebab-maps`, and `next.jdbc.result-set/as-unqualified-kebab-maps` (which are present only if `camel-snake-kebab` is on your classpath). _As of 1.2.659, these are including unconditionally and `next.jdbc` depends directly on `camel-snake-kebab`._ * Correct MySQL batch statement rewrite tip: it's `:rewriteBatchedStatements true` (plural). Also surface the batch statement tips in the **Tips & Tricks** page. * Clarify how combining is interleaving with reducing in **Reducing and Folding with `plan`**. * Use "JDBC URL" consistently everywhere (instead of "JDBC URI" in several places). diff --git a/doc/friendly-sql-functions.md b/doc/friendly-sql-functions.md index e4638ab..32de2b1 100644 --- a/doc/friendly-sql-functions.md +++ b/doc/friendly-sql-functions.md @@ -245,7 +245,14 @@ These quoting functions can be provided to any of the friendly SQL functions abo (sql/insert! ds :my-table {:some "data"} {:table-fn snake-case}) ``` -`next.jdbc` provides `snake-kebab-opts` and `unqualified-snake-kebab-opts` which are hash maps containing `:column-fn` and `:table-fn` that use the `->snake_case` function from the [camel-snake-kebab library](https://github.com/clj-commons/camel-snake-kebab/) which performs a more sophisticated transformation. +`next.jdbc` provides `snake-kebab-opts` and `unqualified-snake-kebab-opts` which are hash maps containing `:column-fn` and `:table-fn` that use the `->snake_case` function from the [camel-snake-kebab library](https://github.com/clj-commons/camel-snake-kebab/) which performs a more sophisticated transformation: + +```clojure +;; transforms :my-table to my_table as above but will also transform +;; column names; in addition, it will perform the reverse transformation +;; on any results, e.g., turning MySQL's :GENERATED_KEY into :generated-key +(sql/insert! ds :my-table {:some "data"} jdbc/snake-kebab-opts) +``` > Note: The entity naming function is passed a string, the result of calling `name` on the keyword passed in. Also note that the default quoting functions do not handle schema-qualified names, such as `dbo.table_name` -- `sql-server` would produce `[dbo.table_name]` from that. Use the `schema` function to wrap the quoting function if you need that behavior, e.g,. `{:table-fn (schema sql-server)}` which would produce `[dbo].[table_name]`. diff --git a/doc/getting-started.md b/doc/getting-started.md index 80429db..a41484b 100644 --- a/doc/getting-started.md +++ b/doc/getting-started.md @@ -154,6 +154,9 @@ In addition, two pre-built option hash maps are available in `next.jdbc`, that l * `snake-kebab-opts` -- provides `:column-fn`, `:table-fn`, `:label-fn`, `:qualifier-fn`, and `:builder-fn` that will convert Clojure identifiers in `:kebab-case` to SQL entities in `snake_case` and will produce result sets with qualified `:kebab-case` names from SQL entities that use `snake_case`, * `unqualified-snake-kebab-opts` -- provides `:column-fn`, `:table-fn`, `:label-fn`, `:qualifier-fn`, and `:builder-fn` that will convert Clojure identifiers in `:kebab-case` to SQL entities in `snake_case` and will produce result sets with _unqualified_ `:kebab-case` names from SQL entities that use `snake_case`. +You can `assoc` any additional options you need into these pre-built option hash maps +and pass the combined options into any of this library's functions. + > Note: Using `camel-snake-kebab` might also be helpful if your database has `camelCase` table and column names, although you'll have to provide `:column-fn` and `:table-fn` yourself as `->camelCase` from that library. Either way, consider relying on the _default_ result set builder first and avoid converting column and table names (see [Advantages of 'snake case': portability and ubiquity](https://vvvvalvalval.github.io/posts/clojure-key-namespacing-convention-considered-harmful.html#advantages_of_'snake_case':_portability_and_ubiquity) for an interesting discussion on kebab-case vs snake_case -- I do not agree with all of the author's points in that article, particularly his position against qualified keywords, but his argument for retaining snake_case around system boundaries is compelling). diff --git a/doc/result-set-builders.md b/doc/result-set-builders.md index d34936d..870112a 100644 --- a/doc/result-set-builders.md +++ b/doc/result-set-builders.md @@ -26,7 +26,7 @@ In addition, the following generic builders can take `:label-fn` and `:qualifier * `as-modified-arrays` -- table-qualified keywords, * `as-unqualified-modified-arrays` -- simple keywords. -An example builder that converts `snake_case` database table/column names to `kebab-case` keywords: +An example builder that naively converts `snake_case` database table/column names to `kebab-case` keywords: ```clojure (defn as-kebab-maps [rs opts] @@ -34,7 +34,9 @@ An example builder that converts `snake_case` database table/column names to `ke (result-set/as-modified-maps rs (assoc opts :qualifier-fn kebab :label-fn kebab)))) ``` -However, a version of `as-kebab-maps` is built-in, as is `as-unqualified-kebab-maps`, which both use the `->kebab-case` function from the [camel-snake-kebab library](https://github.com/clj-commons/camel-snake-kebab/) with `as-modified-maps` and `as-unqualified-modified-maps` respectively. +However, a version of `as-kebab-maps` is built-in, as is `as-unqualified-kebab-maps`, which both use the `->kebab-case` function from the [camel-snake-kebab library](https://github.com/clj-commons/camel-snake-kebab/) with `as-modified-maps` and `as-unqualified-modified-maps` respectively, so you can just use the built-in `result-set/as-kebab-maps` (or `result-set/as-unqualified-kebab-maps`) builder as a `:builder-fn` option instead of writing your own. + +> Note: `next.jdbc/snake-kebab-opts` and `next.jdbc/unqualified-snake-kebab-opts` exist, providing pre-built options hash maps that contain these `:builder-fn` options, as well as appropriate `:table-fn` and `:column-fn` options for the **Friendly SQL Functions** so those are often the most convenient way to enable snake/kebab case conversions with `next.jdbc`. And finally there are two styles of adapters for the existing builders that let you override the default way that columns are read from result sets. The first style takes a `column-reader` function, which is called with the `ResultSet`, the `ResultSetMetaData`, and the column index, and is expected to read the raw column value from the result set and return it. The result is then passed through `read-column-by-index` (from `ReadableColumn`, which may be implemented directly via protocol extension or via metadata on the result of the `column-reader` function):