Skip to content

Commit db12f87

Browse files
committed
More annotations.
1 parent 3422915 commit db12f87

5 files changed

Lines changed: 112 additions & 75 deletions

File tree

project.clj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
:1.5 {:dependencies [[org.clojure/clojure "1.5.1"]]}
1717
:1.6 {:dependencies [[org.clojure/clojure "1.6.0"]]}
1818
:1.7 {:dependencies [[org.clojure/clojure "1.7.0-alpha1"]]}}
19-
:core.typed {:check [yesql.util yesql.parser]}
19+
:core.typed {:check [yesql.annotations yesql.util yesql.parser yesql.types]}
2020
:aliases {"test-all" ["do"
2121
["typed" "check"]
2222
["with-profile" "+1.5:+1.6:+1.7" "expectations"]]

src/yesql/annotations.clj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
(ns yesql.annotations
2-
(:require [clojure.core.typed :refer [ann Option Seq IFn]])
2+
(:require [clojure.core.typed :as t :refer [ann Option Seq Seqable IFn U Any]])
33
(:import [java.net URL]))
44

5-
(ann ^:no-check clojure.java.io/resource [String -> (Option URL)])
6-
(ann ^:no-check clojure.core/slurp (IFn [(java.net.URL) -> String]))
5+
(ann ^:no-check clojure.core/slurp (IFn [java.net.URL -> String]))
76
(ann ^:no-check clojure.core/re-matches [java.util.regex.Pattern String -> (Seq String)])
7+
(ann ^:no-check clojure.java.io/resource [String -> (Option URL)])

src/yesql/parser.clj

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,29 @@
11
(ns yesql.parser
22
(:require [clojure.java.io :as io]
33
[clojure.string :refer [join trim]]
4-
[clojure.core.typed :as t :refer [ann U]]
4+
[clojure.core.typed :as t :refer [ann tc-ignore U Seqable Option Any Seq Keyword IFn Map All HSequential]]
55
[instaparse.core :as instaparse]
66
[yesql.types :refer [map->Query]]
77
[yesql.util :refer [process-instaparse-result str-non-nil]]
88
[yesql.annotations])
99
(:import [java.net URL]))
1010

11-
(ann instaparse/parser [(U String URL) -> instaparse.core.Parser])
11+
(ann ^:no-check instaparse.core/parser [(U String URL) -> instaparse.core.Parser])
12+
(ann ^:no-check instaparse.core/parses
13+
[instaparse.core.Parser String & :optional {:start Keyword} -> (Seqable Any)])
14+
(ann ^:no-check instaparse.core/failure? [Any -> Boolean])
15+
(ann ^:no-check instaparse.core/transform
16+
(All [x]
17+
[(Map Keyword (IFn [Any * -> x])) (Seqable Any) -> (Seqable x)]))
1218

1319
(ann parser instaparse.core.Parser)
1420
(def parser
15-
(some-> "yesql/defqueries.bnf"
16-
io/resource
17-
instaparse/parser))
21+
(let [url (io/resource "yesql/defqueries.bnf")]
22+
(assert url)
23+
(instaparse/parser url)))
1824

19-
(t/tc-ignore
25+
26+
(tc-ignore
2027
(def parser-transforms
2128
{:whitespace str-non-nil
2229
:non-whitespace str-non-nil
@@ -33,13 +40,13 @@
3340
(map->Query (apply merge {} args)))
3441
:queries list}))
3542

36-
37-
(t/tc-ignore
38-
(defn parse-tagged-queries
39-
"Parses a string with Yesql's defqueries syntax into a sequence of `yesql.types.Query` records."
40-
[text]
41-
(process-instaparse-result
42-
(instaparse/transform parser-transforms
43-
(instaparse/parses parser
44-
(str text "\n") ;;; TODO This is a workaround for files with no end-of-line marker.
45-
:start :queries)))))
43+
(ann ^:no-check parse-tagged-queries
44+
[String -> (Seq yesql.types.Query)])
45+
(defn parse-tagged-queries
46+
"Parses a string with Yesql's defqueries syntax into a sequence of maps."
47+
[text]
48+
(process-instaparse-result
49+
(instaparse/transform parser-transforms
50+
(instaparse/parses parser
51+
(str text "\n") ;;; TODO This is a workaround for files with no end-of-line marker.
52+
:start :queries))))

src/yesql/types.clj

Lines changed: 50 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,77 @@
11
(ns yesql.types
22
(: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]]
34
[yesql.named-parameters :refer [split-at-parameters reassemble-query]]
45
[yesql.util :refer [distinct-except slurp-from-classpath]]))
56

67
;; ## Protocol
7-
(defprotocol Definable
8-
(emit-def [query]))
8+
(t/defprotocol Definable
9+
(emit-def [this] :- (t/List Any)))
910

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])
1515

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
1727
"Use the split-up query string to create the different kinds of argument lists:
1828
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.
2232
23-
The result will be a map with these fields."
33+
The result will be a map with these fields."
2434
[split-query]
2535
(let [args (filterv symbol? split-query)
2636
query-args (mapv replace-question-mark-with-gensym args)]
2737
{:query-args query-args
2838
:function-args (distinct query-args)
29-
:display-args (distinct-except #{'?} args)}))
39+
:display-args (distinct-except #{'?} args)})))
3040

31-
(defn- fn-symbol
41+
(tc-ignore
42+
(defn- fn-symbol
3243
"Attach metadata (docstring/argument lists) to the given symbol."
3344
[id docstring statement display-args]
3445
(with-meta id
3546
{:arglists `(quote ([~'db ~@display-args]))
3647
:doc (or docstring "")
37-
::source (str statement)}))
48+
::source (str statement)})))
3849

3950
;; Maintainer's note: clojure.java.jdbc.execute! returns a list of
4051
;; rowcounts, because it takes a list of parameter groups. In our
4152
;; case, we only ever use one group, so we'll unpack the
4253
;; single-element list with `first`.
43-
(defn execute-handler
44-
[db sql-and-params]
45-
(first (jdbc/execute! db sql-and-params)))
4654

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)))
5064

65+
;; (ann emit-query-fn
66+
;; [Query -> (t/List Any)])
67+
68+
(ann ^:no-check emit-query-fn [Query -> (t/List Any)])
5169
(defn- emit-query-fn
5270
"Emit function to run a query.
5371
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."
5775
[{:keys [name docstring statement]}]
5876
(let [split-query (split-at-parameters statement)
5977
{:keys [query-args display-args function-args]} (split-query->args split-query)
@@ -68,7 +86,13 @@
6886
~query-args))))))
6987

7088
;; ## Query Emitter
71-
(defrecord Query [name docstring statement]
72-
Definable
89+
(extend-protocol Definable
90+
Query
7391
(emit-def [this]
7492
(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])

src/yesql/util.clj

Lines changed: 35 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,32 @@
33
(:require [clojure.java.io :as io]
44
[instaparse.core :as instaparse]
55
[clojure.string :as string]
6-
[clojure.core.typed :refer [ann cf tc-ignore Seq Option All IFn U Nothing]]
6+
[clojure.core.typed :as t :refer [ann Seqable Option All IFn U Any]]
77
[yesql.annotations])
88
(:import (java.io FileNotFoundException StringWriter)
99
(java.net URL)))
1010

11+
(ann ^:no-check instaparse.core/get-failure [Any -> (Option instaparse.gll.Failure)])
12+
(ann ^:no-check instaparse.failure/pprint-failure [instaparse.gll.Failure -> nil])
13+
1114
(ann distinct-except
1215
(All [x]
13-
[[x -> Boolean] (Option (Seq x)) -> (Option (Seq x))]))
16+
[[(Option x) -> Any] (Option (Seqable x)) -> (Seqable (Option x))]))
1417
(defn distinct-except
1518
"Same as distinct, but keeps duplicates if they pass exception?"
16-
[exception? [head & tail :as coll]]
19+
[exception? coll]
1720
(lazy-seq
18-
(when head
21+
(when-let [[head & tail] (seq coll)]
1922
(cons head
2023
(distinct-except exception?
2124
(if (exception? head)
2225
tail
23-
(remove (partial = head) tail)))))))
26+
(remove #(= head %)
27+
tail)))))))
2428

2529
(ann whitespace?
2630
(IFn [nil -> false]
27-
[String -> Boolean]))
31+
[String -> Boolean]))
2832
(defn whitespace?
2933
[string]
3034
(if string
@@ -34,38 +38,40 @@
3438

3539
(ann underscores-to-dashes
3640
(IFn [nil -> nil]
37-
[String -> String]))
41+
[String -> String]))
3842
(defn underscores-to-dashes
3943
[string]
4044
(when string
4145
(string/replace string "_" "-")))
4246

43-
(ann str-non-nil [String * -> String])
47+
(ann str-non-nil [Any * -> String])
4448
(defn str-non-nil
4549
"Exactly like `clojure.core/str`, except it returns an empty string
46-
with no args (whereas `str` would return `nil`)."
50+
with no args (whereas `str` would return `nil`)."
4751
[& args]
4852
(apply str "" args))
4953

5054
(ann slurp-from-classpath
51-
[String -> (U String Nothing)])
52-
(tc-ignore
53-
(defn slurp-from-classpath
54-
"Slurps a file from the classpath."
55-
[path]
56-
(if-let [url (io/resource path)]
57-
(slurp url)
58-
(throw (FileNotFoundException. path)))))
55+
[String -> (Option String)])
56+
(defn slurp-from-classpath
57+
"Slurps a file from the classpath."
58+
[path]
59+
(or (some-> path
60+
io/resource
61+
slurp)
62+
(throw (FileNotFoundException. path))))
5963

60-
(tc-ignore
61-
(defn process-instaparse-result
62-
[parsed]
63-
(cond
64-
(instaparse/failure? parsed) (let [failure (instaparse/get-failure parsed)]
65-
(binding [*out* (StringWriter.)]
66-
(instaparse.failure/pprint-failure failure)
67-
(throw (ex-info (.toString *out*)
68-
failure))))
69-
(< 1 (count parsed)) (throw (ex-info "Ambiguous parse - please report this as a bug at https://github.com/krisajenkins/yesql/issues"
70-
{:variations (count parsed)}))
71-
:else (first parsed))))
64+
(ann process-instaparse-result
65+
(All [x]
66+
[(Seqable x) -> (Option x)]))
67+
(defn process-instaparse-result
68+
[parsed]
69+
(if-let [failure (instaparse/get-failure parsed)]
70+
(binding [*out* (StringWriter.)]
71+
(instaparse.failure/pprint-failure failure)
72+
(throw (ex-info (.toString *out*)
73+
failure)))
74+
(if (second parsed)
75+
(throw (ex-info "Ambiguous parse - please report this as a bug at https://github.com/krisajenkins/yesql/issues"
76+
{:variations (count parsed)}))
77+
(first parsed))))

0 commit comments

Comments
 (0)