tonsky / datascript

Immutable database and Datalog query engine for Clojure, ClojureScript and JS
Eclipse Public License 1.0
5.5k stars 309 forks source link

Predicate seems to be lazily evaluated and fails silently #385

Closed frankiesardo closed 3 years ago

frankiesardo commented 3 years ago

Hey @tonsky

I've noticed a behaviour that is substantially different from Datomic, and might be a bug.

I'm using datascript 1.0.3 and I've tested this behaviour both on cljs and clj.

When I'm running

(d/q '[:find ?name ?result
       :in $ ?my-fn
       :where
       [?e :person/name ?name]
       [(?my-fn) ?result]
       [(< ?result 3)]]
     (d/db-with (d/empty-db) [{:person/name "Joe"}])
     (fn [] 5))

=> #{}

I correctly get an empty set (result is greater than 3)

But if I do not force the evaluation of ?result the condition is never checked

(d/q '[:find ?name
       :in $ ?my-fn
       :where
       [?e :person/name ?name]
       [(?my-fn) ?result]
       [(< ?result 3)]]
     (d/db-with (d/empty-db) [{:person/name "Joe"}])
     (fn [] 5))

=> #{["Joe"]}

The same behaviour occurs on the JVM if you call the function directly

(defn my-fn [] 5)

(d/q '[:find ?name
       :in $
       :where
       [?e :person/name ?name]
       [(user/my-fn) ?result]
       [(< ?result 3)]]
     (d/db-with (d/empty-db) [{:person/name "Joe"}]))

=> #{["Joe"]}

The equivalent code in Datomic produces an empty set instead.

(def conn (do (d/create-database "datomic:mem://test") (d/connect "datomic:mem://test")))
(defn my-fn [] 5)

(d/q '[:find ?doc
       :in $
       :where
       [?e :db/doc ?doc]
       [(user/my-fn) ?result]
       [(< ?result 3)]]
     (d/db conn))

=> #{}
tonsky commented 3 years ago

Looks like a bug — I’ll take a look!

tonsky commented 3 years ago

Pushed 1.0.5, hope it fixes the issue

frankiesardo commented 3 years ago

It does, thanks for the quick fix! 🥇