Fork me on GitHub
#datalevin
<
2024-03-17
>
phill14:03:40

Can :db/ident be used to declare enumerated values? Documentation for a certain product says, "... :db/ident ... [may] be used ... to represent enumerated values." Datascript's "Differences from Datomic" says "No :db/ident attributes". Datalevin's "Differences from Datascript" does not mention :db/ident. On the other hand, datalevin's test/datalevin/test/transact.clj appears to assign ident :Petr.

Huahai17:03:43

There is no special status for :db/ident, it is just a keyword valued attribute that is marked as unique, same as other such attributes. There's indeed logic to check for them in entity resolution, but that's after checking lookup ref, so it's not a shortcut either.

Huahai17:03:04

Except it is in implicit schema

Huahai17:03:08

That test is from datascript, probably for compatibility with datomic. So yes, you can use :db/ident for enumerated values purpose and we do support it, but it's nothing special and there's no special advantage for doing so, compared with defining your own unique identity attribute and using lookup ref.

phill15:03:51

pull (https://cljdoc.org/d/datalevin/datalevin/0.9.3/api/datalevin.core#pull) says, "Supported opts: :visitor a fn of 4 arguments, will be called for every entity/attribute pull touches..." What is the role of the visitor function, or, what should it return and can it affect the outcome of the pull?

Huahai17:03:10

The role of visitor is to have side effect, it should return nil, or more precisely, whatever it returns is ignored. It does not affect the outcome of pull.

phill15:03:00

It looks like with-conn evaluates its spec argument 4 times, which is harmless if it is a literal but could cause a surprise if it calls a function with cost or side effects. https://github.com/juji-io/datalevin/blob/0.9.3/src/datalevin/core.clj#L961 (I was puzzled how get-conn and with-conn use the schema if the connection already exists, so I clicked the link to source, which is a very nice feature.)

Huahai17:03:21

Good catch.

Huahai20:03:18

Fixed in master branch.

erdos16:03:18

Hi, I am just checking the recent commits in Datalevin and I am in a bit of trouble figuring out this potential bug in 0.9.3. My understanding is that since with-conn is a macro, spec is passed as a form and is destructured during macro evaluation into distinct let bindings, and so it looks perfectly safe to me. simple_smile Could you please show me an example where the old code could actually lead to multiple evaluations? thanks2

phill23:03:43

You are right @U2E1D7WUB. Oops!

phill16:03:04

For any given data directory, are the Datalog and KV usages mutually exclusive?

Huahai17:03:15

No. The same DB file can have both. Datalog DBIs are not special. A db file can have 128 DBIs by default. The DBIs are searched sequentially by name through, so you don’t want too many of them. You can pass an option to change it

Huahai17:03:52

Datalog uses 6 DBIs, if full text is enabled, the default search engine uses up to 4. But each search domain use that many too.

phill17:03:57

What db/valueType is recommended for an enumerated type? For example, if attribute :e/x will hold one of (a,b,c), and a jillion entities will have attribute :e/x, is it recommended to store :e/x as :a,:b,:c ; or "a", "b", "c" ; or 1, 2, 3 with a distinct mapping, outside the datalevin database, to make sense of those numbers?

Huahai17:03:45

Whatever is cheapest. In this case, strings

Huahai18:03:57

Long has 8 bytes, short strings can be cheaper

Huahai17:03:45

Also, using :db/ident is not required to solve this problem. It's a convenience mechanism that Datomic introduced to have an additional keyword identifier for an entity. In datalevin, it is implemented as the same as other attributes that are marked as unique identity, i.e. it is not special. Because in our storage layer, keywords are more expensive than strings with the same name, I would just use a string instead and use lookup ref for the entity. Of course, if one likes the neatness of using a keyword to stand for an entity, :db/ident is for you. Performance wise, I have not compared the two formally, but I doubt this makes a huge difference. To disambiguate, one probably wants a long namespaced keyword for a :db/ident but one doesn't need to do this for a string valued unique custom attribute. So I personally would favor the later. In any case, it's a matter of personal preference.