mercredi 9 décembre 2015

Modelling two-way symmetric relationships in Ember

Imagine we have two entities, stored in a relational database as:

person(id, name)

friendship(id, personAID, personBID, strength)

Here we can see that two people can be friends and a "strength" (some numerical value) will be given to that friendship. If persons 1 and 2 are friends, then we have the following entry in the friendship table:

xyz | 1 | 2 | 50 |

note that the following corresponding entry does not exist:

abc | 2 | 1 | 50

Only one entry is created per "friendship".

What I struggle with is how to model this in the ember app. A "person" can have many friendships, and a "friendship" relates exactly 2 people.

// models/person.js
DS.Model.extend({
    name: DS.attr('string'),
    friendships: DS.hasMany('friendship', {inverse: 'friends'})
});

The friendship objects are serialized as an array of

{
    id: 'abc',
    friends: ['1', '2'],
    score: '50'
}

so:

// models/friendship.js
DS.Model.extend({
    friends: DS.hasMany('person', {inverse: friendships}),
    personA: Ember.computed(friends, function() {
        return this.get('friends').objectAt('0');
    }),
    personB: Ember.computed(friends, function() {
        return this.get('friends').objectAt('1');
    }),
    getFriend: function(id) {
        if (id === this.get('personA.id')) {
            return this.get('personB');
        }
        if (id === this.get('personB.id')) {
            return this.get('personA');
        }
        return null;
    },
    score: DS.attr('number')
});

The implementation of the friendship model feels hacky for lots of reasons. First of all, a friendship does not "have many" friends. It has exactly two. However, if I change the implementation to:

DS.Model.extend({
    personA: DS.belongsTo('person'),
    personB: DS.belongsTo('person'),
    ...
});

then I'm not sure how to model the "hasMany" relationship of person => friendship. What would the 'inverse' field be set to, for instance?

The "score" field is complicating things. If that didn't exist then this would be a reflexive relation within the "person" model, but the relation has additional data and must be able to be represented as its own entity.

Also, given the situation where I want to list all of the friends of a given person, along with the strength of that friendship, the "getFriend()" function is required. This function smells a bit to me and I can't quite put my finger on why.

So my question is, what do you see as an effective way to model two-way symmetric relationships that contain additional data such as the "score" field? I can't change anything about how the data is stored in the DB, but I do have control over everything else, so I can transform the data into any structure on the way out of the DB and into the Ember client.

Ember and Ember-data 2.x




Aucun commentaire:

Enregistrer un commentaire