chore: 🤖 improve adapters and serializers to match API

This commit is contained in:
Randall Morey committed 2020-05-21 09:22:56 -04:00
1 parent b0921724ba
commit ebdb938ca6
6 files changed
+97 -3

No files matched your search

+19
View File
@@ -18,4 +18,23 @@ export default class ApplicationAdapter extends RESTAdapter {
* @type {string}
*/
namespace = get(config, 'api.namespace');
// =methods
/**
* Overrides default ajax method by rewritting PUT requests as PATCH.
* PATCH is the request method used by our API for updates.
*
* @override
* @method ajax
* @private
* @param {String} url
* @param {String} type The request type GET, POST, PUT, DELETE etc.
* @param {Object} options
* @return {Promise} promise
*/
ajax(url, type, options) {
const method = type === 'PUT' ? 'PATCH' : type;
return super.ajax(url, method, options);
}
}
+20 -1
View File
@@ -1,3 +1,22 @@
import Model from '@ember-data/model';
import { computed } from '@ember/object';
export default class BaseModel extends Model {}
export default class BaseModel extends Model {
// =attributes
/**
* @type {boolean}
*/
@computed('hasDirtyAttributes', 'isSaving')
get canSave() {
return this.hasDirtyAttributes && !this.isSaving;
}
/**
* @type {boolean}
*/
@computed('canSave')
get cannotSave() {
return !this.canSave;
}
}
@@ -20,6 +20,8 @@ export default class ApplicationSerializer extends RESTSerializer {
/**
* If an attribute is annotated as readOnly in the model, don't serialize it.
* Otherwise delegate to default attribute serializer.
*
* @override
* @method serializeAttribute
* @param {Snapshot} snapshot
* @param {Object} json
@@ -30,6 +32,23 @@ export default class ApplicationSerializer extends RESTSerializer {
return options.readOnly ? null : super.serializeAttribute(...arguments);
}
/**
* In our API, request payloads are unrooted. But Ember Data roots request
* payloads for this adapter by default. Instead of assigned a root key
* on the outgoing hash, we copy the serialized attributes into it.
*
* @override
* @method serializeIntoHash
* @param {Object} hash
* @param {Model} typeClass
* @param {Snapshot} snapshot
* @param {Object} options
*/
serializeIntoHash(hash, typeClass, snapshot, options) {
const serialized = this.serialize(snapshot, options);
Object.assign(hash, serialized);
}
/**
* In our API, array payloads are always rooted under the same key `items`.
* Ember Data normally expects them to be rooted under their model name,
@@ -1,6 +1,7 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
import config from 'ember-get-config';
import RESTAdapter from '@ember-data/adapter/rest';
module('Unit | Adapter | application', function (hooks) {
setupTest(hooks);
@@ -17,4 +18,14 @@ module('Unit | Adapter | application', function (hooks) {
const adapter = this.owner.lookup('adapter:application');
assert.equal(adapter.urlPrefix(), config.api.namespace);
});
test('it rewrites PUT to PATCH, but leaves others unchanged', function (assert) {
assert.expect(1);
const adapter = this.owner.lookup('adapter:application');
// TODO this is icky, should be changed to a spy or stub
RESTAdapter.prototype.ajax = (url, type) => {
assert.equal(type, 'PATCH');
};
adapter.ajax('/', 'PUT');
});
});
+26
View File
@@ -10,4 +10,30 @@ module('Unit | Model | base', function (hooks) {
let model = store.createRecord('base', {});
assert.ok(model);
});
test('it has canSave and cannotSave attributes', function (assert) {
assert.expect(8);
const store = this.owner.lookup('service:store');
store.push({
data: {
id: '1',
type: 'project',
attributes: {},
},
});
const model = store.peekRecord('project', '1');
assert.equal(model.canSave, false);
assert.equal(model.cannotSave, true);
// Should be able to save if dirty
model.name = 'Project';
assert.equal(model.hasDirtyAttributes, true);
assert.equal(model.canSave, true);
assert.equal(model.cannotSave, false);
// Should not be able to save while currently saving
model.transitionTo('updated.inFlight');
assert.equal(model.isSaving, true);
assert.equal(model.canSave, false);
assert.equal(model.cannotSave, true);
model.transitionTo('loaded');
});
});
@@ -75,7 +75,7 @@ module('Unit | Serializer | application', function (hooks) {
const projectModelClass = store.createRecord('project').constructor;
const payload = {
id: '1',
name: 'Project 1'
name: 'Project 1',
};
const normalized = serializer.normalizeSingleResponse(
store,
@@ -89,7 +89,7 @@ module('Unit | Serializer | application', function (hooks) {
type: 'project',
attributes: { name: 'Project 1' },
relationships: {},
}
},
});
});
});