diff --git a/src/honey/sql.cljc b/src/honey/sql.cljc index b67fd85..9c829e8 100644 --- a/src/honey/sql.cljc +++ b/src/honey/sql.cljc @@ -31,7 +31,7 @@ (:require [clojure.string :as str] #?(:clj [clojure.template]) [honey.sql.protocols :as p] - [honey.sql.util :refer [str join]])) + [honey.sql.util :refer [str join split-by-separator]])) ;; default formatting for known clauses @@ -316,7 +316,7 @@ [n %] (if aliased [%] - (str/split % #"\.")))) + (split-by-separator % ".")))) parts (parts-fn col-e) entity (join "." (map #(cond-> % (not= "*" %) (quote-fn))) parts)] (suspicious-entity-check entity) @@ -457,7 +457,7 @@ :default (subs (str x) 1)) (str x))] (cond (str/starts-with? c "%") - (let [[f & args] (str/split (subs c 1) #"\.")] + (let [[f & args] (split-by-separator (subs c 1) ".")] [(str (format-fn-name f) "(" (join ", " (map #(format-entity (keyword %) opts)) args) ")")]) diff --git a/src/honey/sql/util.cljc b/src/honey/sql/util.cljc index 1e621ad..471e7c4 100644 --- a/src/honey/sql/util.cljc +++ b/src/honey/sql/util.cljc @@ -75,3 +75,16 @@ :default (clojure.string/join separator (transduce xform conj [] coll))))) + +(defn split-by-separator + "More efficient implementation of `clojure.string/split` for cases when a + literal string (not regex) is used as a separator, and for cases where the + separator is not present in the haystack at all." + [s sep] + (loop [start 0, res []] + (if-let [sep-idx (clojure.string/index-of s sep start)] + (recur (inc sep-idx) (conj res (subs s start sep-idx))) + (if (= start 0) + ;; Fastpath - zero separators in s + [s] + (conj res (subs s start)))))) diff --git a/test/honey/util_test.cljc b/test/honey/util_test.cljc index 7ee6f6c..1cc1f2e 100644 --- a/test/honey/util_test.cljc +++ b/test/honey/util_test.cljc @@ -43,3 +43,11 @@ (is (= "1, 2, 3, 4" (sut/join ", " (remove nil?) [1 nil 2 nil 3 nil nil nil 4]))) (is (= "" (sut/join ", " (remove nil?) [nil nil nil nil])))) + +(deftest split-by-separator-test + (is (= [""] (sut/split-by-separator "" "."))) + (is (= ["" ""] (sut/split-by-separator "." "."))) + (is (= ["hello"] (sut/split-by-separator "hello" "."))) + (is (= ["h" "e" "l" "l" "o"] (sut/split-by-separator "h.e.l.l.o" "."))) + (is (= ["" "h" "e" "" "" "l" "" "l" "o" ""] + (sut/split-by-separator ".h.e...l..l.o." "."))))