datomic

frankitox 2025-10-20T15:23:30.033799Z

I was looking at updating Datomic Pro 1.0.6610 to a newer version, the first thing I notice is the https://docs.datomic.com/operation/aws.html have a deprecation about the CloudFormation related commands. Can I still use create-cf-template ? I see it still exists in bin/datomic of datomic-pro-1.0.7394.

frankitox 2025-10-20T15:33:32.757129Z

Well 🤔 looks like it's working

braai engineer 2025-10-20T16:24:58.905819Z

Is there a value that sorts higher than any value for all types, suitable for passing to d/index-range as end-tuple component? • e.g. (sort [true false nil]) => [nil false true] • so want something like infinity such that (sort [true false infinity]) => [false true infinity] • because (sort [true false :more]) => throws Boolean cannot be cast to clojure.lang.Keyword. Reason being d/index-range's end-tuple is exclusive, so I'm trying to figure out which value I can pass an end-tuple component that will include both true & false in :db.type/boolean tuple components.

braai engineer 2025-10-23T20:55:17.876939Z

Is the performance of take-while equivalent to specifying an end-tuple value?

favila 2025-10-23T20:55:47.803409Z

yes

🙏 1
favila 2025-10-23T20:56:26.723709Z

well, more precisely, depends on the contents of the take-while

favila 2025-10-23T20:57:03.082839Z

there's no significant inherent overhead to consuming the result via take-while and terminating vs index-range doing the same internally

favila 2025-10-20T16:26:21.780719Z

there likely is one, but it would be an accident of implementation

favila 2025-10-20T16:26:49.921669Z

You should make a take-while with the appropriate <= condition

favila 2025-10-20T16:28:25.893589Z

alternatively you can increment the tuple slot to the left by one, leave the trailing items nil

mkvlr 2025-10-20T00:26:53.654789Z

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?

Joe Lane 2025-10-20T15:12:59.869779Z

whoa. I would NOT do that @mkvlr

Joe Lane 2025-10-20T15:18:11.140699Z

The reason is that I would consider this to be entirely in "Undefined Behavior" territory. Maybe what we could do in this conversation is start back at the the question "Why are you trying to use j.t.Instant for #inst in your project?"

2025-10-20T15:33:13.179399Z

> "Why are you trying to use j.t.Instant for #inst in your project?" My takeaway from https://widdindustries.com/blog/what-is-inst.html was that that's acceptable usage for data readers like #inst

favila 2025-10-20T15:42:45.677649Z

Function expressions in queries are compiled with eval. In your case it would be evaluating something like (clojure.core/fn [?exit] (java.util.Date/.before ?exit ) )

favila 2025-10-20T15:43:21.513719Z

But for reasons I don't know, clojure eval invokes the reader on the date object:

favila 2025-10-20T15:43:39.852139Z

(let [v (binding [*data-readers* (assoc *data-readers* 'inst (fn [cs] (prn [(class cs) cs]) (java.util.Date/.toInstant (clojure.instant/read-instant-date cs))))]
          (eval `(fn [] ~(java.util.Date.))))]
  (class (v)))
[java.lang.String "2025-10-20T15:41:46.665-00:00"]
=> java.time.Instant

favila 2025-10-20T15:43:49.171389Z

note there's no datomic in the code above

favila 2025-10-20T15:43:54.995749Z

this is just what clojure eval does

favila 2025-10-20T15:44:34.003629Z

If you don't try to put a date constant into your query, you should be fine; supply the correct date object as an :in parameter

👍 1
favila 2025-10-20T15:48:40.621649Z

Just to be extra clear that eval definitely got a date object, not a string:

favila 2025-10-20T15:48:43.693919Z

(let [d (java.util.Date.)
      expr `(fn [] ~d)
      f (binding [*data-readers* (assoc *data-readers* 'inst (fn [cs] (prn [(class cs) cs]) (java.util.Date/.toInstant (clojure.instant/read-instant-date cs))))]
          (eval expr))
      v (f)]
  {:into-eval [(class (last expr)) (last expr)]
   :out-eval [(class v) v]})
[java.lang.String "2025-10-20T15:53:34.704-00:00"]
=>
{:into-eval [java.util.Date #inst "2025-10-20T15:53:34.704-00:00"],
 :out-eval [java.time.Instant #object [java.time.Instant 0x26cdb25d "2025-10-20T15:53:34.704Z"]]}

mkvlr 2025-10-20T22:48:58.698969Z

@favila oh wow, I had no idea eval does that, thanks for the explanation!

mkvlr 2025-10-20T22:50:22.578609Z

@joe.lane we’re trying to avoid java.util.Date on our project. I had the impression also from https://clojure.org/reference/reader#_built_in_tagged_literals that #inst is just one implementation and changing it is allowed, since there’s even an alternative implementation in clojure.core.

mkvlr 2025-10-20T23:15:44.983689Z

@favila it’s the quoting that brings in the pr / read roundtrip, which makes sense I guess:

(let [date (java.util.Date.)]
  (binding [*data-readers* (assoc *data-readers* 'inst (fn [cs] (java.util.Date/.toInstant (clojure.instant/read-instant-date cs))))]
    {:plain (let [expr date]
              [(type (eval expr)) expr])
     :quoted (let [expr (list 'quote date)]
               [(type (eval expr)) expr])}))
;; => {:plain [java.util.Date #inst "2025-10-20T23:14:51.461-00:00"], :quoted [java.time.Instant (quote #inst "2025-10-20T23:14:51.461-00:00")]}

favila 2025-10-20T23:46:11.203489Z

It's not the quoting, it's just being a subexpression

mkvlr 2025-10-20T23:59:14.253029Z

huh, you’re right

(let [date (java.util.Date.)]
  (binding [*data-readers* (assoc *data-readers* 'inst (fn [cs] (java.util.Date/.toInstant (clojure.instant/read-instant-date cs))))]
    {:plain (let [expr date]
              [(type (eval expr)) expr])
     :in-vector (let [expr [date]]
                  [(type (first (eval expr))) expr])}))
;; => {:plain [java.util.Date #inst "2025-10-20T23:59:40.769-00:00"], :in-vector [java.time.Instant [#inst "2025-10-20T23:59:40.769-00:00"]]}

favila 2025-10-21T00:00:43.242489Z

(let [expr (list 'clojure.core/vector (java.util.Date.))]
  (-> (binding [*data-readers* dr-instant]
        (eval expr))
      first
      class))
=> java.time.Instant
(let [expr (list 'do (java.util.Date.))]
  (-> (binding [*data-readers* dr-instant]
        (eval expr))
      class))
=> java.util.Date
(let [expr (java.util.Date.)]
  (-> (binding [*data-readers* dr-instant]
        (eval expr))
      class))
=> java.util.Date

favila 2025-10-21T00:00:52.528299Z

note the do magic

favila 2025-10-21T00:01:06.783709Z

again, no idea why it's like this, or even how

🤔 1
mkvlr 2025-10-21T00:04:48.874249Z

I was thinking to rebind the #inst reader locally in our datomic wrapper, but that also didn’t help. Is the eval delayed?

mkvlr 2025-10-21T00:05:29.791739Z

I think I’ll throw instead when passing inst? constants as part of the query since it’s discouraged anyway and defeats the caching etc

👆 1
mkvlr 2025-10-20T00:53:02.014509Z

Here’s a gist showing what I mean https://gist.github.com/mk/e1e2955dc4c892ca7214185072047bda

mkvlr 2025-10-20T03:07:48.467109Z

also created an ask for this as I thought something more permanent than slack might be better as a reference : https://ask.datomic.com/index.php/1867/why-does-changing-the-inst-reader-make-my-query-fail