Skip to content

Commit

Permalink
Merge branch 'CodeYellowBV:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
kazachoc authored Jul 1, 2021
2 parents 99d5c10 + 807d877 commit 29aadad
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 27 deletions.
20 changes: 11 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,14 @@ A model or collection can only do requests to an API if you add an `api` instanc

A model is a data container with a set of helper functions. Models should extend `Model` from mobx-spine, and the very least define some properties.

### Constructor: data

The `Model` contructor takes 2 arguments:
- `data`: An object with default values for a model.
- `options`: An object with options.

### Constructor: data

Let's for example define a class `Animal` with 2 properties `id` and `name`.

```js
import { observable } from 'mobx';
import { Model } from 'mobx-spine';
Expand All @@ -48,7 +50,7 @@ class Animal extends Model {
}
```

We've defined a class `Animal` with 2 properties `id` and `name`. If we instantiate a new animal without arguments it will create an empty animal using defaults defined on the model:
If we instantiate a new animal without arguments it will create an empty animal using defaults defined on the model:

```js
// Create an empty instance of an Animal.
Expand Down Expand Up @@ -90,8 +92,8 @@ console.log(cat.undefinedProperty); // undefined

### Constructor: options

|key|default| | |
|-|-|-|-|-|-|
|key|default| | |
|---|---|---|---|
|relations|undefined|Relations to be instantiated when instantiating this model as well. Should be an array of strings.| `['location', 'owner.parents']`


Expand Down Expand Up @@ -213,8 +215,8 @@ animal.save().then(() => {

The `save` function accepts a few paramaters as an `options` object:

|key|default| | |
|-|-|-|-|-|-|
|key|default| | |
|---|---|---|---|
|onlyChanges|false|When true, only changes made with `setInput` are saved.| `animal.save({ onlyChanges: true })`
|url|undefined|When set, use specified url for the request.| `animal.save({ url: '/api/animal/special/url' })`
|data|undefined|When set, append `data` to result. Existing keys from `toBackend` will be overwritten by data, while new keys will be added. | `animal.save({ data: { id: 1, some_other_field: 'will be added' } })`
Expand Down Expand Up @@ -394,8 +396,8 @@ A Store (Collection in Backbone) is holds multiple instances of models and have

### Constructor: options

|key|default| | |
|-|-|-|-|-|-|
|key|default| | |
|---|---|---|---|
|relations|undefined|Relations to be instantiated when new models are instantiated using `add()`. Should be an array of strings.| `animalStore = new AnimalStore({ relations: ['location', 'owner.parents'] })`
|limit|25|Page size per fetch, also able to set using `setLimit()`. By default a limit is always set, but there are occations where you want to fetch everything. In this case, set limit to false. | `animalStore = new AnimalStore({ limit: false })`
|comparator|undefined| The models in the store will be sorted by comparator. When it's a string, the models will be sorted by that property name. If it's a function, the models will be sorted using the [default array sort](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort). | `animalStore = new AnimalStore({ comparator: 'name' })`
Expand Down
11 changes: 6 additions & 5 deletions dist/mobx-spine.cjs.js
Original file line number Diff line number Diff line change
Expand Up @@ -1381,7 +1381,7 @@ var Model = (_class$1 = (_temp$1 = _class2$1 = function () {
} else if (_this9.__activeCurrentRelations.includes(attr)) {
// In Binder, a relation property is an `int` or `[int]`, referring to its ID.
// However, it can also be an object if there are nested relations (non flattened).
if (lodash.isPlainObject(value) || lodash.isPlainObject(lodash.get(value, '[0]'))) {
if (lodash.isPlainObject(value) || Array.isArray(value) && value.every(lodash.isPlainObject)) {
_this9[attr].parse(value);
} else if (value === null) {
// The relation is cleared.
Expand Down Expand Up @@ -2125,11 +2125,11 @@ function checkMomentInstance(attr, value) {
}

function checkLuxonDateTime(attr, value) {
invariant(moment.isMoment(value), 'Attribute `' + attr + '` is not a luxon DateTime.');
invariant(luxon.DateTime.isDateTime(value), 'Attribute `' + attr + '` is not a luxon instance.');
}

var LUXON_DATE_FORMAT = 'yyyy-LL-dd';
var LUXON_DATETIME_FORMAT = 'yyy-LL-ddTHH:mm:ssZZZ';
var LUXON_DATETIME_FORMAT = "yyyy'-'LL'-'dd'T'HH':'mm':'ssZZ";

var CASTS = {
momentDate: {
Expand Down Expand Up @@ -2171,7 +2171,7 @@ var CASTS = {
if (value === null || value === undefined) {
return null;
}
return luxon.DateTime.fromFormat(value, LUXON_DATE_FORMAT);
return luxon.DateTime.fromISO(value);
},
toJS: function toJS(attr, value) {
if (value === null || value === undefined) {
Expand All @@ -2188,7 +2188,8 @@ var CASTS = {
if (value === null) {
return null;
}
return luxon.DateTime.fromFormat(value, LUXON_DATETIME_FORMAT);

return luxon.DateTime.fromISO(value);
},
toJS: function toJS(attr, value) {
if (value === null) {
Expand Down
11 changes: 6 additions & 5 deletions dist/mobx-spine.es.js
Original file line number Diff line number Diff line change
Expand Up @@ -1375,7 +1375,7 @@ var Model = (_class$1 = (_temp$1 = _class2$1 = function () {
} else if (_this9.__activeCurrentRelations.includes(attr)) {
// In Binder, a relation property is an `int` or `[int]`, referring to its ID.
// However, it can also be an object if there are nested relations (non flattened).
if (isPlainObject(value) || isPlainObject(get(value, '[0]'))) {
if (isPlainObject(value) || Array.isArray(value) && value.every(isPlainObject)) {
_this9[attr].parse(value);
} else if (value === null) {
// The relation is cleared.
Expand Down Expand Up @@ -2119,11 +2119,11 @@ function checkMomentInstance(attr, value) {
}

function checkLuxonDateTime(attr, value) {
invariant(moment.isMoment(value), 'Attribute `' + attr + '` is not a luxon DateTime.');
invariant(DateTime.isDateTime(value), 'Attribute `' + attr + '` is not a luxon instance.');
}

var LUXON_DATE_FORMAT = 'yyyy-LL-dd';
var LUXON_DATETIME_FORMAT = 'yyy-LL-ddTHH:mm:ssZZZ';
var LUXON_DATETIME_FORMAT = "yyyy'-'LL'-'dd'T'HH':'mm':'ssZZ";

var CASTS = {
momentDate: {
Expand Down Expand Up @@ -2165,7 +2165,7 @@ var CASTS = {
if (value === null || value === undefined) {
return null;
}
return DateTime.fromFormat(value, LUXON_DATE_FORMAT);
return DateTime.fromISO(value);
},
toJS: function toJS$$1(attr, value) {
if (value === null || value === undefined) {
Expand All @@ -2182,7 +2182,8 @@ var CASTS = {
if (value === null) {
return null;
}
return DateTime.fromFormat(value, LUXON_DATETIME_FORMAT);

return DateTime.fromISO(value);
},
toJS: function toJS$$1(attr, value) {
if (value === null) {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "mobx-spine",
"version": "0.28.0",
"version": "0.28.2",
"license": "ISC",
"author": "Kees Kluskens <[email protected]>",
"description": "MobX with support for models, relations and an API.",
Expand Down
11 changes: 6 additions & 5 deletions src/Casts.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ function checkMomentInstance(attr, value) {

function checkLuxonDateTime(attr, value) {
invariant(
moment.isMoment(value),
`Attribute \`${attr}\` is not a luxon DateTime.`
DateTime.isDateTime(value),
`Attribute \`${attr}\` is not a luxon instance.`
);
}

const LUXON_DATE_FORMAT = 'yyyy-LL-dd';
const LUXON_DATETIME_FORMAT = 'yyy-LL-ddTHH:mm:ssZZZ';
const LUXON_DATETIME_FORMAT = "yyyy'-'LL'-'dd'T'HH':'mm':'ssZZ";

const CASTS = {
momentDate: {
Expand Down Expand Up @@ -70,7 +70,7 @@ const CASTS = {
if (value === null || value === undefined) {
return null;
}
return DateTime.fromFormat(value, LUXON_DATE_FORMAT);
return DateTime.fromISO(value);
},
toJS(attr, value) {
if (value === null || value === undefined) {
Expand All @@ -86,7 +86,8 @@ const CASTS = {
if (value === null) {
return null;
}
return DateTime.fromFormat(value, LUXON_DATETIME_FORMAT);

return DateTime.fromISO(value);
},
toJS(attr, value) {
if (value === null) {
Expand Down
2 changes: 1 addition & 1 deletion src/Model.js
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,7 @@ export default class Model {
} else if (this.__activeCurrentRelations.includes(attr)) {
// In Binder, a relation property is an `int` or `[int]`, referring to its ID.
// However, it can also be an object if there are nested relations (non flattened).
if (isPlainObject(value) || isPlainObject(get(value, '[0]'))) {
if (isPlainObject(value) || (Array.isArray(value) && value.every(isPlainObject))) {
this[attr].parse(value);
} else if (value === null) {
// The relation is cleared.
Expand Down
37 changes: 37 additions & 0 deletions src/__tests__/Casts/datetime.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Model, Casts } from '../../';
import { observable } from 'mobx';
import { Settings } from 'luxon';
import moment from 'moment';
import momentLocale from 'moment/min/moment-with-locales';

Expand Down Expand Up @@ -79,3 +80,39 @@ test('moment instance with locale should be recognized', () => {
animal.bornAt = momentLocale('2017-03-22T22:08:23+00:00');
expect(animal.toJS().bornAt).toEqual(expect.stringContaining('2017-03-22'));
});

describe('luxon compatibility', () => {
Settings.defaultZoneName = 'utc';

class LuxonAnimal extends Animal {
@observable createdAt = '';

casts() {
return {
bornAt: Casts.luxonDatetime,
};
}
};

test('toJS() should throw error when luxon instance is gone', () => {
const animal = new LuxonAnimal({ bornAt: '2017-03-22T22:08:23+00:00' });

animal.bornAt = 'asdf';

expect(() => {
return animal.toJS();
}).toThrow('Attribute `bornAt` is not a luxon instance.');
});

test('should be serialized in toBackend()', () => {
const animal = new LuxonAnimal({ bornAt: '2017-03-22T22:08:23+00:00' });

expect(animal.toBackend().born_at).toEqual('2017-03-22T22:08:23+00:00');
});

test('should be serialized in toBackend() when given a binder specific format', () => {
const animal = new LuxonAnimal({ bornAt: '2017-03-22T22:08:23.575242+0000' });

expect(animal.toBackend().born_at).toEqual('2017-03-22T22:08:23+00:00');
});
});
12 changes: 11 additions & 1 deletion src/__tests__/Model.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import axios from 'axios';
import { toJS, observable } from 'mobx';
import MockAdapter from 'axios-mock-adapter';
import _ from 'lodash';
import { Model, BinderApi } from '../';
import { Model, BinderApi, Casts } from '../';
import {
Animal,
AnimalStore,
Expand Down Expand Up @@ -990,6 +990,16 @@ test('setInput to parse store relation', () => {
expect(animal.pastOwners.length).toBe(0);
});

test('parse empty list', () => {
const animal = new Animal(
{ pastOwners: [{}, {}] },
{ relations: ['pastOwners'] },
);
expect(animal.pastOwners.length).toEqual(2);
animal.parse({ pastOwners: [] });
expect(animal.pastOwners.length).toEqual(0);
});

describe('requests', () => {
let mock;
beforeEach(() => {
Expand Down

0 comments on commit 29aadad

Please sign in to comment.