datascript

Nik 2024-03-22T02:52:43.453259Z

Hi, I'm learning datalog and datascript. I tried to use example from https://github.com/kristianmandrup/datascript-tutorial/blob/master/pull_data.md When I try same query (in clojure project). I get error

(d/pull-many (d/db conn) '[*] (d/q '[:find ?e :where [?e]]
                                   ))
;; Error - Too few inputs passed, expected: [$], got: 0
When I pass db to inner query
(d/pull-many (d/db conn) '[*] (d/q '[:find ?e :where [?e]]
                                   (d/db conn)))
;; Error - Lookup ref should contain 2 elements: [100]
which I think is happening as result set looks like #{[4] [5] [100]} . If it change to vector and flatten (flatten (vec ids)) and pass it to pull-many then it works. Is there a mistake in guide or am I missing something that will let me chain query to pull expression?

πŸ‘ 1
Niki 2024-03-22T14:18:42.530529Z

Yes, it looks like a mistake. I think it should be

(d/pull-many
  db
  '[*]
  (d/q
    '[:find [?e ...]
      :where [?e]]
    db))

Niki 2024-03-22T14:20:27.525859Z

That’s very strange way of using it though. You can put pull directly inside query:

(d/q
  '[:find [(pull ?e [*]) ...]
    :where [?e]]
  db))

πŸ™ŒπŸΌ 1
Nik 2024-03-22T15:35:06.718499Z

The second option seems better so I'll go ahead with it. Thanks!

Nik 2024-03-22T04:35:05.987259Z

In simple todo app. How to write query to find todos which have only 2 tags. would it something like this?

(d/q '[:find ?todo
         :where
         [?todo :tags ?t]
         [(= 2 (count ?t))]])

2024-03-22T12:52:35.270919Z

You can use a subquery:

(ds/q '[:find ?todo
        :in $
        :where
        [(ds/q [:find ?todo (count ?t)
                :in $
                :where [?todo :tags ?t]]
           $)         
         [[?todo ?ct] ...]]
        [(= ?ct 2)]]
  (ds/db-with (ds/empty-db {:tags {:db/cardinality :db.cardinality/many}})
    [{:tags [:a :b :c]}
     {:tags [:a :b]}
     {:tags [:x :y]}]))

πŸ‘ 1
πŸ‘πŸΌ 1
Nik 2024-03-22T13:08:11.292879Z

Thanks