|
1 | 1 | (ns yesql.types |
2 | 2 | (:require [clojure.java.jdbc :as jdbc] |
| 3 | + [clojure.core.typed :as t :refer [ann defalias U Seqable Option Any Seq Keyword IFn Map HMap tc-ignore Symbol]] |
3 | 4 | [yesql.named-parameters :refer [split-at-parameters reassemble-query]] |
4 | 5 | [yesql.util :refer [distinct-except slurp-from-classpath]])) |
5 | 6 |
|
6 | 7 | ;; ## Protocol |
7 | | -(defprotocol Definable |
8 | | - (emit-def [query])) |
| 8 | +(t/defprotocol Definable |
| 9 | + (emit-def [this] :- (t/List Any))) |
9 | 10 |
|
10 | | -(defn- replace-question-mark-with-gensym |
11 | | - [parameter] |
12 | | - (if (= parameter '?) |
13 | | - (gensym "P_") |
14 | | - parameter)) |
| 11 | +(t/ann-record Query [name :- String |
| 12 | + docstring :- String |
| 13 | + statement :- String]) |
| 14 | +(defrecord Query [name docstring statement]) |
15 | 15 |
|
16 | | -(defn- split-query->args |
| 16 | +;; (ann replace-question-mark-with-gensym |
| 17 | +;; [Symbol -> Symbol]) |
| 18 | +(tc-ignore |
| 19 | + (defn- replace-question-mark-with-gensym |
| 20 | + [parameter] |
| 21 | + (if (= parameter '?) |
| 22 | + (gensym "P_") |
| 23 | + parameter))) |
| 24 | + |
| 25 | +(tc-ignore |
| 26 | + (defn- split-query->args |
17 | 27 | "Use the split-up query string to create the different kinds of argument lists: |
18 | 28 |
|
19 | | - - `:query-args`: the symbols for the tail of the query vector, |
20 | | - - `:function-args`: the symbols for the query assembly and execution functions, |
21 | | - - `:display-args`: the symbols to be attached in the metadata. |
| 29 | + - `:query-args`: the symbols for the tail of the query vector, |
| 30 | + - `:function-args`: the symbols for the query assembly and execution functions, |
| 31 | + - `:display-args`: the symbols to be attached in the metadata. |
22 | 32 |
|
23 | | - The result will be a map with these fields." |
| 33 | + The result will be a map with these fields." |
24 | 34 | [split-query] |
25 | 35 | (let [args (filterv symbol? split-query) |
26 | 36 | query-args (mapv replace-question-mark-with-gensym args)] |
27 | 37 | {:query-args query-args |
28 | 38 | :function-args (distinct query-args) |
29 | | - :display-args (distinct-except #{'?} args)})) |
| 39 | + :display-args (distinct-except #{'?} args)}))) |
30 | 40 |
|
31 | | -(defn- fn-symbol |
| 41 | +(tc-ignore |
| 42 | + (defn- fn-symbol |
32 | 43 | "Attach metadata (docstring/argument lists) to the given symbol." |
33 | 44 | [id docstring statement display-args] |
34 | 45 | (with-meta id |
35 | 46 | {:arglists `(quote ([~'db ~@display-args])) |
36 | 47 | :doc (or docstring "") |
37 | | - ::source (str statement)})) |
| 48 | + ::source (str statement)}))) |
38 | 49 |
|
39 | 50 | ;; Maintainer's note: clojure.java.jdbc.execute! returns a list of |
40 | 51 | ;; rowcounts, because it takes a list of parameter groups. In our |
41 | 52 | ;; case, we only ever use one group, so we'll unpack the |
42 | 53 | ;; single-element list with `first`. |
43 | | -(defn execute-handler |
44 | | - [db sql-and-params] |
45 | | - (first (jdbc/execute! db sql-and-params))) |
46 | 54 |
|
47 | | -(defn insert-handler |
48 | | - [db [statement & params]] |
49 | | - (jdbc/db-do-prepared-return-keys db statement params)) |
| 55 | +(tc-ignore |
| 56 | + (defn execute-handler |
| 57 | + [db sql-and-params] |
| 58 | + (first (jdbc/execute! db sql-and-params)))) |
| 59 | + |
| 60 | +(tc-ignore |
| 61 | + (defn insert-handler |
| 62 | + [db [statement & params]] |
| 63 | + (jdbc/db-do-prepared-return-keys db statement params))) |
50 | 64 |
|
| 65 | +;; (ann emit-query-fn |
| 66 | +;; [Query -> (t/List Any)]) |
| 67 | + |
| 68 | +(ann ^:no-check emit-query-fn [Query -> (t/List Any)]) |
51 | 69 | (defn- emit-query-fn |
52 | 70 | "Emit function to run a query. |
53 | 71 |
|
54 | | - - If the query name ends in `!` it will call `clojure.java.jdbc/execute!`, |
55 | | - - If the query name ends in `<!` it will call `clojure.java.jdbc/insert!`, |
56 | | - - otherwise `clojure.java.jdbc/query` will be used." |
| 72 | + - If the query name ends in `!` it will call `clojure.java.jdbc/execute!`, |
| 73 | + - If the query name ends in `<!` it will call `clojure.java.jdbc/insert!`, |
| 74 | + - otherwise `clojure.java.jdbc/query` will be used." |
57 | 75 | [{:keys [name docstring statement]}] |
58 | 76 | (let [split-query (split-at-parameters statement) |
59 | 77 | {:keys [query-args display-args function-args]} (split-query->args split-query) |
|
68 | 86 | ~query-args)))))) |
69 | 87 |
|
70 | 88 | ;; ## Query Emitter |
71 | | -(defrecord Query [name docstring statement] |
72 | | - Definable |
| 89 | +(extend-protocol Definable |
| 90 | + Query |
73 | 91 | (emit-def [this] |
74 | 92 | (emit-query-fn this))) |
| 93 | + |
| 94 | +;; (ann yesql.types/map->Query |
| 95 | +;; [(HMap :mandatory {:name String |
| 96 | +;; :docstring String |
| 97 | +;; :statement String}) |
| 98 | +;; -> yesql.types.Query]) |
0 commit comments