mobx-decorated-models
Advanced tools
Comparing version 0.0.2 to 0.0.3
import { | ||
serialize, deserialize, createModelSchema, primitive, list, object, | ||
identifier, getDefaultModelSchema, update, custom, | ||
identifier, getDefaultModelSchema, update, map, | ||
} from 'serializr'; | ||
@@ -33,18 +32,37 @@ | ||
return { | ||
serializer: function (value) { | ||
return undefined; | ||
}, | ||
deserializer: defaultSerial.deserializer | ||
serializer: () => undefined, | ||
deserializer: defaultSerial.deserializer, | ||
}; | ||
} | ||
function getSerializer(options, defaultSerializer){ | ||
let serializer; | ||
if (options.type === 'object') { | ||
serializer = map; | ||
} else if (options.type === 'array') { | ||
serializer = list; | ||
} else { | ||
serializer = defaultSerializer; | ||
} | ||
if (options.writeOnly) { | ||
return { | ||
serializer: () => undefined, | ||
deserializer: serializer.deserializer, | ||
}; | ||
} | ||
return serializer(); | ||
} | ||
const SimpleHandlers = { | ||
identifier: () => identifier(), | ||
fields: () => primitive(), | ||
session: () => readonlyPrimitive(), | ||
identifier: options => getSerializer(options, identifier), | ||
field: options => getSerializer(options, primitive), | ||
session: options => | ||
getSerializer(Object.assign({}, options, { writeOnly: true }), primitive), | ||
}; | ||
const AsyncHandlers = { | ||
hasMany: model => list(object(model)), | ||
belongsTo: model => object(model), | ||
hasMany: modelRef => list(object(modelRef)), | ||
belongsTo: (model, opt) => { | ||
return object(getDefaultModelSchema(model)) | ||
}, | ||
}; | ||
@@ -74,4 +92,2 @@ | ||
export default function (model) { | ||
// console.log('decorate', model); | ||
Object.assign(model.prototype, MixedInInstanceMethods); | ||
@@ -104,4 +120,4 @@ Object.assign(model, MixedInClassMethods); | ||
if (referencedModel) { | ||
const parentModelSchema = getDefaultModelSchema(parentModel) | ||
parentModelSchema.props[propName] = cb(model, options); | ||
const parentModelSchema = getDefaultModelSchema(parentModel); | ||
parentModelSchema.props[propName] = cb(referencedModel, options); | ||
PendingLookups.splice(i, 1); | ||
@@ -108,0 +124,0 @@ } |
@@ -7,4 +7,22 @@ import { | ||
const Initializers = { | ||
object: () => observable.map({}), | ||
array: () => observable.array([]), | ||
}; | ||
const TypeInitializers = { | ||
hasMany: Initializers.array, | ||
}; | ||
function getInitializer(type, options) { | ||
return TypeInitializers[type] || Initializers[options.type]; | ||
} | ||
function addAttribute(type, target, property, descriptor, options = {}) { | ||
getModelSchema(target.constructor).set(property, { type, options }); | ||
getModelSchema(target.constructor).set(property, { name: property, type, options }); | ||
const initializer = getInitializer(type, options); | ||
if (initializer) { | ||
descriptor.initializer = initializer; | ||
} | ||
return observable(target, property, descriptor); | ||
@@ -21,15 +39,10 @@ } | ||
const identifier = (...args) => | ||
buildAttributeDecorator('identifier', args); | ||
const field = (...args) => | ||
buildAttributeDecorator('fields', args); | ||
const session = (...args) => | ||
buildAttributeDecorator('session', args); | ||
const belongsTo = (...args) => | ||
buildAttributeDecorator('belongsTo', args); | ||
const identifier = (...args) => buildAttributeDecorator('identifier', args); | ||
const field = (...args) => buildAttributeDecorator('field', args); | ||
const session = (...args) => buildAttributeDecorator('session', args); | ||
const belongsTo = (...args) => buildAttributeDecorator('belongsTo', args); | ||
const hasManyBuilder = (type, target, property, descriptor, options = {}) => { | ||
descriptor.initializer = () => observable.array([]); | ||
return addAttribute(type, target, property, descriptor, options); | ||
}; | ||
const hasManyBuilder = (type, target, property, descriptor, options = {}) => | ||
addAttribute(type, target, property, descriptor, options); | ||
const hasMany = (...args) => buildAttributeDecorator('hasMany', args, hasManyBuilder); | ||
@@ -36,0 +49,0 @@ |
{ | ||
"name": "mobx-decorated-models", | ||
"version": "0.0.2", | ||
"version": "0.0.3", | ||
"description": "Decorators to make using Mobx for model type structures easier", | ||
"main": "index.js", | ||
"main": "dist/build.full.js", | ||
"module": "dist/build.module.js", | ||
"jsnext:main": "dist/build.module.js", | ||
"repository": "https://github.com/nathanstitt/mobx-decorated-models", | ||
@@ -13,3 +15,19 @@ "author": "Nathan Stitt", | ||
}, | ||
"scripts": { | ||
"test": "./node_modules/jest-cli/bin/jest.js", | ||
"build": "rollup -c", | ||
"prepublish": "npm build && npm test" | ||
}, | ||
"keywords": [ | ||
"mobx", | ||
"model", | ||
"json", | ||
"serialize", | ||
"deserialize" | ||
], | ||
"devDependencies": { | ||
"babel": "^6.5.2", | ||
"babel-loader": "^6.2.10", | ||
"babel-plugin-add-module-exports": "^0.2.1", | ||
"babel-plugin-external-helpers": "^6.22.0", | ||
"babel-plugin-transform-class-properties": "^6.22.0", | ||
@@ -19,4 +37,7 @@ "babel-plugin-transform-decorators-legacy": "^1.3.4", | ||
"babel-preset-stage-2": "^6.22.0", | ||
"jest": "^18.1.0" | ||
"babelrc-rollup": "^3.0.0", | ||
"jest": "^18.1.0", | ||
"rollup": "^0.41.4", | ||
"rollup-plugin-babel": "^2.7.1" | ||
} | ||
} |
# Decorators for creating model type structures with mobx | ||
mobx-decorated-models is a collection of es7 decorators that help decorate a | ||
class to make it easily observable and serializable. | ||
mobx-decorated-models is a collection of es7 decorators to make a class observable and serializable. | ||
@@ -10,3 +9,3 @@ [![Build Status](https://travis-ci.org/nathanstitt/mobx-decorated-models.svg?branch=master)](https://travis-ci.org/nathanstitt/mobx-decorated-models) | ||
[Mobx](https://mobx.js.org) makes state management super simple, but it doesn't have any | ||
[Mobx](https://mobx.js.org) makes state management super simple, but it doesn't offer an | ||
opinion on how to get data in and out of the observed data structures. | ||
@@ -16,8 +15,12 @@ | ||
Combining the two libraries isn't difficult, but it mean you end up specifing each attribute twice, | ||
once so Mobx will observe it and once to create a schema for Serializr. | ||
Combining the two libraries isn’t difficult, but then you end up specifing each attribute twice; | ||
once so Mobx will observe it, and once to create a schema for Serializr. | ||
This library is a collection of decorators that will make co-ordinate making | ||
This library is a collection of decorators that co-ordinates making | ||
fields both observable and serializable. | ||
While it’s at it, it also handles model lookups so different models can refer | ||
to one another regardless of import order. When one model refers to another, a | ||
reference of the requirement is stored and then later resolved when the class becomes known. | ||
## Example | ||
@@ -53,5 +56,5 @@ | ||
box = new Box(); | ||
box.update({ width: 2, height: 3, depth: 8 }); | ||
box.volume(); // => 48 | ||
const box = Box.deserialize({ id: 1, width: 2, height: 3, depth: 8 }); // returns an instance of Box | ||
console.log(box.volume); // => 48 | ||
console.log(box.serialize()); // => { id: 1, width: 2, height: 3, depth: 8, items: [] } | ||
``` | ||
@@ -81,2 +84,19 @@ | ||
The type of field can be set to `array` or `object` by specifying options. | ||
*example:* | ||
```javascript | ||
class Foo { | ||
@field({ type: 'object' }) options; // will default to an observable map | ||
@field({ type: 'array' }) tags; // defaults to [] | ||
} | ||
const foo = new Foo(); | ||
foo.tags.push('one'); | ||
foo.options.set('one', 1); | ||
foo.serialize(); // => { tags: ['one'], options: { one: 1 } } | ||
``` | ||
#### belongsTo | ||
@@ -109,2 +129,2 @@ | ||
* Use a provided lookup function to control the lookup | ||
* Sessions properties that will be set from JSON but won't be serialized | ||
* Sessions properties that will be set from JSON but won't be serialized. |
@@ -6,3 +6,3 @@ import { Container, Box } from './test-models'; | ||
it('adds static deserialize method and serialize to prototype', () => { | ||
const attrs = { id: 42, name: 'TV1', location: 'mid-ship', boxes: [ | ||
const attrs = { id: 42, name: 'TV1', location: 'mid-ship', tags: [], boxes: [ | ||
{ id: 1, width: 8, depth: 12, height: 8 }, | ||
@@ -12,3 +12,8 @@ ] }; | ||
expect(container.boxes).toHaveLength(1); | ||
expect(container.serialize()).toEqual(attrs); | ||
expect(container.serialize()).toEqual({ | ||
id: 42, location: 'mid-ship', name: 'TV1', tags: [], | ||
boxes: [ | ||
{ container: undefined, depth: 12, height: 8, id: 1, metadata: {}, width: 8}, | ||
], | ||
}); | ||
}); | ||
@@ -35,4 +40,6 @@ | ||
box.update(attrs); | ||
attrs.container.boxes = []; | ||
expect(box.serialize()).toEqual(attrs); | ||
expect(box.serialize()).toEqual({ | ||
container: { boxes: [], id: 1, location: 'Building #1', name: '#12', tags: [] }, | ||
depth: 12, height: 4, id: 2, metadata: {}, width: 3, | ||
}); | ||
}); | ||
@@ -42,20 +49,14 @@ | ||
const box = new Box(); | ||
const container = Container.deserialize({ id: 1, name: '#12', location: 'Building #1' }); | ||
expect(box.constructor).toEqual(Box); | ||
box.update({ id: 2, width: 3, depth: 12, height: 4 }); | ||
box.container = container; | ||
expect(box.container).toEqual(container); | ||
const container = { id: 1, name: '#12', location: 'Building #1' }; | ||
box.update({ id: 32, width: 3, depth: 12, height: 4, container }); | ||
expect(box.serialize()).toEqual({ | ||
id: 2, width: 3, depth: 12, height: 4, | ||
container: { | ||
id: 1, name: '#12', location: 'Building #1', boxes: [], | ||
id: 1, boxes: [], tags: [], | ||
location: 'Building #1', name: '#12', | ||
}, | ||
depth: 12, height: 4, id: 32, metadata: {}, width: 3, | ||
}); | ||
}); | ||
xit('hasMany', () => { | ||
it('hasMany', () => { | ||
const container = new Container({ id: 1, name: 'C23', location: 'z1' }); | ||
@@ -65,8 +66,7 @@ container.boxes.push(new Box({ id: 1, width: 8, depth: 12, height: 8 })); | ||
container.boxes[1].x = 4; | ||
expect(container.serialize()).toEqual({ | ||
id: 1, name: 'C23', location: 'z1', | ||
id: undefined, location: undefined, name: undefined, tags: [], | ||
boxes: [ | ||
{ id: 1, width: 8, depth: 12, height: 8, container: undefined }, | ||
{ id: 2, width: 4, depth: 12, height: 4, container: undefined }, | ||
{ container: undefined, depth: 1, height: 1, id: undefined, metadata: {}, width: 1 }, | ||
{ container: undefined, depth: 1, height: 1, id: undefined, metadata: {}, width: 1 }, | ||
], | ||
@@ -73,0 +73,0 @@ }); |
@@ -42,3 +42,3 @@ import { Box, Container } from './test-models'; | ||
it('can objserve associations', () => { | ||
const container = Container.deserialize({ id: 1, firstName: 'Bob', lastName: 'Smith' }); | ||
const container = Container.deserialize({ id: 1, name: 'Bob', location: 'water' }); | ||
const spy = jest.fn(); | ||
@@ -55,2 +55,23 @@ autorun(() => { | ||
}); | ||
it('can set property to be object', () => { | ||
const box = Box.deserialize({ | ||
width: 3, metadata: { barcode: 'Z12', color: 'black' }, | ||
}); | ||
expect(box.metadata.toJS()).toEqual({ barcode: 'Z12', color: 'black' }); | ||
expect(box.serialize()).toEqual({ | ||
container: undefined, depth: 1, height: 1, id: undefined, width: 3, | ||
metadata: { barcode: 'Z12', color: 'black' }, | ||
}); | ||
}); | ||
it('can set property to be array', () => { | ||
const tags = ['one', 'two', 'three']; | ||
const container = Container.deserialize({ id: 1, tags }); | ||
expect(container.tags.slice()).toEqual(tags); | ||
expect(container.serialize()).toEqual({ | ||
boxes: [], id: 1, location: undefined, name: undefined, tags, | ||
}); | ||
}); | ||
}); |
@@ -18,2 +18,4 @@ import { observable, computed } from 'mobx'; | ||
@field({ type: 'object' }) metadata; | ||
@computed get volume() { | ||
@@ -33,2 +35,4 @@ return this.width * this.height * this.depth; | ||
@field({ type: 'array' }) tags = []; | ||
@computed get description() { | ||
@@ -35,0 +39,0 @@ return `${this.name} ${this.location}`; |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
146045
21
755
126
12
1