replikativ / datahike

A fast, immutable, distributed & compositional Datalog engine for everyone.
https://datahike.io
Eclipse Public License 1.0
1.62k stars 95 forks source link

[Bug]: Pulled attributes are not correct when attribute-refs are used #680

Closed jonasseglare closed 2 months ago

jonasseglare commented 2 months ago

What version of Datahike are you using?

0.6.1659

What version of Java are you using?

openjdk version "20.0.1" 2023-04-18

What operating system are you using?

Ubuntu 22

What database EDN configuration are you using?

{:store {:backend :mem, :id "ref-config"},
 :writer {:backend :self},
 :attribute-refs? true,
 :keep-history? false,
 :schema-flexibility :write}

Describe the bug

I added the following code to datahike.test.attribute-refs.query-pull-test:

(deftest test-pull-attribute
  (testing "Pull an attribute"
    (let [db (d/db-with ref-db [{:db/ident :attribute-to-use
                                 :db/cardinality :db.cardinality/one
                                 :db/valueType :db.type/keyword}])
          result (d/q '[:find (pull ?attr [*])
                        :in $ ?attr-name
                        :where
                        [?attr :db/ident ?attr-name]]
                      db :attribute-to-use)
   ....

When I run this code, the result gets bound to the following value:

[[#:db{:id 62,
       :ident :attribute-to-use,
       :valueType 23,
       :cardinality 11}]]

This is not what we want. We would like the values at :db/valueType and :db/cardinality to be maps that have at least the keys :db/id but also :db/ident, because that is what Datomic would return.

What is the expected behaviour?

We want result to be something like the following (apart from possibly different values at the :db/id keys):

[[#:db{:id 62,
       :ident :attribute-to-use,
       :valueType #:db{:id 23, :ident :db.type/keyword},
       :cardinality #:db{:id 11, :ident :db.cardinality/one}}]]

How can the behaviour be reproduced?

Add the following unit test to the namespace datahike.test.attribute-refs.query-pull-test:

(deftest test-pull-attribute
  (testing "Pull an attribute"
    (let [db (d/db-with ref-db [{:db/ident :attribute-to-use
                                 :db/cardinality :db.cardinality/one
                                 :db/valueType :db.type/keyword}])
          result (d/q '[:find (pull ?attr [*])
                        :in $ ?attr-name
                        :where
                        [?attr :db/ident ?attr-name]]
                      db :attribute-to-use)
          [[x]] result
          ids [(:db/id x)
               (-> x :db/valueType :db/id)
               (-> x :db/cardinality :db/id)]]
      (is (= 1 (count result)))
      (is (= 1 (count (first result))))
      (is (= #{:db/id :db/ident :db/valueType :db/cardinality} (set (keys x))))
      (is (number? (:db/id x)))
      (is (= :attribute-to-use (:db/ident x)))
      (is (= :db.type/keyword (-> x :db/valueType :db/ident)))
      (is (= :db.cardinality/one (-> x :db/cardinality :db/ident)))
      (is (every? number? ids))
      (is (= (count (set ids))
             (count ids))))))

Currently, this unit test would fail against the main branch. If we fix the problem, it is going to succeed.