diff --git a/src/honeysql/format.clj b/src/honeysql/format.clj index 86c5ff5..6d48ccb 100644 --- a/src/honeysql/format.clj +++ b/src/honeysql/format.clj @@ -30,6 +30,8 @@ (def ^:dynamic *param-counter* nil) +(def ^:dynamic *all-param-counter* nil) + (def ^:dynamic *input-params* nil) (def ^:dynamic *fn-context?* false) @@ -42,7 +44,12 @@ :sqlserver #(str \[ % \]) :oracle #(str \" % \")}) +(def ^:private parameterizers + {:postgresql #(str "$" (swap! *all-param-counter* inc)) + :jdbc (constantly "?")}) + (def ^:dynamic *quote-identifier-fn* nil) +(def ^:dynamic *parameterizer* nil) (defn- undasherize [s] (string/replace s "-" "_")) @@ -204,6 +211,7 @@ :params - input parameters :quoting - quote style to use for identifiers; one of :ansi (PostgreSQL), :mysql, :sqlserver, or :oracle. Defaults to no quoting. + :parameterizer - style of parameter naming, one of :postgresql or :jdbc, defaults to :jdbc :return-param-names - when true, returns a vector of [sql-str param-values param-names]" [sql-map & params-or-opts] @@ -214,9 +222,11 @@ (:params opts))] (binding [*params* (atom []) *param-counter* (atom 0) + *all-param-counter* (atom 0) *param-names* (atom []) *input-params* (atom params) - *quote-identifier-fn* (quote-fns (:quoting opts))] + *quote-identifier-fn* (quote-fns (:quoting opts)) + *parameterizer* (parameterizers (or (:parameterizer opts) :jdbc))] (let [sql-str (to-sql sql-map)] (if (seq @*params*) (if (:return-param-names opts) @@ -306,7 +316,7 @@ [x (keyword (str "_" (swap! *param-counter* inc)))])] (swap! *param-names* conj pname) (swap! *params* conj x) - "?"))) + (*parameterizer*)))) (defn sqlable? [x] (satisfies? ToSql x)) diff --git a/test/honeysql/core_test.clj b/test/honeysql/core_test.clj index faa1e4b..e58c49c 100644 --- a/test/honeysql/core_test.clj +++ b/test/honeysql/core_test.clj @@ -56,7 +56,11 @@ "bort" "gabba" 2] (sql/format m1 {:param1 "gabba" :param2 2})))) (testing "SQL data prints and reads correctly" - (is (= m1 (read-string (pr-str m1))))))) + (is (= m1 (read-string (pr-str m1))))) + (testing "SQL data formats correctly with alternate param naming" + (is (= (sql/format m1 :params {:param1 "gabba" :param2 2} :parameterizer :postgresql) + ["SELECT DISTINCT f.*, b.baz, c.quux, b.bla AS bla_bla, now(), @x := 10 FROM foo f, baz b INNER JOIN draq ON f.b = draq.x LEFT JOIN clod c ON f.a = c.d RIGHT JOIN bock ON bock.z = c.e FULL JOIN beck ON beck.x = c.y WHERE ((f.a = $1 AND b.baz <> $2) OR (1 < 2 AND 2 < 3) OR (f.e in (1, $3, 3)) OR f.e BETWEEN 10 AND 20) GROUP BY f.a HAVING 0 < f.e ORDER BY b.baz DESC, c.quux LIMIT 50 OFFSET 10 " + "bort" "gabba" 2]))))) (deftest test-cast (is (= ["SELECT foo, CAST(bar AS integer)"]