Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: Comparisons in queries fail when mixing values of different types #684

Closed
jonasseglare opened this issue Jun 20, 2024 · 0 comments · Fixed by #685
Closed

[Bug]: Comparisons in queries fail when mixing values of different types #684

jonasseglare opened this issue Jun 20, 2024 · 0 comments · Fixed by #685
Labels
bug Something isn't working triage

Comments

@jonasseglare
Copy link
Collaborator

What version of Datahike are you using?

0.6.1566

What version of Java are you using?

openjdk 20.0.1 2023-04-18

What operating system are you using?

Ubuntu 22

What database EDN configuration are you using?

(-> (db/empty-db)
               (d/db-with [{:db/id 1, :name  "Ivan", :age   15}
                           {:db/id 2, :name  "Petr", :age   "37"}
                           {:db/id 3, :name  "Ivan", :age   :thirtyseven}
                           {:db/id 4, :age 15}]))

Describe the bug

The Clojure compare function cannot compare values of very different types, such as strings and numbers. Here is a small unit test to illustrate that:

(deftest test-mixed-age-types
  (let [db (-> (db/empty-db)
               (d/db-with [{:db/id 1, :name  "Ivan", :age   15}
                           {:db/id 2, :name  "Petr", :age   "37"}
                           {:db/id 3, :name  "Ivan", :age   :thirtyseven}
                           {:db/id 4, :age 15}]))]
    (is (= (d/q '[:find  ?e ?name
                  :where
                  [?e :name ?name]
                  [?e :age "37"]] db)
           #{[2 "Petr"]}))))

We initialize the database with entities that have :age attributes whose values are a mix of strings, number and keywords. Then we query entities based on the :age attribute being the string "37". This produces an exception, because the comparator used when running the query cannot compare strings and numbers.

What is the expected behaviour?

The provided unit test should successfully pass, that is the result of the query should be #{[2 "Petr"]}.

All we need is a comparator that compares different types in a well-defined way. How it orders them is not so important.

How can the behaviour be reproduced?

The following unit test (added to the source of datahike.test.query-test) produces an exception:

(deftest test-mixed-age-types
  (let [db (-> (db/empty-db)
               (d/db-with [{:db/id 1, :name  "Ivan", :age   15}
                           {:db/id 2, :name  "Petr", :age   "37"}
                           {:db/id 3, :name  "Ivan", :age   :thirtyseven}
                           {:db/id 4, :age 15}]))]
    (is (= (d/q '[:find  ?e ?name
                  :where
                  [?e :name ?name]
                  [?e :age "37"]] db)
           #{[2 "Petr"]}))))

The exception and stacktrace is:

   class java.lang.String cannot be cast to class java.lang.Number
   (java.lang.String and java.lang.Number are in module java.base of
   loader 'bootstrap')

                 Util.java:  152  clojure.lang.Util/compare
                datom.cljc:  259  datahike.datom$cmp_nil/invokeStatic
                datom.cljc:  256  datahike.datom$cmp_nil/invoke
       persistent_set.cljc:  129  datahike.index.persistent_set$fn__28839$G__28742__28856/invoke
            AFunction.java:   51  clojure.lang.AFunction/compare
                ANode.java:   76  me.tonsky.persistent_sorted_set.ANode/searchFirst
  PersistentSortedSet.java:  106  me.tonsky.persistent_sorted_set.PersistentSortedSet/slice
 persistent_sorted_set.clj:   34  me.tonsky.persistent-sorted-set/slice
 persistent_sorted_set.clj:   26  me.tonsky.persistent-sorted-set/slice
       persistent_set.cljc:  180  datahike.index.persistent_set$eval28900$fn__28903/invoke
            interface.cljc:    4  datahike.index.interface$eval26330$fn__26460$G__26299__26471/invoke
               search.cljc:   69  datahike.db.search$search_indices/invokeStatic
               search.cljc:   60  datahike.db.search$search_indices/invoke
               search.cljc:  102  datahike.db.search$search_current_indices$fn__32907/invoke
               search.cljc:   21  datahike.db.search$memoize_for/invokeStatic
               search.cljc:   18  datahike.db.search$memoize_for/invoke
               search.cljc:  100  datahike.db.search$search_current_indices/invokeStatic
               search.cljc:   99  datahike.db.search$search_current_indices/invoke
                   db.cljc:  140  datahike.db.DB/_search
                query.cljc:  607  datahike.query$lookup_pattern_db/invokeStatic
                query.cljc:  600  datahike.query$lookup_pattern_db/invoke
                query.cljc:  645  datahike.query$lookup_pattern/invokeStatic
                query.cljc:  642  datahike.query$lookup_pattern/invoke
                query.cljc: 1174  datahike.query$lookup_and_sum_pattern_rels/invokeStatic
                query.cljc: 1166  datahike.query$lookup_and_sum_pattern_rels/invoke
                query.cljc: 1186  datahike.query$lookup_patterns/invokeStatic
                query.cljc: 1180  datahike.query$lookup_patterns/invoke
                query.cljc: 1298  datahike.query$_resolve_clause_STAR_/invokeStatic
                query.cljc: 1199  datahike.query$_resolve_clause_STAR_/invoke
                query.cljc: 1306  datahike.query$_resolve_clause$fn__37006/invoke
          query_stats.cljc:   31  datahike.query_stats$update_ctx_with_stats/invokeStatic
          query_stats.cljc:   19  datahike.query_stats$update_ctx_with_stats/invoke
                query.cljc: 1305  datahike.query$_resolve_clause/invokeStatic
                query.cljc: 1301  datahike.query$_resolve_clause/invoke
                query.cljc: 1303  datahike.query$_resolve_clause/invokeStatic
                query.cljc: 1301  datahike.query$_resolve_clause/invoke
                query.cljc: 1315  datahike.query$resolve_clause/invokeStatic
                query.cljc: 1308  datahike.query$resolve_clause/invoke
                tools.cljc:  187  datahike.tools$reduce_clauses/invokeStatic
                tools.cljc:  179  datahike.tools$reduce_clauses/invoke
                tools.cljc:  194  datahike.tools$resolve_clauses/invokeStatic
                tools.cljc:  191  datahike.tools$resolve_clauses/invoke
                query.cljc: 1319  datahike.query$_q/invokeStatic
                query.cljc: 1317  datahike.query$_q/invoke
                query.cljc: 1457  datahike.query$raw_q/invokeStatic
                query.cljc: 1445  datahike.query$raw_q/invoke
                query.cljc:   81  datahike.query$q/invokeStatic
                query.cljc:   75  datahike.query$q/doInvoke
               RestFn.java:  423  clojure.lang.RestFn/invoke
           query_test.cljc:   46  datahike.test.query_test$fn__66885/invokeStatic
           query_test.cljc:   40  datahike.test.query_test$fn__66885/invoke
                  test.clj:  304  cider.nrepl.middleware.test/test-var/fn
                  test.clj:  303  cider.nrepl.middleware.test/test-var
                  test.clj:  293  cider.nrepl.middleware.test/test-var
                  test.clj:  336  cider.nrepl.middleware.test/test-vars/fn/fn/fn

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working triage
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant