ribelo / doxa

The Unlicense
232 stars 8 forks source link

question: queries with missing fields #15

Open spacegangster opened 3 years ago

spacegangster commented 3 years ago

Maybe a no-op, but is there an option to query a field that's missing in the source data map? Maybe some

  (let [db (dx/create-dx [{:db/id 1 :m/gist "ggg"} ; <- no :m/status field
                                          {:db/id 2 :m/status false :m/gist "ggg"}])
        q-status #{nil false true}]
    (dx/q [:find ?e
           :in ?pat ?q-status
           :where
           [?e :m/gist ?g]
           [?e :m/status ?status] ; <- maybe some default binding here?
           [(re-find ?pat ?g)]
           [(contains? ?q-status ?status)]]
          db #"" q-status)))

; yields [[2]]

Or, alternatively, to dynamically compose a query like here

  (let [db (dx/create-dx [{:db/id 1 :m/gist "ggg"} {:db/id 2 :m/status false :m/gist "ggg"}])
        q-status nil
        cond1 (if (nil? q-status)
                ['?e :db/id]
                ['?e :m/status '?status])]
    (dx/q [:find ?e
           :in ?pat ?q-status
           :where
           [?e :m/gist ?g]
           cond1
           [(re-find ?pat ?g)]]
          db #"" q-status)))
spacegangster commented 3 years ago

also, I've made a walkover for doxa and my etude for it https://github.com/spacegangster/rf-doxa-etude https://youtu.be/t0gG1zzIT_c The video is unlisted at the moment, I would make it public after your permission.

ribelo commented 3 years ago

Is that what this is about?

(let [db (dx/create-dx [{:db/id 1 :name "ivan" :age 15}
                        {:db/id 2 :name "petr"}])]
  (dx/q [:find ?e
         :where
         [?e :age (m/not (m/some ?age))]]
    db))
;; => [[2]]

for ?v is the freedom to create queries that the meander understands.

ribelo commented 3 years ago

As for the video, the code is on unlicense and you are free to do whatever you want. I am pleased that you want to do anything at all with doxa.

spacegangster commented 3 years ago

Is that what this is about?

(let [db (dx/create-dx [{:db/id 1 :name "ivan" :age 15}
                        {:db/id 2 :name "petr"}])]
  (dx/q [:find ?e
         :where
         [?e :age (m/not (m/some ?age))]]
    db))
;; => [[2]]

for ?v is the freedom to create queries that the meander understands.

Cool!

Is there an option for dynamic query composition though? For me as a user it would be neat to write my query like:

  (let [db (dx/create-dx [{:db/id 1 :m/gist "some"}
                          {:db/id 2 :m/status true :m/gist "some"}])]
    (dx/q [:find ?e
           :in ?q-status
           :where
           [?e :m/status (if (some? ?q-status) ?q-status (m/any ?status))]]
          db nil))

Ultimately would be nice to havedx/q accepting quoted lists/vectors, that would solve everything. Or maybe have a second fn – qq for now, to have two simpler options.

ribelo commented 3 years ago

Unfortunately, this cannot be done in a simple way. As far as I know meander, it will not work in this form. However, it can be done the meander style.

(let [db (dx/create-dx [{:db/id 1 :m/gist "some"}
                          {:db/id 2 :m/status true :m/gist "some"}])]
    (dx/q [:find ?e
           :in ?q-status
           :where
           [?e :m/status (m/or (m/and ?q-status (m/guard (some? ?q-status)))
                               (m/some))]]
      db nil))
; [[2]]

However, I think it doesn't really make sense, it's better to write with pure meander syntax then, because there's no need to obfuscate the code so much. What q really is in doxa, is a translator from datalog to meander rewrites. Not everything can be handled, and even what can be handled is often easier to write in pure meander.

Meander itself is much more advanced than datalog and you can write amazing queries in it. It is however much less concise, but as @noprompt wrote, conciseness was never the goal.

I personally stopped using datalog in favour of meander, at least on the CLJS side.