Fork me on GitHub
#datascript
<
2017-01-22
>
bbss19:01:39

I want to be able to check if an entity I'm adding is already in the collection, but using a ref won't work because there are multiple keys that make the entity unique, and making multiple keys unique makes a new addition upsert. So I thought I'd just query first, but the problem now arises that I don't know how many key/values the entity will have beforehand. I tried something like this:

(def contains?-conn (d/create-conn {}))

(d/transact! contains?-conn [{:db/id -1 :thing/name "bla" :thing/other "blabla"}])

(d/q `[:find ?id .
       :in $
       :where
       ~(for [[key val]
             {:thing/name "bla"
              :thing/other "blabla"}]
         ['?id key val])]
     @contains?-conn
     )
But that gives:
Cannot parse binding, expected (bind-scalar | bind-tuple |
   bind-coll | bind-rel)
   {:error :parser/binding, :form :thing/other}

bbss19:01:43

Any idea how to give a variadic amount of where clauses? I thought maybe passing a list of key-values as an argument and then using the ... in datascript query. But not sure how I would do that.

bbss19:01:02

I guess there is a clue to it in the readme with this example:

(d/q '[ :find  ?k ?x
        :in    [[?k [?min ?max]] ...] ?range
        :where [(?range ?min ?max) [?x ...]]
               [(even? ?x)] ]
      { :a [1 7], :b [2 4] }
      range)
But the [?x ...] clause is hard to understand, let's see if I can understand better after reading relevant test files.

bbss19:01:02

This almost does it:

(d/q '[:find ?id .
       :in $ [[?k ?v] ...]
       :where
       [?id ?k ?v]
       ]
     @contains?-conn
     {:thing/name "bla"
      :thing/other "blabla"})
But that only needs to match one of the key-values.

bbss20:01:45

Great! This seems to do what I want:

(d/q (concat
      '[:find ?id
        :in $
        :where
        ]
      (for [[key val]
            {:thing/name "bla"
             :thing/other "blabla"}]
        ['?id key val]))
     @contains?-conn
     )