datascript
datascript copied to clipboard
Entity equality check only includes type and id
If I'm reading the code correctly, only type and entity id are being checked when testing entity equality.
The problem with this approach is you can have the same entity from different db's which has different attributes, yet those entities test as equal.
Per the Datomic documentation:
Two entities are equal if they have the same id and their databases have the same id
I think that's reasonable as long as the db check is fairly cheap. It keeps you from having to realize all attributes to do the check, yet still lets you know that the entities aren't guaranteed to have equal attributes.
This could be added, but would make sense only for apps that use multiple DataScript DBs.
Note that Datomic’s DB id does not change as you make transaction to the single database. It’s a constant id assigned to DB at its creation (like "datomic:free://localhost:4334/xxx") to distinguish different connections to different transactors.
E.g. this code will still return true in Datomic:
(let [db1 (d/db conn) _ @(d/transact conn [[:db/add id :name "abc"]]) db2 (d/db conn)](= %28d/entity db1 id%29 %28d/entity db2 id%29))
Another strategy is to have DB change its id after each transaction, effectively make all entity equal checks to return false (pessimistic case: if DB changed in any way, we behave like all entities have changed). Not sure is this strategy is valuable or not, I mean, I don’t see cases when this saves us anything, it’s almost the same as not doing equality checks at all.
I do not have strong opinion on this, but both options seems lousy to me.
Maybe a pragmatic solution is to use pull API when you need optimization for compare and, if using entities, do not rely on entities equality checks at all.=
Regarding the datomic behavior, that's not how I read those docs at all, but I've verified that what you say is true.
I agree with your assessment.
I do, however, think it would be valuable to go ahead and follow their API and run the check on the db id, even though it doesn't fix my use case.
Another strategy is to have DB change its id after each transaction, effectively make all entity equal checks to return false (pessimistic case: if DB changed in any way, we behave like all entities have changed). Not sure is this strategy is valuable or not, I mean, I don’t see cases when this saves us anything, it’s almost the same as not doing equality checks at all.
I do think this is the sanest approach: two Entities objects are equal if they point to the same logical entity in the same database value.
Example use case
- You have a React app, which state consists of both an "information" DataScript db, plus "local UI state" in an ordinary Clojure map.
- Some React components read from both a DataScript entity and a part of the state map: both of these reads use caching.
In particular, if expensive DataScript queries are made based on the Entity, you wouldn't want to redo them just because the local UI state changed. Granted, changes to the underlying Db will affect all Entities, but AFAICT that sort of change is typically much less frequent than changes to the local UI state (essentially, because navigation actions are much more frequent than database-writing actions).
In such a case, you really want sound equality semantics on Entities, and that's where the equality on database values comes into play.
Remarks
You might find it disturbing that the equality of Entities should involve entire database values. I think this starts feeling natural when you stop viewing Entities as local/bounded objects: semantically, Entities are more like database values with a starting point. If users want bounded information, they should use the Pull API.
By the way, I don't know if this is the appropriate place to discuss this, but I don't think it would hurt to use identical?
for equality of Database values, rather than scanning the whole index. As a user, I cannot imagine a use case for content-based equality of DataScript db values.
This should be fixed by #435 , available in release 1.3.14. Thx