This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-06-29
Channels
- # announcements (44)
- # architecture (12)
- # babashka (45)
- # beginners (56)
- # calva (16)
- # cider (34)
- # clj-kondo (6)
- # clojure (47)
- # clojure-austin (2)
- # clojure-brasil (3)
- # clojure-europe (39)
- # clojure-germany (2)
- # clojure-nl (1)
- # clojure-norway (39)
- # clojurescript (7)
- # cursive (1)
- # datahike (2)
- # datomic (28)
- # emacs (8)
- # gratitude (3)
- # humbleui (4)
- # hyperfiddle (45)
- # kaocha (1)
- # lsp (94)
- # nbb (2)
- # off-topic (29)
- # practicalli (8)
- # releases (2)
- # shadow-cljs (6)
- # squint (17)
- # tools-deps (12)
- # vim (11)
On Datomic Cloud, how can I convert a basisT value (obtained from a :db-after
value, with the basis-t
function below), into a wall clock time?
Do I have to dig :db/txInstant
out of the :data
attr of a d/tx-range
return value?
(defn basis-t
"Return the basis T of a db-val, regardless of its concrete implementation."
[db-val]
(or (-> db-val :basisT) ;; (d/client {:server-type :dev-local})
(-> db-val :t) ;; (d/client {:server-type :cloud}) or :ion
))
I do have something like this at the moment, which is specific to our use-case:
(def ^:datomic/q q:latest-sync-tx-instant
'{:find [?tx-time]
:in [$ ?source-ref]
:where [[?source-ref :source/latest-sync _ ?t]
[?t :db/txInstant ?tx-time]]})
but it would be nice, if there would be some more obvious way to do this, since Datomic Pro does have something like this, iirc.Here’s what I would do for Datomic Cloud:
(let [{conn :datomic/connection} @user/sysref
{:keys [db-after] [d & tx-data] :tx-data :as result} (d/transact conn {:tx-data [{:st.legal-person/name "Chris Cyrus Hapgood"}]})]
(d/pull db-after '[*] (:tx d)))
This relies on the fact that all transacted datoms share the same (reified) transaction entity, and that the basisT/`:db/id` of the tx are https://docs.datomic.com/client-api/datomic.client.api.html#var-datoms and that entity carries the tx-instant.this also works, btw, but it requires a datomic connection, instead of a database value:
(defn tx-inst [conn basis-t]
(-> (d/tx-range conn {:start basis-t :end (inc basis-t)})
first :data
(->> (filter (fn [{:keys [e _a v tx]}] (and (= e tx) (inst? v)))))
first :v))
example:
(tx-inst conn 10)
=> #inst"2023-06-29T12:29:57.921-00:00"
it finds the 1st instant valued datom of a transaction entity from the transaction :data
retrieved via d/tx-range
, based on a basisT.
it would be more precise to just assert, that the attribute of the datom is :db/txInstant
, but i would need the entity ID of that attribute and not sure whether that's always the same in every database or not.
i only have the db value as-of the basisT, so i don't have tx-data at hand, but i know, that the last tx was the one, which i want to see the :db/txInstant
for.
I don’t think you can safely make any assumptions about schema attr ids… they might even change if the base schema ever gets updated. Why not just pull the transaction entity directly?
given a db value as-of some time, i can't tell, what's the last transaction's entity id, without having access to the db connection too
well... i guess i have to do this lookup earlier in my transformation pipeline, where i still have access to the conn
I had a rule with two implementations that I rewrote as an or-join
, which I understand to be semantically identical. The rule implementation works as expected but the or-join
implementation throws an IndexOutOfBoundsException
from within datomic.datalog/join-project-coll-with
. 🧵
rule implementation:
[(filter-group-roadmap-container-by-teams [?group] ?entity-id ?epic)
[(!= :none ?group)]
(or-join [?group ?entity-id]
[?entity-id :group-roadmap-container/group ?group]
(and
[?roadmap-entry-id :epic-roadmap-entry/container ?entity-id]
[?roadmap-entry-id :epic-roadmap-entry/epic ?epic]
[?epic :epic/group ?group]))]
[(filter-group-roadmap-container-by-teams [?group] ?entity-id ?epic)
[(= :none ?group)]
(or-join [?group ?entity-id]
(not [?entity-id :group-roadmap-container/group])
(and
[?roadmap-entry-id :epic-roadmap-entry/container ?entity-id]
[?roadmap-entry-id :epic-roadmap-entry/epic ?epic]))]
or-join
version:
'[(or-join [?group ?entity-id ?roadmap-container-epic]
(and
[(!= :none ?group)]
(or-join [?group ?entity-id ?roadmap-container-epic]
[?entity-id :group-roadmap-container/group ?group]
(and
[?roadmap-entry-id :epic-roadmap-entry/container ?entity-id]
[?roadmap-entry-id :epic-roadmap-entry/epic ?roadmap-container-epic]
[?roadmap-container-epic :epic/group ?group])))
(and
[(= :none ?group)]
(or-join [?group ?entity-id ?roadmap-container-epic]
(not [?entity-id :group-roadmap-container/group])
(and
[?roadmap-entry-id :epic-roadmap-entry/container ?entity-id]
[?roadmap-entry-id :epic-roadmap-entry/epic ?roadmap-container-epic]
(not [?roadmap-container-epic :epic/group])))))]
Error/stacktrace:
processing rule: (q__549760 ?entity-id), message: processing clause:
clojure.lang.LazySeq@bdc436e2, message: processing rule: [arule__539777
?group:0:3 ?entity-id ?roadmap-container-epic], message: processing clause:
clojure.lang.LazySeq@bda6aac3, message: java.lang.IndexOutOfBoundsException
datalog.clj: 1483 datomic.datalog/eval-rule/fn
datalog.clj: 1463 datomic.datalog/eval-rule
datalog.clj: 1442 datomic.datalog/eval-rule
datalog.clj: 1506 datomic.datalog/eval-query
datalog.clj: 1489 datomic.datalog/eval-query
datalog.clj: 1596 datomic.datalog/qsqr/fn
query_stats.clj: 61 datomic.measure.query-stats/with-phase-stats
query_stats.clj: 48 datomic.measure.query-stats/with-phase-stats
datalog.clj: 1595 datomic.datalog/qsqr
datalog.clj: 1534 datomic.datalog/qsqr
datalog.clj: 1552 datomic.datalog/qsqr
datalog.clj: 1534 datomic.datalog/qsqr
query.clj: 757 datomic.query/q*
query.clj: 744 datomic.query/q*
query.clj: 785 datomic.query/query*
query.clj: 778 datomic.query/query*
query.clj: 805 datomic.query/query/f
io_stats.clj: 93 datomic.io-stats/with-raw-io-stats/fn
io_stats.clj: 93 datomic.io-stats/with-raw-io-stats
io_stats.clj: 60 datomic.io-stats/with-raw-io-stats
io_stats.clj: 132 datomic.io-stats/with-io-stats
io_stats.clj: 126 datomic.io-stats/with-io-stats
query.clj: 807 datomic.query/query/fn
query.clj: 812 datomic.query/query
query.clj: 798 datomic.query/query
api.clj: 48 datomic.api/query
api.clj: 46 datomic.api/query
in the sense of it’s not pushed down, or it attempts to unify against something that isn’t in the outer form
it’s the first branch that seems to be the issue. If I take ?roadmap-container-epic out of the first nested or-join but leave it in the second and in the top-level or-join, it runs
oh, there is one difference, not sure it matters, but the rule requires a binding but the or-join does not
right … which makes it even more odd that the or-join would throw in a situation where the rule does not. since if anything it should be more tolerant in its expectations.