does datomic pro print and read queries during datomic.api/q, maybe as part of its query cache? we’ve changed the #inst
reader in our project to return java.time.Instant and now a java.util.Date we pass to a query comes out as a java.time.Instant
. Is that expected & documented somewhere?
(require '[datomic.api])
;; this is demonstrating an issue we ran into where overwriting the
;; `#inst` reader broke `datomic.api/q` in surprising ways.
(def schema
[{:db/ident :exit/datetime
:db/valueType :db.type/instant
:db/cardinality :db.cardinality/one}])
(def conn
(datomic.api/connect (doto "datomic:mem://inst-java-time-readers" datomic.api/create-database)))
@(datomic.api/transact conn schema)
(def db+data
(:db-after
@(datomic.api/transact conn [{:exit/datetime #inst "2024"}
{:exit/datetime #inst "2025"}
{:exit/datetime #inst "2026"}])))
;; this works
(count (datomic.api/q [:find '?f
:where
'[?f :exit/datetime ?exit]
[(list '< '?exit (java.util.Date.))]]
db+data))
;; fails silently (returns incorrect number of results)
(binding [*data-readers* (assoc *data-readers* 'inst (fn [cs] (java.util.Date/.toInstant (clojure.instant/read-instant-date cs))))]
(count (datomic.api/q [:find '?f
:where
'[?f :exit/datetime ?exit]
[(list '< '?exit (java.util.Date.))]]
db+data)))
;; fails loudly with processing rule: (q__124130 ?f), message:
;; processing clause: [?f :exit/datetime ?exit], message:
;; java.lang.ClassCastException: class java.time.Instant cannot be
;; cast to class java.util.Date (java.time.Instant and java.util.Date
;; are in module java.base of loader 'bootstrap')
(binding [*data-readers* (assoc *data-readers* 'inst (fn [cs] (java.util.Date/.toInstant (clojure.instant/read-instant-date cs))))]
(count (datomic.api/q [:find '?f
:where
'[?f :exit/datetime ?exit]
[(list java.util.Date/.before '?exit (java.util.Date.))]]
db+data)))
;; My guess is that this is related to datomic's [query
;; caching](https://docs.datomic.com/query/query-executing.html#query-caching)
;; because once a query has been cached, a sucessive call with the
;; same query value and a bound #inst reader succeeds:
(let [query [:find '?f
:where
'[?f :exit/datetime ?exit]
[(list java.util.Date/.before '?exit (java.util.Date.))]]]
(= (count (datomic.api/q query db+data))
(binding [*data-readers* (assoc *data-readers* 'inst (fn [cs] (java.util.Date/.toInstant (clojure.instant/read-instant-date cs))))]
(count (datomic.api/q query db+data)))))