Fork me on GitHub
#asami
<
2022-04-07
>
nijssels11:04:23

Hello, I intend to use Asami in a ClojureScript frontend. The data used in the app contains current and old data (distinguished by timestamps). Is it possible to import/transact that data using those timestamps? Much like Datomic can, using :db/txInstant. (See https://cjohansen.no/annotating-datomic-transactions/ )

quoll11:04:59

How is the data coming in? Is it structured (as in a seq of Clojure structures) or as edn? Then yes.

quoll11:04:48

If it's JSON, then there's no schema to tell the transaction function to do that translation

nijssels11:04:26

Its structured. I pull the data from a Clojure webserver as transitjs. The data is "flat" at that point, as in resembling records from a database. The data might look like (extremely simplified): ID Value Timestamp 1 x yesterday 1 y today 2 z today

nijssels11:04:19

How can I tel Asami to use those timestamps?

quoll13:04:23

For the in-memory version (which is what you're using in a browser), Asami just lets you insert them.

quoll13:04:53

Even on disk (in the JVM), a number of timestamp formats are accepted

nijssels15:04:34

The point isnt necessarily about reading the timestamp, but later being able to use the timestamps for since/as-of operations.

quoll17:04:42

The since and as-is functions do not apply to data (they get applied to databases). So I don't know what you're referring to here

Jakub Holý (HolyJak)17:04:03

So it seems Asami makes it possible to use :id for lookup but does not ensure its uniqueness:

(let [conn ...]
    @(d/transact conn {:tx-data [{:db/id -1 :id [:duplicate-test/id :SAME]}]})
    ; => :tempids {-1 #a/n[24], [:duplicate-test/id :SAME] #a/n[24]}}
    @(d/transact conn {:tx-data [{:db/id -1 :id [:duplicate-test/id :SAME]}]})
    ;  => :tempids {-1 #a/n[25], [:duplicate-test/id :SAME] #a/n[25]}}
    (d/q '[:find ?e :where [?e :id [:duplicate-test/id :SAME]]] conn))
  ; => ([#a/n[24]] [#a/n[25]])
so I guess before I insert anything presumably new I should run a query to verify the :id value is not used. Or is there a better way?

quoll17:04:11

This comes about because I did not conceive of trying to do the same thing 2 different ways at the same time

quoll17:04:20

I could try to merge them, though the default approach would be to throw an exception when doing this

quoll18:04:09

The code for this is asking, "Have you specified the object you're referring to? If so, then is it one that you have specified somewhere earlier in this transaction, or is it already present in the database?" To do this, it looks for identifiers. The first one it looks for is :db/id. You've specified this as a negative number, and it hasn't appeared already in the current transaction, so that says that you need to create a new object. At that point, it doesn't care about :id, because the "which object?" question has been answered. However, the :id field is attached, so it gets stored. In your second transaction, you do it again. You specified :db/id to be a negative number, and it hasn't been seen yet in this transaction, so that means you want a new object. At this point, it doesn't care about the :id, but you did specify it, so it gets stored.

quoll18:04:19

i.e. It did precisely what you asked of it

quoll18:04:42

So, what I think I should do here is probably throw an exception if more than one identifier is present. Or, alternatively, if more than one is present, then perhaps I could do a lookup to see if they're consistent with each other

👍 1
Jakub Holý (HolyJak)08:04:27

Ah, thank you for the explanation! I must admit that it wasn't really clear to me what the relation of the three possible IDs is. Thus I will only use :id and, when I need to refer to the entity inside the transaction, the [:id ...] . Thanks a lot!

quoll17:04:17

The better way is to not define a :db/id. You have an :id, so you don't need it

👍 1