Skip to content
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

Relationship Refactor (part 2): The graph should coordinate state updates #7493

Merged
merged 6 commits into from
May 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,7 @@ module('async belongs-to rendering tests', function (hooks) {
assert.ok(pirate.get('bestHuman') === null, 'precond - pirate has no best human');
assert.ok(bestDog === null, 'precond - Chris has no best dog');

// locally update
chris.set('bestDog', shen);
bestDog = await chris.get('bestDog');
await settled();
Expand All @@ -385,6 +386,7 @@ module('async belongs-to rendering tests', function (hooks) {
assert.ok(pirate.get('bestHuman') === null, 'scene 1 - pirate has no best human');
assert.ok(bestDog === shen, "scene 1 - Shen is Chris's best dog");

// locally update to a different value
chris.set('bestDog', pirate);
bestDog = await chris.get('bestDog');
await settled();
Expand All @@ -394,6 +396,7 @@ module('async belongs-to rendering tests', function (hooks) {
assert.ok(pirate.get('bestHuman') === chris, 'scene 2 - pirate now has Chris as best human');
assert.ok(bestDog === pirate, "scene 2 - Pirate is now Chris's best dog");

// locally clear the relationship
chris.set('bestDog', null);
bestDog = await chris.get('bestDog');
await settled();
Expand Down
6 changes: 3 additions & 3 deletions packages/-ember-data/tests/helpers/accessors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ import { recordIdentifierFor } from '@ember-data/store';
type CoreStore = import('@ember-data/store/-private/system/core-store').default;
type BelongsToRelationship = import('@ember-data/record-data/-private').BelongsToRelationship;
type ManyRelationship = import('@ember-data/record-data/-private').ManyRelationship;
type Relationship = import('@ember-data/record-data/-private').Relationship;
type ImplicitRelationship = import('@ember-data/record-data/-private').Relationship;
type RecordDataStoreWrapper = import('@ember-data/store/-private').RecordDataStoreWrapper;
type StableRecordIdentifier = import('@ember-data/store/-private/ts-interfaces/identifier').StableRecordIdentifier;
type RelationshipDict = import('@ember-data/store/-private/ts-interfaces/utils').ConfidentDict<Relationship>;
type RelationshipDict = import('@ember-data/store/-private/ts-interfaces/utils').ConfidentDict<ImplicitRelationship>;

export function getRelationshipStateForRecord(
record: { store: CoreStore },
propertyName: string
): BelongsToRelationship | ManyRelationship | Relationship {
): BelongsToRelationship | ManyRelationship | ImplicitRelationship {
const identifier = recordIdentifierFor(record);
return graphFor(record.store._storeWrapper).get(identifier, propertyName);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,7 @@ module('Store.createRecord() coverage', function (hooks) {
assert.deepEqual(pets, ['Shen'], 'Precondition: Chris has Shen as a pet');

pet.unloadRecord();

assert.ok(pet.get('owner') === null, 'Shen no longer has an owner');

// check that the relationship has been dissolved
pets = chris
.get('pets')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -266,21 +266,21 @@ module('Editing a Record', function (hooks) {
assert.deepEqual(pets, ['Shen', 'Rocky'], 'Precondition: Chris has Shen and Rocky as pets');

shen.set('owner', john);
assert.ok(shen.get('owner') === john, 'Precondition: John is the new owner of Shen');
assert.ok(shen.get('owner') === john, 'After Update: John is the new owner of Shen');

pets = chris.pets.toArray().map((pet) => pet.name);
assert.deepEqual(pets, ['Rocky'], 'Precondition: Chris has Rocky as a pet');
assert.deepEqual(pets, ['Rocky'], 'After Update: Chris has Rocky as a pet');

pets = john.pets.toArray().map((pet) => pet.name);
assert.deepEqual(pets, ['Shen'], 'Precondition: John has Shen as a pet');
assert.deepEqual(pets, ['Shen'], 'After Update: John has Shen as a pet');

chris.unloadRecord();

assert.ok(rocky.get('owner') === null, 'Rocky has no owner');
assert.ok(shen.get('owner') === john, 'John should still be the owner of Shen');
assert.ok(rocky.get('owner') === null, 'After Unload: Rocky has no owner');
assert.ok(shen.get('owner') === john, 'After Unload: John should still be the owner of Shen');

pets = john.pets.toArray().map((pet) => pet.name);
assert.deepEqual(pets, ['Shen'], 'John still has Shen as a pet');
assert.deepEqual(pets, ['Shen'], 'After Unload: John still has Shen as a pet');
});
});

Expand Down
140 changes: 66 additions & 74 deletions packages/-ember-data/tests/integration/records/unload-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import JSONAPIAdapter from '@ember-data/adapter/json-api';
import JSONAPISerializer from '@ember-data/serializer/json-api';
import { recordDataFor } from '@ember-data/store/-private';

function idsFromOrderedSet(set) {
return set.list.map((i) => i.id);
function idsFromArr(arr) {
return arr.map((i) => i.id);
}

const { attr, belongsTo, hasMany, Model } = DS;
Expand Down Expand Up @@ -429,26 +429,24 @@ module('integration/unload - Unloading Records', function (hooks) {
};
}

test('unloadAll(type) does not leave stranded internalModels in relationships (rediscover via store.push)', function (assert) {
test('unloadAll(type) does not leave stranded internalModels in relationships (rediscover via store.push)', async function (assert) {
assert.expect(15);

let person = run(() =>
store.push({
data: {
type: 'person',
id: '1',
attributes: {
name: 'Could be Anybody',
},
relationships: {
boats: {
data: [{ type: 'boat', id: '1' }],
},
let person = store.push({
data: {
type: 'person',
id: '1',
attributes: {
name: 'Could be Anybody',
},
relationships: {
boats: {
data: [{ type: 'boat', id: '1' }],
},
},
included: [makeBoatOneForPersonOne()],
})
);
},
included: [makeBoatOneForPersonOne()],
});

let boat = store.peekRecord('boat', '1');
let initialBoatInternalModel = boat._internalModel;
Expand All @@ -463,10 +461,10 @@ module('integration/unload - Unloading Records', function (hooks) {
assert.true(store.hasRecordForId('boat', '1'));

// ensure the relationship was established (we reach through the async proxy here)
let peopleBoats = run(() => person.get('boats.content'));
let boatPerson = run(() => boat.get('person.content'));
let peopleBoats = await person.get('boats');
let boatPerson = await boat.get('person');

assert.equal(relationshipState.canonicalMembers.size, 1, 'canonical member size should be 1');
assert.equal(relationshipState.canonicalState.length, 1, 'canonical member size should be 1');
assert.equal(relationshipState.members.size, 1, 'members size should be 1');
assert.ok(get(peopleBoats, 'length') === 1, 'Our person has a boat');
assert.ok(peopleBoats.objectAt(0) === boat, 'Our person has the right boat');
Expand All @@ -479,7 +477,7 @@ module('integration/unload - Unloading Records', function (hooks) {
// ensure that our new state is correct
assert.equal(knownPeople.models.length, 1, 'one person record is loaded');
assert.equal(knownBoats.models.length, 0, 'no boat records are loaded');
assert.equal(relationshipState.canonicalMembers.size, 1, 'canonical member size should still be 1');
assert.equal(relationshipState.canonicalState.length, 1, 'canonical member size should still be 1');
assert.equal(relationshipState.members.size, 1, 'members size should still be 1');
assert.ok(get(peopleBoats, 'length') === 0, 'Our person thinks they have no boats');

Expand Down Expand Up @@ -543,7 +541,7 @@ module('integration/unload - Unloading Records', function (hooks) {
let peopleBoats = run(() => person.get('boats.content'));
let boatPerson = run(() => boat.get('person.content'));

assert.equal(relationshipState.canonicalMembers.size, 1, 'canonical member size should be 1');
assert.equal(relationshipState.canonicalState.length, 1, 'canonical member size should be 1');
assert.equal(relationshipState.members.size, 1, 'members size should be 1');
assert.ok(get(peopleBoats, 'length') === 1, 'Our person has a boat');
assert.ok(peopleBoats.objectAt(0) === boat, 'Our person has the right boat');
Expand All @@ -556,7 +554,7 @@ module('integration/unload - Unloading Records', function (hooks) {
// ensure that our new state is correct
assert.equal(knownPeople.models.length, 1, 'one person record is loaded');
assert.equal(knownBoats.models.length, 0, 'no boat records are loaded');
assert.equal(relationshipState.canonicalMembers.size, 1, 'canonical member size should still be 1');
assert.equal(relationshipState.canonicalState.length, 1, 'canonical member size should still be 1');
assert.equal(relationshipState.members.size, 1, 'members size should still be 1');
assert.ok(get(peopleBoats, 'length') === 0, 'Our person thinks they have no boats');

Expand Down Expand Up @@ -614,8 +612,8 @@ module('integration/unload - Unloading Records', function (hooks) {
let peopleBoats = run(() => person.get('boats.content'));
let boatPerson = run(() => boat.get('person.content'));

assert.deepEqual(idsFromOrderedSet(relationshipState.canonicalMembers), ['1'], 'canonical member size should be 1');
assert.deepEqual(idsFromOrderedSet(relationshipState.members), ['1'], 'members size should be 1');
assert.deepEqual(idsFromArr(relationshipState.canonicalState), ['1'], 'canonical member size should be 1');
assert.deepEqual(idsFromArr(relationshipState.currentState), ['1'], 'members size should be 1');
assert.ok(get(peopleBoats, 'length') === 1, 'Our person has a boat');
assert.ok(peopleBoats.objectAt(0) === boat, 'Our person has the right boat');
assert.ok(boatPerson === person, 'Our boat has the right person');
Expand All @@ -635,12 +633,8 @@ module('integration/unload - Unloading Records', function (hooks) {
);
assert.ok(knownBoats.models[0] === initialBoatInternalModel, 'We still have our boat');
assert.true(initialBoatInternalModel.currentState.isEmpty, 'Model is in the empty state');
assert.deepEqual(
idsFromOrderedSet(relationshipState.canonicalMembers),
['1'],
'canonical member size should still be 1'
);
assert.deepEqual(idsFromOrderedSet(relationshipState.members), ['1'], 'members size should still be 1');
assert.deepEqual(idsFromArr(relationshipState.canonicalState), ['1'], 'canonical member size should still be 1');
assert.deepEqual(idsFromArr(relationshipState.currentState), ['1'], 'members size should still be 1');
assert.ok(get(peopleBoats, 'length') === 0, 'Our person thinks they have no boats');

run(() =>
Expand All @@ -652,8 +646,8 @@ module('integration/unload - Unloading Records', function (hooks) {
let reloadedBoat = store.peekRecord('boat', '1');
let reloadedBoatInternalModel = reloadedBoat._internalModel;

assert.deepEqual(idsFromOrderedSet(relationshipState.canonicalMembers), ['1'], 'canonical member size should be 1');
assert.deepEqual(idsFromOrderedSet(relationshipState.members), ['1'], 'members size should be 1');
assert.deepEqual(idsFromArr(relationshipState.canonicalState), ['1'], 'canonical member size should be 1');
assert.deepEqual(idsFromArr(relationshipState.currentState), ['1'], 'members size should be 1');
assert.ok(
reloadedBoatInternalModel === initialBoatInternalModel,
'after an unloadRecord, subsequent fetch results in the same InternalModel'
Expand All @@ -673,8 +667,8 @@ module('integration/unload - Unloading Records', function (hooks) {
let yaBoat = store.peekRecord('boat', '1');
let yaBoatInternalModel = yaBoat._internalModel;

assert.deepEqual(idsFromOrderedSet(relationshipState.canonicalMembers), ['1'], 'canonical member size should be 1');
assert.deepEqual(idsFromOrderedSet(relationshipState.members), ['1'], 'members size should be 1');
assert.deepEqual(idsFromArr(relationshipState.canonicalState), ['1'], 'canonical member size should be 1');
assert.deepEqual(idsFromArr(relationshipState.currentState), ['1'], 'members size should be 1');
assert.ok(
yaBoatInternalModel === initialBoatInternalModel,
'after an unloadRecord, subsequent same-loop push results in the same InternalModel'
Expand Down Expand Up @@ -1837,48 +1831,46 @@ module('integration/unload - Unloading Records', function (hooks) {
};
};

let [person1, person2] = run(() =>
store.push({
data: [
{
id: 1,
type: 'person',
relationships: {
friends: {
data: [
{
id: 3,
type: 'person',
},
{
id: 4,
type: 'person',
},
],
},
let [person1, person2] = store.push({
data: [
{
id: 1,
type: 'person',
relationships: {
friends: {
data: [
{
id: 3,
type: 'person',
},
{
id: 4,
type: 'person',
},
],
},
},
{
id: 2,
type: 'person',
relationships: {
friends: {
data: [
{
id: 3,
type: 'person',
},
{
id: 4,
type: 'person',
},
],
},
},
{
id: 2,
type: 'person',
relationships: {
friends: {
data: [
{
id: 3,
type: 'person',
},
{
id: 4,
type: 'person',
},
],
},
},
],
})
);
},
],
});

let person1Friends, person3, person4;

Expand Down
Loading