datomic 2025-06-10

Why am I getting output from d/datoms for a tuple attribute, but no results when using d/index-range on the tuple, when using in-memory On Prem? I'm passing values that I know exist based on d/datoms:

(into [] (d/datoms db :avet :eacl.permission/resource-type+permission-name))
=> [#datom[17592186045426 96 [:account :admin] 13194139534313 true]
 #datom[17592186045427 96 [:account :view] 13194139534313 true]
 ...] 

(into [] (d/index-range db :eacl.permission/resource-type+permission-name [:account :admin] [:account :admin]))
=> []
(the tuple contains keywords, not eids)

Ah, I see that end is exclusive. I'm getting output for this:

(into [] (d/index-range db :eacl.permission/resource-type+permission-name [:account :admin] nil)) => results
where end is nil, or
(into [] (d/index-range db :eacl.permission/resource-type+permission-name [:account :admin] [:server nil])) => results
But if there's only one result starting with :account, I'm not sure how to query that without fetching everything, e.g. this is empty:
(into [] (d/index-range db :eacl.permission/resource-type+permission-name [:account :admin] [:account nil])) => []
How to use index-range if there's only one value for the starting key?

Surprised I can't do this:

(into [] (d/index-range db :eacl.permission/resource-type+permission-name [:account :admin] [nil nil]))
(get an empty result set)

Just take-while

reason nil doesn't work as an end is it sorts lower than any other value. It's not understood as a "no limit" sentinel unless the entire end argument is nil

(sequence
 (take-while (fn [datom] (= [:account :admin] (:v datom))))
 (d/index-range db :eacl.permission/resource-type+permission-name [:account :admin] nil)
 )
example of take-while

πŸ‘ 1

d/datom would work fine for this simple case also

(d/datoms db :avet :eacl.permission/resource-type+permission-name [:account :admin])

benchmarked d/datoms vs d/seek-datoms and was surprised that d/datoms was ~10x faster via criterium (we’re talking nano & milliseconds here)

were you comparing equivalent things?

this was the last benchmark I ran:

(quick-bench
  (first (d/datoms (d/db conn) :avet :eacl.relationship/subject+relation-name+resource
    [(:db/id super-user) :super_admin (:db/id platform)])))
vs.:
(quick-bench
    (first (d/seek-datoms (d/db conn) :avet :eacl.relationship/subject+relation-name+resource
    [(:db/id super-user) :super_admin (:db/id platform)])))
so either I'm misunderstanding how it works, or d/seek-datoms is chunking

seek-datoms does not terminate

πŸ‘ 1

there's no guarantee that first item matches your parameters

this is also mostly measuring setup costs, not the cost of scanning

what is the standard practice to enforce right-to-be-forgotten in datomic?

there are two:

1. use excision (datomic pro only)

❀️ 1

2. use a supplemental storage for PII that supports delete, store a pointer in datomic.

Thanks. Had no idea excision was there. Didn't come across in docs neither (as usual) gpt revealed it.

> 1. use excision (datomic pro only) Any plans of supporting it in Cloud?

not ruled out, but no concrete plans to add right now

😒 2
βœ… 1