mobx-decorated-models
Advanced tools
Comparing version 0.4.4 to 0.4.5
@@ -208,9 +208,5 @@ (function (global, factory) { | ||
function modelDecorator(modelOrIdentifier) { | ||
if (typeof modelOrIdentifier === 'function') { | ||
modelOrIdentifier.identifiedBy = modelOrIdentifier.name; | ||
return decorateModel(modelOrIdentifier); | ||
} | ||
function identifiedBy(modelId) { | ||
return function (model) { | ||
model.identifiedBy = modelOrIdentifier; | ||
Object.defineProperty(model, 'identifiedBy', { value: modelId, writable: false }); | ||
return decorateModel(model); | ||
@@ -298,6 +294,2 @@ }; | ||
function addLazyInitializer(target, fn) { | ||
target.__mobxLazyInitializers.push(fn); | ||
} | ||
function setupModel(_ref) { | ||
@@ -338,9 +330,48 @@ var attrs = _ref.attrs, | ||
function onBelongsToSet(change, _ref2) { | ||
var modelClass = _ref2.modelClass, | ||
defaultAttributes = _ref2.defaultAttributes, | ||
inverseOf = _ref2.inverseOf, | ||
parentModel = _ref2.parentModel, | ||
parentModelProp = _ref2.parentModelProp; | ||
function onCollectionChangeInterceptor(_ref, parentModel, parentModelProp) { | ||
var modelClass = _ref.modelClass, | ||
model = _ref.model, | ||
defaultAttributes = _ref.defaults, | ||
inverseOf = _ref.inverseOf; | ||
return function (change) { | ||
if (!change.newValue) { | ||
change.newValue = {}; | ||
} | ||
if (!modelClass) { | ||
modelClass = findModel(model, parentModelProp); | ||
} | ||
if (change.type === 'splice') { | ||
for (var i = 0; i < change.added.length; i += 1) { | ||
change.added[i] = setupModel({ | ||
attrs: change.added[i], array: change.object, modelClass: modelClass, | ||
defaultAttributes: defaultAttributes, inverseOf: inverseOf, parentModel: parentModel, parentModelProp: parentModelProp }); | ||
} | ||
} else if (change.type === 'update') { | ||
change.newValue = setupModel({ | ||
attrs: change.newValue, array: change.object, modelClass: modelClass, | ||
defaultAttributes: defaultAttributes, inverseOf: inverseOf, parentModel: parentModel, parentModelProp: parentModelProp }); | ||
} | ||
return change; | ||
}; | ||
} | ||
function createCollection(options, parentModel, parentModelProp) { | ||
var ary = mobx.observable.array([]); | ||
if (options && options.model) { | ||
ary.intercept(onCollectionChangeInterceptor(options, parentModel, parentModelProp)); | ||
} | ||
return ary; | ||
} | ||
function addLazyInitializer(target, fn) { | ||
target.__mobxLazyInitializers.push(fn); | ||
} | ||
function onBelongsToSet(change, _ref) { | ||
var modelClass = _ref.modelClass, | ||
defaultAttributes = _ref.defaultAttributes, | ||
inverseOf = _ref.inverseOf, | ||
parentModel = _ref.parentModel, | ||
parentModelProp = _ref.parentModelProp; | ||
change.newValue = setupModel({ | ||
@@ -353,8 +384,8 @@ attrs: change.newValue, modelClass: modelClass, | ||
function onHasManySet(change, _ref3) { | ||
var modelClass = _ref3.modelClass, | ||
defaultAttributes = _ref3.defaultAttributes, | ||
inverseOf = _ref3.inverseOf, | ||
parentModel = _ref3.parentModel, | ||
parentModelProp = _ref3.parentModelProp; | ||
function onHasManySet(change, _ref2) { | ||
var modelClass = _ref2.modelClass, | ||
defaultAttributes = _ref2.defaultAttributes, | ||
inverseOf = _ref2.inverseOf, | ||
parentModel = _ref2.parentModel, | ||
parentModelProp = _ref2.parentModelProp; | ||
@@ -383,38 +414,2 @@ if (change.type !== 'update' || !change.newValue) { | ||
function onCollectionChangeInterceptor(_ref4, parentModel, parentModelProp) { | ||
var modelClass = _ref4.modelClass, | ||
model = _ref4.model, | ||
defaultAttributes = _ref4.defaults, | ||
inverseOf = _ref4.inverseOf; | ||
return function (change) { | ||
if (!change.newValue) { | ||
change.newValue = {}; | ||
} | ||
if (!modelClass) { | ||
modelClass = findModel(model, parentModelProp); | ||
} | ||
if (change.type === 'splice') { | ||
for (var i = 0; i < change.added.length; i += 1) { | ||
change.added[i] = setupModel({ | ||
attrs: change.added[i], array: change.object, modelClass: modelClass, | ||
defaultAttributes: defaultAttributes, inverseOf: inverseOf, parentModel: parentModel, parentModelProp: parentModelProp }); | ||
} | ||
} else if (change.type === 'update') { | ||
change.newValue = setupModel({ | ||
attrs: change.newValue, array: change.object, modelClass: modelClass, | ||
defaultAttributes: defaultAttributes, inverseOf: inverseOf, parentModel: parentModel, parentModelProp: parentModelProp }); | ||
} | ||
return change; | ||
}; | ||
} | ||
function buildCollection(options, parentModel, parentModelProp) { | ||
var ary = mobx.observable.array([]); | ||
if (options.classId || options.model) { | ||
ary.intercept(onCollectionChangeInterceptor(options, parentModel, parentModelProp)); | ||
} | ||
return ary; | ||
} | ||
var Initializers = { | ||
@@ -424,7 +419,7 @@ object: function object$$1() { | ||
}, | ||
array: buildCollection | ||
array: createCollection | ||
}; | ||
var TypeInitializers = { | ||
hasMany: buildCollection | ||
hasMany: createCollection | ||
}; | ||
@@ -534,3 +529,3 @@ | ||
exports.lookupModelUsing = lookupModelUsing; | ||
exports.modelDecorator = modelDecorator; | ||
exports.identifiedBy = identifiedBy; | ||
exports.unresolvedAssociations = unresolvedAssociations; | ||
@@ -542,3 +537,3 @@ exports.field = field; | ||
exports.identifier = identifier$1; | ||
exports.buildCollection = buildCollection; | ||
exports.createCollection = createCollection; | ||
@@ -545,0 +540,0 @@ Object.defineProperty(exports, '__esModule', { value: true }); |
@@ -205,9 +205,5 @@ import { createModelSchema, deserialize, getDefaultModelSchema, identifier, list, object, primitive, serialize, update } from 'serializr'; | ||
function modelDecorator(modelOrIdentifier) { | ||
if (typeof modelOrIdentifier === 'function') { | ||
modelOrIdentifier.identifiedBy = modelOrIdentifier.name; | ||
return decorateModel(modelOrIdentifier); | ||
} | ||
function identifiedBy(modelId) { | ||
return function (model) { | ||
model.identifiedBy = modelOrIdentifier; | ||
Object.defineProperty(model, 'identifiedBy', { value: modelId, writable: false }); | ||
return decorateModel(model); | ||
@@ -295,6 +291,2 @@ }; | ||
function addLazyInitializer(target, fn) { | ||
target.__mobxLazyInitializers.push(fn); | ||
} | ||
function setupModel(_ref) { | ||
@@ -335,9 +327,48 @@ var attrs = _ref.attrs, | ||
function onBelongsToSet(change, _ref2) { | ||
var modelClass = _ref2.modelClass, | ||
defaultAttributes = _ref2.defaultAttributes, | ||
inverseOf = _ref2.inverseOf, | ||
parentModel = _ref2.parentModel, | ||
parentModelProp = _ref2.parentModelProp; | ||
function onCollectionChangeInterceptor(_ref, parentModel, parentModelProp) { | ||
var modelClass = _ref.modelClass, | ||
model = _ref.model, | ||
defaultAttributes = _ref.defaults, | ||
inverseOf = _ref.inverseOf; | ||
return function (change) { | ||
if (!change.newValue) { | ||
change.newValue = {}; | ||
} | ||
if (!modelClass) { | ||
modelClass = findModel(model, parentModelProp); | ||
} | ||
if (change.type === 'splice') { | ||
for (var i = 0; i < change.added.length; i += 1) { | ||
change.added[i] = setupModel({ | ||
attrs: change.added[i], array: change.object, modelClass: modelClass, | ||
defaultAttributes: defaultAttributes, inverseOf: inverseOf, parentModel: parentModel, parentModelProp: parentModelProp }); | ||
} | ||
} else if (change.type === 'update') { | ||
change.newValue = setupModel({ | ||
attrs: change.newValue, array: change.object, modelClass: modelClass, | ||
defaultAttributes: defaultAttributes, inverseOf: inverseOf, parentModel: parentModel, parentModelProp: parentModelProp }); | ||
} | ||
return change; | ||
}; | ||
} | ||
function createCollection(options, parentModel, parentModelProp) { | ||
var ary = observable.array([]); | ||
if (options && options.model) { | ||
ary.intercept(onCollectionChangeInterceptor(options, parentModel, parentModelProp)); | ||
} | ||
return ary; | ||
} | ||
function addLazyInitializer(target, fn) { | ||
target.__mobxLazyInitializers.push(fn); | ||
} | ||
function onBelongsToSet(change, _ref) { | ||
var modelClass = _ref.modelClass, | ||
defaultAttributes = _ref.defaultAttributes, | ||
inverseOf = _ref.inverseOf, | ||
parentModel = _ref.parentModel, | ||
parentModelProp = _ref.parentModelProp; | ||
change.newValue = setupModel({ | ||
@@ -350,8 +381,8 @@ attrs: change.newValue, modelClass: modelClass, | ||
function onHasManySet(change, _ref3) { | ||
var modelClass = _ref3.modelClass, | ||
defaultAttributes = _ref3.defaultAttributes, | ||
inverseOf = _ref3.inverseOf, | ||
parentModel = _ref3.parentModel, | ||
parentModelProp = _ref3.parentModelProp; | ||
function onHasManySet(change, _ref2) { | ||
var modelClass = _ref2.modelClass, | ||
defaultAttributes = _ref2.defaultAttributes, | ||
inverseOf = _ref2.inverseOf, | ||
parentModel = _ref2.parentModel, | ||
parentModelProp = _ref2.parentModelProp; | ||
@@ -380,38 +411,2 @@ if (change.type !== 'update' || !change.newValue) { | ||
function onCollectionChangeInterceptor(_ref4, parentModel, parentModelProp) { | ||
var modelClass = _ref4.modelClass, | ||
model = _ref4.model, | ||
defaultAttributes = _ref4.defaults, | ||
inverseOf = _ref4.inverseOf; | ||
return function (change) { | ||
if (!change.newValue) { | ||
change.newValue = {}; | ||
} | ||
if (!modelClass) { | ||
modelClass = findModel(model, parentModelProp); | ||
} | ||
if (change.type === 'splice') { | ||
for (var i = 0; i < change.added.length; i += 1) { | ||
change.added[i] = setupModel({ | ||
attrs: change.added[i], array: change.object, modelClass: modelClass, | ||
defaultAttributes: defaultAttributes, inverseOf: inverseOf, parentModel: parentModel, parentModelProp: parentModelProp }); | ||
} | ||
} else if (change.type === 'update') { | ||
change.newValue = setupModel({ | ||
attrs: change.newValue, array: change.object, modelClass: modelClass, | ||
defaultAttributes: defaultAttributes, inverseOf: inverseOf, parentModel: parentModel, parentModelProp: parentModelProp }); | ||
} | ||
return change; | ||
}; | ||
} | ||
function buildCollection(options, parentModel, parentModelProp) { | ||
var ary = observable.array([]); | ||
if (options.classId || options.model) { | ||
ary.intercept(onCollectionChangeInterceptor(options, parentModel, parentModelProp)); | ||
} | ||
return ary; | ||
} | ||
var Initializers = { | ||
@@ -421,7 +416,7 @@ object: function object$$1() { | ||
}, | ||
array: buildCollection | ||
array: createCollection | ||
}; | ||
var TypeInitializers = { | ||
hasMany: buildCollection | ||
hasMany: createCollection | ||
}; | ||
@@ -527,3 +522,3 @@ | ||
export { registerModel, findModel, rememberModelUsing, lookupModelUsing, modelDecorator, unresolvedAssociations, field, session, belongsTo, hasMany, identifier$1 as identifier, buildCollection }; | ||
export { registerModel, findModel, rememberModelUsing, lookupModelUsing, identifiedBy, unresolvedAssociations, field, session, belongsTo, hasMany, identifier$1 as identifier, createCollection }; | ||
//# sourceMappingURL=build.module.js.map |
@@ -134,9 +134,5 @@ import { | ||
export function modelDecorator(modelOrIdentifier) { | ||
if (typeof modelOrIdentifier === 'function') { | ||
modelOrIdentifier.identifiedBy = modelOrIdentifier.name; | ||
return decorateModel(modelOrIdentifier); | ||
} | ||
export function identifiedBy(modelId) { | ||
return (model) => { | ||
model.identifiedBy = modelOrIdentifier; | ||
Object.defineProperty(model, 'identifiedBy', { value: modelId, writable: false }); | ||
return decorateModel(model); | ||
@@ -143,0 +139,0 @@ }; |
import { observable, intercept } from 'mobx'; | ||
import { getDefaultModelSchema } from 'serializr'; | ||
import { findModel } from './model-lookup'; | ||
import getModelSchema from './schema'; | ||
import { markNonserializable } from './serializable' | ||
@@ -11,32 +9,5 @@ function addLazyInitializer(target, fn) { | ||
} | ||
import createCollection from './collection'; | ||
function setupModel({ | ||
attrs, modelClass: Klass, array, defaultAttributes, | ||
inverseOf, parentModel, parentModelProp, | ||
}) { | ||
if (!attrs || typeof attrs !== 'object') { | ||
return attrs; | ||
} | ||
if (defaultAttributes) { | ||
if (typeof defaultAttributes === 'function') { | ||
defaultAttributes = defaultAttributes.call(parentModel, array, parentModel); | ||
} | ||
Object.keys(defaultAttributes).forEach((key) => { | ||
if (!attrs[key]) { | ||
attrs[key] = defaultAttributes[key]; | ||
} | ||
}); | ||
} | ||
if (inverseOf) { | ||
if (parentModelProp) { | ||
attrs[`${inverseOf}_association_name`] = parentModelProp; | ||
} | ||
attrs[inverseOf] = parentModel; | ||
} | ||
const model = (Klass && !(attrs instanceof Klass)) ? new Klass(attrs) : attrs; | ||
if (inverseOf) { | ||
markNonserializable(model, inverseOf); | ||
} | ||
return model; | ||
} | ||
import setupModel from './setup-model'; | ||
@@ -75,43 +46,10 @@ function onBelongsToSet(change, | ||
function onCollectionChangeInterceptor( | ||
{ modelClass, model, defaults: defaultAttributes, inverseOf }, | ||
parentModel, parentModelProp, | ||
) { | ||
return (change) => { | ||
if (!change.newValue) { | ||
change.newValue = {}; | ||
} | ||
if (!modelClass) { | ||
modelClass = findModel(model, parentModelProp); | ||
} | ||
if (change.type === 'splice') { | ||
for (let i = 0; i < change.added.length; i += 1) { | ||
change.added[i] = setupModel({ | ||
attrs: change.added[i], array: change.object, modelClass, | ||
defaultAttributes, inverseOf, parentModel, parentModelProp }); | ||
} | ||
} else if (change.type === 'update') { | ||
change.newValue = setupModel({ | ||
attrs: change.newValue, array: change.object, modelClass, | ||
defaultAttributes, inverseOf, parentModel, parentModelProp }); | ||
} | ||
return change; | ||
}; | ||
} | ||
function buildCollection(options, parentModel, parentModelProp) { | ||
const ary = observable.array([]); | ||
if (options.classId || options.model) { | ||
ary.intercept(onCollectionChangeInterceptor(options, parentModel, parentModelProp)); | ||
} | ||
return ary; | ||
} | ||
const Initializers = { | ||
object: () => observable.object({}), | ||
array: buildCollection, | ||
array: createCollection, | ||
}; | ||
const TypeInitializers = { | ||
hasMany: buildCollection, | ||
hasMany: createCollection, | ||
}; | ||
@@ -178,2 +116,2 @@ | ||
export { field, session, belongsTo, hasMany, identifier, buildCollection }; | ||
export { field, session, belongsTo, hasMany, identifier, createCollection }; |
{ | ||
"name": "mobx-decorated-models", | ||
"version": "0.4.4", | ||
"version": "0.4.5", | ||
"description": "Decorators to make using Mobx for model type structures easier", | ||
@@ -5,0 +5,0 @@ "main": "dist/build.full.js", |
@@ -29,3 +29,3 @@ # Decorators for creating model type structures with mobx | ||
@modelDecorator('box') | ||
@identifiedBy('box') | ||
export class Box { | ||
@@ -62,4 +62,4 @@ @identifier id; | ||
The class `@modelDecorator` uses either the `name` property of each class, or can be supplied with a unique string that should be used as a lookup key so | ||
that `hasMany` and `belongsTo` relation ships can be established. | ||
The class `@identifiedBy` accepts a unique string that should be used as a lookup key so | ||
that `hasMany` and `belongsTo` relationships can be established. | ||
@@ -72,5 +72,5 @@ This allows things like the below mappings to still work even though the two files can't easily include each other: | ||
import { modelDecorator, belongsTo } from 'mobx-decorated-models'; | ||
import { identifiedBy, belongsTo } from 'mobx-decorated-models'; | ||
@modelDecorator('chair') | ||
@identifiedBy('chair') | ||
class Chair { | ||
@@ -82,5 +82,5 @@ belongsTo 'table' | ||
// table.js | ||
import { model, hasMany } from 'mobx-decorated-models'; | ||
import { identifiedBy, hasMany } from 'mobx-decorated-models'; | ||
@modelDecorator('table') | ||
@identifiedBy('table') | ||
class Table { | ||
@@ -91,5 +91,26 @@ hasMany({ model: 'chair' }) 'seats' | ||
### Collections | ||
The same logic that is used for belongsTo can also build a stand-alone collection. Collections built this way are instances of mobx `observable.array` with an interceptor that converts assigment into model creation. | ||
A collecton can be created like so: | ||
```javascript | ||
import { createCollection } from 'mobx-decorated-models'; | ||
class Foo { | ||
constructor(attrs) { Object.assign(this, attrs); } | ||
myName() { return this.name; } | ||
} | ||
const collection = createCollection({ model: ModelInCollection }); | ||
collection.push({ name: 'bar' }); | ||
collection[0].myName(); // will return "bar", since it's coerced into an instance of Foo | ||
``` | ||
Note that the "model" objects a collection is set to do not have to be decorated by the `@identifiedBy` decorator if they're given directly as shown in the exmple above. However if they were, then the identifier could be given to 'model' instead of the class. | ||
### Decorators | ||
#### model | ||
#### identifiedBy('<identifier>') | ||
@@ -101,2 +122,3 @@ Marks a class as serializable. | ||
* static `deserialize` method. Used to turn JSON structure into a model (or collection of models) | ||
* a read-only static `identifiedBy` value that matches the string provided to the decorator | ||
* an `update` method. Updates a model's attributes and child associations. | ||
@@ -121,3 +143,3 @@ * `serialize`. Converts the model's attributes and it's associations to JSON. | ||
```javascript | ||
@modelDecorator | ||
@identifiedBy('foo') | ||
class Foo { | ||
@@ -137,9 +159,9 @@ @field({ type: 'object' }) options; // will default to an observable map | ||
Makes a property as referring to another model. Will attempt to map | ||
the referenced class based on the name, i.e. a property named `box` will | ||
look for a class named `Box`. | ||
Makes a property as referring to another model. Will map to | ||
the referenced class based on it's identifiedBy and the property name, i.e. a property named `box` will | ||
look for a class identified by `box`. | ||
Optionally can be given an option object with a `model` property to control the mapping. | ||
`model` can be either a string which matches a value given to the modelDecorator, or a reference to the model itself. | ||
`model` can be either a string which matches a value given to the identifiedBy decorator, or a reference to the model itself. | ||
@@ -149,3 +171,3 @@ *example:* | ||
```javascript | ||
@modelDecorator | ||
@identifiedBy('person') | ||
class Person({ | ||
@@ -161,3 +183,3 @@ @identifier id; | ||
@modelDecorator('pants') | ||
@identifiedBy('pants') | ||
class Pants { | ||
@@ -208,3 +230,3 @@ @session color; | ||
```javascript | ||
@modelDecorator | ||
@identifiedBy('tire') | ||
class Tire { | ||
@@ -215,3 +237,3 @@ @session numberInSet; | ||
@modelDecorator | ||
@identifiedBy('car') | ||
class Car { | ||
@@ -223,3 +245,3 @@ @belongsTo home; | ||
@modelDecorator | ||
@identifiedBy('garage') | ||
class Garage { | ||
@@ -239,3 +261,3 @@ @session owner; | ||
mobx-decorated-models attempts to do lazy lookups for the model that **hasMany** and **belongsTo** should use. In order to do so, it keeps track of associations that are not immediatly resolved in the hope that the model for them will be decorated with **@modelDecorator** later. | ||
mobx-decorated-models attempts to do lazy lookups for the model that **hasMany** and **belongsTo** should use. In order to do so, it keeps track of associations that are not immediatly resolved in the hope that the model for them will be decorated with **@identifiedBy** later. | ||
@@ -247,5 +269,7 @@ However if the model is never decorated the association will continue to be set to a plain observable.object. | ||
**Example:** | ||
```javascript | ||
import { model, field, session, belongsTo, hasMany, identifier } from 'mobx-decorated-models'; | ||
@modelDecorator | ||
@identifiedBy('shape') | ||
class Parallelogram { | ||
@@ -255,3 +279,3 @@ | ||
@modelDecorator('box') | ||
@identifiedBy('box') | ||
class Box { | ||
@@ -266,2 +290,3 @@ hasMany sides; | ||
// outputs: The model for box(sides) cannot be found | ||
``` | ||
@@ -268,0 +293,0 @@ |
@@ -95,5 +95,6 @@ import { Container, Box, Ship } from './test-models'; | ||
it('uses string identifier with decorator', () => { | ||
it('sets identifier from decorator', () => { | ||
expect(Ship.identifiedBy).toEqual('boat'); | ||
expect(findModel('ship', 'boat')).toBe(Ship) | ||
expect(() => (Ship.identifiedBy = 'bar')).toThrow(); | ||
expect(findModel('ship', 'boat')).toBe(Ship); | ||
}); | ||
@@ -100,0 +101,0 @@ |
import { Container, Box } from './test-models'; | ||
import { modelDecorator } from '../index'; | ||
import { identifiedBy } from '../index'; | ||
import * as ModelLookup from '../lib/model-lookup'; | ||
@@ -22,3 +22,3 @@ | ||
ModelLookup.rememberModelUsing(spy); | ||
@modelDecorator | ||
@identifiedBy('foo') | ||
class ThisIsTest { } | ||
@@ -25,0 +25,0 @@ expect(spy).toHaveBeenCalledWith(ThisIsTest); |
import { observable, computed } from 'mobx'; | ||
import { modelDecorator, field, session, belongsTo, hasMany, identifier } from '../index'; | ||
import { identifiedBy, field, session, belongsTo, hasMany, identifier } from '../index'; | ||
@@ -11,3 +11,3 @@ class RectangularCuboid { | ||
@modelDecorator('boat') | ||
@identifiedBy('boat') | ||
export class Ship { | ||
@@ -19,3 +19,3 @@ @identifier name; | ||
@modelDecorator('box') | ||
@identifiedBy('box') | ||
export class Box extends RectangularCuboid { | ||
@@ -40,3 +40,3 @@ @identifier id; | ||
@modelDecorator('container') | ||
@identifiedBy('container') | ||
export class Container extends RectangularCuboid { | ||
@@ -43,0 +43,0 @@ @identifier id; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
212316
27
1567
280