diff --git a/doc/prepared-statements.md b/doc/prepared-statements.md index 02852b7..5cc1e63 100644 --- a/doc/prepared-statements.md +++ b/doc/prepared-statements.md @@ -23,14 +23,17 @@ You can provide the parameters in the `prepare` call or you can provide them via ## Prepared Statement Parameters -If parameters are provided in the vector along with the SQL statement, in the call to `prepare`, then `set-parameter` is called for each of them. This is part of the `SettableParameter` protocol: +If parameters are provided in the vector along with the SQL statement, in the call to `prepare`, then `set-parameter` is behind the scenes called for each of them. This is part of the `SettableParameter` protocol: * `(set-parameter v ps i)` -- by default this calls `(.setObject ps i v)` (for `nil` and `Object`) -This can be extended to any Clojure data type, to provide a customized way to add specific types of values as parameters to any `PreparedStatement`. For example, to have all `java.time.LocalDate` and `java.time.LocalDateTime` objects converted to `java.sql.Timestamp` automatically: +This can be extended to any Clojure data type, to provide a customized way to add specific types of values as parameters to any `PreparedStatement`. For example, to have all `java.time.Instant`, `java.time.LocalDate` and `java.time.LocalDateTime` objects converted to `java.sql.Timestamp` automatically: ```clojure (extend-protocol p/SettableParameter + java.time.Instant + (set-parameter [^java.time.Instant v ^PreparedStatement s ^long i] + (.setTimestamp ps i (java.sql.Timestamp/from v))) java.time.LocalDate (set-parameter [^java.time.LocalDate v ^PreparedStatement s ^long i] (.setTimestamp ps i (java.sql.Timestamp/valueOf (.atStartOfDay v)))) @@ -55,6 +58,8 @@ If you need more specialized parameter handling than the protocol can provide, t By default, `next.jdbc` assumes that you are providing a single set of parameter values and then executing the prepared statement. If you want to run a single prepared statement with multiple groups of parameters, you might want to take advantage of the increased performance that may come from using JDBC's batching machinery. +You could do this manually: + ```clojure ;; assuming require next.jdbc.prepare :as p (with-open [con (jdbc/get-connection ds) @@ -78,7 +83,7 @@ Here we set parameters and add them in batches to the prepared statement, then w (.executeBatch ps)) ; returns int[] ``` -A helper function is provided in `next.jdbc.prepare` to automate the execution of batched parameters: +Both of those are somewhat ugly and contain a fair bit of boilerplate and Java interop, so a helper function is provided in `next.jdbc.prepare` to automate the execution of batched parameters: ```clojure (with-open [con (jdbc/get-connection ds) diff --git a/doc/result-set-builders.md b/doc/result-set-builders.md index 072be8c..7307756 100644 --- a/doc/result-set-builders.md +++ b/doc/result-set-builders.md @@ -73,7 +73,18 @@ In addition, inside `plan`, as each value is looked up by name in the current st The default implementation of this protocol is for these two functions to return `nil` as `nil`, a `Boolean` value as a canonical `true` or `false` value (unfortunately, JDBC drivers cannot be relied on to return unique values here!), and for all other objects to be returned as-is. -Common extensions here could include converting `java.sql.Timestamp` to `java.time.Instant` for example but `next.jdbc` makes no assumptions beyond `nil` and `Boolean`. +`next.jdbc` makes no assumptions beyond `nil` and `Boolean`, but common extensions here could include converting `java.sql.Timestamp` to `java.time.Instant` for example: + +```clojure +(extend-protocol rs/ReadableColumn + java.sql.Timestamp + (read-column-by-label ^java.time.Instant [^java.sql.Timestamp v _] + (.toInstant v)) + (read-column-by-index ^java.time.Instant [^java.sql.Timestamp v _2 _3] + (.toInstant v))) +``` + +Remember that a protocol extension will apply to all code running in your application so with the above code **all** timestamp values coming from the database will be converted to `java.time.Instant` for all queries. Note that the converse, converting Clojure values to database-specific types is handled by the `SettableParameters`, discussed in the next section (Prepared Statements).