Add 2 more compatible libs (#1171)

This commit is contained in:
Gabriel Horner 2022-02-10 07:45:15 -05:00 committed by GitHub
parent a1007efdac
commit ac6ad33fcb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 795 additions and 3 deletions

View file

@ -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

View file

@ -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

1 maven-name git-url
10 circleci/bond https://github.com/circleci/bond
11 clj-commons/clj-yaml https://github.com/clj-commons/clj-yaml
12 clj-commons/multigrep https://github.com/clj-commons/multigrep
13 clj-stacktrace/clj-stacktrace https://github.com/mmcgrana/clj-stacktrace
14 clojure-csv/clojure-csv https://github.com/davidsantiago/clojure-csv
15 clojure-term-colors/clojure-term-colors https://github.com/trhura/clojure-term-colors
16 com.exoscale/lingo https://github.com/exoscale/lingo
44 io.github.swirrl/dogstatsd https://github.com/swirrl/dogstatsd
45 io.github.technomancy/limit-break https://github.com/technomancy/limit-break
46 io.helins/binf https://github.com/helins/binf.cljc
47 io.lambdaforge/datalog-parser https://github.com/lambdaforge/datalog-parser
48 io.replikativ/hasch https://github.com/replikativ/hasch
49 java-http-clj/java-http-clj http://www.github.com/schmee/java-http-clj
50 lambdaisland/regal https://github.com/lambdaisland/regal

View file

@ -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

View file

@ -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"}}

View 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)))))

View 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+))))))

View 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")})))))

View 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)

View 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#)))))

View 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"))

View 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))))))))