-
Notifications
You must be signed in to change notification settings - Fork 588
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
Override entity IDs #7
Comments
Yep, for sync you should use a lower-level API. I'll try to document this better sometime soon. But in short, you can either use: record._setRaw('id', myId) But if you're pulling a record from the server, and you have a simple JSON-like object with the record's data, you can also do: import { sanitizedRaw } from 'watermelondb/RawRecord'
collection.create(record => {
record._raw = sanitizedRaw({ id: xxx, foo: x, bar: z }, collection.schema)
}) |
This I get the following error @radex Is there any change that is needed on schema or model level to make it work. Am using version |
right, this doesn't work for |
I want to use the same In summary, I want to be able to use the same unique id from my server to perform
|
so when exactly would you want to assign an ID to the record? In the sync code? Can you give me a larger snippet of code? |
I want to assign it in sync code, i.e as soon as I receive the record from the server, I want to save the record locally and then have the HOCs picks it up using the observable. The need to use the same id is meant to make the code compatible with existing HOCs that uses the server id to query for a record. Note am migrating an existing code base to watermelon incrementally.
|
@Kabangi have you figured it out? you need something like this: const contactCollection = database.collections.get('contacts')
contactCollection.create(record => {
record._raw = sanitizedRaw({ id: c.id, sid: c.id, username: c.username, .... }, contactCollection.schema)
}) |
Yes, ended up using ._raw.id=id, though am afraid in future there might be a breaking change in regard to this but can deal with it then |
@radex
This is mainly because watermelon uses a Map with the |
@Kabangi |
correct, Watermelon assumes IDs are globally unique. But I don't think you should be getting "Record ID was sent over the bridge, but it's not cached" — since record caching is done per-collection. |
I'm looking into it, because it would be useful for me to be able to have the same ids across multiple models, and so far I've found that (at least for sqlite) the Native.query method seems to return a string of an object's id if it has previously returned another object with the same id, which then causes the cached error. I would assume that this is due to how the caching works, so it only requests an object once, and caches based on the ids. Please do correct me if my assumption is wrong! Would it perhaps be possible/feasible to change this caching behaviour to work with multiple models with the same ids, or do you want to leave the assumption that IDs are globally unique? |
Looking just at the iOS code, DatabaseDriver.swift seems to cache query records simply by storing their ids' in a set, I can't see anything indicating that the caching here happens per collection! |
ah, correct. on JS side, caching Model objects happens per-collection, but native code assumes global IDs. I don't think reusing IDs is a good practice. If you need a one-to-one relationship, you can just add a column pointing to another object. It would be feasible to mark cached IDs per-table in native code, but it would require some work — I think it will be easier for you to tweak your schema a little not to reuse IDs. But let me know if there's a really good reason why you do |
Okay, thank you for the information! The only reason I was interested in doing it this way was to mirror our company db, which has sequentially numbered ids for each entry in a table, so duplicate ids across different tables. However, I agree it would be easiest to just modify the schemas to store the company db's id in a separate field, and allow WatermelonDB to generate its unique IDs 🙂 |
you could store 11111 as |
I have just found a case where it would be useful to be able to specify the model ids directly: When there are associations. I don't believe there is a way to have an association without pointing to the parent or childs id field, is this correct? In this case it would be very useful to be able to specify our own ids, and allow duplicate ids across models, as we have quite a lot of models that relate to one another! Perhaps I'll look into the native caching by model rather than the whole db. |
well again, can't you make your backend IDs unique by prepending them with table name? PS. You could also fork watermelon and remove the "only send ID" optimization. you'd get warnings about not sending cached records, but that would work correctly, just a little slower |
That could work, I just feel that it's going to be a bit of a hassle prepending the table name to all primary keys and any foreign keys as well. I think for now I might just remove that optimization, just to speed up our development. But I'll look into how easy it would be to change the caching optimization to cache ids on a model basis, so it wouldn't globally cache ids. Either way, thank you for an awesome library, still much happier using this than redux! And sorry for all the comments on this closed issue haha. |
I've submitted a PR to handle the comment by @adam-aerobotics
@radex Could you please review and let me know your feedback? |
@ahmadbaraka Great work on this PR #175, indeed it does fully resolve the issue. @adam-aerobotics If you still want to take advantage of the caching you could use this PR before @radex reviews it To directly use it you might need this small script to install it on your project
Then add a @radex Do you think it would be worth to add the instructions above to the docs i.e how to consume a PR that is yet to be merged to the master |
@ahmadbaraka Thanks so much for the PR! This solves my problem exactly. It seems you work a lot faster than I do! 😄 @Kabangi Thank you for the script, I'll implement it in my project while I wait for the PR to be merged. |
I believe it's written up in Contributing.md — can you verify the instructions there are also appropriate? |
@radex we're re-iterating on our sync solution with WatermelonDB and consider using client-side IDs now. I stumbled over this thread again and thought - is there any reason not to make |
Nope, I think it's reasonable to have some sort of an override. PRs appreciated :) |
Alright - picking this one up as we will be needing it ;) |
@radex maybe some input on design directions would be helpful here. I thought it would make sense to add the id generator function to the table / app schema object. |
@sebastian-schlecht as far as i can tell, only So I would maybe consider doing it the "wrong" way (given that only a small handful of people would ever need this) — adding to utils/common/randomId an export that allows you to override the randomId generator globally. Icky, but… maybe? Do a global search for |
@radex i thought about parameters too but indeed that would be a lot of work. I would agree with some way to override it (like the silence() ) for the database. I am however not 100% sure how the js module / require cache works - one would need to make sure that the override is used in all other files properly and not the (potentially) cached, original version of it?
… On 19. Apr 2019, at 15:29, Radek Pietruszewski ***@***.***> wrote:
@sebastian-schlecht as far as i can tell, only sanitizedRaw() references the randomId() function. We could add a parameter to sanitizedRaw() taking an id generator but this is referenced in so many places I worry it would create a ton of noise just passing this function around…
So I would maybe consider doing it the "wrong" way (given that only a small handful of people would ever need this) — adding to utils/common/randomId an export that allows you to override the randomId generator globally. Icky, but… maybe?
Do a global search for randomId( and sanitizedRaw( and tell me what you think
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.
|
I haven't look at source code closely, but maybe something like (pseudo code):
|
PR is up. |
@sebastian-schlecht hey, Sebastian, great, but it's only exchange one random generator by another random generator. Why not a more generic way with additional information? Then you can derive the id from table and db model. Furthermore, it could be possible to use server id. Or I'm missing something? |
@Bessonov for our use-case we only need to have the random id to be a specific format, we don't need prefixes or anything similar right now. Regarding server-id's, I think I don't understand the connection here. The PR is currently only dealing with the client-side stuff. We are moving to have consistent IDs client and server-side to avoid mapping issues. |
@sebastian-schlecht maybe I'm wrong, but here you have access to setGenerator((dirtyRaw: DirtyRaw, tableSchema: TableSchema) => {
if (tableSchema.name === 'tableWithServerId') {
return dirtyRaw.myFieldWithIdWhichWasGeneratedOnServer
}
// original behavior for other tables
return randomId()
}) |
@Bessonov I still think that I am missing things here - sorry 😄 So when you import raw records from the server (using Watermelon built-in sync) the IDs are taken from the server anyway. When you create stuff on device, there is a local ID to be generated (which the server would consume). Moreover, I am not that much into Watermelon to understand the ID field completely. Afaik, attempting to set the ID during record creation results in a constraint violation that IDs are read-only. See WatermelonDB/src/Model/index.js Line 67 in 08d8dd6
|
Ahmm... did you looked at my reference and code snippet? :) It is exactly how you can use generator to avoid the readonly problem. |
@Bessonov FYI, the function call in WatermelonDB/src/RawRecord/index.js Line 84 in a5b9988
dirtyRaw or tableSchema , so your snippet does not seem to work as these are always undefined. Or maybe I'm missing something?
|
@dedene yes, you missed, that it was a proposal to pass |
Hey,
we are currently evaluating this for our app. Since we try to implement our own sync engine on top, I'd be curious if it's possible to specify entity IDs whenever you create one.
Right now, if I try to set an ID in the builder function, I get the following error:
Diagnostic error: Attempt to set new value on a property Model.prototype.id marked as @readonly
Great work by the way, this looks very promising!
The text was updated successfully, but these errors were encountered: