-
-
Notifications
You must be signed in to change notification settings - Fork 153
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
Check persisted using real existence (instead of id presence) #248
Conversation
Thanks @aderyabin for your PR. I've been reviewing your PR and we can't make a find every creation, it isn't inneficient. We should remove the unless or create a way for the entity knows the custom id. Cc @lotus/core-team |
One thing, do you need the id? A workaround you can use is create another attribute instead id for your custom id |
Yes, as discussed before I can use custom id field. But it is a compromise. In general I don't see any problem to use find on creation. It's like find_or_create from Rails. It's an effortless operation for database. |
@AlfonsoUceda I have no problem with this approach at all, so it is 👍 from me |
@joneslee85 but for that we'd have |
@AlfonsoUceda the other better way is to ensure that attributes that map to |
@joneslee85 . I think that is not good idea too because |
cc @jodosha what do you think? |
@aderyabin Thank you, but I agree with @AlfonsoUceda It's inefficient. The example that you mentioned about AR In that case a developer wants to find a record or otherwise create it, they are aware of the cost of the operation. Here instead, we're adding a perf tax which is unnecessary and unexpected by devs. I also won't suggest to setup id by hand, because you can run into this error in case of creation:
..or update the wrong record by mistake in update. |
@jodosha {
id: 123,
login: `aderyabin`
}
I have to save this data and don't duplicate users. I tried this code class User
include Lotus::Entity
attributes :login
end
u = User.new(id: 123, login: 'aderyabin')
UserCollection.permit(u) And it doesn't work, because Lotus think that entity is permitted (because This PR check entity is permitted really (instead of virtual). |
@aderyabin Fine. I'm determined to find a solution to your problem, but this isn't the way to proceed. It has a perf cost and introduces race conditions with the database. Can you please open a new PR with a different purpose?
This should give more control on |
@jodosha |
Lotus has many adapters, some can raise PG::UniqueViolation: ERROR, some be silent by default. I think that behavior should be equal for all. |
@aderyabin Okay, replied while in a hurry. Sorry. RE RE Unique constraint: if it's easy to implement for memory adapter, please go ahead. 👍 |
My 2 cents (might be to late as there is already a PR waiting, sorry)
|
@AlfonsoUceda @pascalbetz Can you please explain the idea? IMO Ref #258 |
There is a difference between id assigned and persisted. More so if the id can be provided from the outside (which apparently is a requirement). An entity is persisted IFF it was previously saved or previously loaded from the repository, not if its identity is non-nil. If i create an entity: foo = Foo.new(id: 12, name: 'foo') then you can not tell if you need to save or update that entity. If there is an additional attribute (maybe Does that make sense? |
I do think I understand @pascalbetz example and I have a similar situation in my application where I use Lotus: In our application logic we generate uuids and use that as the identity for entities. In our database we don't use any sequential assigned id; we use the uuid in postgres as our primary key. When we want to persist new records and setting an entity's ID to the assigned uuid we have a confused repository not wanting to |
@thhermansen Hello, I see your point and #258 will be merged soon. /cc @aderyabin @aderyabin I understand the technical difference between assigned id and persisted record. However, I'm still thinking that it's a perf tax that we don't want to add to the framework, and it's a race condition, because two threads can assign the same id, and because the check and the writing aren't atomic, we'll have a problem then. If you instantiate an entity What I'm trying to say is that, we should rely on conventions to avoid unnecessary overhead. /cc @pascalbetz |
If the ID is assigned by the client, then it's in his responsibility to make sure he does not use the same ID twice and also to deal with errors related to that. So no need to run a check. Just let the thing crash. Yes, you can tell from the context in that case. And you can then make sure you call the right method (INSERT vs. UPDATE). But IMHO it is something that is dealt with in the framework otherwise the if/else code will be in many places in the client code instead of just the framework. Also it is something that the entity should know (in case you need to pass it to other pieces of code): have i been saved or not. |
Well, if you're assigning |
No. Still i think that this is something the entity should know, not the context the entity "lives" in. |
@pascalbetz The only way to know for sure is to do the database check that @aderyabin suggested. Which I assume is out of scope. |
Yes, to "know for sure" i agree. Because there might be concurrent processes. But for the use cases i had where an external ID is involved this was not an issue because the source of the external ID (usually another DB or a UUID service) made sure that there is no clash. My proposal is to add another attribute foo = Foo.new(id: 12, name: 'foo')
foo.persisted? gives the right response ( |
@pascalbetz Ok, we should hold on with this feature, because I want to experiment with a different way to persist data: foo = FooRepository.create({id: 23, name: 'foo'}) This will solve this issue and also this discussion reported here: https://discuss.lotusrb.org/t/change-the-behavior-of-repository-create-persist/117 |
Currently if the entity has
id
,there are no way to persist this entity because
.create
returns nil because id are present and.update
fails because record in database with thisid
are not exists.I suggest to check on persistance by real query to repository. If repository do not have entity with the equal id then and entity are not persisted.
It easy to display by example/test:
// cc @AlfonsoUceda, you asked me to prepare use case and PR. :)