Skip to content

Commit

Permalink
[BUGFIX beta] Fix client-side delete + resurrection
Browse files Browse the repository at this point in the history
Previously relationships were only cleared for new records.  Now they
are cleared for destroyed records as well, allowing destroyed records to
be pushed back into the store and properly update their inverse
relationships.

This fixes the public API for client-side delete via an adapter,
see #5136.
  • Loading branch information
hjdivad committed Nov 2, 2017
1 parent ce606b1 commit 9e39629
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 12 deletions.
16 changes: 4 additions & 12 deletions addon/-private/system/model/internal-model.js
Original file line number Diff line number Diff line change
Expand Up @@ -772,7 +772,7 @@ export default class InternalModel {
}

if (this.isNew()) {
this.removeFromInverseRelationships(true);
this.removeFromInverseRelationships();
}

if (this.isValid()) {
Expand Down Expand Up @@ -891,19 +891,13 @@ export default class InternalModel {
It will remove this record from any associated relationships.
If `isNew` is true (default false), it will also completely reset all
relationships to an empty state as well.
@method removeFromInverseRelationships
@param {Boolean} isNew whether to unload from the `isNew` perspective
@private
*/
removeFromInverseRelationships(isNew = false) {
removeFromInverseRelationships() {
this._relationships.forEach((name, rel) => {
rel.removeCompletelyFromInverse();
if (isNew === true) {
rel.clear();
}
rel.clear();
});

let implicitRelationships = this._implicitRelationships;
Expand All @@ -913,9 +907,7 @@ export default class InternalModel {
let rel = implicitRelationships[key];

rel.removeCompletelyFromInverse();
if (isNew === true) {
rel.clear();
}
rel.clear();
});
}

Expand Down
88 changes: 88 additions & 0 deletions tests/integration/adapter/client-side-delete-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { resolve } from 'rsvp';
import { run } from '@ember/runloop';
import setupStore from 'dummy/tests/helpers/store';

import { module, test } from 'qunit';

import DS from 'ember-data';

module('integration/adapter/store-adapter - client-side delete', {
beforeEach() {
this.Bookstore = DS.Model.extend({
books: DS.hasMany('book', { async: false, inverse: 'bookstore' })
});
this.Book = DS.Model.extend({
bookstore: DS.belongsTo('bookstore', { inverse: 'books' })
});

this.env = setupStore({
bookstore: this.Bookstore,
book: this.Book
});
this.store = this.env.store;
this.adapter = this.env.adapter;
},

afterEach() {
run(this.env.container, 'destroy');
}
});

test('client-side deleted records can be added back from an inverse', function(assert) {
this.adapter.deleteRecord = function (store, modelClass, snapshot) {
if (snapshot.adapterOptions.clientSideDelete) {
return resolve();
}

assert.ok(false, 'unreachable');
}

run(() => this.store.push({
data: {
id: '1',
type: 'bookstore',
relationships: {
books: {
data: [{
id: '1', type: 'book'
}, {
id: '2', type: 'book'
}]
}
}
}, included: [{
id: '1',
type: 'book'
}, {
id: '2',
type: 'book'
}]
}));

let bookstore = this.store.peekRecord('bookstore', '1');
assert.deepEqual(bookstore.get('books').mapBy('id'), ['1', '2'], 'initial hasmany loaded');

let book2 = this.store.peekRecord('book', '2');
return run(() => book2.destroyRecord({ adapterOptions: { clientSideDelete: true } })).then(() => {
run(() => book2.unloadRecord());
assert.equal(this.store.hasRecordForId('book', '2'), false, 'book 2 unloaded');
assert.deepEqual(bookstore.get('books').mapBy('id'), ['1'], 'one book client-side deleted');

run(() => this.store.push({
data: {
id: '2',
type: 'book',
relationships: {
bookstore: {
data: {
id: '1',
type: 'bookstore'
}
}
}
}
}));

assert.deepEqual(bookstore.get('books').mapBy('id'), ['1', '2'], 'the deleted book (with same id) is pushed back into the store');
});
});

0 comments on commit 9e39629

Please sign in to comment.