redux-orm / redux-orm

NOT MAINTAINED – A small, simple and immutable ORM to manage relational data in your Redux store.

Home Page:https://redux-orm.github.io/redux-orm/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

many-many, reverse field updates and etc

plandem opened this issue · comments

I'm catching myself doing it again and again - i'm talking about working with relation from reverse side. E.g. we have next models:

import { Model, attr, fk, many, oneToOne } from 'redux-orm';

class User extends Model {}
User.modelName = 'user';
User.fields = {
	id: attr(),
	name: attr(),
};

class Team extends Model {}
Team.modelName = 'team';
Team.fields = {
	id: attr(),
	name: attr(),
	users: many('user', 'teams'),
};

and lets we have such setup:

Team.create({ name: 'team0' });
Team.create({ name: 'team1' });

User.create({ name: 'user0' });
User.create({ name: 'user1' });
User.create({ name: 'user2' });

const teamFirst = Team.first();
const userFirst = User.first();
const userLast = User.last();

And here is reality:

forward field + update() - works

teamFirst.update({ users: [userFirst, userLast] });
console.log(session.TeamUsers.all().toRefArray());
//[ { fromTeamId: 0, toUserId: 0, id: 0 },
//{ fromTeamId: 0, toUserId: 2, id: 1 } ]

forward field + add() - works

teamFirst.users.add(userFirst, userLast);
console.log(session.TeamUsers.all().toRefArray());
//[ { fromTeamId: 0, toUserId: 0, id: 0 },
//{ fromTeamId: 0, toUserId: 2, id: 1 } ]

As you see, in both cases we will have same state. But in case of reverse field we will have different story.

reverse field + update - fails (state is empty):

userFirst.update({ teams: [teamFirst] });
userLast.update({ teams: [teamFirst] });
console.log(session.TeamUsers.all().toRefArray());
//[]

reverse field + add - fails (state is different from forward field updates)

userFirst.teams.add(teamFirst);
userLast.teams.add(teamFirst);
console.log(session.TeamUsers.all().toRefArray());
//[ { fromTeamId: 0, toUserId: 0, id: 0 },
//{ fromTeamId: 2, toUserId: 0, id: 1 } ]

All 4 cases must output same result. So looks like we have bug here that must be fixed.

@tiii @markerikson @tommikaikkonen @NathanBWaters

@tiii @markerikson @tommikaikkonen @NathanBWaters guys...it's quite critical bug I think, I would like to have this patch asap. So please do review and let's publish it.

LGTM. Especially since it's already in develop ;)

@tiii revert is possible :) locally it was git-flow :) I provided tests, so you can look at tests and confirm/decline - bug or not :)

LGTM = looks good to me. Sorry for the confusion 😕

Nonetheless I now checked out the code and ran the test on the old and the new codebase. I can confirm this is a bug and you fixed it 🎊

What I noticed: The codecov reporter is also run locally and fails because of the missing token. Maybe we could only run this on the CI (once it's installed in the repo)?

codeconv requires token, but in case of github it doesn't. So locally it will fail to upload. Have no idea how to fix it without token - create another command at package.json for local testing? e.g.: test-ci (like now), test (run tests without codecov)

Oh and for a future version:
I would favor a more explicit implementation, where you have to describe the relation in both models. Then we could get rid of all this reverse stuff in the model + descriptors and you can see the relations of every model right away from its file instead of having to know if there are relations to it declared in other models. What do you think of that?

Wouldn't it be enough to add && codecov to the test section in .travis.yml?

@tiii yep, wants it too :) less magic, less surprises :) But I'm thinking about explicit/implicit - current behaviour, but also allow to define relation in both models and just throw error in case if names differ.

@tiii about .travis.yml - need to check :)

I would intoduce this in new a major release so, I would vote for dropping implicit relation declaration completely. Otherwise we still would have to keep reverse stuff in there which is makes it kind of hard to read the code.

for me both ways are fine, but not sure that we must drop implicit. E.g. at iOS CoreData you can set reverse name and use it.

reverse updates fixed at 0.9.1