Comparing version 1.0.1 to 1.0.2
@@ -215,16 +215,2 @@ import { Collection, apiClient } from '../src' | ||
}) | ||
describe('given a successful non-array response', () => { | ||
beforeEach(() => { | ||
resolve({ name: 'bob' })() | ||
}) | ||
it('throws an error', async () => { | ||
collection.fetch().then((result) => { | ||
throw new Error('expected promise to fail but it succeeded') | ||
}, (err) => { | ||
expect(err.message).toBe('expected an array response') | ||
}) | ||
}) | ||
}) | ||
}) | ||
@@ -231,0 +217,0 @@ |
@@ -11,4 +11,19 @@ import { Collection, Model, apiClient } from '../src' | ||
} | ||
model () { | ||
return MyModel | ||
} | ||
} | ||
class MyModel extends Model { | ||
url () { | ||
const id = this.has('id') && this.get('id') | ||
if (id) { | ||
return `/resources/${id}` | ||
} else { | ||
return '/resources' | ||
} | ||
} | ||
} | ||
describe('Model', () => { | ||
@@ -85,8 +100,86 @@ let collection | ||
describe('and it does not have a collection', () => { | ||
it('throws an error', () => { | ||
const newModel = new Model() | ||
newModel.save(item).catch((s) => { | ||
expect(s).toBeTruthy() | ||
beforeEach(() => { | ||
model.collection = null | ||
}) | ||
describe('if its optimistic (default)', () => { | ||
it('it sets model straight away', () => { | ||
model.save({ name }) | ||
expect(model.get('name')).toBe('dylan') | ||
expect(model.get('album')).toBe(item.album) | ||
expect(model.request.label).toBe('creating') | ||
}) | ||
describe('when it fails', () => { | ||
beforeEach(reject) | ||
it('sets the error', () => { | ||
return model.save({ name }).catch(() => { | ||
expect(model.error.label).toBe('creating') | ||
expect(model.error.body).toBe(error) | ||
}) | ||
}) | ||
it('nullifies the request', () => { | ||
return model.save({ name }).catch(() => { | ||
expect(model.request).toBe(null) | ||
}) | ||
}) | ||
}) | ||
describe('when it succeeds', () => { | ||
beforeEach(() => { | ||
resolve({ id: 1, name: 'coltrane' })() | ||
}) | ||
it('updates the data from the server', () => { | ||
return model.save({ name }).then(() => { | ||
expect(model.get('name')).toBe('coltrane') | ||
}) | ||
}) | ||
it('nullifies the request', () => { | ||
return model.save({ name }).then(() => { | ||
expect(model.request).toBe(null) | ||
}) | ||
}) | ||
}) | ||
}) | ||
describe('if its pessimistic', () => { | ||
describe('when it fails', () => { | ||
beforeEach(reject) | ||
it('sets the error', () => { | ||
return model.save({ name }, { optimistic: false }).catch(() => { | ||
expect(model.error.label).toBe('creating') | ||
expect(model.error.body).toBe(error) | ||
}) | ||
}) | ||
it('nullifies the request', () => { | ||
return model.save({ name }).catch(() => { | ||
expect(model.request).toBe(null) | ||
}) | ||
}) | ||
}) | ||
describe('when it succeeds', () => { | ||
beforeEach(() => { | ||
resolve({ id: 2, name: 'dylan' })() | ||
}) | ||
it('adds data from the server', () => { | ||
return model.save({ name }, { optimistic: false }).then(() => { | ||
expect(model.get('name')).toBe('dylan') | ||
}) | ||
}) | ||
it('nullifies the request', () => { | ||
return model.save({ name }).then(() => { | ||
expect(model.request).toBe(null) | ||
}) | ||
}) | ||
}) | ||
}) | ||
}) | ||
@@ -158,3 +251,3 @@ }) | ||
describe('if its pessimistic (default)', () => { | ||
describe('if its pessimistic', () => { | ||
describe('when it fails', () => { | ||
@@ -161,0 +254,0 @@ beforeEach(reject) |
@@ -141,3 +141,3 @@ 'use strict'; | ||
value: function _ids() { | ||
return this.models.map(function (item) { | ||
return (0, _lodash.map)(this.models, function (item) { | ||
return item.id; | ||
@@ -144,0 +144,0 @@ }).filter(Boolean); |
216
lib/Model.js
@@ -230,2 +230,4 @@ 'use strict'; | ||
* It supports optimistic and patch updates. | ||
* | ||
* TODO: Add progress | ||
*/ | ||
@@ -245,3 +247,3 @@ | ||
var originalAttributes, newAttributes, data, label, _apiClient$put, promise, abort, response; | ||
var newAttributes, data, label, originalAttributes, _apiClient$put, promise, abort, response; | ||
@@ -252,8 +254,4 @@ return regeneratorRuntime.wrap(function _callee2$(_context2) { | ||
case 0: | ||
originalAttributes = this.attributes.toJS(); | ||
newAttributes = void 0; | ||
data = void 0; | ||
if (this.has('id')) { | ||
_context2.next = 8; | ||
_context2.next = 7; | ||
break; | ||
@@ -265,3 +263,3 @@ } | ||
if (!this.collection) { | ||
_context2.next = 7; | ||
_context2.next = 6; | ||
break; | ||
@@ -272,7 +270,10 @@ } | ||
case 6: | ||
return _context2.abrupt('return', this._create(attributes, { optimistic: optimistic })); | ||
case 7: | ||
throw new Error('This model does not have a collection defined'); | ||
case 8: | ||
newAttributes = void 0; | ||
data = void 0; | ||
label = 'updating'; | ||
originalAttributes = this.attributes.toJS(); | ||
@@ -300,14 +301,14 @@ | ||
response = void 0; | ||
_context2.prev = 14; | ||
_context2.next = 17; | ||
_context2.prev = 16; | ||
_context2.next = 19; | ||
return promise; | ||
case 17: | ||
case 19: | ||
response = _context2.sent; | ||
_context2.next = 24; | ||
_context2.next = 26; | ||
break; | ||
case 20: | ||
_context2.prev = 20; | ||
_context2.t0 = _context2['catch'](14); | ||
case 22: | ||
_context2.prev = 22; | ||
_context2.t0 = _context2['catch'](16); | ||
@@ -322,3 +323,3 @@ (0, _mobx.runInAction)('save-fail', function () { | ||
case 24: | ||
case 26: | ||
@@ -332,3 +333,3 @@ (0, _mobx.runInAction)('save-done', function () { | ||
case 26: | ||
case 28: | ||
case 'end': | ||
@@ -338,3 +339,3 @@ return _context2.stop(); | ||
} | ||
}, _callee2, this, [[14, 20]]); | ||
}, _callee2, this, [[16, 22]]); | ||
})); | ||
@@ -350,18 +351,17 @@ | ||
/** | ||
* Destroys the resurce on the client and | ||
* requests the backend to delete it there | ||
* too | ||
* Internal method that takes care of creating a model that does | ||
* not belong to a collection | ||
*/ | ||
}, { | ||
key: 'destroy', | ||
key: '_create', | ||
value: function () { | ||
var _ref4 = _asyncToGenerator(regeneratorRuntime.mark(function _callee3() { | ||
var _ref4 = _asyncToGenerator(regeneratorRuntime.mark(function _callee3(attributes) { | ||
var _this3 = this; | ||
var _ref5 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, | ||
var _ref5 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, | ||
_ref5$optimistic = _ref5.optimistic, | ||
optimistic = _ref5$optimistic === undefined ? true : _ref5$optimistic; | ||
var label, _apiClient$del, promise, abort; | ||
var label, onProgress, _apiClient$post, abort, promise, data; | ||
@@ -372,4 +372,88 @@ return regeneratorRuntime.wrap(function _callee3$(_context3) { | ||
case 0: | ||
label = 'creating'; | ||
onProgress = (0, _lodash.debounce)(function onProgress(progress) { | ||
if (optimistic && this.request) { | ||
this.request.progress = progress; | ||
} | ||
}, 300); | ||
_apiClient$post = (0, _apiClient2.default)().post(this.url(), attributes, { onProgress: onProgress }), abort = _apiClient$post.abort, promise = _apiClient$post.promise; | ||
if (optimistic) { | ||
this.request = { | ||
label: label, | ||
abort: (0, _mobx.asReference)(abort), | ||
progress: 0 | ||
}; | ||
} | ||
data = void 0; | ||
_context3.prev = 5; | ||
_context3.next = 8; | ||
return promise; | ||
case 8: | ||
data = _context3.sent; | ||
_context3.next = 15; | ||
break; | ||
case 11: | ||
_context3.prev = 11; | ||
_context3.t0 = _context3['catch'](5); | ||
(0, _mobx.runInAction)('create-error', function () { | ||
_this3.error = { label: label, body: _context3.t0 }; | ||
_this3.request = null; | ||
}); | ||
throw _context3.t0; | ||
case 15: | ||
(0, _mobx.runInAction)('create-done', function () { | ||
_this3.set(data); | ||
_this3.request = null; | ||
}); | ||
return _context3.abrupt('return', data); | ||
case 17: | ||
case 'end': | ||
return _context3.stop(); | ||
} | ||
} | ||
}, _callee3, this, [[5, 11]]); | ||
})); | ||
function _create(_x5) { | ||
return _ref4.apply(this, arguments); | ||
} | ||
return _create; | ||
}() | ||
/** | ||
* Destroys the resurce on the client and | ||
* requests the backend to delete it there | ||
* too | ||
*/ | ||
}, { | ||
key: 'destroy', | ||
value: function () { | ||
var _ref6 = _asyncToGenerator(regeneratorRuntime.mark(function _callee4() { | ||
var _this4 = this; | ||
var _ref7 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, | ||
_ref7$optimistic = _ref7.optimistic, | ||
optimistic = _ref7$optimistic === undefined ? true : _ref7$optimistic; | ||
var label, _apiClient$del, promise, abort; | ||
return regeneratorRuntime.wrap(function _callee4$(_context4) { | ||
while (1) { | ||
switch (_context4.prev = _context4.next) { | ||
case 0: | ||
if (!(!this.has('id') && this.collection)) { | ||
_context3.next = 3; | ||
_context4.next = 3; | ||
break; | ||
@@ -379,3 +463,3 @@ } | ||
this.collection.remove([this.optimisticId], { optimistic: optimistic }); | ||
return _context3.abrupt('return', Promise.resolve()); | ||
return _context4.abrupt('return', Promise.resolve()); | ||
@@ -397,23 +481,23 @@ case 3: | ||
_context3.prev = 7; | ||
_context3.next = 10; | ||
_context4.prev = 7; | ||
_context4.next = 10; | ||
return promise; | ||
case 10: | ||
_context3.next = 16; | ||
_context4.next = 16; | ||
break; | ||
case 12: | ||
_context3.prev = 12; | ||
_context3.t0 = _context3['catch'](7); | ||
_context4.prev = 12; | ||
_context4.t0 = _context4['catch'](7); | ||
(0, _mobx.runInAction)('destroy-fail', function () { | ||
if (optimistic && _this3.collection) { | ||
_this3.collection.add([_this3.attributes.toJS()]); | ||
if (optimistic && _this4.collection) { | ||
_this4.collection.add([_this4.attributes.toJS()]); | ||
} | ||
_this3.error = { label: label, body: _context3.t0 }; | ||
_this3.request = null; | ||
_this4.error = { label: label, body: _context4.t0 }; | ||
_this4.request = null; | ||
}); | ||
throw _context3.t0; | ||
throw _context4.t0; | ||
@@ -423,20 +507,20 @@ case 16: | ||
(0, _mobx.runInAction)('destroy-done', function () { | ||
if (!optimistic && _this3.collection) { | ||
_this3.collection.remove([_this3.id]); | ||
if (!optimistic && _this4.collection) { | ||
_this4.collection.remove([_this4.id]); | ||
} | ||
_this3.request = null; | ||
_this4.request = null; | ||
}); | ||
return _context3.abrupt('return', null); | ||
return _context4.abrupt('return', null); | ||
case 18: | ||
case 'end': | ||
return _context3.stop(); | ||
return _context4.stop(); | ||
} | ||
} | ||
}, _callee3, this, [[7, 12]]); | ||
}, _callee4, this, [[7, 12]]); | ||
})); | ||
function destroy() { | ||
return _ref4.apply(this, arguments); | ||
return _ref6.apply(this, arguments); | ||
} | ||
@@ -456,14 +540,14 @@ | ||
value: function () { | ||
var _ref6 = _asyncToGenerator(regeneratorRuntime.mark(function _callee4(method, body) { | ||
var _this4 = this; | ||
var _ref8 = _asyncToGenerator(regeneratorRuntime.mark(function _callee5(method, body) { | ||
var _this5 = this; | ||
var label, _apiClient$post, promise, abort, response; | ||
var label, _apiClient$post2, promise, abort, response; | ||
return regeneratorRuntime.wrap(function _callee4$(_context4) { | ||
return regeneratorRuntime.wrap(function _callee5$(_context5) { | ||
while (1) { | ||
switch (_context4.prev = _context4.next) { | ||
switch (_context5.prev = _context5.next) { | ||
case 0: | ||
label = 'updating'; // TODO: Maybe differentiate? | ||
_apiClient$post = (0, _apiClient2.default)().post(this.url() + '/' + method, body || {}), promise = _apiClient$post.promise, abort = _apiClient$post.abort; | ||
_apiClient$post2 = (0, _apiClient2.default)().post(this.url() + '/' + method, body || {}), promise = _apiClient$post2.promise, abort = _apiClient$post2.abort; | ||
@@ -478,21 +562,21 @@ | ||
response = void 0; | ||
_context4.prev = 4; | ||
_context4.next = 7; | ||
_context5.prev = 4; | ||
_context5.next = 7; | ||
return promise; | ||
case 7: | ||
response = _context4.sent; | ||
_context4.next = 14; | ||
response = _context5.sent; | ||
_context5.next = 14; | ||
break; | ||
case 10: | ||
_context4.prev = 10; | ||
_context4.t0 = _context4['catch'](4); | ||
_context5.prev = 10; | ||
_context5.t0 = _context5['catch'](4); | ||
(0, _mobx.runInAction)('accept-fail', function () { | ||
_this4.request = null; | ||
_this4.error = { label: label, body: _context4.t0 }; | ||
_this5.request = null; | ||
_this5.error = { label: label, body: _context5.t0 }; | ||
}); | ||
throw _context4.t0; | ||
throw _context5.t0; | ||
@@ -503,14 +587,14 @@ case 14: | ||
return _context4.abrupt('return', response); | ||
return _context5.abrupt('return', response); | ||
case 16: | ||
case 'end': | ||
return _context4.stop(); | ||
return _context5.stop(); | ||
} | ||
} | ||
}, _callee4, this, [[4, 10]]); | ||
}, _callee5, this, [[4, 10]]); | ||
})); | ||
function rpc(_x6, _x7) { | ||
return _ref6.apply(this, arguments); | ||
function rpc(_x8, _x9) { | ||
return _ref8.apply(this, arguments); | ||
} | ||
@@ -517,0 +601,0 @@ |
{ | ||
"name": "mobx-rest", | ||
"version": "1.0.1", | ||
"version": "1.0.2", | ||
"description": "REST conventions for mobx.", | ||
@@ -5,0 +5,0 @@ "repository": { |
65135
1609