Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Datomic - working with OR clause

I'm currently working on migrating my clojure app(with korma) to Datomic framework and been in a loop while I was translating the queries. I realise the queries are not completely flexible(compared to korma), for example i would like to evaluate conditional clauses around different variables.

Considering a korma query,

(select users
   (where (or (and {:first_name [= "user"]}
                   {:last_name [= "sample"]})
              {:email [= "[email protected]"]})))

this can be converted to Datomic, with something like this?

 [:find ?e
  :where (or (and [?u :user/first-name "user"]
                  [?u :user/last-name "sample"])
             [?u :user/email "[email protected]"])

but this is not the recommended way of querying(according to Datomic docs), as all clauses used in an or clause must use the same set of variables. How do I set an OR clause around different sets of variables?

like image 938
Coding active Avatar asked May 20 '15 06:05

Coding active


1 Answers

Your query should work. All of your clauses do use the same variable: ?u

(d/q '[:find ?u
       :where (or (and [?u :user/first-name "user"]
                       [?u :user/last-name "sample"])
                  [?u :user/email "[email protected]"])]
  [[1 :user/first-name "user"]
   [1 :user/last-name "sample"]
   [2 :user/email "[email protected]"]
   [3 :user/first-name "user"]
   [3 :user/last-name "not sample"]])

=> #{[1] [2]}

If you need them to use different variables, you can use or-join to explicitly list them:

(d/q '[:find ?u
       :in $ ?first-name ?last-name ?email
       :where (or-join [?u ?first-name ?last-name ?email]
                (and [?u :user/first-name ?first-name]
                     [?u :user/last-name ?last-name])
                [?u :user/email ?email])]
     [[1 :user/first-name "user"]
      [1 :user/last-name "sample"]
      [2 :user/email "[email protected]"]
      [3 :user/first-name "user"]
      [3 :user/last-name "not sample"]]
     "user"
     "sample"
     "[email protected]")

=> #{[1] [2]}
like image 154
Anthony R. Avatar answered Oct 08 '22 18:10

Anthony R.