Skip to content

Commit dbc0aaf

Browse files
committed
implement $isPersisted
1 parent 00dccef commit dbc0aaf

File tree

8 files changed

+44
-15
lines changed

8 files changed

+44
-15
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,12 @@ This plugin has an opinion how the GraphQL API schema should look like:
126126
You can see query examples in the [project wiki](https://github.com/vuex-orm/vuex-orm-apollo/wiki/Example-Queries).
127127

128128

129+
## Special record properties
130+
131+
This plugin adds a special property to your models: `$isPersisted`, which represents if this record is persisted on
132+
the server. It's true for all records except newly created ones.
133+
134+
129135

130136
## Known issues
131137

src/context.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,19 @@ export default class Context {
5959
const model: Model = new Model(entity.model as ORMModel, this);
6060
this.models.set(model.singularName, model);
6161

62-
this.addFields(model);
62+
this.augmentModel(model);
6363
});
6464
}
6565

66+
private augmentModel (model: Model) {
67+
const originalFieldGenerator = model.baseModel.fields.bind(model.baseModel);
6668

67-
private addFields(model: Model) {
68-
// FIXME model.baseModel.fields.push('$isDirty');
69-
// FIXME model.baseModel.fields.push('$isPersisted');
69+
model.baseModel.fields = () => {
70+
const originalFields = originalFieldGenerator();
71+
72+
originalFields['$isPersisted'] = model.baseModel.attr(false);
73+
74+
return originalFields;
75+
};
7076
}
7177
}

src/interfaces.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export interface ORMModel {
3636
fields (): any;
3737
dispatch (name: string, ...params: Array<any>): any;
3838
getters (name: string, ...params: Array<any>): any;
39+
attr (defaultValue: any): Field;
3940
}
4041

4142
export interface Field {

src/queryBuilder.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,9 +195,12 @@ export default class QueryBuilder {
195195
if (!recursiveCall) {
196196
this.context.logger.log('Transformed data:', result);
197197
this.context.logger.groupEnd();
198+
} else {
199+
result['$isPersisted'] = true;
198200
}
199201

200-
return result;
202+
// MAke sure this is really a plain JS object. We had some issues in testing here.
203+
return JSON.parse(JSON.stringify(result));
201204
}
202205

203206
/**

src/vuex-orm-apollo.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,12 @@ export default class VuexORMApollo {
118118
const mutationName = `create${upcaseFirstLetter(model.singularName)}`;
119119
await this.mutate(mutationName, args, dispatch, model, false);
120120

121-
// TODO is this really necessary?
122-
return model.baseModel.getters('find')(id);
121+
const record = model.baseModel.getters('find')(id);
122+
123+
record.$isPersisted = true;
124+
record.$dispatch('update', { where: record.id, data: record });
125+
126+
return record;
123127
}
124128
}
125129

test/integration/VuexORMApollo.spec.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -377,15 +377,15 @@ mutation SignupUser($user: UserInput!, $captchaToken: String!) {
377377

378378
describe('$isDirty', () => {
379379
it('is false for newly created records', async () => {
380-
let user = store.dispatch('entities/users/create', { name: 'Snoopy' });
380+
let user = await store.dispatch('entities/users/insert', { data: { name: 'Snoopy' }} );
381381
expect(user.$isDirty).toBeFalsy();
382382

383383
user = store.getters['entities/users/find'](user.id);
384384
expect(user.$isDirty).toBeFalsy();
385385
});
386386

387387
it('is true for changed but unsaved records', async () => {
388-
let user = store.dispatch('entities/users/create', { name: 'Snoopy' });
388+
let user = await store.dispatch('entities/users/insert', { data: { name: 'Snoopy' }} );
389389
user.name = 'Snoop Dog';
390390
expect(user.$isDirty).toBeTruthy();
391391

@@ -394,7 +394,7 @@ mutation SignupUser($user: UserInput!, $captchaToken: String!) {
394394
});
395395

396396
it('is false for changed and saved records', async () => {
397-
let user = store.dispatch('entities/users/create', { name: 'Snoopy' });
397+
let user = await store.dispatch('entities/users/insert', { data: { name: 'Snoopy' }} );
398398
user.name = 'Snoop Dog';
399399
store.dispatch('entities/users/update', { where: user.id, data: user });
400400
expect(user.$isDirty).toBeFalsy();
@@ -406,7 +406,7 @@ mutation SignupUser($user: UserInput!, $captchaToken: String!) {
406406

407407
describe('$isPersisted', () => {
408408
it('is false for newly created records', async () => {
409-
let user = store.dispatch('entities/users/create', { name: 'Snoopy' });
409+
let user = await store.dispatch('entities/users/insert', { data: { name: 'Snoopy' }} );
410410
expect(user.$isPersisted).toBeFalsy();
411411

412412
user = store.getters['entities/users/find'](user.id);

test/support/Helpers.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import _ from 'lodash';
22
import Vue from 'vue';
33
import Vuex from 'vuex';
44
import VuexORM, { Database, Model } from '@vuex-orm/core';
5-
import installVuexORMApollo from 'app';
65
import fetchMock from 'fetch-mock';
76
import VuexORMApolloPlugin from "app";
87

test/unit/QueryBuilder.spec.js

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ describe('QueryBuilder', () => {
163163

164164

165165
describe('.transformIncomingData', () => {
166-
it('transforms incoming data into Vuex-ORM a readable structure', () => {
166+
it('transforms incoming data into a Vuex-ORM readable structure', () => {
167167
const incomingData = {
168168
"contracts": {
169169
"nodes": [
@@ -218,8 +218,10 @@ describe('QueryBuilder', () => {
218218
const expectedData = {
219219
"contracts": [
220220
{
221+
"$isPersisted": true,
221222
"contractOptions": [
222223
{
224+
"$isPersisted": true,
223225
"description": "Very foo, much more bar",
224226
"id": 1,
225227
"name": "Foo Bar 1",
@@ -231,8 +233,10 @@ describe('QueryBuilder', () => {
231233
"slug": "contract-s",
232234
},
233235
{
236+
"$isPersisted": true,
234237
"contractOptions": [
235238
{
239+
"$isPersisted": true,
236240
"description": "Very foo, much more bar",
237241
"id": 1,
238242
"name": "Foo Bar 1",
@@ -244,8 +248,10 @@ describe('QueryBuilder', () => {
244248
"slug": "contract-m",
245249
},
246250
{
251+
"$isPersisted": true,
247252
"contractOptions": [
248253
{
254+
"$isPersisted": true,
249255
"description": "Very foo, much more bar",
250256
"id": 1,
251257
"name": "Foo Bar 1",
@@ -266,7 +272,7 @@ describe('QueryBuilder', () => {
266272

267273

268274
describe('.transformIncomingData', () => {
269-
it('transforms incoming data after a mutation into Vuex-ORM a readable structure', () => {
275+
it('transforms incoming data after a mutation into a Vuex-ORM readable structure', () => {
270276
const incomingData = {
271277
"createContract": {
272278
"id": "1",
@@ -286,8 +292,10 @@ describe('QueryBuilder', () => {
286292
};
287293
const expectedData = {
288294
"contract": {
295+
"$isPersisted": true,
289296
"contractOptions": [
290297
{
298+
"$isPersisted": true,
291299
"description": "Very foo, much more bar",
292300
"id": 1,
293301
"name": "Foo Bar 1",
@@ -301,7 +309,9 @@ describe('QueryBuilder', () => {
301309
};
302310

303311
const model = vuexOrmApollo.context.getModel('contract');
304-
expect(queryBuilder.transformIncomingData(incomingData, model, true)).toEqual(expectedData);
312+
const transformedData = queryBuilder.transformIncomingData(incomingData, model, true);
313+
314+
expect(transformedData).toEqual(expectedData);
305315
});
306316
});
307317

0 commit comments

Comments
 (0)