-
-
Notifications
You must be signed in to change notification settings - Fork 311
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Storing raw JS objects and querying according to pointer equality ===
#248
Comments
Objects are not serialized, but they are compared using CLJS compare datascript/src/datascript/db.cljc Line 290 in eaa8384
|
What does CLJS compare do with objects that are instantiated from classes? The above code shows that it works for This would be a very useful function for me, because I need a table that I can query that stores pointers. And some rows may store the same pointer. And then I would update all rows with the same pointer to point to something new. It would support an immutable keyless B+tree. |
Here’s the code: I guess maybe first case falls under |
Extending the type to be [12 {x: 12, other: "bar"}]
[15 {x: 15, other: "foo"}] Those value will be comparable to CLJS and will also properly be sorted (important for initializing the DB which uses FWIW, I think CLJS could be more lax about this and allow all objects to |
I really need it to compare based on pointer equality of the object itself. Are you saying to tag each object created with a special unique id before inserting into datascript? Also I'm sure there are certain value types that cannot be ordered, I wouldn't think of pointers to objects as being ordered. So I'm not sure what kind of benefit sorting is for this situation. |
I found that |
If you store values in Datascript and query by them (as above) you absolutely need to make your values comparable. If you really just care for identity and don't have a natural ordering for your values then I'd do the following:
Then only ever query by |
Thanks for the advice, however I'm not familiar with clojure. What would those 3 steps look like in JS? |
Still I'm confused why would there be a different behaviour from using just |
Another test: const d = require('datascript');
const obj1 = { x: 1 };
const obj2 = { x: 1};
const db = d.empty_db();
const db1 = d.db_with(db, [[':db/add', 1, 'obj', obj1], [':db/add', 2, 'obj', obj2]]);
d.pull(db1, '[*]', 1).obj === obj1; // false (there was a parentheses typo here) It shows that these are no longer the same object. That must mean datascript must be doing a shallow or deep copy of the normal object that is being inserted. (Later I found out that it was in fact a deep copy.) I think the docs should make clear that when inserting JS objects, if they are literal objects, they get copied, while if they are class instantiated objects, they are inserted by reference. This occurs even when the class instantiated objects are deeply nested. |
DataScript certainly does not do that. Check your tests |
@tonsky Have you tried running this?
It shows that with obj1 which is just plainly I've tested again with |
I don't know the JS side API of datascript so I can't help you there. Forget about the difference between Obj vs Class instance. Both won't work, you just can't query by values which are not comparable. Try implementing my idea above. Pseudo code:
Use a factory method to get you a new object with a newly generated id. |
I’m sorry, you’re right. DS does tries to convert entities to CLJS values and back datascript/src/datascript/js.cljs Line 36 in eaa8384
|
@rauhs Just a clarification, does this mean datascript cannot index things that are not ordered (like using hash indexing)? I just tried it:
|
usually it can store incomparable values. You can’t store them cardinality-many attributes, you can’t make them indexed or unique. Otherwise it should be fine. |
I'm making an adapter to make sure all my object keys are given unique numbers so they can be indexed by datascript. But I had a thought experiment as to whether datascript in the future could index JS objects. Well I found that other than ES6 Map and WeakMap, there's no other easy way to index object keys in JS. But I looked at Facebook's immutable.js codebase, and here's their implementation for "hashing" JS objects that can be used as keys in their Immutable Map and Ordered Map. https://github.com/facebook/immutable-js/blob/7f4e61601d92fc874c99ccf7734d6f33239cec8c/src/Hash.js#L85-L153 Maybe a feature request for the future? There's also a discussion about this feature: immutable-js/immutable-js#84 Previously immutable.js also couldn't store objects as keys, but after that commit, objects could be stored as keys for immutable sets, maps and orderedmap. |
cool, thanks |
Here we go: https://github.com/MatrixAI/js-object-tagger |
BTW @rauhs even if I use object tagging to allow object keys to be indexed by proxy of the numeric tag. I still need to make sure my objects are class instantiated (not
I hope one day this feature will be made explicit, the ability to make sure even literal objects are stored by reference and not copied. Found another hack to get referenced objects: |
I want to use datascript to store "pointers" to raw JS objects, and be able to query for them.
So I did a small test to see if it could work.
First with a class which works:
Second with just a normal object:
But the second one doesn't, it just returns nothing.
Also are certain objects ever directly serialised? What determines whether to compare objects by their serialised form vs by their object pointer?
The text was updated successfully, but these errors were encountered: