Fork me on GitHub
#datomic
<
2022-08-12
>
pppaul14:08:03

how do i find the schema for a transaction? (the the ent that has :txInstant and some other keys...) i just don't know what keys it has and i can't find documentation on it. i can't even find examples of how to add a doc string to a transaction

pppaul14:08:21

i found these

{:db/cardinality {:db/id 35},
   :db/doc "Attribute whose value is a :db.type/instant. A :db/txInstant is recorded automatically with every transaction.",
   :db/id 50,
   :db/ident :db/txInstant,
   :db/index true,
   :db/valueType {:db/id 25}}

{:db/doc "Partition used to store data about transactions. Transaction data always includes a :db/txInstant which is the transaction's timestamp, and can be extended to store other information at transaction granularity.",
   :db/id 3,
   :db/ident :db.part/tx}

pppaul14:08:42

can't find anything else on tx schema

pppaul14:08:22

is it the case that a transaction can just have any data on it so long as there is a schema for it in in DB?

favila14:08:27

A transaction is an entity. Just like any entity, it can be in the E or V slot of any datom

favila14:08:50

To add an assertion to the current transaction, use the tempid "datomic.tx"

pppaul14:08:41

ok, i thought that transactions may be a bit more special than that. thanks

favila15:08:20

They are special only in that their ids must be in the tx partition, only they may have :db/txInstant assertions (this assertion is what makes it a transaction), and :db/txInstant cannot decrease in value relative to the previous transaction.

pppaul15:08:26

that is something i ran into when seeding my DB

lassemaatta17:08:41

Datomic docs often say something like ”the variable is bound”, eg. wrt rule bindings. What exactly does bound mean in this context?

favila17:08:55

It means that values are known for it.

lassemaatta17:08:57

I’ve been reading about rules and required rule bindings and I’m not quite sure I understand the description

favila17:08:34

Every variable mentioned in a clause is bound (i.e. some set of values was assigned to it) at the end of the clause’s evaluation

favila17:08:25

but not all may be bound on entering a clause

favila17:08:06

because some clauses produce the bindings (e.g. by pattern-matching, by unifying other already-bound values, by executing a function and binding the result, etc)

lassemaatta17:08:15

So if I specify that a particular rule argument is required, I should have a where clause (either before or after) which refers to it?

favila17:08:33

by “required” I assume you mean “must be bound”, i.e. this rule declaration syntax (rule-name [?must ?bind ?these] ?maybe-unbound)?

favila17:08:03

this says that ?must ?bind and ?these must have values before entering the rule.

favila17:08:17

the rule itself is not allowed to bind them

favila17:08:31

it can only read/unify on their values

favila17:08:54

?maybe-unbound may or may not be bound, doesn’t matter

favila17:08:09

but it will be bound by the time the rule finishes evaluating

lassemaatta17:08:38

Related question: what exactly does unify mean? Again, it’s one of those words used often, yet I dont quite grasp it

favila17:08:09

:in ?a 
; bound by args: ?a
:where          
; bound: ?a
[?a ?b ?c]
; bound: ?a ?b ?c
[?c ?d]
; bound: ?a ?b ?c ?d
(myrule ?x ?y)
; bound: ?a ?b ?c ?d ?x ?y
[(myfn ?x) ?g]
; bound: ?a ?b ?c ?d ?x ?y ?g

lassemaatta17:08:08

What happens if you first refer to a rule, which has a required variable, and then provide a normal where clause which binds the variable? Does it first ”execute” the latter clause and then ”execute” the rule?

favila17:08:56

datomic will only sometimes push clauses down not up

favila17:08:08

so you will just get an error

favila17:08:58

I wouldn’t rely on clause reordering though. the point of that syntax is to make sure that the rule doesn’t evaluate in an inefficient order

favila17:08:20

clauses are generally not reordered, so selectivity of the first clause is very important

favila17:08:23

inside a rule, it can be less predictable than in a :where how the rule was “invoked” in various queries, so someone may have left the vars for the first clauses unbound, causing a potentially large result set.

favila17:08:41

that syntax is a defense against that

favila17:08:16

a smarter system would reorder the clause evaluation in the rule based on selectivity or cardinality information, but datomic does not do that

favila17:08:38

re: unification, imagine that you have a table, and each variable in the query is a column

favila18:08:10

when a variable is bound, it adds rows to the query with values for that column

favila18:08:38

the unbound columns remain “blank”

favila18:08:45

when you “unify” vars, you discard entire rows where a clause is not satisfied for the corresponding vars mentioned

lassemaatta18:08:30

oh and thanks a lot for explaining this stuff, I should really read a prolog book or something 🙂

favila18:08:44

e.g. [?a 1] if ?a is unbound gives you a table of all (unique) ?a where the attribute slot is 1.

favila18:08:35

[(+ ?a 1) ?b] if ?b is unbound just adds a column ?b with +1 every ?a value for every row

favila18:08:53

but if it is bound, it discards any rows where ?b is not one more than ?a

lassemaatta18:08:34

the reason I'm reading about this (and asking silly questions) is that earlier today I was looking at some code in review where it had a where clause with a) first a few rules which required some bound variables and b) later a very lax normal clauses which bound those variables. I was a bit confused because I had understood that the variables should be bound before the rule is invoked but apparently the code worked. but later we noticed that with a larger db size it was also quite slow. does this make any sense?

lassemaatta18:08:02

(I should really test this in a repl instead of just pondering about it..)

favila18:08:21

yep. It sounds like it pushed down the rule, but only as far as needed to get something bound, and you just got lucky that it was enough to satisfy the requirements?

lassemaatta18:08:22

yeah, that would explain the poor performance. It couldn't satisfy the requirements of the rules, until it found the clauses it could bind (returning a huge set of data) which it finally ran through the rules

lassemaatta18:08:39

although reading the datomic documentation sometimes feels a bit like reading clojure spec docs: it all makes sense but first you have to do the work to really understand it yourself 🙂

lassemaatta18:08:22

in any case, thanks a lot for helping me

favila18:08:37

happy to help

nando20:08:06

Regarding dev-local, can I simply copy and paste the the db.log and log.idx files under the system and database directories to move a database from one computer to another? Any potential issues with that approach?

ghadi21:08:45

no issue, you can just plop them over @nando

👍 1
nando21:08:23

Thank you!

pppaul22:08:31

I'm trying to make a view to display all the entities i deleted in a transaction. i've been looking over the docs and at the datomic API, and i'm not very sure how to do this. i've used filtered DBs before, but i need 1 or 2 extra steps and i'm not sure what they are. right now i just have the entity that is the tx where the deletions occured. i need to get the IDs of the things that were deleted. this is what i have so far

(let [t (->> (d/entity db entity-id)
                 (d/entity-db)
                 (d/basis-t))]
      (->> (d/tx-range (d/log conn) nil t)
           first
           :data
           (map (fn [[e a v _]]
                  [e a v]))))
the datoms i'm getting back look like they are from the start of my DB creation
(let [t (->> (d/entity db entity-id)
                 (d/entity-db)
                 (d/basis-t))]
      (->> (d/tx-range (d/log conn) nil t)
           ;;first
           (take-last 5)
           (mapcat :data)
           (map (fn [[e a v _]]
                  [e a v]))))
if i do the above i get datoms that seem to have the right dates, but they don't look like my deleted data (d/tx-range (d/log conn) (dec t) (inc t)) this seems to give me the deleted data. it's still a mess to look at cus there are no idents for attributes. can i do a pull on this data somehow? -----------------------SOLVED---------------------
(let [t (->> (d/entity db entity-id)
                 (d/entity-db)
                 (d/basis-t))
          deleted-ids (->>
                        (d/tx-range (d/log conn) t (inc t))
                        (mapcat :data)
                        (map (fn [[e a v _]]
                               e))
                        (into #{})
                        vec)]
      (d/pull-many
        (d/as-of db (dec t))
        '[*]
        deleted-ids))
yey!

favila01:08:19

When you say “deleted entities”, do you mean entities which had retractions?

favila01:08:13

And you just want those entity ids? Or you want to pull from them in some way?

pppaul12:08:15

yeah, retractions that i want to pull, which is what i showed in the code

pppaul23:08:52

would really appreciate alternative ways to do this. cus that's a pretty crazy path i went down