-
Notifications
You must be signed in to change notification settings - Fork 4
References
The main feature of the library are the references between models. There are two types of references, and they can be defined with the refs
property on the model:
The direct reference can be used if a JSON API model contains a relationship to a different model:
{
id: 1,
type: 'person',
attributes: {
firstName: 'John',
lastName: 'Doe',
},
relationships: {
pet: {
data: {
id: 1,
type: 'pet',
}
},
spouse: {
data: {
id: 2,
type: 'person',
}
}
}
}
The references are defined in the refs
property in the format {propertyName: referencedModelType}
or in this case, it would be {pet: 'pet', spouse: 'person'}
- it references a pet model in the property pet, and it references a person model in the property spouse.
There is also an additional property created for every direct reference - the id property. In the case of the spouse
property, it would be called spouseId
;
const jane = store.add({firstName: 'Jane', pet: {name: 'Paw'}, id: 1}, 'person');
const steve = store.add({firstName: 'Steve', spouse: 1}, 'person');
console.log(steve.spouse.firstName); // Jane
console.log(steve.spouseId); // 1
console.log(jane.pet.name); // Paw
console.log(jane.petId); // 2
Indirect references are used when the object is not directly referencing the target model. However, the other model has a direct reference to our object. In the previous example, we had a Person model that had a direct reference to the Pet model. Since there is a direct reference in one direction, we can create a indirect reference in the other direction:
class Pet extends Record {}
Pet.type = 'pet';
Pet.refs = {
owner: {
model: 'person',
property: 'pet',
}
};
In this example, we define that the Pet model has a reference to all Person models that have the reference to this Pet model instance in the pet
property.
To make things more complicated, we can define the following direct reference:
class Person extends Record {}
Person.type = 'person';
Person.refs = {
parents: 'person',
spouse: 'person',
};
Keep in mind that a reference can either be a single model or an array of models. Once we have a direct reference to persons parents, we can also define the opposite reference - children:
class Person extends Record {}
Person.type = 'person';
Person.refs = {
parents: 'person',
spouse: 'person',
children: {
model: 'person',
property: 'parents',
}
};
This way, when we create a parents
reference from one model to another, the children
reference will also exist.
const steve = store.add({firstName: 'Steve'}, 'person');
const jane = store.add({firstName: 'Jane'}, 'person');
const bob = store.add({firstName: 'Bob'}, 'person');
const john = store.add({firstName: 'John'}, 'person');
steve.spouse = jane;
bob.parents = [steve, jane]; // We can expect this to be an array...
john.parents = steve; // ...or we can set it as a single model reference for now
console.log(jane.children[0].firstName); // Bob
console.log(steve.children[0].firstName); // Bob
console.log(steve.children[1].firstName); // John
If you need to add an reference that is specific only to one instance of the model, you can use the assignRef
method:
bob.assignRef('siblings', [john]);
There are currently four limitations:
- There is no way to force a reference to be a single model or an array. Depending on the data, it will be one or the other.
- A indirect reference can't be set, e.g. we can't set the persons
children
, only theparents
. - A reference can only be to a single model type, e.g. a
pet
reference can refer to apet
model, but can't refer to thecat
anddog
models at the same time. - There is no way to have both direct and indirect references for the same property, e.g. when we set a
spouse
property on the steve model, jane model won't have the spouse property automatically defined - we need to do it manually.