From 4be9ec47fd4e0f2122af1b35079ad09fbe7dabd8 Mon Sep 17 00:00:00 2001 From: Alexander Kiel Date: Tue, 20 Oct 2015 10:45:01 +0200 Subject: [PATCH 01/14] Trims One Semicolon at the End of Each Statement If I use the defqueries mode where I have more than one query in one SQL file, I have a problem with my editor. I use IntelliJ and it likes to have semicolons at the end of each statement. Otherwise its not able to parse the statements and therefore can't provide error checking and other stuff. However my Oracle database does not like the semicolons if I run the query. --- src/yesql/queryfile_parser.clj | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/yesql/queryfile_parser.clj b/src/yesql/queryfile_parser.clj index 55e0856..9834d90 100644 --- a/src/yesql/queryfile_parser.clj +++ b/src/yesql/queryfile_parser.clj @@ -1,6 +1,6 @@ (ns yesql.queryfile-parser (:require [clojure.java.io :as io] - [clojure.string :refer [join trim]] + [clojure.string :as str :refer [join trim]] [instaparse.core :as instaparse] [yesql.types :refer [map->Query]] [yesql.util :refer [str-non-nil]] @@ -11,6 +11,9 @@ (assert url) (instaparse/parser url))) +(defn- rm-semicolon [s] + (str/replace s #";$" "")) + (def parser-transforms {:whitespace str-non-nil :non-whitespace str-non-nil @@ -22,7 +25,7 @@ :docstring (fn [& comments] [:docstring (trim (join (map second comments)))]) :statement (fn [& lines] - [:statement (trim (join lines))]) + [:statement (rm-semicolon (trim (join lines)))]) :query (fn [& args] (map->Query (into {} args))) :queries list}) From 3db8eeb5ed07c354d9f33697077218a4dece35c5 Mon Sep 17 00:00:00 2001 From: burhanloey Date: Mon, 7 Dec 2015 22:44:21 +0800 Subject: [PATCH 02/14] Fix typo: maxage->min_age --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7bb3ade..505d592 100644 --- a/README.md +++ b/README.md @@ -262,7 +262,7 @@ And then supply the `IN`-list as a vector, like so: {:connection db-spec}) (find-users {:id [1001 1003 1005] - :maxage 18}) + :min_age 18}) ``` The query will be automatically expanded to `... IN (1001, 1003, 1005) From c43b2a4c6d554114139afd783a9adc114d050e8a Mon Sep 17 00:00:00 2001 From: LionsHead Date: Sun, 7 Feb 2016 16:23:57 +0300 Subject: [PATCH 03/14] add link to php library Simply PHP verion. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9c9d347..2d6ccaa 100644 --- a/README.md +++ b/README.md @@ -383,6 +383,7 @@ Yesql has inspired ports to other languages: |Ruby|[yayql](https://github.com/gnarmis/yayql)| |Erlang|[eql](https://github.com/artemeff/eql)| |Clojure|[YeSPARQL](https://github.com/joelkuiper/yesparql)| +|PHP|[YepSQL](https://github.com/LionsHead/YepSQL)| ## Status From b7e08c4b1de7439c0d453542f852323991c8bbca Mon Sep 17 00:00:00 2001 From: iku000888 Date: Sun, 21 Feb 2016 00:38:45 +0900 Subject: [PATCH 04/14] Mention that h2 is also supported Happened to find out by booting a Luminus framework application with h2. (Luminus uses yesql by default) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9c9d347..ff38b54 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ check, because there may be a newer version available): |Oracle|`[com.oracle/ojdbc14 "10.2.0.4.0"]`| |SQLite|`[org.xerial/sqlite-jdbc "3.7.2"]`| |Derby|`[org.apache.derby/derby "10.11.1.1"]`| +|h2|`[com.h2database/h2 "1.4.191"]`| (Any database with a JDBC driver should work. If you know of a driver that's not listed here, please open a pull request to update this From d6a35c14f6424bbddddb0f474b08ae4c55f95ae3 Mon Sep 17 00:00:00 2001 From: Kris Jenkins Date: Mon, 22 Feb 2016 09:13:22 +0000 Subject: [PATCH 05/14] Correcting some README typos around country/country_code. --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 9c9d347..04791a3 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ query: -- name: users-by-country SELECT * FROM users -WHERE country_code = :country +WHERE country_code = :country_code ``` ...and then read that file to turn it into a regular Clojure function: @@ -76,8 +76,8 @@ WHERE country_code = :country ;;; A function with the name `users-by-country` has been created. ;;; Let's use it: -(users-by-country {:country "GB"}) -;=> ({:name "Kris" :country "GB" ...} ...) +(users-by-country {:country_code "GB"}) +;=> ({:name "Kris" :country_code "GB" ...} ...) ``` By keeping the SQL and Clojure separate you get: @@ -141,7 +141,7 @@ in the REPL: ;=> ------------------------- ;=> user/users-by-country -;=> ([{:keys [country_code]}] +;=> ([{:keys [country_code]}] ;=> [{:keys [country_code]} {:keys [connection]}]) ;=> ;=> Counts the users in a given country. @@ -151,15 +151,15 @@ Now we can use it: ```clojure ; Use it standalone. -(users-by-country {:country "GB"}) +(users-by-country {:country_code "GB"}) ;=> ({:count 58}) ; Use it in a clojure.java.jdbc transaction. (require '[clojure.java.jdbc :as jdbc]) (jdbc/with-db-transaction [tx db-spec] - {:limeys (users-by-country {:country "GB"} {:connection tx}) - :yanks (users-by-country {:country "US"} {:connection tx})}) + {:limeys (users-by-country {:country_code "GB"} {:connection tx}) + :yanks (users-by-country {:country_code "US"} {:connection tx})}) ``` ### One File, Many Queries From f22ca8be5b7797953147af07014fa8a4dd181f54 Mon Sep 17 00:00:00 2001 From: Kris Jenkins Date: Mon, 22 Feb 2016 09:14:30 +0000 Subject: [PATCH 06/14] Changing a parameter name in the README. maxage should be max_age, for consistency with the other examples. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 792fdcd..a817029 100644 --- a/README.md +++ b/README.md @@ -209,14 +209,14 @@ WHERE ( OR country_code = ? ) -AND age < :maxage +AND age < :max_age ``` Supply the `?` parameters as a vector under the `:?` key, like so: ```clojure (young-users-by-country {:? ["GB" "US"] - :maxage 18}) + :max_age 18}) ``` #### Selectively import queries From 6bc3518aa3d18a5b245eabf6d86767771e31fea7 Mon Sep 17 00:00:00 2001 From: Kris Jenkins Date: Thu, 24 Mar 2016 17:32:02 +0000 Subject: [PATCH 07/14] Updating the Derby dependency. --- project.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.clj b/project.clj index e9cb7cb..4410267 100644 --- a/project.clj +++ b/project.clj @@ -10,7 +10,7 @@ :scm {:name "git" :url "https://github.com/krisajenkins/yesql"} :profiles {:dev {:dependencies [[expectations "2.1.3" :exclusions [org.clojure/clojure]] - [org.apache.derby/derby "10.11.1.1"]] + [org.apache.derby/derby "10.12.1.1"]] :plugins [[lein-autoexpect "1.4.0"] [lein-expectations "0.0.8"]]} :1.5 {:dependencies [[org.clojure/clojure "1.5.1"]]} From 09e1a4cc6daf716bd9f89f5b7003304a3cc080ed Mon Sep 17 00:00:00 2001 From: Kris Jenkins Date: Wed, 27 Apr 2016 14:36:27 +0100 Subject: [PATCH 08/14] Bumping the base Clojure version to 1.8. --- project.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.clj b/project.clj index 4410267..3613f85 100644 --- a/project.clj +++ b/project.clj @@ -3,7 +3,7 @@ :url "https://github.com/krisajenkins/yesql" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} - :dependencies [[org.clojure/clojure "1.6.0"] + :dependencies [[org.clojure/clojure "1.8.0"] [org.clojure/java.jdbc "0.4.2"] [instaparse "1.4.1" :exclusions [org.clojure/clojure]]] :pedantic? :abort From ee86fb342f75c56917a89b449c4da71cba91b039 Mon Sep 17 00:00:00 2001 From: Kris Jenkins Date: Wed, 27 Apr 2016 14:39:33 +0100 Subject: [PATCH 09/14] Updating to JDBC 0.5.8. --- project.clj | 2 +- src/yesql/generate.clj | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/project.clj b/project.clj index 3613f85..907e88c 100644 --- a/project.clj +++ b/project.clj @@ -4,7 +4,7 @@ :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.8.0"] - [org.clojure/java.jdbc "0.4.2"] + [org.clojure/java.jdbc "0.5.8"] [instaparse "1.4.1" :exclusions [org.clojure/clojure]]] :pedantic? :abort :scm {:name "git" diff --git a/src/yesql/generate.clj b/src/yesql/generate.clj index 9ff489a..61209a7 100644 --- a/src/yesql/generate.clj +++ b/src/yesql/generate.clj @@ -76,8 +76,8 @@ (first (jdbc/execute! db sql-and-params))) (defn insert-handler - [db [statement & params] call-options] - (jdbc/db-do-prepared-return-keys db statement params)) + [db statement-and-params call-options] + (jdbc/db-do-prepared-return-keys db statement-and-params)) (defn query-handler [db sql-and-params @@ -87,9 +87,9 @@ result-set-fn doall} :as call-options}] (jdbc/query db sql-and-params - :identifiers identifiers - :row-fn row-fn - :result-set-fn result-set-fn)) + {:identifiers identifiers + :row-fn row-fn + :result-set-fn result-set-fn})) (defn generate-query-fn "Generate a function to run a query. From 17225841ff8b8a13c24079939098febcd0e54112 Mon Sep 17 00:00:00 2001 From: Kris Jenkins Date: Wed, 27 Apr 2016 14:46:19 +0100 Subject: [PATCH 10/14] Adding pedantic version exclusions. --- project.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.clj b/project.clj index 907e88c..04fe6a5 100644 --- a/project.clj +++ b/project.clj @@ -12,7 +12,7 @@ :profiles {:dev {:dependencies [[expectations "2.1.3" :exclusions [org.clojure/clojure]] [org.apache.derby/derby "10.12.1.1"]] :plugins [[lein-autoexpect "1.4.0"] - [lein-expectations "0.0.8"]]} + [lein-expectations "0.0.8" :exclusions [org.clojure/clojure]]]} :1.5 {:dependencies [[org.clojure/clojure "1.5.1"]]} :1.6 {:dependencies [[org.clojure/clojure "1.6.0"]]} :1.7 {:dependencies [[org.clojure/clojure "1.7.0"]]} From 55355c1a819b7f455b2667ad5e578dd9aa0fc71e Mon Sep 17 00:00:00 2001 From: Kris Jenkins Date: Wed, 27 Apr 2016 14:53:19 +0100 Subject: [PATCH 11/14] Version 0.5.3. --- project.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.clj b/project.clj index 04fe6a5..bdc49d3 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject yesql "0.5.2" +(defproject yesql "0.5.3" :description "A Clojure library for using SQL" :url "https://github.com/krisajenkins/yesql" :license {:name "Eclipse Public License" From 5d6002c6ce698a133f754d25e5ff32e9c57c50b5 Mon Sep 17 00:00:00 2001 From: Ian Barrick Date: Thu, 5 May 2016 16:28:04 -0400 Subject: [PATCH 12/14] changed assertion Error to Exception --- src/yesql/generate.clj | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/yesql/generate.clj b/src/yesql/generate.clj index 61209a7..80db969 100644 --- a/src/yesql/generate.clj +++ b/src/yesql/generate.clj @@ -5,7 +5,8 @@ [yesql.util :refer [create-root-var]] [yesql.types :refer [map->Query]] [yesql.statement-parser :refer [tokenize]]) - (:import [yesql.types Query])) + (:import [yesql.types Query]) + (import java.lang.IllegalArgumentException)) (def in-list-parameter? "Check if a type triggers IN-list expansion." @@ -38,17 +39,17 @@ actual-keys (set (keys (dissoc initial-args :?))) actual-positional-count (count (:? initial-args)) missing-keys (set/difference expected-keys actual-keys)] - (assert (empty? missing-keys) - (format "Query argument mismatch.\nExpected keys: %s\nActual keys: %s\nMissing keys: %s" + (if-not (empty? missing-keys) + (throw (IllegalArgumentException. (format "Query argument mismatch.\nExpected keys: %s\nActual keys: %s\nMissing keys: %s" (str (seq expected-keys)) (str (seq actual-keys)) - (str (seq missing-keys)))) - (assert (= expected-positional-count actual-positional-count) - (format (join "\n" + (str (seq missing-keys)))))) + (if-not (= expected-positional-count actual-positional-count) + (throw (IllegalArgumentException. (format (join "\n" ["Query argument mismatch." "Expected %d positional parameters. Got %d." "Supply positional parameters as {:? [...]}"]) - expected-positional-count actual-positional-count)) + expected-positional-count actual-positional-count)))) (let [[final-query final-parameters consumed-args] (reduce (fn [[query parameters args] token] (cond From b6de24755acefc5c72bdd72b8bf80fbf1f98ead8 Mon Sep 17 00:00:00 2001 From: Ian Barrick Date: Thu, 5 May 2016 16:37:55 -0400 Subject: [PATCH 13/14] changed test cases --- test/yesql/generate_test.clj | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/yesql/generate_test.clj b/test/yesql/generate_test.clj index 3b0e4f5..cba9077 100644 --- a/test/yesql/generate_test.clj +++ b/test/yesql/generate_test.clj @@ -2,7 +2,8 @@ (:require [expectations :refer :all] [clojure.template :refer [do-template]] [yesql.statement-parser :refer [tokenize]] - [yesql.generate :refer :all])) + [yesql.generate :refer :all]) + (:import [java.lang IllegalArgumentException])) (do-template [statement _ expected-parameters] (expect expected-parameters @@ -82,13 +83,13 @@ "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 +(expect IllegalArgumentException (rewrite-query-for-jdbc (tokenize "SELECT age FROM users WHERE country = :country AND name = :name") {:country "gb"})) -(expect AssertionError +(expect IllegalArgumentException (rewrite-query-for-jdbc (tokenize "SELECT age FROM users WHERE country = ? AND name = ?") {})) From d634f7d6469322753e48ce5649e6710af8278f49 Mon Sep 17 00:00:00 2001 From: Ian Barrick Date: Mon, 20 Jun 2016 18:37:41 -0400 Subject: [PATCH 14/14] added batch insert support --- project.clj | 2 +- src/yesql/generate.clj | 50 ++++++++++++++++++++++++++---------------- 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/project.clj b/project.clj index bdc49d3..729872f 100644 --- a/project.clj +++ b/project.clj @@ -11,7 +11,7 @@ :url "https://github.com/krisajenkins/yesql"} :profiles {:dev {:dependencies [[expectations "2.1.3" :exclusions [org.clojure/clojure]] [org.apache.derby/derby "10.12.1.1"]] - :plugins [[lein-autoexpect "1.4.0"] + :plugins [[lein-autoexpect "1.4.0" :exclusions [org.clojure/tools.namespace]] [lein-expectations "0.0.8" :exclusions [org.clojure/clojure]]]} :1.5 {:dependencies [[org.clojure/clojure "1.5.1"]]} :1.6 {:dependencies [[org.clojure/clojure "1.6.0"]]} diff --git a/src/yesql/generate.clj b/src/yesql/generate.clj index 80db969..bfdf2b5 100644 --- a/src/yesql/generate.clj +++ b/src/yesql/generate.clj @@ -36,7 +36,7 @@ (defn rewrite-query-for-jdbc [tokens initial-args] (let [{:keys [expected-keys expected-positional-count]} (analyse-statement-tokens tokens) - actual-keys (set (keys (dissoc initial-args :?))) + actual-keys (set (keys (dissoc (if (or (vector? initial-args) (list? initial-args)) (apply merge initial-args) initial-args) :?))) actual-positional-count (count (:? initial-args)) missing-keys (set/difference expected-keys actual-keys)] (if-not (empty? missing-keys) @@ -50,23 +50,33 @@ "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)))) + (if (or (vector? initial-args) (list? 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) [(str query (args-to-placeholders "")) + (conj parameters (keyword token)) + args])) ["" [] initial-args] tokens)] (concat [final-query] (mapv (apply juxt final-parameters) 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 @@ -78,7 +88,9 @@ (defn insert-handler [db statement-and-params call-options] - (jdbc/db-do-prepared-return-keys db statement-and-params)) + (if (vector? (second statement-and-params)) + (apply jdbc/db-do-prepared db statement-and-params) + (jdbc/db-do-prepared-return-keys db statement-and-params))) (defn query-handler [db sql-and-params