Add 2 more compatible libs (#1171)
This commit is contained in:
parent
a1007efdac
commit
ac6ad33fcb
11 changed files with 795 additions and 3 deletions
4
deps.edn
4
deps.edn
|
|
@ -120,7 +120,9 @@
|
|||
meta-merge/meta-merge {:mvn/version "1.0.0"}
|
||||
com.exoscale/lingo {:mvn/version "1.0.0-alpha14"}
|
||||
io.github.swirrl/dogstatsd {:mvn/version "0.1.39"}
|
||||
org.clojure/algo.monads {:mvn/version "0.1.6"}}
|
||||
org.clojure/algo.monads {:mvn/version "0.1.6"}
|
||||
io.lambdaforge/datalog-parser {:mvn/version "0.1.9"}
|
||||
clj-stacktrace/clj-stacktrace {:mvn/version "0.2.8"}}
|
||||
:classpath-overrides {org.clojure/clojure nil
|
||||
org.clojure/spec.alpha nil}}
|
||||
:clj-nvd
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ camel-snake-kebab/camel-snake-kebab,https://github.com/clj-commons/camel-snake-k
|
|||
circleci/bond,https://github.com/circleci/bond
|
||||
clj-commons/clj-yaml,https://github.com/clj-commons/clj-yaml
|
||||
clj-commons/multigrep,https://github.com/clj-commons/multigrep
|
||||
clj-stacktrace/clj-stacktrace,https://github.com/mmcgrana/clj-stacktrace
|
||||
clojure-csv/clojure-csv,https://github.com/davidsantiago/clojure-csv
|
||||
clojure-term-colors/clojure-term-colors,https://github.com/trhura/clojure-term-colors
|
||||
com.exoscale/lingo,https://github.com/exoscale/lingo
|
||||
|
|
@ -43,6 +44,7 @@ io.github.cognitect-labs/test-runner,https://github.com/cognitect-labs/test-runn
|
|||
io.github.swirrl/dogstatsd,https://github.com/swirrl/dogstatsd
|
||||
io.github.technomancy/limit-break,https://github.com/technomancy/limit-break
|
||||
io.helins/binf,https://github.com/helins/binf.cljc
|
||||
io.lambdaforge/datalog-parser,https://github.com/lambdaforge/datalog-parser
|
||||
io.replikativ/hasch,https://github.com/replikativ/hasch
|
||||
java-http-clj/java-http-clj,http://www.github.com/schmee/java-http-clj
|
||||
lambdaisland/regal,https://github.com/lambdaisland/regal
|
||||
|
|
|
|||
|
|
|
@ -78,7 +78,8 @@
|
|||
(let [lib-dir (if branch
|
||||
(gl/procure git-url lib-name branch)
|
||||
(or (gl/procure git-url lib-name "master")
|
||||
(gl/procure git-url lib-name "main")))
|
||||
(gl/procure git-url lib-name "main")
|
||||
(throw (ex-info "Unable to clone git-url" {}))))
|
||||
_ (println "Git clone is at" lib-dir)
|
||||
lib-root-dir (if directory (fs/file lib-dir directory) lib-dir)
|
||||
test-dirs (if test-directories
|
||||
|
|
|
|||
|
|
@ -103,4 +103,6 @@
|
|||
meta-merge/meta-merge {:git-url "https://github.com/weavejester/meta-merge", :test-namespaces (meta-merge.core-test), :git-sha "c968c38baccd4219fe0ba592d89af37ea8e426bf"}
|
||||
com.exoscale/lingo {:git-url "https://github.com/exoscale/lingo", :test-namespaces (exoscale.lingo.test.core-test), :git-sha "30b5084fab28d24c99ec683e21535366910d9f2f" :skip-windows true}
|
||||
io.github.swirrl/dogstatsd {:git-url "https://github.com/swirrl/dogstatsd", :test-namespaces (swirrl.dogstatsd-test), :git-sha "e110caae452cd1185e65e389a359b69502076d61"}
|
||||
org.clojure/algo.monads {:git-url "https://github.com/clojure/algo.monads", :test-namespaces (clojure.algo.test-monads), :git-sha "3a985b0b099110b1654d568fecf597bc9c8d1ff5"}}
|
||||
org.clojure/algo.monads {:git-url "https://github.com/clojure/algo.monads", :test-namespaces (clojure.algo.test-monads), :git-sha "3a985b0b099110b1654d568fecf597bc9c8d1ff5"}
|
||||
io.lambdaforge/datalog-parser {:git-url "https://github.com/lambdaforge/datalog-parser", :test-namespaces (datalog.parser.pull-test datalog.parser.test.util datalog.parser.impl-test datalog.parser-test datalog.unparser-test), :git-sha "02d193f397afc3f93da704e7c6c850b194f0e797"}
|
||||
clj-stacktrace/clj-stacktrace {:git-url "https://github.com/mmcgrana/clj-stacktrace", :test-namespaces (clj-stacktrace.repl-test clj-stacktrace.core-test), :git-sha "94dc2dd748710e79800e94b713e167e5dc525717"}}
|
||||
|
|
|
|||
83
test-resources/lib_tests/clj_stacktrace/core_test.clj
Normal file
83
test-resources/lib_tests/clj_stacktrace/core_test.clj
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
(ns clj-stacktrace.core-test
|
||||
(:use clojure.test)
|
||||
(:use clj-stacktrace.core)
|
||||
(:use clj-stacktrace.utils))
|
||||
|
||||
(def cases
|
||||
[["foo.bar$biz__123" "invoke" "bar.clj" 456
|
||||
{:clojure true :ns "foo.bar" :fn "biz"
|
||||
:file "bar.clj" :line 456 :anon-fn false}]
|
||||
|
||||
["foo.bar$biz_bat__123" "invoke" "bar.clj" 456
|
||||
{:clojure true :ns "foo.bar" :fn "biz-bat"
|
||||
:file "bar.clj" :line 456 :anon-fn false}]
|
||||
|
||||
["foo.bar$biz_bat_QMARK___448" "invoke" "bar.clj" 456
|
||||
{:clojure true :ns "foo.bar" :fn "biz-bat?"
|
||||
:file "bar.clj" :line 456 :anon-fn false}]
|
||||
|
||||
["foo.bar$biz_bat_QMARK___448$fn__456" "invoke" "bar.clj" 456
|
||||
{:clojure true :ns "foo.bar" :fn "biz-bat?"
|
||||
:file "bar.clj" :line 456 :anon-fn true}]
|
||||
|
||||
["foo.bar$repl$fn__5629.invoke" "invoke" "bar.clj" 456
|
||||
{:clojure true :ns "foo.bar" :fn "repl"
|
||||
:file "bar.clj" :line 456 :anon-fn true}]
|
||||
|
||||
["foo.bar$repl$read_eval_print__5624" "invoke" "bar.clj" 456
|
||||
{:clojure true :ns "foo.bar" :fn "repl"
|
||||
:file "bar.clj" :line 456 :anon-fn true}]
|
||||
|
||||
["foo.bar$biz__123$fn__456" "invoke" "bar.clj" 789
|
||||
{:clojure true :ns "foo.bar" :fn "biz"
|
||||
:file "bar.clj" :line 789 :anon-fn true}]
|
||||
|
||||
["foo.bar_bat$biz__123" "invoke" "bar.clj" 456
|
||||
{:clojure true :ns "foo.bar-bat" :fn "biz"
|
||||
:file "bar.clj" :line 456 :anon-fn false}]
|
||||
|
||||
["user$eval__345" "invoke" nil -1
|
||||
{:clojure true :ns "user" :fn "eval"
|
||||
:file nil :line nil :anon-fn false}]
|
||||
|
||||
["lamina.core.observable.ConstantObservable" "message" "observable.clj" 198
|
||||
{:clojure true :ns "lamina.core.observable"
|
||||
:fn "lamina.core.observable.ConstantObservable"
|
||||
:file "observable.clj" :line 198 :anon-fn false}]
|
||||
|
||||
["clojure.lang.Var" "invoke" "Var.java" 123
|
||||
{:java true :class "clojure.lang.Var" :method "invoke"
|
||||
:file "Var.java" :line 123}]
|
||||
|
||||
["clojure.proxy.space.SomeClass" "someMethod" "SomeClass.java" 123
|
||||
{:java true :class "clojure.proxy.space.SomeClass" :method "someMethod"
|
||||
:file "SomeClass.java" :line 123}]
|
||||
|
||||
["some.space.SomeClass" "someMethod" "SomeClass.java" 123
|
||||
{:java true :class "some.space.SomeClass" :method "someMethod"
|
||||
:file "SomeClass.java" :line 123}]
|
||||
|
||||
["some.space.SomeClass$SomeInner" "someMethod" "SomeClass.java" 123
|
||||
{:java true :class "some.space.SomeClass$SomeInner" :method "someMethod"
|
||||
:file "SomeClass.java" :line 123}]
|
||||
|
||||
["some.space.SomeClass" "someMethod" nil -1
|
||||
{:java true :class "some.space.SomeClass" :method "someMethod"
|
||||
:file nil :line nil}]])
|
||||
|
||||
(deftest test-parse-trace-elem
|
||||
(doseq [[class method file line parsed] cases
|
||||
:let [elem (StackTraceElement. class method file line)]]
|
||||
(is (= parsed (parse-trace-elem elem)))))
|
||||
|
||||
(deftest test-trim-redundant
|
||||
(let [trim-fn (resolve 'clj-stacktrace.core/trim-redundant)]
|
||||
(is (= '(d c) (trim-fn '(d c b a) '(f e b a))))
|
||||
(is (= '(c) (trim-fn '(c b a) '(f e b a))))
|
||||
(is (= '(d c) (trim-fn '(d c b a) '(e b a))))))
|
||||
|
||||
(deftest test-parse-exception
|
||||
(try
|
||||
(eval '(/))
|
||||
(catch Exception e
|
||||
(is (parse-exception e)))))
|
||||
31
test-resources/lib_tests/clj_stacktrace/repl_test.clj
Normal file
31
test-resources/lib_tests/clj_stacktrace/repl_test.clj
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
(ns clj-stacktrace.repl-test
|
||||
(:use clojure.test)
|
||||
(:use clj-stacktrace.utils)
|
||||
(:use clj-stacktrace.repl))
|
||||
|
||||
(defmacro with-cascading-exception
|
||||
"Execute body in the context of a variable bound to an exception instance
|
||||
that includes a caused-by cascade."
|
||||
[binding-sym & body]
|
||||
`(try (first (lazy-seq (cons (/) nil)))
|
||||
(catch Exception e#
|
||||
(let [~binding-sym e#]
|
||||
~@body))))
|
||||
|
||||
(deftest test-pst
|
||||
(with-cascading-exception e
|
||||
(is (with-out-str (pst e)))
|
||||
(binding [*e e]
|
||||
(is (with-out-str (pst))))))
|
||||
|
||||
(deftest test-pst-str
|
||||
(with-cascading-exception e
|
||||
(is (pst-str e))
|
||||
(binding [*e e]
|
||||
(is (pst-str)))))
|
||||
|
||||
(deftest test-pst+
|
||||
(with-cascading-exception e
|
||||
(is (with-out-str (pst+ e)))
|
||||
(binding [*e e]
|
||||
(is (with-out-str (pst+))))))
|
||||
492
test-resources/lib_tests/datalog/parser/impl_test.cljc
Normal file
492
test-resources/lib_tests/datalog/parser/impl_test.cljc
Normal file
|
|
@ -0,0 +1,492 @@
|
|||
(ns datalog.parser.impl-test
|
||||
(:require #?(:cljs [cljs.test :refer-macros [is are deftest testing]]
|
||||
:clj [clojure.test :refer [is are deftest testing]])
|
||||
[datalog.parser.impl :as dp]
|
||||
[datalog.parser.type :as t]
|
||||
[datalog.parser.test.util])
|
||||
(:import [clojure.lang ExceptionInfo]))
|
||||
|
||||
(deftest bindings
|
||||
(are [form res] (= (dp/parse-binding form) res)
|
||||
'?x
|
||||
(t/->BindScalar (t/->Variable '?x))
|
||||
|
||||
'_
|
||||
(t/->BindIgnore)
|
||||
|
||||
'[?x ...]
|
||||
(t/->BindColl (t/->BindScalar (t/->Variable '?x)))
|
||||
|
||||
'[?x]
|
||||
(t/->BindTuple [(t/->BindScalar (t/->Variable '?x))])
|
||||
|
||||
'[?x ?y]
|
||||
(t/->BindTuple [(t/->BindScalar (t/->Variable '?x)) (t/->BindScalar (t/->Variable '?y))])
|
||||
|
||||
'[_ ?y]
|
||||
(t/->BindTuple [(t/->BindIgnore) (t/->BindScalar (t/->Variable '?y))])
|
||||
|
||||
'[[_ [?x ...]] ...]
|
||||
(t/->BindColl
|
||||
(t/->BindTuple [(t/->BindIgnore)
|
||||
(t/->BindColl
|
||||
(t/->BindScalar (t/->Variable '?x)))]))
|
||||
|
||||
'[[?a ?b ?c]]
|
||||
(t/->BindColl
|
||||
(t/->BindTuple [(t/->BindScalar (t/->Variable '?a))
|
||||
(t/->BindScalar (t/->Variable '?b))
|
||||
(t/->BindScalar (t/->Variable '?c))])))
|
||||
|
||||
(is (thrown-with-msg? ExceptionInfo #"Cannot parse binding"
|
||||
(dp/parse-binding :key))))
|
||||
|
||||
(deftest in
|
||||
(are [form res] (= (dp/parse-in form) res)
|
||||
'[?x]
|
||||
[(t/->BindScalar (t/->Variable '?x))]
|
||||
|
||||
'[$ $1 % _ ?x]
|
||||
[(t/->BindScalar (t/->SrcVar '$))
|
||||
(t/->BindScalar (t/->SrcVar '$1))
|
||||
(t/->BindScalar (t/->RulesVar))
|
||||
(t/->BindIgnore)
|
||||
(t/->BindScalar (t/->Variable '?x))]
|
||||
|
||||
'[$ [[_ [?x ...]] ...]]
|
||||
[(t/->BindScalar (t/->SrcVar '$))
|
||||
(t/->BindColl
|
||||
(t/->BindTuple [(t/->BindIgnore)
|
||||
(t/->BindColl
|
||||
(t/->BindScalar (t/->Variable '?x)))]))])
|
||||
|
||||
(is (thrown-with-msg? ExceptionInfo #"Cannot parse binding"
|
||||
(dp/parse-in ['?x :key]))))
|
||||
|
||||
(deftest with
|
||||
(is (= (dp/parse-with '[?x ?y])
|
||||
[(t/->Variable '?x) (t/->Variable '?y)]))
|
||||
|
||||
(is (thrown-with-msg? ExceptionInfo #"Cannot parse :with clause"
|
||||
(dp/parse-with '[?x _]))))
|
||||
|
||||
(deftest test-parse-find
|
||||
(is (= (dp/parse-find '[?a ?b])
|
||||
(t/->FindRel [(t/->Variable '?a) (t/->Variable '?b)])))
|
||||
(is (= (dp/parse-find '[[?a ...]])
|
||||
(t/->FindColl (t/->Variable '?a))))
|
||||
(is (= (dp/parse-find '[?a .])
|
||||
(t/->FindScalar (t/->Variable '?a))))
|
||||
(is (= (dp/parse-find '[[?a ?b]])
|
||||
(t/->FindTuple [(t/->Variable '?a) (t/->Variable '?b)]))))
|
||||
|
||||
(deftest test-parse-aggregate
|
||||
(is (= (dp/parse-find '[?a (count ?b)])
|
||||
(t/->FindRel [(t/->Variable '?a) (t/->Aggregate (t/->PlainSymbol 'count) [(t/->Variable '?b)])])))
|
||||
(is (= (dp/parse-find '[[(count ?a) ...]])
|
||||
(t/->FindColl (t/->Aggregate (t/->PlainSymbol 'count) [(t/->Variable '?a)]))))
|
||||
(is (= (dp/parse-find '[(count ?a) .])
|
||||
(t/->FindScalar (t/->Aggregate (t/->PlainSymbol 'count) [(t/->Variable '?a)]))))
|
||||
(is (= (dp/parse-find '[[(count ?a) ?b]])
|
||||
(t/->FindTuple [(t/->Aggregate (t/->PlainSymbol 'count) [(t/->Variable '?a)]) (t/->Variable '?b)]))))
|
||||
|
||||
(deftest test-parse-custom-aggregates
|
||||
(is (= (dp/parse-find '[(aggregate ?f ?a)])
|
||||
(t/->FindRel [(t/->Aggregate (t/->Variable '?f) [(t/->Variable '?a)])])))
|
||||
(is (= (dp/parse-find '[?a (aggregate ?f ?b)])
|
||||
(t/->FindRel [(t/->Variable '?a) (t/->Aggregate (t/->Variable '?f) [(t/->Variable '?b)])])))
|
||||
(is (= (dp/parse-find '[[(aggregate ?f ?a) ...]])
|
||||
(t/->FindColl (t/->Aggregate (t/->Variable '?f) [(t/->Variable '?a)]))))
|
||||
(is (= (dp/parse-find '[(aggregate ?f ?a) .])
|
||||
(t/->FindScalar (t/->Aggregate (t/->Variable '?f) [(t/->Variable '?a)]))))
|
||||
(is (= (dp/parse-find '[[(aggregate ?f ?a) ?b]])
|
||||
(t/->FindTuple [(t/->Aggregate (t/->Variable '?f) [(t/->Variable '?a)]) (t/->Variable '?b)]))))
|
||||
|
||||
(deftest test-parse-find-elements
|
||||
(is (= (dp/parse-find '[(count ?b 1 $x) .])
|
||||
(t/->FindScalar (t/->Aggregate (t/->PlainSymbol 'count)
|
||||
[(t/->Variable '?b)
|
||||
(t/->Constant 1)
|
||||
(t/->SrcVar '$x)])))))
|
||||
|
||||
(deftest clauses
|
||||
(are [form res] (= (set (dp/parse-rules form)) res)
|
||||
'[[(rule ?x)
|
||||
[?x :name _]]]
|
||||
#{(t/->Rule
|
||||
(t/->PlainSymbol 'rule)
|
||||
[(t/->RuleBranch
|
||||
(t/->RuleVars nil [(t/->Variable '?x)])
|
||||
[(t/->Pattern
|
||||
(t/->DefaultSrc)
|
||||
[(t/->Variable '?x) (t/->Constant :name) (t/->Placeholder)])])])})
|
||||
(is (thrown-with-msg? ExceptionInfo #"Reference to the unknown variable"
|
||||
(dp/parse-rules '[[(rule ?x) [?x :name ?y]]]))))
|
||||
|
||||
(deftest rule-vars
|
||||
(are [form res] (= (set (dp/parse-rules form)) res)
|
||||
'[[(rule [?x] ?y)
|
||||
[_]]]
|
||||
#{(t/->Rule
|
||||
(t/->PlainSymbol 'rule)
|
||||
[(t/->RuleBranch
|
||||
(t/->RuleVars [(t/->Variable '?x)] [(t/->Variable '?y)])
|
||||
[(t/->Pattern (t/->DefaultSrc) [(t/->Placeholder)])])])}
|
||||
|
||||
'[[(rule [?x ?y] ?a ?b)
|
||||
[_]]]
|
||||
#{(t/->Rule
|
||||
(t/->PlainSymbol 'rule)
|
||||
|
||||
[(t/->RuleBranch
|
||||
(t/->RuleVars [(t/->Variable '?x) (t/->Variable '?y)]
|
||||
[(t/->Variable '?a) (t/->Variable '?b)])
|
||||
[(t/->Pattern (t/->DefaultSrc) [(t/->Placeholder)])])])}
|
||||
|
||||
'[[(rule [?x])
|
||||
[_]]]
|
||||
#{(t/->Rule
|
||||
(t/->PlainSymbol 'rule)
|
||||
[(t/->RuleBranch
|
||||
(t/->RuleVars [(t/->Variable '?x)] nil)
|
||||
[(t/->Pattern (t/->DefaultSrc) [(t/->Placeholder)])])])})
|
||||
|
||||
(is (thrown-with-msg? ExceptionInfo #"Cannot parse rule-vars"
|
||||
(dp/parse-rules '[[(rule) [_]]])))
|
||||
|
||||
(is (thrown-with-msg? ExceptionInfo #"Cannot parse rule-vars"
|
||||
(dp/parse-rules '[[(rule []) [_]]])))
|
||||
|
||||
(is (thrown-with-msg? ExceptionInfo #"Rule variables should be distinct"
|
||||
(dp/parse-rules '[[(rule ?x ?y ?x) [_]]])))
|
||||
|
||||
(is (thrown-with-msg? ExceptionInfo #"Rule variables should be distinct"
|
||||
(dp/parse-rules '[[(rule [?x ?y] ?z ?x) [_]]]))))
|
||||
|
||||
(deftest branches
|
||||
(are [form res] (= (set (dp/parse-rules form)) res)
|
||||
'[[(rule ?x)
|
||||
[:a]
|
||||
[:b]]
|
||||
[(rule ?x)
|
||||
[:c]]]
|
||||
#{(t/->Rule
|
||||
(t/->PlainSymbol 'rule)
|
||||
[(t/->RuleBranch
|
||||
(t/->RuleVars nil [(t/->Variable '?x)])
|
||||
[(t/->Pattern (t/->DefaultSrc) [(t/->Constant :a)])
|
||||
(t/->Pattern (t/->DefaultSrc) [(t/->Constant :b)])])
|
||||
(t/->RuleBranch
|
||||
(t/->RuleVars nil [(t/->Variable '?x)])
|
||||
[(t/->Pattern (t/->DefaultSrc) [(t/->Constant :c)])])])}
|
||||
|
||||
'[[(rule ?x)
|
||||
[:a]
|
||||
[:b]]
|
||||
[(other ?x)
|
||||
[:c]]]
|
||||
#{(t/->Rule
|
||||
(t/->PlainSymbol 'rule)
|
||||
[(t/->RuleBranch
|
||||
(t/->RuleVars nil [(t/->Variable '?x)])
|
||||
[(t/->Pattern (t/->DefaultSrc) [(t/->Constant :a)])
|
||||
(t/->Pattern (t/->DefaultSrc) [(t/->Constant :b)])])])
|
||||
(t/->Rule
|
||||
(t/->PlainSymbol 'other)
|
||||
[(t/->RuleBranch
|
||||
(t/->RuleVars nil [(t/->Variable '?x)])
|
||||
[(t/->Pattern (t/->DefaultSrc) [(t/->Constant :c)])])])})
|
||||
|
||||
(is (thrown-with-msg? ExceptionInfo #"Rule branch should have clauses"
|
||||
(dp/parse-rules '[[(rule ?x)]])))
|
||||
|
||||
(is (thrown-with-msg? ExceptionInfo #"Arity mismatch"
|
||||
(dp/parse-rules '[[(rule ?x) [_]]
|
||||
[(rule ?x ?y) [_]]])))
|
||||
|
||||
(is (thrown-with-msg? ExceptionInfo #"Arity mismatch"
|
||||
(dp/parse-rules '[[(rule ?x) [_]]
|
||||
[(rule [?x]) [_]]]))))
|
||||
|
||||
(deftest pattern
|
||||
(are [clause pattern] (= (dp/parse-clause clause) pattern)
|
||||
'[?e ?a ?v]
|
||||
(t/->Pattern (t/->DefaultSrc) [(t/->Variable '?e) (t/->Variable '?a) (t/->Variable '?v)])
|
||||
|
||||
'[_ ?a _ _]
|
||||
(t/->Pattern (t/->DefaultSrc) [(t/->Placeholder) (t/->Variable '?a) (t/->Placeholder) (t/->Placeholder)])
|
||||
|
||||
'[$x _ ?a _ _]
|
||||
(t/->Pattern (t/->SrcVar '$x) [(t/->Placeholder) (t/->Variable '?a) (t/->Placeholder) (t/->Placeholder)])
|
||||
|
||||
'[$x _ :name ?v]
|
||||
(t/->Pattern (t/->SrcVar '$x) [(t/->Placeholder) (t/->Constant :name) (t/->Variable '?v)])
|
||||
|
||||
'[$x _ sym ?v]
|
||||
(t/->Pattern (t/->SrcVar '$x) [(t/->Placeholder) (t/->Constant 'sym) (t/->Variable '?v)])
|
||||
|
||||
'[$x _ $src-sym ?v]
|
||||
(t/->Pattern (t/->SrcVar '$x) [(t/->Placeholder) (t/->Constant '$src-sym) (t/->Variable '?v)]))
|
||||
|
||||
(is (thrown-with-msg? ExceptionInfo #"Pattern could not be empty"
|
||||
(dp/parse-clause '[]))))
|
||||
|
||||
(deftest test-pred
|
||||
(are [clause res] (= (dp/parse-clause clause) res)
|
||||
'[(pred ?a 1)]
|
||||
(t/->Predicate (t/->PlainSymbol 'pred) [(t/->Variable '?a) (t/->Constant 1)])
|
||||
|
||||
'[(pred)]
|
||||
(t/->Predicate (t/->PlainSymbol 'pred) [])
|
||||
|
||||
'[(?custom-pred ?a)]
|
||||
(t/->Predicate (t/->Variable '?custom-pred) [(t/->Variable '?a)])))
|
||||
|
||||
(deftest test-fn
|
||||
(are [clause res] (= (dp/parse-clause clause) res)
|
||||
'[(fn ?a 1) ?x]
|
||||
(t/->Function (t/->PlainSymbol 'fn) [(t/->Variable '?a) (t/->Constant 1)] (t/->BindScalar (t/->Variable '?x)))
|
||||
|
||||
'[(fn) ?x]
|
||||
(t/->Function (t/->PlainSymbol 'fn) [] (t/->BindScalar (t/->Variable '?x)))
|
||||
|
||||
'[(?custom-fn) ?x]
|
||||
(t/->Function (t/->Variable '?custom-fn) [] (t/->BindScalar (t/->Variable '?x)))
|
||||
|
||||
'[(?custom-fn ?arg) ?x]
|
||||
(t/->Function (t/->Variable '?custom-fn) [(t/->Variable '?arg)] (t/->BindScalar (t/->Variable '?x)))))
|
||||
|
||||
(deftest rule-expr
|
||||
(are [clause res] (= (dp/parse-clause clause) res)
|
||||
'(friends ?x ?y)
|
||||
(t/->RuleExpr (t/->DefaultSrc) (t/->PlainSymbol 'friends) [(t/->Variable '?x) (t/->Variable '?y)])
|
||||
|
||||
'(friends "Ivan" _)
|
||||
(t/->RuleExpr (t/->DefaultSrc) (t/->PlainSymbol 'friends) [(t/->Constant "Ivan") (t/->Placeholder)])
|
||||
|
||||
'($1 friends ?x ?y)
|
||||
(t/->RuleExpr (t/->SrcVar '$1) (t/->PlainSymbol 'friends) [(t/->Variable '?x) (t/->Variable '?y)])
|
||||
|
||||
'(friends something)
|
||||
(t/->RuleExpr (t/->DefaultSrc) (t/->PlainSymbol 'friends) [(t/->Constant 'something)]))
|
||||
|
||||
(is (thrown-with-msg? ExceptionInfo #"rule-expr requires at least one argument"
|
||||
(dp/parse-clause '(friends)))))
|
||||
|
||||
(deftest not-clause
|
||||
(are [clause res] (= (dp/parse-clause clause) res)
|
||||
'(not [?e :follows ?x])
|
||||
(t/->Not
|
||||
(t/->DefaultSrc)
|
||||
[(t/->Variable '?e) (t/->Variable '?x)]
|
||||
[(t/->Pattern
|
||||
(t/->DefaultSrc)
|
||||
[(t/->Variable '?e) (t/->Constant :follows) (t/->Variable '?x)])])
|
||||
|
||||
'(not
|
||||
[?e :follows ?x]
|
||||
[?x _ ?y])
|
||||
(t/->Not
|
||||
(t/->DefaultSrc)
|
||||
[(t/->Variable '?e) (t/->Variable '?x) (t/->Variable '?y)]
|
||||
[(t/->Pattern
|
||||
(t/->DefaultSrc)
|
||||
[(t/->Variable '?e) (t/->Constant :follows) (t/->Variable '?x)])
|
||||
(t/->Pattern
|
||||
(t/->DefaultSrc)
|
||||
[(t/->Variable '?x) (t/->Placeholder) (t/->Variable '?y)])])
|
||||
|
||||
'($1 not [?x])
|
||||
(t/->Not
|
||||
(t/->SrcVar '$1)
|
||||
[(t/->Variable '?x)]
|
||||
[(t/->Pattern (t/->DefaultSrc) [(t/->Variable '?x)])])
|
||||
|
||||
'(not-join [?e ?y]
|
||||
[?e :follows ?x]
|
||||
[?x _ ?y])
|
||||
(t/->Not
|
||||
(t/->DefaultSrc)
|
||||
[(t/->Variable '?e) (t/->Variable '?y)]
|
||||
[(t/->Pattern
|
||||
(t/->DefaultSrc)
|
||||
[(t/->Variable '?e) (t/->Constant :follows) (t/->Variable '?x)])
|
||||
(t/->Pattern
|
||||
(t/->DefaultSrc)
|
||||
[(t/->Variable '?x) (t/->Placeholder) (t/->Variable '?y)])])
|
||||
|
||||
'($1 not-join [?e] [?e :follows ?x])
|
||||
(t/->Not
|
||||
(t/->SrcVar '$1)
|
||||
[(t/->Variable '?e)]
|
||||
[(t/->Pattern
|
||||
(t/->DefaultSrc)
|
||||
[(t/->Variable '?e) (t/->Constant :follows) (t/->Variable '?x)])]))
|
||||
|
||||
(is (thrown-with-msg? ExceptionInfo #"Join variable not declared inside clauses: \[\?x\]"
|
||||
(dp/parse-clause '(not-join [?x] [?y]))))
|
||||
|
||||
(is (thrown-with-msg? ExceptionInfo #"Join variables should not be empty"
|
||||
(dp/parse-clause '(not-join [] [?y]))))
|
||||
|
||||
(is (thrown-with-msg? ExceptionInfo #"Join variables should not be empty"
|
||||
(dp/parse-clause '(not [_]))))
|
||||
|
||||
(is (thrown-with-msg? ExceptionInfo #"Cannot parse 'not-join' clause"
|
||||
(dp/parse-clause '(not-join [?x]))))
|
||||
|
||||
(is (thrown-with-msg? ExceptionInfo #"Cannot parse 'not' clause"
|
||||
(dp/parse-clause '(not))))
|
||||
|
||||
(is (thrown-with-msg? ExceptionInfo #"Join variable not declared inside clauses: \[\?y\]"
|
||||
(dp/parse-clause '(not-join [?y]
|
||||
(not-join [?x]
|
||||
[?x :follows ?y]))))))
|
||||
|
||||
(deftest or-clause
|
||||
(are [clause res] (= (dp/parse-clause clause) res)
|
||||
'(or [?e :follows ?x])
|
||||
(t/->Or
|
||||
(t/->DefaultSrc)
|
||||
(t/->RuleVars nil [(t/->Variable '?e) (t/->Variable '?x)])
|
||||
[(t/->Pattern
|
||||
(t/->DefaultSrc)
|
||||
[(t/->Variable '?e) (t/->Constant :follows) (t/->Variable '?x)])])
|
||||
|
||||
'(or
|
||||
[?e :follows ?x]
|
||||
[?e :friend ?x])
|
||||
(t/->Or
|
||||
(t/->DefaultSrc)
|
||||
(t/->RuleVars nil [(t/->Variable '?e) (t/->Variable '?x)])
|
||||
[(t/->Pattern
|
||||
(t/->DefaultSrc)
|
||||
[(t/->Variable '?e) (t/->Constant :follows) (t/->Variable '?x)])
|
||||
(t/->Pattern
|
||||
(t/->DefaultSrc)
|
||||
[(t/->Variable '?e) (t/->Constant :friend) (t/->Variable '?x)])])
|
||||
|
||||
'(or
|
||||
[?e :follows ?x]
|
||||
(and
|
||||
[?e :friend ?x]
|
||||
[?x :friend ?e]))
|
||||
(t/->Or
|
||||
(t/->DefaultSrc)
|
||||
(t/->RuleVars nil [(t/->Variable '?e) (t/->Variable '?x)])
|
||||
[(t/->Pattern
|
||||
(t/->DefaultSrc)
|
||||
[(t/->Variable '?e) (t/->Constant :follows) (t/->Variable '?x)])
|
||||
(t/->And
|
||||
[(t/->Pattern
|
||||
(t/->DefaultSrc)
|
||||
[(t/->Variable '?e) (t/->Constant :friend) (t/->Variable '?x)])
|
||||
(t/->Pattern
|
||||
(t/->DefaultSrc)
|
||||
[(t/->Variable '?x) (t/->Constant :friend) (t/->Variable '?e)])])])
|
||||
|
||||
'($1 or [?x])
|
||||
(t/->Or
|
||||
(t/->SrcVar '$1)
|
||||
(t/->RuleVars nil [(t/->Variable '?x)])
|
||||
[(t/->Pattern (t/->DefaultSrc) [(t/->Variable '?x)])])
|
||||
|
||||
'(or-join [?e]
|
||||
[?e :follows ?x]
|
||||
[?e :friend ?y])
|
||||
(t/->Or
|
||||
(t/->DefaultSrc)
|
||||
(t/->RuleVars nil [(t/->Variable '?e)])
|
||||
[(t/->Pattern
|
||||
(t/->DefaultSrc)
|
||||
[(t/->Variable '?e) (t/->Constant :follows) (t/->Variable '?x)])
|
||||
(t/->Pattern
|
||||
(t/->DefaultSrc)
|
||||
[(t/->Variable '?e) (t/->Constant :friend) (t/->Variable '?y)])])
|
||||
|
||||
'(or-join [[?e]]
|
||||
(and [?e :follows ?x]
|
||||
[?e :friend ?y]))
|
||||
(t/->Or
|
||||
(t/->DefaultSrc)
|
||||
(t/->RuleVars [(t/->Variable '?e)] nil)
|
||||
[(t/->And
|
||||
[(t/->Pattern
|
||||
(t/->DefaultSrc)
|
||||
[(t/->Variable '?e) (t/->Constant :follows) (t/->Variable '?x)])
|
||||
(t/->Pattern
|
||||
(t/->DefaultSrc)
|
||||
[(t/->Variable '?e) (t/->Constant :friend) (t/->Variable '?y)])])])
|
||||
|
||||
'($1 or-join [[?e] ?x]
|
||||
[?e :follows ?x])
|
||||
(t/->Or
|
||||
(t/->SrcVar '$1)
|
||||
(t/->RuleVars [(t/->Variable '?e)] [(t/->Variable '?x)])
|
||||
[(t/->Pattern
|
||||
(t/->DefaultSrc)
|
||||
[(t/->Variable '?e) (t/->Constant :follows) (t/->Variable '?x)])]))
|
||||
|
||||
;; These tests reflect the or-join semantics of Datomic Datalog, https://docs.datomic.com/on-prem/query.html
|
||||
;; TODO use record constructors instead of wordy literals as for rest in this buffer
|
||||
(is (= (dp/parse-clause '(or-join [?x] [?y]))
|
||||
'#datalog.parser.type.Or{:source #datalog.parser.type.DefaultSrc{},
|
||||
:rule-vars #datalog.parser.type.RuleVars{:required nil,
|
||||
:free [#datalog.parser.type.Variable{:symbol ?x}]},
|
||||
:clauses [#datalog.parser.type.Pattern{:source #datalog.parser.type.DefaultSrc{},
|
||||
:pattern [#datalog.parser.type.Variable{:symbol ?y}]}]}))
|
||||
(is (= (dp/parse-clause '(or-join [?x ?y] [?x ?y] [?y]))
|
||||
'#datalog.parser.type.Or{:source #datalog.parser.type.DefaultSrc{},
|
||||
:rule-vars #datalog.parser.type.RuleVars{:required nil,
|
||||
:free [#datalog.parser.type.Variable{:symbol ?x}
|
||||
#datalog.parser.type.Variable{:symbol ?y}]},
|
||||
:clauses [#datalog.parser.type.Pattern{:source #datalog.parser.type.DefaultSrc{},
|
||||
:pattern [#datalog.parser.type.Variable{:symbol ?x}
|
||||
#datalog.parser.type.Variable{:symbol ?y}]}
|
||||
#datalog.parser.type.Pattern{:source #datalog.parser.type.DefaultSrc{},
|
||||
:pattern [#datalog.parser.type.Variable{:symbol ?y}]}]}))
|
||||
|
||||
(is (= (dp/parse-clause '(or-join [?y]
|
||||
(or-join [?x]
|
||||
[?x :follows ?y])))
|
||||
'#datalog.parser.type.Or{:source #datalog.parser.type.DefaultSrc{},
|
||||
:rule-vars #datalog.parser.type.RuleVars{:required nil,
|
||||
:free [#datalog.parser.type.Variable{:symbol ?y}]},
|
||||
:clauses [#datalog.parser.type.Or{:source #datalog.parser.type.DefaultSrc{},
|
||||
:rule-vars #datalog.parser.type.RuleVars{:required nil,
|
||||
:free [#datalog.parser.type.Variable{:symbol ?x}]},
|
||||
:clauses [#datalog.parser.type.Pattern{:source #datalog.parser.type.DefaultSrc{},
|
||||
:pattern [#datalog.parser.type.Variable{:symbol ?x}
|
||||
#datalog.parser.type.Constant{:value :follows} #datalog.parser.type.Variable{:symbol ?y}]}]}]}))
|
||||
|
||||
|
||||
(is (thrown-with-msg? ExceptionInfo #"Join variable not declared inside clauses: \[\?y\]"
|
||||
(dp/parse-clause '(or [?x] [?x ?y]))))
|
||||
|
||||
(is (thrown-with-msg? ExceptionInfo #"Join variable not declared inside clauses: \[\?y\]"
|
||||
(dp/parse-clause '(or [?x] [?y]))))
|
||||
|
||||
(is (thrown-with-msg? ExceptionInfo #"Cannot parse rule-vars"
|
||||
(dp/parse-clause '(or-join [] [?y]))))
|
||||
|
||||
(is (thrown-with-msg? ExceptionInfo #"Join variables should not be empty"
|
||||
(dp/parse-clause '(or [_]))))
|
||||
|
||||
(is (thrown-with-msg? ExceptionInfo #"Cannot parse 'or-join' clause"
|
||||
(dp/parse-clause '(or-join [?x]))))
|
||||
|
||||
(is (thrown-with-msg? ExceptionInfo #"Cannot parse 'or' clause"
|
||||
(dp/parse-clause '(or)))))
|
||||
|
||||
|
||||
(deftest test-parse-return-maps
|
||||
(testing "failed parsing"
|
||||
(is (thrown-with-msg? ExceptionInfo #"Only one of these three options is allowed: :keys :strs :syms"
|
||||
(dp/parse-return-maps {:keys '("keys" "strs" "syms") :syms '("keys" "strs" "syms")}))))
|
||||
(testing "parsing correct options"
|
||||
(is (= #datalog.parser.type.ReturnMaps{:mapping-type :keys, :mapping-keys (#datalog.parser.type.MappingKey{:mapping-key "keys"} #datalog.parser.type.MappingKey{:mapping-key "strs"} #datalog.parser.type.MappingKey{:mapping-key "syms"})}
|
||||
(dp/parse-return-maps {:keys '("keys" "strs" "syms")})))
|
||||
(is (= #datalog.parser.type.ReturnMaps{:mapping-type :strs, :mapping-keys (#datalog.parser.type.MappingKey{:mapping-key "keys"} #datalog.parser.type.MappingKey{:mapping-key "strs"} #datalog.parser.type.MappingKey{:mapping-key "syms"})}
|
||||
(dp/parse-return-maps {:strs '("keys" "strs" "syms")})))
|
||||
(is (= #datalog.parser.type.ReturnMaps{:mapping-type :syms, :mapping-keys (#datalog.parser.type.MappingKey{:mapping-key "keys"} #datalog.parser.type.MappingKey{:mapping-key "strs"} #datalog.parser.type.MappingKey{:mapping-key "syms"})}
|
||||
(dp/parse-return-maps {:syms '("keys" "strs" "syms")})))))
|
||||
42
test-resources/lib_tests/datalog/parser/pull_test.cljc
Normal file
42
test-resources/lib_tests/datalog/parser/pull_test.cljc
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
(ns datalog.parser.pull-test
|
||||
(:require [datalog.parser.pull :as dpp]
|
||||
#?(:cljs [cljs.test :as t :refer-macros [is are deftest testing]]
|
||||
:clj [clojure.test :as t :refer [is are deftest testing]])))
|
||||
|
||||
#?(:cljs
|
||||
(def Throwable js/Error))
|
||||
|
||||
(deftest test-parse-pattern
|
||||
(are [pattern expected] (= expected (dpp/parse-pull pattern))
|
||||
'[:db/id :foo/bar]
|
||||
(dpp/->PullSpec false {:db/id {:attr :db/id}
|
||||
:foo/bar {:attr :foo/bar}})
|
||||
|
||||
'[(limit :foo 1)]
|
||||
(dpp/->PullSpec false {:foo {:attr :foo :limit 1}})
|
||||
|
||||
'[* (default :foo "bar")]
|
||||
(dpp/->PullSpec true {:foo {:attr :foo :default "bar"}})
|
||||
|
||||
'[{:foo ...}]
|
||||
(dpp/->PullSpec false {:foo {:attr :foo :recursion nil}})
|
||||
|
||||
'[{(limit :foo 2) [:bar :me]}]
|
||||
(dpp/->PullSpec
|
||||
false
|
||||
{:foo {:attr :foo
|
||||
:limit 2
|
||||
:subpattern (dpp/->PullSpec
|
||||
false
|
||||
{:bar {:attr :bar}
|
||||
:me {:attr :me}})}})))
|
||||
|
||||
(deftest test-parse-bad-limit
|
||||
(is
|
||||
(thrown? Throwable (dpp/parse-pull '[(limit :foo :bar)]))))
|
||||
|
||||
(deftest test-parse-bad-default
|
||||
(is
|
||||
(thrown? Throwable (dpp/parse-pull '[(default 1 :bar)]))))
|
||||
|
||||
#_(t/test-ns 'datahike.test.pull-parser)
|
||||
16
test-resources/lib_tests/datalog/parser/test/util.cljc
Normal file
16
test-resources/lib_tests/datalog/parser/test/util.cljc
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
(ns datalog.parser.test.util
|
||||
(:require [#?(:clj clojure.test :cljs cljs.test) :as test]))
|
||||
|
||||
#?(:clj
|
||||
(defmethod test/assert-expr 'thrown-msg? [msg form]
|
||||
(let [[_ match & body] form]
|
||||
`(try ~@body
|
||||
(test/do-report {:type :fail, :message ~msg, :expected '~form, :actual nil})
|
||||
(catch Throwable e#
|
||||
(let [m# (.getMessage e#)]
|
||||
(test/do-report
|
||||
{:type (if (= ~match m#) :pass :fail)
|
||||
:message ~msg
|
||||
:expected '~form
|
||||
:actual e#}))
|
||||
e#)))))
|
||||
96
test-resources/lib_tests/datalog/parser_test.cljc
Normal file
96
test-resources/lib_tests/datalog/parser_test.cljc
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
(ns datalog.parser-test
|
||||
(:require #?(:cljs [cljs.test :refer-macros [are deftest]]
|
||||
:clj [clojure.test :refer [are deftest]])
|
||||
[datalog.parser :as parser]
|
||||
[datalog.parser.test.util]))
|
||||
|
||||
(deftest validation
|
||||
(are [q result] (= result (parser/parse q))
|
||||
'[:find ?e
|
||||
:in $ ?fname ?lname
|
||||
:keys foo
|
||||
:where [?e :user/firstName ?fname]
|
||||
[?e :user/lastName ?lname]]
|
||||
'#datalog.parser.type.Query{:qfind #datalog.parser.type.FindRel{:elements [#datalog.parser.type.Variable{:symbol ?e}]}, :qwith nil, :qin [#datalog.parser.type.BindScalar{:variable #datalog.parser.type.SrcVar{:symbol $}} #datalog.parser.type.BindScalar{:variable #datalog.parser.type.Variable{:symbol ?fname}} #datalog.parser.type.BindScalar{:variable #datalog.parser.type.Variable{:symbol ?lname}}], :qwhere [#datalog.parser.type.Pattern{:source #datalog.parser.type.DefaultSrc{}, :pattern [#datalog.parser.type.Variable{:symbol ?e} #datalog.parser.type.Constant{:value :user/firstName} #datalog.parser.type.Variable{:symbol ?fname}]} #datalog.parser.type.Pattern{:source #datalog.parser.type.DefaultSrc{}, :pattern [#datalog.parser.type.Variable{:symbol ?e} #datalog.parser.type.Constant{:value :user/lastName} #datalog.parser.type.Variable{:symbol ?lname}]}], :qlimit nil, :qoffset nil, :qreturnmaps #datalog.parser.type.ReturnMaps{:mapping-type :keys, :mapping-keys (#datalog.parser.type.MappingKey{:mapping-key foo})}}
|
||||
|
||||
'[:find ?e
|
||||
:in $ ?fname ?lname
|
||||
:strs foo
|
||||
:where [?e :user/firstName ?fname]
|
||||
[?e :user/lastName ?lname]]
|
||||
'#datalog.parser.type.Query{:qfind #datalog.parser.type.FindRel{:elements [#datalog.parser.type.Variable{:symbol ?e}]}, :qwith nil, :qin [#datalog.parser.type.BindScalar{:variable #datalog.parser.type.SrcVar{:symbol $}} #datalog.parser.type.BindScalar{:variable #datalog.parser.type.Variable{:symbol ?fname}} #datalog.parser.type.BindScalar{:variable #datalog.parser.type.Variable{:symbol ?lname}}], :qwhere [#datalog.parser.type.Pattern{:source #datalog.parser.type.DefaultSrc{}, :pattern [#datalog.parser.type.Variable{:symbol ?e} #datalog.parser.type.Constant{:value :user/firstName} #datalog.parser.type.Variable{:symbol ?fname}]} #datalog.parser.type.Pattern{:source #datalog.parser.type.DefaultSrc{}, :pattern [#datalog.parser.type.Variable{:symbol ?e} #datalog.parser.type.Constant{:value :user/lastName} #datalog.parser.type.Variable{:symbol ?lname}]}], :qlimit nil, :qoffset nil, :qreturnmaps #datalog.parser.type.ReturnMaps{:mapping-type :strs, :mapping-keys (#datalog.parser.type.MappingKey{:mapping-key foo})}}
|
||||
|
||||
'[:find ?e
|
||||
:in $ ?fname ?lname
|
||||
:syms foo
|
||||
:where [?e :user/firstName ?fname]
|
||||
[?e :user/lastName ?lname]]
|
||||
'#datalog.parser.type.Query{:qfind #datalog.parser.type.FindRel{:elements [#datalog.parser.type.Variable{:symbol ?e}]}, :qwith nil, :qin [#datalog.parser.type.BindScalar{:variable #datalog.parser.type.SrcVar{:symbol $}} #datalog.parser.type.BindScalar{:variable #datalog.parser.type.Variable{:symbol ?fname}} #datalog.parser.type.BindScalar{:variable #datalog.parser.type.Variable{:symbol ?lname}}], :qwhere [#datalog.parser.type.Pattern{:source #datalog.parser.type.DefaultSrc{}, :pattern [#datalog.parser.type.Variable{:symbol ?e} #datalog.parser.type.Constant{:value :user/firstName} #datalog.parser.type.Variable{:symbol ?fname}]} #datalog.parser.type.Pattern{:source #datalog.parser.type.DefaultSrc{}, :pattern [#datalog.parser.type.Variable{:symbol ?e} #datalog.parser.type.Constant{:value :user/lastName} #datalog.parser.type.Variable{:symbol ?lname}]}], :qlimit nil, :qoffset nil, :qreturnmaps #datalog.parser.type.ReturnMaps{:mapping-type :syms, :mapping-keys (#datalog.parser.type.MappingKey{:mapping-key foo})}}
|
||||
|
||||
'{:find [?e]
|
||||
:in [$ ?fname ?lname]
|
||||
:keys [foo]
|
||||
:where [[?e :user/firstName ?fname]
|
||||
[?e :user/lastName ?lname]]}
|
||||
'#datalog.parser.type.Query{:qfind #datalog.parser.type.FindRel{:elements [#datalog.parser.type.Variable{:symbol ?e}]}, :qwith nil, :qin [#datalog.parser.type.BindScalar{:variable #datalog.parser.type.SrcVar{:symbol $}} #datalog.parser.type.BindScalar{:variable #datalog.parser.type.Variable{:symbol ?fname}} #datalog.parser.type.BindScalar{:variable #datalog.parser.type.Variable{:symbol ?lname}}], :qwhere [#datalog.parser.type.Pattern{:source #datalog.parser.type.DefaultSrc{}, :pattern [#datalog.parser.type.Variable{:symbol ?e} #datalog.parser.type.Constant{:value :user/firstName} #datalog.parser.type.Variable{:symbol ?fname}]} #datalog.parser.type.Pattern{:source #datalog.parser.type.DefaultSrc{}, :pattern [#datalog.parser.type.Variable{:symbol ?e} #datalog.parser.type.Constant{:value :user/lastName} #datalog.parser.type.Variable{:symbol ?lname}]}], :qlimit nil, :qoffset nil, :qreturnmaps #datalog.parser.type.ReturnMaps{:mapping-type :keys, :mapping-keys (#datalog.parser.type.MappingKey{:mapping-key foo})}}
|
||||
|
||||
'{:find [[?e ?fname]]
|
||||
:keys [foo]
|
||||
:in [$ ?fname ?lname]
|
||||
:where [[?e :user/firstName ?fname]
|
||||
[?e :user/lastName ?lname]]}
|
||||
#datalog.parser.type.Query{:qfind #datalog.parser.type.FindTuple{:elements [#datalog.parser.type.Variable{:symbol ?e} #datalog.parser.type.Variable{:symbol ?fname}]}, :qwith nil, :qin [#datalog.parser.type.BindScalar{:variable #datalog.parser.type.SrcVar{:symbol $}} #datalog.parser.type.BindScalar{:variable #datalog.parser.type.Variable{:symbol ?fname}} #datalog.parser.type.BindScalar{:variable #datalog.parser.type.Variable{:symbol ?lname}}], :qwhere [#datalog.parser.type.Pattern{:source #datalog.parser.type.DefaultSrc{}, :pattern [#datalog.parser.type.Variable{:symbol ?e} #datalog.parser.type.Constant{:value :user/firstName} #datalog.parser.type.Variable{:symbol ?fname}]} #datalog.parser.type.Pattern{:source #datalog.parser.type.DefaultSrc{}, :pattern [#datalog.parser.type.Variable{:symbol ?e} #datalog.parser.type.Constant{:value :user/lastName} #datalog.parser.type.Variable{:symbol ?lname}]}], :qlimit nil, :qoffset nil, :qreturnmaps #datalog.parser.type.ReturnMaps{:mapping-type :keys, :mapping-keys (#datalog.parser.type.MappingKey{:mapping-key foo})}}
|
||||
))
|
||||
|
||||
(deftest validation-fails
|
||||
(are [q msg] (thrown-msg? msg (parser/parse q))
|
||||
'[:find ?e :where [?x]]
|
||||
"Query for unknown vars: [?e]"
|
||||
|
||||
'[:find ?e :with ?f :where [?e]]
|
||||
"Query for unknown vars: [?f]"
|
||||
|
||||
'[:find ?e ?x ?t :in ?x :where [?e]]
|
||||
"Query for unknown vars: [?t]"
|
||||
|
||||
'[:find ?x ?e :with ?y ?e :where [?x ?e ?y]]
|
||||
":find and :with should not use same variables: [?e]"
|
||||
|
||||
'[:find ?e :in $ $ ?x :where [?e]]
|
||||
"Vars used in :in should be distinct"
|
||||
|
||||
'[:find ?e :in ?x $ ?x :where [?e]]
|
||||
"Vars used in :in should be distinct"
|
||||
|
||||
'[:find ?e :in $ % ?x % :where [?e]]
|
||||
"Vars used in :in should be distinct"
|
||||
|
||||
'[:find ?n :with ?e ?f ?e :where [?e ?f ?n]]
|
||||
"Vars used in :with should be distinct"
|
||||
|
||||
'[:find ?x :where [$1 ?x]]
|
||||
"Where uses unknown source vars: [$1]"
|
||||
|
||||
'[:find ?x :in $1 :where [$2 ?x]]
|
||||
"Where uses unknown source vars: [$2]"
|
||||
|
||||
'[:find ?e :where (rule ?e)]
|
||||
"Missing rules var '%' in :in"
|
||||
|
||||
'[:find ?e :where [?e] :limit [42]]
|
||||
"Cannot parse :limit, expected java.lang.Long"
|
||||
|
||||
'[:find ?e :where [?e] :offset [666]]
|
||||
"Cannot parse :offset, expected java.lang.Long"
|
||||
|
||||
'[:find ?e :keys foo bar :where [?e] :offset 666]
|
||||
"Count of :keys/:strs/:syms must match count of :find"
|
||||
|
||||
'[:find ?e ?f :keys foo :where [?e ?f] :offset 666]
|
||||
"Count of :keys/:strs/:syms must match count of :find"
|
||||
|
||||
'[:find [?e ?f] :keys foo bar :where [?e ?f] :offset 666]
|
||||
"Count of :keys/:strs/:syms must match count of :find"
|
||||
|
||||
'[:find ?e :strs '(foo bar) :keys '("foo" "bar") :where [?e] :offset 666]
|
||||
"Only one of these three options is allowed: :keys :strs :syms"))
|
||||
25
test-resources/lib_tests/datalog/unparser_test.clj
Normal file
25
test-resources/lib_tests/datalog/unparser_test.clj
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
(ns datalog.unparser-test
|
||||
(:require [datalog.unparser :refer [unparse]]
|
||||
[datalog.parser :refer [parse]]
|
||||
[clojure.test :refer [deftest testing is] :as test])
|
||||
(:use [datalog.unparser]))
|
||||
|
||||
(let [q '[:find (sum ?balance-before) ?balance-before
|
||||
:in $before $after $txn $txs
|
||||
:where
|
||||
[(= ?balance-before 42)]]]
|
||||
(deftest unparse-roundtrip-test
|
||||
(testing "Datahike query unparsing."
|
||||
(is (= q (unparse (parse q)))))))
|
||||
|
||||
|
||||
|
||||
(comment ;; TODO
|
||||
(let [q '[:find ?foo ?baz
|
||||
:in $before $after
|
||||
:where
|
||||
[(= ?balance-before 42)]
|
||||
(not [?foo :bar ?baz])]]
|
||||
(deftest unparse-roundtrip-test
|
||||
(testing "Datahike query unparsing."
|
||||
(is (= q (unparse (parse q))))))))
|
||||
Loading…
Reference in a new issue