From 94b83d3870ee82f48b1b0dcc7755480c9ab7f90f Mon Sep 17 00:00:00 2001 From: Leif Andersen Date: Mon, 14 Jul 2025 12:24:00 -0400 Subject: [PATCH 1/7] Add exponentation, sqrt, sin, cos, tan operators --- resources/gensql/query/base.bnf | 11 +++++++++-- resources/gensql/query/permissive.bnf | 2 +- resources/gensql/query/strict.bnf | 2 +- src/gensql/query/scalar.cljc | 6 +++++- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/resources/gensql/query/base.bnf b/resources/gensql/query/base.bnf index aac1a3a2..b5d61964 100644 --- a/resources/gensql/query/base.bnf +++ b/resources/gensql/query/base.bnf @@ -125,7 +125,8 @@ scalar-expr ::= scalar-expr-0 ::= scalar-expr-4 | expr-binop ::= scalar-expr-5 | expr-addition | expr-subtraction ::= scalar-expr-6 | expr-multiplication | expr-division - ::= scalar-expr-7 | expr-function-call + ::= scalar-expr-7 | expr-exponentiation + ::= scalar-expr-8 | expr-function-call expr-disjunction ::= scalar-expr-0 ws #'(?i)OR' ws scalar-expr-1 expr-conjunction ::= scalar-expr-1 ws #'(?i)AND' ws scalar-expr-2 @@ -140,9 +141,15 @@ expr-subtraction ::= scalar-expr-4 ws? '-' ws? scalar-expr-5 expr-multiplication ::= scalar-expr-5 ws? '*' ws? scalar-expr-6 expr-division ::= scalar-expr-5 ws? '/' ws? scalar-expr-6 +expr-exponentiation ::= scalar-expr-6 ws? '^' ws? scalar-expr-7 + (* currently only log - will likely add more later *) - ::= expr-function-call-log + ::= expr-function-call-log | expr-function-call-sqrt | expr-function-call-sin | expr-function-call-cos | expr-function-call-tan expr-function-call-log ::= 'log(' ws? scalar-expr-6 ws? ')' +expr-function-call-sqrt ::= 'sqrt(' ws? scalar-expr-6 ws? ')' +expr-function-call-sin ::= 'sin(' ws? scalar-expr-6 ws? ')' +expr-function-call-cos ::= 'cos(' ws? scalar-expr-6 ws? ')' +expr-function-call-tan ::= 'tan(' ws? scalar-expr-6 ws? ')' scalar-expr-group ::= '(' ws? scalar-expr ws? ')' diff --git a/resources/gensql/query/permissive.bnf b/resources/gensql/query/permissive.bnf index e0b074fa..f4cc3774 100644 --- a/resources/gensql/query/permissive.bnf +++ b/resources/gensql/query/permissive.bnf @@ -1,5 +1,5 @@ ::= scalar-expr-1 | expr-disjunction | probability-expr | mutual-info-expr - ::= scalar-expr-group | identifier | value + ::= scalar-expr-group | identifier | value (* model-expr *) diff --git a/resources/gensql/query/strict.bnf b/resources/gensql/query/strict.bnf index 4673f718..bd3c0105 100644 --- a/resources/gensql/query/strict.bnf +++ b/resources/gensql/query/strict.bnf @@ -1,4 +1,4 @@ - ::= scalar-expr-group + ::= scalar-expr-group | identifier | value | probability-expr diff --git a/src/gensql/query/scalar.cljc b/src/gensql/query/scalar.cljc index 8192fbb0..5454e5b2 100644 --- a/src/gensql/query/scalar.cljc +++ b/src/gensql/query/scalar.cljc @@ -60,8 +60,10 @@ [:expr-subtraction left _ right] `(~'- ~(plan left) ~(plan right)) [:expr-multiplication left _ right] `(~'* ~(plan left) ~(plan right)) [:expr-division left _ right] `(~'/ ~(plan left) ~(plan right)) + [:expr-exponentiation left _ right] `(~'pow ~(plan left) ~(plan right)) [:expr-function-call-log _log child _] `(~'log ~(plan child)) + [:expr-function-call-sqrt _sqrt child _] `(~'sqrt ~(plan child)) [:expr-binop left [:binop [:is _]] right] `(~'= ~(plan left) ~(plan right)) [:expr-binop left [:binop [:is-not & _]] right] `(~'not= ~(plan left) ~(plan right)) @@ -299,7 +301,9 @@ '- (nil-safe (auto-unbox -)) '* (nil-safe (auto-unbox *)) '/ (nil-safe (auto-unbox /)) - 'log (nil-safe (auto-unbox math/log))} + 'pow (nil-safe (auto-unbox math/pow)) + 'log (nil-safe (auto-unbox math/log)) + 'sqrt (nil-safe (auto-unbox math/sqrt))} 'gensql {'safe-get safe-get 'prob prob 'pdf pdf From 246926c34e35f59c6ee641895604b6108dcaec50 Mon Sep 17 00:00:00 2001 From: Leif Andersen Date: Mon, 11 Aug 2025 17:53:41 -0400 Subject: [PATCH 2/7] Add catch all reader test. --- src/gensql/query/db.cljc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/gensql/query/db.cljc b/src/gensql/query/db.cljc index 2acc92ad..1b2cd0d4 100644 --- a/src/gensql/query/db.cljc +++ b/src/gensql/query/db.cljc @@ -11,7 +11,10 @@ (defn read-string [s] (let [sppl-readers {'gensql.gpm.spe/SPE (dynaload/dynaload 'gensql.gpm.sppl/read-string) - 'inferenceql.gpm.spe/SPE (dynaload/dynaload 'gensql.gpm.sppl/read-string)} ; for backwards-compatibility + 'inferenceql.gpm.spe/SPE (dynaload/dynaload 'gensql.gpm.sppl/read-string) ; for backwards-compatibility + 'default (fn [tag value] + (println "Found unknown tag:" tag "with value:" value) + {:tag tag :value value})} readers (merge gpm/readers sppl-readers)] (edn/read-string {:readers readers} s))) From b42d724dd49565cdd4369553c0a6a577bf5cc7f8 Mon Sep 17 00:00:00 2001 From: Leif Andersen Date: Mon, 11 Aug 2025 18:01:03 -0400 Subject: [PATCH 3/7] Proper syntax for default --- src/gensql/query/db.cljc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/gensql/query/db.cljc b/src/gensql/query/db.cljc index 1b2cd0d4..0c8d311c 100644 --- a/src/gensql/query/db.cljc +++ b/src/gensql/query/db.cljc @@ -11,12 +11,13 @@ (defn read-string [s] (let [sppl-readers {'gensql.gpm.spe/SPE (dynaload/dynaload 'gensql.gpm.sppl/read-string) - 'inferenceql.gpm.spe/SPE (dynaload/dynaload 'gensql.gpm.sppl/read-string) ; for backwards-compatibility - 'default (fn [tag value] + 'inferenceql.gpm.spe/SPE (dynaload/dynaload 'gensql.gpm.sppl/read-string)} ; for backwards-compatibility + readers (merge gpm/readers sppl-readers)] + (edn/read-string {:readers readers + :default (fn [tag value] (println "Found unknown tag:" tag "with value:" value) {:tag tag :value value})} - readers (merge gpm/readers sppl-readers)] - (edn/read-string {:readers readers} s))) + s))) #?(:clj (defn slurp [x] From 0c3d4c413cbcc076779ed0a9419d584f5575cdc5 Mon Sep 17 00:00:00 2001 From: Leif Andersen Date: Mon, 11 Aug 2025 18:11:52 -0400 Subject: [PATCH 4/7] Handle reading datetime objects. --- src/gensql/query/db.cljc | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/gensql/query/db.cljc b/src/gensql/query/db.cljc index 0c8d311c..846a2b56 100644 --- a/src/gensql/query/db.cljc +++ b/src/gensql/query/db.cljc @@ -10,9 +10,16 @@ (defn read-string [s] - (let [sppl-readers {'gensql.gpm.spe/SPE (dynaload/dynaload 'gensql.gpm.sppl/read-string) + (let [object-reader {'object (fn [[class-name _ string-repr]] + (case class-name + java.time.LocalDate + (java.time.LocalDate/parse string-repr), + java.time.LocalDateTime + (java.time.LocalDateTime/parse string-repr), + string-repr))} + sppl-readers {'gensql.gpm.spe/SPE (dynaload/dynaload 'gensql.gpm.sppl/read-string) 'inferenceql.gpm.spe/SPE (dynaload/dynaload 'gensql.gpm.sppl/read-string)} ; for backwards-compatibility - readers (merge gpm/readers sppl-readers)] + readers (merge object-reader gpm/readers sppl-readers)] (edn/read-string {:readers readers :default (fn [tag value] (println "Found unknown tag:" tag "with value:" value) From 1cccea4ce2ccd71c19963cd1058dfbabaae5309c Mon Sep 17 00:00:00 2001 From: Leif Andersen Date: Fri, 15 Aug 2025 13:30:02 -0400 Subject: [PATCH 5/7] Should up the deps to fix a bug in the inference module. --- deps.edn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps.edn b/deps.edn index 0e0513fd..6cfa9dad 100644 --- a/deps.edn +++ b/deps.edn @@ -5,7 +5,7 @@ metosin/muuntaja {:mvn/version "0.6.8"} net.cgrand/macrovich {:mvn/version "0.2.1"} net.cgrand/xforms {:mvn/version "0.19.2"} - io.github.OpenGen/GenSQL.inference {:git/sha "689fe740dead93f3ba349a88efa52f2544aa138b"} + io.github.OpenGen/GenSQL.inference {:git/sha "2958f582b28ee88efc945ee4f480f946b73e4094"} org.babashka/sci {:mvn/version "0.3.32"} org.clojure/clojure {:mvn/version "1.11.1"} com.google.javascript/closure-compiler-unshaded {:mvn/version "v20230802"} From bc440e76d15f91c1932cf54eb61649864ae18f05 Mon Sep 17 00:00:00 2001 From: Leif Andersen Date: Tue, 19 Aug 2025 10:44:20 -0400 Subject: [PATCH 6/7] Update deps to pre-release version of GenSQL.inference --- deps.edn | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/deps.edn b/deps.edn index 6cfa9dad..0476a81a 100644 --- a/deps.edn +++ b/deps.edn @@ -5,7 +5,9 @@ metosin/muuntaja {:mvn/version "0.6.8"} net.cgrand/macrovich {:mvn/version "0.2.1"} net.cgrand/xforms {:mvn/version "0.19.2"} - io.github.OpenGen/GenSQL.inference {:git/sha "2958f582b28ee88efc945ee4f480f946b73e4094"} + io.github.OpenGen/GenSQL.inference + {:git/url "https://github.com/LeifAndersen/GenSQL.inference" + :sha "9decae2d54c8ff37920a2515a9a964398662cdfc"} org.babashka/sci {:mvn/version "0.3.32"} org.clojure/clojure {:mvn/version "1.11.1"} com.google.javascript/closure-compiler-unshaded {:mvn/version "v20230802"} From 3a844d9dfd77e79a4d246f808665b217f1e8498a Mon Sep 17 00:00:00 2001 From: Leif Andersen Date: Sun, 28 Sep 2025 21:10:29 -0400 Subject: [PATCH 7/7] feat: Add OFFSET to grammer. OFFSET is generally part of SQL languages, and is missing here. This commit fixes this. So now you can make queries such as: SELECT * FROM data LIMIT 5 OFFSET 3 --- resources/gensql/query/base.bnf | 3 ++- src/gensql/query/plan.cljc | 27 ++++++++++++++++++--------- src/gensql/query/relation.cljc | 4 ++-- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/resources/gensql/query/base.bnf b/resources/gensql/query/base.bnf index b5d61964..719045e8 100644 --- a/resources/gensql/query/base.bnf +++ b/resources/gensql/query/base.bnf @@ -100,7 +100,8 @@ order-by-clause ::= #'(?i)ORDER' ws #'(?i)BY' ws identifier (ws (asc | desc))? asc ::= #'(?i)ASC' desc ::= #'(?i)DESC' -limit-clause ::= #'(?i)LIMIT' ws int +limit-clause ::= #'(?i)LIMIT' ws int (ws offset-clause)? +offset-clause ::= #'(?i)OFFSET' ws int (* aggregation *) diff --git a/src/gensql/query/plan.cljc b/src/gensql/query/plan.cljc index 68c31c0b..03b62545 100644 --- a/src/gensql/query/plan.cljc +++ b/src/gensql/query/plan.cljc @@ -92,9 +92,10 @@ ::variables variables}) (defn limit - [op limit] + [op limit offset] {::type :gensql.query.plan.type/limit ::limit limit + ::offset offset ::plan op}) (defn distinct @@ -191,13 +192,13 @@ elsewhere in the parse tree, as is the case with \"SELECT\" subclauses." ([node] (let [pln (with-meta (plan-impl node) - {::parser/node node})] + {::parser/node node})] (tap> #:plan{:node node :plan pln}) pln)) ([node op] (let [pln (if (some? node) (with-meta (plan-impl node op) - {::parser/node node}) + {::parser/node node}) op)] (tap> #:plan{:node node :plan pln :op op}) pln))) @@ -265,9 +266,9 @@ relation." [node] (tree/match [node] - [[:selection "(" child ")"]] (output-attr child) - [[:selection _ [:alias-clause _as id-node]]] (literal/read id-node) - [[:selection child]] (parser/unparse child))) + [[:selection "(" child ")"]] (output-attr child) + [[:selection _ [:alias-clause _as id-node]]] (literal/read id-node) + [[:selection child]] (parser/unparse child))) (defn ^:private selection-plan [node op] @@ -403,9 +404,17 @@ (rename (plan relation-expr) (literal/read identifier)))) (defmethod plan-impl :limit-clause + [node op] + (let [n (eval-literal-in node [:int]) + offset (if-let [offset-clause (tree/get-node node :offset-clause)] + (plan-impl offset-clause op) + 0)] + (limit op n offset))) + +(defmethod plan-impl :offset-clause [node op] (let [n (eval-literal-in node [:int])] - (limit op n))) + (or n 0))) (defmethod plan-impl :distinct-clause [_ op] @@ -557,9 +566,9 @@ (defmethod eval :gensql.query.plan.type/limit [plan env bindings] - (let [{::keys [limit plan]} plan + (let [{::keys [limit offset plan]} plan rel (eval plan env bindings)] - (relation/limit rel limit))) + (relation/limit rel limit offset))) (defmethod eval :gensql.query.plan.type/distinct [plan env bindings] diff --git a/src/gensql/query/relation.cljc b/src/gensql/query/relation.cljc index c141ce3c..35429468 100644 --- a/src/gensql/query/relation.cljc +++ b/src/gensql/query/relation.cljc @@ -80,8 +80,8 @@ (meta rel))) (defn limit - [rel n] - (with-meta (take n (tuples rel)) + [rel n offset] + (with-meta (take n (drop offset (tuples rel))) (meta rel))) (defn distinct