improve performance of optional arguments

Signed-off-by: Sean Corfield <sean@corfield.org>
This commit is contained in:
Sean Corfield 2024-10-11 09:12:07 -07:00
parent 203e923f99
commit a187ba98f1
No known key found for this signature in database
2 changed files with 216 additions and 203 deletions

View file

@ -2,6 +2,7 @@
* 2.6.next in progress * 2.6.next in progress
* Fix [#548](https://github.com/seancorfield/honeysql/issues/548) which was a regression introduced in [#526](https://github.com/seancorfield/honeysql/issues/526). * Fix [#548](https://github.com/seancorfield/honeysql/issues/548) which was a regression introduced in [#526](https://github.com/seancorfield/honeysql/issues/526).
* Replace all optional argument destructuring with multiple arities to improve performance.
* 2.6.1196 -- 2024-10-06 * 2.6.1196 -- 2024-10-06
* Address [#547](https://github.com/seancorfield/honeysql/issues/547) by adding examples of conditional SQL building with the helpers to the README and the `honey.sql.helpers` ns docstring. * Address [#547](https://github.com/seancorfield/honeysql/issues/547) by adding examples of conditional SQL building with the helpers to the README and the `honey.sql.helpers` ns docstring.

View file

@ -279,7 +279,8 @@
return the equivalent SQL fragment (as a string -- no parameters). return the equivalent SQL fragment (as a string -- no parameters).
Handles quoting, splitting at / or ., replacing - with _ etc." Handles quoting, splitting at / or ., replacing - with _ etc."
[e & [{:keys [aliased drop-ns]}]] ([e] (format-entity e {}))
([e {:keys [aliased drop-ns]}]
(let [e (if (and aliased (keyword? e) (str/starts-with? (name e) "'")) (let [e (if (and aliased (keyword? e) (str/starts-with? (name e) "'"))
;; #497 quoted alias support (should behave like string) ;; #497 quoted alias support (should behave like string)
(subs (name e) 1) (subs (name e) 1)
@ -320,7 +321,7 @@
parts (parts-fn col-e) parts (parts-fn col-e)
entity (join "." (map #(cond-> % (not= "*" %) (quote-fn))) parts)] entity (join "." (map #(cond-> % (not= "*" %) (quote-fn))) parts)]
(suspicious-entity-check entity) (suspicious-entity-check entity)
entity)) entity)))
(comment (comment
(for [v [:foo-bar "foo-bar" ; symbol is the same as keyword (for [v [:foo-bar "foo-bar" ; symbol is the same as keyword
@ -415,19 +416,23 @@
[x] [x]
(upper-case (str/replace (name x) "-" "_"))) (upper-case (str/replace (name x) "-" "_")))
(defn- format-simple-var [x & [c opts]] (defn- format-simple-var
(let [c (or c ([x]
(if (keyword? x) (let [c (if (keyword? x)
#?(:clj (str (.sym ^clojure.lang.Keyword x)) ;; Omits leading colon #?(:clj (str (.sym ^clojure.lang.Keyword x)) ;; Omits leading colon
:default (subs (str x) 1)) :default (subs (str x) 1))
(str x)))] (str x))]
(format-simple-var x c {})))
([x c opts]
(if (str/starts-with? c "'") (if (str/starts-with? c "'")
(do (do
(reset! *formatted-column* true) (reset! *formatted-column* true)
[(subs c 1)]) [(subs c 1)])
[(format-entity x opts)]))) [(format-entity x opts)])))
(defn- format-var [x & [opts]] (defn- format-var
([x] (format-var x {}))
([x opts]
;; rather than name/namespace, we want to allow ;; rather than name/namespace, we want to allow
;; for multiple / in the %fun.call case so that ;; for multiple / in the %fun.call case so that
;; qualified column names can be used: ;; qualified column names can be used:
@ -449,7 +454,7 @@
:else :else
["?" (->param k)])) ["?" (->param k)]))
:else :else
(format-simple-var x c opts)))) (format-simple-var x c opts)))))
(defn- format-entity-alias [x] (defn- format-entity-alias [x]
(cond (sequential? x) (cond (sequential? x)
@ -577,7 +582,8 @@
"If the expression has metadata, format it as a sequence of keywords, "If the expression has metadata, format it as a sequence of keywords,
treating `:foo true` as `FOO` and `:foo :bar` as `FOO BAR`. treating `:foo true` as `FOO` and `:foo :bar` as `FOO BAR`.
Return nil if there is no metadata." Return nil if there is no metadata."
[x & [sep]] ([x] (format-meta x nil))
([x sep]
(when-let [data (meta x)] (when-let [data (meta x)]
(let [items (reduce-kv (fn [acc k v] (let [items (reduce-kv (fn [acc k v]
(cond (number? v) (cond (number? v)
@ -600,7 +606,7 @@
:end-line :end-column] :end-line :end-column]
*ignored-metadata*)))] *ignored-metadata*)))]
(when (seq items) (when (seq items)
(join (str sep " ") (map sql-kw) items))))) (join (str sep " ") (map sql-kw) items))))))
(comment (comment
(format-meta ^{:foo true :bar :baz :original {:line 1} :top 10} []) (format-meta ^{:foo true :bar :baz :original {:line 1} :top 10} [])
@ -650,7 +656,9 @@
(into params') (into params')
(into params''))))) (into params'')))))
(defn- format-selectable-dsl [x & [{:keys [as aliased] :as opts}]] (defn- format-selectable-dsl
([x] (format-selectable-dsl x {}))
([x {:keys [as aliased] :as opts}]
(cond (map? x) (cond (map? x)
(format-dsl x {:nested true}) (format-dsl x {:nested true})
@ -666,7 +674,7 @@
[(format-entity x opts)] [(format-entity x opts)]
:else :else
(format-expr x))) (format-expr x))))
(defn- reduce-sql (defn- reduce-sql
([xs] (reduce-sql identity xs)) ([xs] (reduce-sql identity xs))
@ -699,7 +707,8 @@
This allows for argument lists like: This allows for argument lists like:
* [:overlay :foo :*placing :?subs :*from 3 :*for 4] * [:overlay :foo :*placing :?subs :*from 3 :*for 4]
* [:trim :*leading-from :bar]" * [:trim :*leading-from :bar]"
[args & [opts]] ([args] (format-interspersed-expr-list args {}))
([args opts]
(loop [exprs (keep #(when-not (inline-kw? %) (loop [exprs (keep #(when-not (inline-kw? %)
(format-expr % opts)) (format-expr % opts))
args) args)
@ -723,7 +732,7 @@
(into params) (into params)
(into params'))))) (into params')))))
(recur (rest exprs) args' false (conj result (first exprs)))))) (recur (rest exprs) args' false (conj result (first exprs))))))
(reduce-sql result)))) (reduce-sql result)))))
(comment (comment
(format-interspersed-expr-list [:foo :*placing :?subs :*from 3 :*for 4] (format-interspersed-expr-list [:foo :*placing :?subs :*from 3 :*for 4]
@ -744,12 +753,13 @@
This is intended to be used when writing your own formatters to This is intended to be used when writing your own formatters to
extend the DSL supported by HoneySQL." extend the DSL supported by HoneySQL."
[exprs & [opts]] ([exprs] (format-expr-list exprs {}))
([exprs opts]
(when-not (sequential? exprs) (when-not (sequential? exprs)
(throw (ex-info (str "format-expr-list expects a sequence of expressions, found: " (throw (ex-info (str "format-expr-list expects a sequence of expressions, found: "
(type exprs)) (type exprs))
{:exprs exprs}))) {:exprs exprs})))
(reduce-sql (map #(format-expr % opts)) exprs)) (reduce-sql (map #(format-expr % opts)) exprs)))
(comment (comment
(format-expr-list :?tags) (format-expr-list :?tags)
@ -1617,7 +1627,8 @@
This is intended to be used when writing your own formatters to This is intended to be used when writing your own formatters to
extend the DSL supported by HoneySQL." extend the DSL supported by HoneySQL."
[statement-map & [{:keys [aliased nested pretty]}]] ([statement-map] (format-dsl statement-map {}))
([statement-map {:keys [aliased nested pretty]}]
(binding [*dsl* statement-map] (binding [*dsl* statement-map]
(let [[sqls params leftover] (let [[sqls params leftover]
(reduce (fn [[sql params leftover] k] (reduce (fn [[sql params leftover] k]
@ -1644,7 +1655,7 @@
pretty pretty
(as-> s (str "\n" s "\n")) (as-> s (str "\n" s "\n"))
(and nested (not aliased)) (and nested (not aliased))
(as-> s (str "(" s ")")))] params))))) (as-> s (str "(" s ")")))] params))))))
(def ^:private infix-aliases (def ^:private infix-aliases
"Provided for backward compatibility with earlier HoneySQL versions." "Provided for backward compatibility with earlier HoneySQL versions."
@ -2031,7 +2042,8 @@
This is intended to be used when writing your own formatters to This is intended to be used when writing your own formatters to
extend the DSL supported by HoneySQL." extend the DSL supported by HoneySQL."
[expr & [{:keys [nested] :as opts}]] ([expr] (format-expr expr {}))
([expr {:keys [nested] :as opts}]
(cond (ident? expr) (cond (ident? expr)
(format-var expr opts) (format-var expr opts)
@ -2069,7 +2081,7 @@
*numbered* *numbered*
(->numbered expr) (->numbered expr)
:else :else
["?" expr]))) ["?" expr]))))
(defn- check-dialect [dialect] (defn- check-dialect [dialect]
(when-not (contains? @dialects dialect) (when-not (contains? @dialects dialect)