diff --git a/src/Model.js b/src/Model.js index d0185f2..b61f281 100644 --- a/src/Model.js +++ b/src/Model.js @@ -26,6 +26,7 @@ import { import Store from './Store'; import { invariant, snakeToCamel, camelToSnake, relationsToNestedKeys, forNestedRelations } from './utils'; import Axios from 'axios'; +import {Relation} from "./Relations"; function concatInDict(dict, key, value) { dict[key] = dict[key] ? dict[key].concat(value) : value; @@ -172,7 +173,12 @@ export default class Model { // Find all attributes. Not all observables are an attribute. forIn(this, (value, key) => { - if (!key.startsWith('__') && isObservableProp(this, key)) { + + // Register relations + if (value instanceof Relation) { + this.__relations[key] = value.model; + this[key] = undefined + } else if (!key.startsWith('__') && isObservableProp(this, key)) { invariant( !FORBIDDEN_ATTRS.includes(key), `Forbidden attribute key used: \`${key}\`` @@ -966,4 +972,17 @@ export default class Model { this[currentRel].clear(); }); } + + /************** + * New way of doing relations + *************/ + __relations = {} + + relation(modelOrSTore) { + return new Relation(modelOrSTore) + } + + relations() { + return this.__relations; + } } diff --git a/src/Relations.js b/src/Relations.js new file mode 100644 index 0000000..6f94979 --- /dev/null +++ b/src/Relations.js @@ -0,0 +1,11 @@ +export class Relation { + __toModel = null; + + constructor(toModel) { + this.__toModel = toModel + } + + get model() { + return this.__toModel + } +} diff --git a/src/__tests__/NewRelation.js b/src/__tests__/NewRelation.js new file mode 100644 index 0000000..e4b28ef --- /dev/null +++ b/src/__tests__/NewRelation.js @@ -0,0 +1,59 @@ +import { Kind, Person, PersonStore} from "./fixtures/Animal"; +import {observable} from "mobx"; +import Model from "../Model"; +import {BinderApi} from "../index"; + +class Animal extends Model { + urlRoot = '/api/animal/'; + api = new BinderApi(); + static backendResourceName = 'animal'; + @observable id = null; + @observable name = ''; + + @observable kind = this.relation(Kind); + + @observable owner = this.relation(Person); + + @observable pastOwner = this.relation(PersonStore) +} + +describe('Model with new way of defining relations', () => { + test('Initialize model with valid data', () => { + const animal = new Animal({}) + }); + + test('Relation should not be initialized by default', () => { + const animal = new Animal(); + + expect(animal.kind).toBeUndefined(); + }); + + test('Initialize one-level relation', () => { + const animal = new Animal(null, { + relations: ['kind'], + }); + + expect(animal.kind).toBeInstanceOf(Kind); + }); + test('Initialize multiple relations', () => { + const animal = new Animal(null, { + relations: ['kind', 'owner'], + }); + + expect(animal.kind).toBeInstanceOf(Kind); + expect(animal.owner).toBeInstanceOf(Person); + }); + + test('Non existent relation should throw an error', () => { + expect(() => { + return new Animal(null, { + relations: ['ponyfoo'], + }); + }).toThrow('Specified relation "ponyfoo" does not exist on model.'); + }); + + +}) + + +