From af382708e5494aaf6ed4d03c97e419aa60081700 Mon Sep 17 00:00:00 2001 From: Sean Corfield Date: Fri, 9 Apr 2021 15:58:56 -0700 Subject: [PATCH] Fixes #319 by making register-clause! idempotent Technically, it removes any instance of the clause from the ordering before it attempts to add it back in, allowing you to correct the order if you got it wrong. --- CHANGELOG.md | 1 + src/honey/sql.cljc | 37 ++++++++++++++++++++----------------- test/honey/sql_test.cljc | 8 ++++++++ 3 files changed, 29 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d335a2..8f8fa6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changes * 2.0.next in progress + * Fix #319 by ensuring `register-clause!` is idempotent. * Fix #317 by dropping qualifiers in `:set` clauses (just like we do with `:insert` columns). Note that you can still use explicit _dotted_ names if you want table qualification. * Fix #312 by adding `:raw` as a clause. There is no helper function equivalent (because it would be ambiguous whether you meant a function form -- `[:raw ..]` -- or a clause form -- `{:raw ..}`; and for the same reason, there is no `nest` helper function since that also works as a clause and as a function/special syntax). diff --git a/src/honey/sql.cljc b/src/honey/sql.cljc index f79ef19..4e58ee6 100644 --- a/src/honey/sql.cljc +++ b/src/honey/sql.cljc @@ -60,29 +60,32 @@ :with-data]) (defn- add-clause-before - "Low-level helper just to insert a new clause." + "Low-level helper just to insert a new clause. + + If the clause is already in the list, remove it." [order clause before] - (if before - (do - (when-not (contains? (set order) before) - (throw (ex-info (str "Unrecognized clause: " before) - {:known-clauses order}))) - (reduce (fn [v k] - (if (= k before) - (conj v clause k) - (conj v k))) - [] - order)) - (conj order clause))) + (let [clauses (set order) + order (if (contains? clauses clause) + (filterv #(not= % clause) order) + order)] + (if before + (do + (when-not (contains? clauses before) + (throw (ex-info (str "Unrecognized clause: " before) + {:known-clauses order}))) + (reduce (fn [v k] + (if (= k before) + (conj v clause k) + (conj v k))) + [] + order)) + (conj order clause)))) (def ^:private dialects {:ansi {:quote #(str \" % \")} :sqlserver {:quote #(str \[ % \])} :mysql {:quote #(str \` % \`) - :clause-order-fn (fn [order] - ;; MySQL :set has different priority - (-> (filterv (complement #{:set}) order) - (add-clause-before :set :where)))} + :clause-order-fn #(add-clause-before % :set :where)} :oracle {:quote #(str \" % \") :as false}}) ; should become defonce diff --git a/test/honey/sql_test.cljc b/test/honey/sql_test.cljc index e774603..1ccafa1 100644 --- a/test/honey/sql_test.cljc +++ b/test/honey/sql_test.cljc @@ -623,3 +623,11 @@ ORDER BY id = ? DESC (format {:insert-into :table :values [{:name name :enabled enabled}]}))))) + +(deftest issue-319-test + (testing "that registering a clause is idempotent" + (is (= ["FOO"] + (do + (sut/register-clause! :foo (constantly ["FOO"]) nil) + (sut/register-clause! :foo (constantly ["FOO"]) nil) + (format {:foo []}))))))