Skip to content

Commit

Permalink
Add backendResourceName for model and store
Browse files Browse the repository at this point in the history
When using `model.toBackendAll()`, the name of the relation is sometimes
not the same as the name of the model or store. e.g.

```js
relations() {
	return { activities: ActivityStore };
}
```

But the backend knows the `activities` relation by the name `activity`.
To fix this, you can now set `backendResourceName` on a model or store:

```js
class ActivityStore extends Store {
	static backendResourceName = 'activity';
}
```
  • Loading branch information
SpaceK33z committed Apr 18, 2017
1 parent 5775b41 commit 12f70aa
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 1 deletion.
15 changes: 14 additions & 1 deletion src/Model.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ function generateNegativeId() {

export default class Model {
static primaryKey = 'id';
// How the model is known at the backend. This is useful when the model is in a relation that has a different name.
static backendResourceName = '';
urlRoot;

__attributes = [];
Expand Down Expand Up @@ -61,6 +63,12 @@ export default class Model {
);
}

set backendResourceName(v) {
throw new Error(
'`backendResourceName` should be a static property on the model.'
);
}

casts() {
return {};
}
Expand Down Expand Up @@ -176,7 +184,12 @@ export default class Model {
data[relBackendName] = myNewId;
}
const relBackendData = rel.toBackendAll(myNewId);
relations[relBackendName] = relBackendData.data;
// Sometimes the backend knows the relation by a different name, e.g. the relation is called
// `activities`, but the name in the backend is `activity`.
// In that case, you can add `static backendResourceName = 'activity';` to that model.
const realBackendName =
rel.constructor.backendResourceName || relBackendName;
relations[realBackendName] = relBackendData.data;
forIn(relBackendData.relations, (relB, key) => {
relations[key] = relations[key]
? relations[key].concat(relB)
Expand Down
7 changes: 7 additions & 0 deletions src/Store.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export default class Store {
api = null;
__repository;
__nestedRepository = {};
static backendResourceName = '';

@computed get isLoading() {
return this.__pendingRequestCount > 0;
Expand All @@ -37,6 +38,12 @@ export default class Store {
return this.models.length;
}

set backendResourceName(v) {
throw new Error(
'`backendResourceName` should be a static property on the store.'
);
}

constructor(options = {}) {
if (!isPlainObject(options)) {
throw Error(
Expand Down
35 changes: 35 additions & 0 deletions src/__tests__/Model.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
AnimalWithoutApi,
AnimalWithoutUrl,
AnimalCircular,
AnimalResourceName,
Kind,
Breed,
Person,
Expand Down Expand Up @@ -423,6 +424,40 @@ test('toBackendAll with nested store relation', () => {
expect(serialized).toMatchSnapshot();
});

test('toBackendAll with `backendResourceName` property model', () => {
const animal = new AnimalResourceName(
{},
{ relations: ['blaat', 'owners'] }
);

animal.parse({
id: 1,
blaat: {
id: 2,
},
owners: [
{
id: 3,
},
],
});

const serialized = animal.toBackendAll();
expect(serialized).toMatchSnapshot();
});

test('backendResourceName defined as not static should throw error', () => {
class Zebra extends Model {
backendResourceName = 'blaat';
}

expect(() => {
return new Zebra();
}).toThrow(
'`backendResourceName` should be a static property on the model.'
);
});

test('toBackend with frontend-only prop', () => {
const animal = new AnimalWithFrontendProp({
id: 3,
Expand Down
13 changes: 13 additions & 0 deletions src/__tests__/Store.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import { Store } from '../';
import {
Animal,
AnimalStore,
Expand Down Expand Up @@ -260,6 +261,18 @@ test('clear models', () => {
expect(animalStore.length).toBe(0);
});

test('backendResourceName defined as not static should throw error', () => {
class Zebra extends Store {
backendResourceName = 'blaat';
}

expect(() => {
return new Zebra();
}).toThrow(
'`backendResourceName` should be a static property on the store.'
);
});

test('One-level store relation', () => {
const animalStore = new AnimalStore({
relations: ['pastOwners'],
Expand Down
26 changes: 26 additions & 0 deletions src/__tests__/__snapshots__/Model.js.snap
Original file line number Diff line number Diff line change
@@ -1,5 +1,31 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`toBackendAll with \`backendResourceName\` property model 1`] = `
Object {
"data": Array [
Object {
"blaat": 2,
"id": 1,
"owners": Array [
3,
],
},
],
"relations": Object {
"kind": Array [
Object {
"id": 2,
},
],
"person": Array [
Object {
"id": 3,
},
],
},
}
`;

exports[`toBackendAll with deep nested relation 1`] = `
Object {
"data": Array [
Expand Down
24 changes: 24 additions & 0 deletions src/__tests__/fixtures/Animal.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,27 @@ export class AnimalCircular extends Model {
};
}
}
export class KindResourceName extends Model {
api = new BinderApi();
static backendResourceName = 'kind';
@observable id = null;
}
export class PersonStoreResourceName extends Store {
Model = KindResourceName;
static backendResourceName = 'person';
api = new BinderApi();
}

export class AnimalResourceName extends Model {
api = new BinderApi();
@observable id = null;

relations() {
return {
blaat: KindResourceName,
owners: PersonStoreResourceName,
};
}
}

0 comments on commit 12f70aa

Please sign in to comment.