datomic

linuss 2017-06-29T12:11:03.040679Z

@linuss has joined the channel

linuss 2017-06-29T12:11:31.048016Z

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?

hmaurer 2017-06-29T12:26:24.279628Z

@linuss maybe you could use a disjunction? http://blog.datomic.com/2015/01/datalog-enhancements.html

2017-06-29T13:09:58.074031Z

@linuss there will never be a nil value in datomic. Instead use missing? http://docs.datomic.com/query.html#sec-5-12-5

linuss 2017-06-29T13:13:46.150983Z

Ah, right!

linuss 2017-06-29T13:26:07.416596Z

Hm, even when I replace the nil? with missing?, the query returns all :functiontypes

favila 2017-06-29T13:28:19.466989Z

query predicates only do query var replacement at the first level

favila 2017-06-29T13:30:33.520455Z

[(or (nil? ?fid) (= ?ftid ?value))] is always true, because those inner items of or are literal lists

favila 2017-06-29T13:30:41.523955Z

what you want to do cannot be done without changing the query

favila 2017-06-29T13:31:07.534038Z

or at least without branching

favila 2017-06-29T13:32:12.558889Z

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

favila 2017-06-29T13:32:42.570554Z

Personally I almost always use cond-> to create different queries dynamically

linuss 2017-06-29T13:33:21.585100Z

Okay, thanks! I'll try that 🙂

hmaurer 2017-06-29T13:34:37.613250Z

@favila what do you mean by cond->?

linuss 2017-06-29T13:34:37.613372Z

But the or in datomic doesn't short-circuit, right?

linuss 2017-06-29T13:34:53.619627Z

So, it will return datoms that match either set of predicates

linuss 2017-06-29T13:35:00.622373Z

so I'll always get all the functiontypes

favila 2017-06-29T13:35:37.636523Z

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

linuss 2017-06-29T13:35:49.640979Z

ah! clever!

favila 2017-06-29T13:38:55.712796Z

@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]))}})

hmaurer 2017-06-29T13:41:24.770460Z

@favila oh, so you build up the query dynamically based on the presence of a filter. Neat

linuss 2017-06-29T13:48:30.938032Z

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)

linuss 2017-06-29T13:50:43.991501Z

oh

linuss 2017-06-29T13:50:48.993435Z

no and clause

hmaurer 2017-06-29T14:14:15.594331Z

@linuss isn’t a vector the way to model a and clause?

linuss 2017-06-29T14:18:36.704086Z

That results in Join variables should not be empty

2017-06-29T18:31:14.935596Z

@ghopper has joined the channel

hmaurer 2017-06-29T18:49:07.344573Z

@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