@linuss has joined the channel
Hey guys. I want to query some data that is filtered by a value, but ONLY if that value is not nil. I currently have:
'[:find ?label ?value
:where
[?i :functiontype/functiontype ?label]
[?i :functiontype/functiontypeid ?value]
[?i :functiontype/blocked false]
[_ :offer/function ?fid]
[?j :functions/functionid ?fid]
[?j :functions/functiontypeid ?ftid]
[(or (nil? ?fid) (= ?ftid ?value))]]
but that doesn't seem to work, and also doesn't seem very idiomatic... Could anybody suggest an alternative?@linuss maybe you could use a disjunction? http://blog.datomic.com/2015/01/datalog-enhancements.html
@linuss there will never be a nil value in datomic. Instead use missing? http://docs.datomic.com/query.html#sec-5-12-5
Ah, right!
Hm, even when I replace the nil? with missing?, the query returns all :functiontypes
query predicates only do query var replacement at the first level
[(or (nil? ?fid) (= ?ftid ?value))] is always true, because those inner items of or are literal lists
what you want to do cannot be done without changing the query
or at least without branching
you could have a top-level or (or a rule) with two branches, one of which asserts value is nil, and this is the nil-case query, another one starts with [?i :functiontype/functiontypeid ?value] and is the non-nil case
Personally I almost always use cond-> to create different queries dynamically
Okay, thanks! I'll try that 🙂
@favila what do you mean by cond->?
But the or in datomic doesn't short-circuit, right?
So, it will return datoms that match either set of predicates
so I'll always get all the functiontypes
yes, but one branch will assert that ?value is nil, and the other one will match on nil, and both of these can't be true at the same time
ah! clever!
@hmaurer eg
(defn query-with-optional-filters [name]
{:query {:find '[?e]
:in (cond-> '[$]
name (conj '?name))
:where
(cond-> '[[?e :foo :bar]]
name (conj '[?e :name ?name]))}})@favila oh, so you build up the query dynamically based on the presence of a filter. Neat
Okay, so this is my new query:
[:find ?label ?value
:where
(or
(and [?i :functiontypes/functiontype ?label]
[?i :functiontypes/functiontypeid ?value]
[(missing $ ?e :offer/function)])
(and [_ offer/function ?fid]
[?i :function/functionid ?fid]
[?i :function/functiontypeid ?value]
[?j :functiontypes/functiontypeid ?value]
[?j :functiontypes/functiontype ?label]))]
but this won't run, saying Cannot parse clause, expected (data-pattern | pred-expr | fn-expr | rule-expr | not-clause | not-join-clause | or-clause | or-join-clause)oh
no and clause
@linuss isn’t a vector the way to model a and clause?
That results in Join variables should not be empty
@ghopper has joined the channel
@marshall did you answer the earlier question on why d/with cannot be used with d/as-of? If you did, sorry, I missed it