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 []}))))))