Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
move query assertions into separate fn
moving query assertions, making it compatible with vec
  • Loading branch information
ninanator committed Mar 14, 2016
commit 81d26345aafa2f3bc4c1bef647a509b752c57917
48 changes: 27 additions & 21 deletions src/yesql/generate.clj
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,11 @@
expected-keys
(conj expected-keys :?))))

(defn rewrite-query-for-jdbc
[tokens initial-args]
(defn sane-query? [tokens initial-args]
(let [{:keys [expected-keys expected-positional-count]} (analyse-statement-tokens tokens)
actual-keys (set (keys (dissoc initial-args :?)))
actual-keys (if (vector? initial-args)
(-> (mapcat keys initial-args) set (disj :?))
(-> (keys initial-args) set (disj :?)))
actual-positional-count (count (:? initial-args))
missing-keys (set/difference expected-keys actual-keys)]
(assert (empty? missing-keys)
Expand All @@ -48,24 +49,28 @@
["Query argument mismatch."
"Expected %d positional parameters. Got %d."
"Supply positional parameters as {:? [...]}"])
expected-positional-count actual-positional-count))
(let [[final-query final-parameters consumed-args]
(reduce (fn [[query parameters args] token]
(cond
(string? token) [(str query token)
parameters
args]
(symbol? token) (let [[arg new-args] (if (= '? token)
[(first (:? args)) (update-in args [:?] rest)]
[(get args (keyword token)) args])]
[(str query (args-to-placeholders arg))
(vec (if (in-list-parameter? arg)
(concat parameters arg)
(conj parameters arg)))
new-args])))
["" [] initial-args]
tokens)]
(concat [final-query] final-parameters))))
expected-positional-count actual-positional-count))))

(defn rewrite-query-for-jdbc
[tokens initial-args]
(sane-query? tokens initial-args)
(let [[final-query final-parameters consumed-args]
(reduce (fn [[query parameters args] token]
(cond
(string? token) [(str query token)
parameters
args]
(symbol? token) (let [[arg new-args] (if (= '? token)
[(first (:? args)) (update-in args [:?] rest)]
[(get args (keyword token)) args])]
[(str query (args-to-placeholders arg))
(vec (if (in-list-parameter? arg)
(concat parameters arg)
(conj parameters arg)))
new-args])))
["" [] initial-args]
tokens)]
(concat [final-query] final-parameters)))

;; Maintainer's note: clojure.java.jdbc.execute! returns a list of
;; rowcounts, because it takes a list of parameter groups. In our
Expand All @@ -80,6 +85,7 @@
(if (vector? params)
(let [full-query (apply str sql)
table-name (re-find insert-table-name-regex full-query)]
(sane-query? sql params)
(apply jdbc/insert! db table-name params))
(let [[rewritten-sql & rewritten-params] (rewrite-query-for-jdbc sql params)]
(jdbc/db-do-prepared-return-keys db rewritten-sql rewritten-params))))
Expand Down
7 changes: 6 additions & 1 deletion test/yesql/acceptance_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
{:connection connection})
(insert-person<! {:name "Bob"
:age 25}
{:connection connection} )))
{:connection connection})))

(expect 4 (count (find-older-than {:age 10})))

Expand All @@ -76,6 +76,11 @@
:age "Eamonn"}
{:connection derby-db}))

;;; Attempt insert with incorrect parameters
(expect SQLSyntaxErrorException
(insert-person<! [{:name "Mary" :height 20}
{:name "Parker" :age 20}]))

;; Drop
(expect (drop-person-table!))

Expand Down
17 changes: 12 additions & 5 deletions test/yesql/generate_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,20 @@
"SELECT * FROM users WHERE group_ids IN(:group_ids) AND parent_id = :parent_id"
{:group_ids [1 2]
:parent_id 3}
=> ["SELECT * FROM users WHERE group_ids IN(?,?) AND parent_id = ?" 1 2 3])
=> ["SELECT * FROM users WHERE group_ids IN(?,?) AND parent_id = ?" 1 2 3])

;;; Incorrect parameters.
(expect AssertionError
(rewrite-query-for-jdbc (tokenize "SELECT age FROM users WHERE country = :country AND name = :name")
{:country "gb"}))
(sane-query?
(tokenize "SELECT age FROM users WHERE country = :country AND name = :name")
{:country "gb"}))

(expect AssertionError
(rewrite-query-for-jdbc (tokenize "SELECT age FROM users WHERE country = ? AND name = ?")
{}))
(sane-query?
(tokenize "SELECT age FROM users WHERE country = ? AND name = ?")
{}))

(expect AssertionError
(sane-query?
(tokenize "INSERT INTO users (country, name) VALUES (:country, :name)")
[{:country "gb"} {:country "us"}]))