This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-04-12
Channels
- # announcements (1)
- # babashka (79)
- # beginners (165)
- # calva (29)
- # cider (20)
- # clara (3)
- # cljdoc (1)
- # cljs-dev (52)
- # clojure (42)
- # clojure-chicago (5)
- # clojure-europe (48)
- # clojure-germany (1)
- # clojure-italy (4)
- # clojure-nl (2)
- # clojure-spec (10)
- # clojure-uk (19)
- # clojurescript (50)
- # clojureverse-ops (5)
- # conjure (8)
- # datomic (16)
- # depstar (2)
- # events (1)
- # figwheel-main (23)
- # fulcro (26)
- # girouette (41)
- # graalvm (9)
- # heroku (3)
- # honeysql (10)
- # jackdaw (20)
- # lambdaisland (6)
- # lein-figwheel (1)
- # lsp (34)
- # malli (7)
- # meander (3)
- # music (1)
- # off-topic (14)
- # polylith (7)
- # re-frame (14)
- # reitit (8)
- # reveal (15)
- # ring (3)
- # schema (1)
- # sci (15)
- # shadow-cljs (42)
- # spacemacs (1)
- # startup-in-a-month (12)
- # tools-deps (59)
- # vim (1)
- # xtdb (27)
I am having issues with using a predicate in a query. Is there any reason why this shoud not work? Not using a logic variable to try to find the error. Ns t is java-time. [(t/contains? (t/interval "2020-10-18T09:21:31Z/2020-10-30T12:10:00Z") (t/instant))]
I think there are two issues here:
1. namespaces have to be fully qualified, since the query engine won't have access to your local aliases
2. predicates aren't quite as a flexible as arbitrary clojure forms, they will only work 1-level-deep. So here your 2 parameters to t/contains?
will be seen by the query engine as lists and not evaluated expressions. To work around this you can create additional clauses with intermediate variables, e.g.
[(tick.alpha.api/interval "2020-10-18T09:21:31Z/2020-10-30T12:10:00Z") time][(tick.alpha.api/instant) now] [(tick.alpha.api/contains? time now)]
And then again not. I am creating a function to take the interval and run the query, but I think I am messing up the quoting. Normally when I build these types of functions I quote the logic varibales individually. But this does not work here as the arguments to contains are never resolved.
(q
{:find '[(pull ?i [*])]
:where [['?i :type event-type]
['?i :time '?time]
[(java-time/interval interval) ?it]
[(java-time/contains? ?it ?time)]]})
hmm, should that be:
(q
{:find '[(pull ?i [*])]
:where [['?i :type event-type]
['?i :time '?time]
'[(java-time/interval interval) ?it]
'[(java-time/contains? ?it ?time)]]})
or you can do:
(q
{:find '[(pull ?i [*])]
:where [['?i :type event-type]
['?i :time '?time]
[(list java-time/interval 'interval) '?it]
[(list java-time/contains? '?it '?time)]]})
Both fails with :
"Clause refers to unknown variable: interval {:pred {:pred-fn #function[java-time.interval/interval], :args [interval]}, :return [:scalar ?it]}"}
error.clj: 12 crux.error/illegal-arg
For reference here is the entire function def:
(defn events-of-type
[interval event-type]
(map first
(q
{:find '[(pull ?i [*])]
:where [['?i :type event-type]
['?i :time '?time]
'[(java-time/interval interval) ?it]
'[(java-time/contains? ?it ?time)]]})))
thanks, that helps! you probably want this:
(defn events-of-type
[interval event-type]
(map first
(q
{:find '[(pull ?i [*])]
:where [['?i :type event-type]
['?i :time '?time]
[(list java-time/interval interval) '?it]
'[(java-time/contains? ?it ?time)]]})))
you could also use :in
bindings to pass in the interval
value (this will also have a very minor performance benefit, since compiled queries are cached)
This fails with:
Unhandled crux.IllegalArgumentException
Query didn't match expected structure
{:crux.error/error-type :illegal-argument,
:crux.error/error-key :query-spec-failed,
:crux.error/message "Query didn't match expected structure",
:explain
#:clojure.spec.alpha{:problems
({:path [:where :triple :e],
:pred
(clojure.core/some-fn
crux.query/logic-var?
crux.codec/valid-id?
clojure.core/set?),
:val
(#function[java-time.interval/interval]
"2020-10-18T09:21:31Z/2020-10-30T12:10:00Z"),
:via
[:crux.query/query
:crux.query/where
:crux.query/term
:crux.query/triple],
:in [:where 2 0]}
{:path [:where :not],
:pred clojure.core/seq?,
:val
[(#function[java-time.interval/interval]
"2020-10-18T09:21:31Z/2020-10-30T12:10:00Z")
?it],
:via
[:crux.query/query
:crux.query/where
:crux.query/term
:crux.query/not],
:in [:where 2]}
{:path [:where :not-join],
:pred clojure.core/seq?,
:val
[(#function[java-time.interval/interval]
"2020-10-18T09:21:31Z/2020-10-30T12:10:00Z")
?it],
:via
[:crux.query/query
:crux.query/where
:crux.query/term
:crux.query/not-join],
:in [:where 2]}
{:path [:where :or],
:pred clojure.core/seq?,
:val
[(#function[java-time.interval/interval]
"2020-10-18T09:21:31Z/2020-10-30T12:10:00Z")
?it],
:via
[:crux.query/query
:crux.query/where
:crux.query/term
:crux.query/or],
:in [:where 2]}
{:path [:where :or-join],
:pred clojure.core/seq?,
:val
[(#function[java-time.interval/interval]
"2020-10-18T09:21:31Z/2020-10-30T12:10:00Z")
?it],
:via
[:crux.query/query
:crux.query/where
:crux.query/term
:crux.query/or-join],
:in [:where 2]}
{:path [:where :range],
:pred (clojure.core/= (clojure.core/count %) 1),
:val
[(#function[java-time.interval/interval]
"2020-10-18T09:21:31Z/2020-10-30T12:10:00Z")
?it],
:via
[:crux.query/query
:crux.query/where
:crux.query/term
:crux.query/range],
:in [:where 2]}
{:path [:where :rule],
:pred clojure.core/list?,
:val
[(#function[java-time.interval/interval]
"2020-10-18T09:21:31Z/2020-10-30T12:10:00Z")
?it],
:via
[:crux.query/query
:crux.query/where
:crux.query/term
:crux.query/rule],
:in [:where 2]}
{:path [:where :pred :pred :pred-fn],
:pred clojure.core/symbol?,
:val #function[java-time.interval/interval],
:via
[:crux.query/query
:crux.query/where
:crux.query/term
:crux.query/pred
:crux.query/pred-fn
:crux.query/pred-fn],
:in [:where 2 0 0]}),
:spec :crux.query/query,
:value
{:find [(pull ?i [*])],
:where
[[?i :type :incident]
[?i :time ?time]
[(#function[java-time.interval/interval]
"2020-10-18T09:21:31Z/2020-10-30T12:10:00Z")
?it]
[(java-time/contains? ?it ?time)]]}}}
error.clj: 12 crux.error/illegal-arg
error.clj: 3 crux.error/illegal-arg
error.clj: 7 crux.error/illegal-arg
error.clj: 3 crux.error/illegal-arg
query.clj: 248 crux.query/normalize-and-conform-query/fn
second_chance.clj: 44 crux.cache.second-chance.SecondChanceCache/computeIfAbsent
cache.clj: 7 crux.cache/compute-if-absent
cache.clj: 6 crux.cache/compute-if-absent
query.clj: 240 crux.query/normalize-and-conform-query
query.clj: 235 crux.query/normalize-and-conform-query
query.clj: 1813 crux.query.QueryDatasource/open_q_STAR_
query.clj: 1788 crux.query.QueryDatasource/q_STAR_
api.clj: 349 crux.api/q
api.clj: 343 crux.api/q
RestFn.java: 425 clojure.lang.RestFn/invoke
REPL: 68 hypercontracts.domains.interpreter.db/q
REPL: 66 hypercontracts.domains.interpreter.db/q
REPL: 92 hypercontracts.domains.interpreter.db/events-of-type
REPL: 89 hypercontracts.domains.interpreter.db/events-of-type
REPL: 99 hypercontracts.domains.interpreter.db/eval88897
REPL: 99 hypercontracts.domains.interpreter.db/eval88897
Compiler.java: 7181 clojure.lang.Compiler/eval
Compiler.java: 7136 clojure.lang.Compiler/eval
core.clj: 3202 clojure.core/eval
core.clj: 3198 clojure.core/eval
interruptible_eval.clj: 87 nrepl.middleware.interruptible-eval/evaluate/fn/fn
AFn.java: 152 clojure.lang.AFn/applyToHelper
AFn.java: 144 clojure.lang.AFn/applyTo
core.clj: 667 clojure.core/apply
core.clj: 1977 clojure.core/with-bindings*
core.clj: 1977 clojure.core/with-bindings*
RestFn.java: 425 clojure.lang.RestFn/invoke
interruptible_eval.clj: 87 nrepl.middleware.interruptible-eval/evaluate/fn
main.clj: 437 clojure.main/repl/read-eval-print/fn
main.clj: 437 clojure.main/repl/read-eval-print
main.clj: 458 clojure.main/repl/fn
main.clj: 458 clojure.main/repl
main.clj: 368 clojure.main/repl
RestFn.java: 137 clojure.lang.RestFn/applyTo
core.clj: 667 clojure.core/apply
core.clj: 662 clojure.core/apply
regrow.clj: 20 refactor-nrepl.ns.slam.hound.regrow/wrap-clojure-repl/fn
RestFn.java: 1523 clojure.lang.RestFn/invoke
interruptible_eval.clj: 84 nrepl.middleware.interruptible-eval/evaluate
interruptible_eval.clj: 56 nrepl.middleware.interruptible-eval/evaluate
interruptible_eval.clj: 152 nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
AFn.java: 22 clojure.lang.AFn/run
session.clj: 202 nrepl.middleware.session/session-exec/main-loop/fn
session.clj: 201 nrepl.middleware.session/session-exec/main-loop
AFn.java: 22 clojure.lang.AFn/run
Thread.java: 834 java.lang.Thread/run
oh yeah, good spot by the query compiler 🙂 this is the key line > :val (#function[java-time.interval/interval] > "2020-10-18T09:21:31Z/2020-10-30T12:10:00Z")
i.e.
(defn events-of-type
[interval event-type]
(map first
(q
{:find '[(pull ?i [*])]
:where [['?i :type event-type]
['?i :time '?time]
[(list 'java-time/interval interval) '?it]
'[(java-time/contains? ?it ?time)]]})))
the alternative approach, with :in
looks like:
(defn events-of-type
[interval event-type]
(map first
(q
'{:find [(pull ?i [*])]
:in [?event-type ?interval]
:where [[?i :type event-type]
[?i :time ?time]
[(java-time/interval ?interval) ?it]
[(java-time/contains? ?it ?time)]]}
event-type interval)))
First one works 🙂 The :in version fails with
Unhandled clojure.lang.ArityException
Wrong number of args (3) passed to: hypercontracts.domains.interpreter.db/q
I thought there were double [ missing around the :in clause, but that does not make a difference.
Oh I assumed that was the Crux q function! You need to make your custom q function support & args
I just spotted that 🙂 sorry. N q is the below. I think I stole that from some of your example code.
(defn q
[query]
(crux/q (crux/db node) query))
@U899JBRPF Thanks for your help. I must say I don't find quoting rules easy to figure out. Using :in
seems to make it much more straightforward.