Skip to content

Commit

Permalink
Update to ember 1.13 serializer api.
Browse files Browse the repository at this point in the history
  • Loading branch information
benkonrath committed Jul 15, 2015
1 parent a68ee08 commit 4e04404
Show file tree
Hide file tree
Showing 10 changed files with 138 additions and 223 deletions.
140 changes: 53 additions & 87 deletions addon/serializers/drf.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,51 +10,47 @@ import Ember from 'ember';
* @class DRFSerializer
* @extends DS.RESTSerializer
*/
export default DS.RESTSerializer.extend({
/**
* Normalizes a part of the JSON payload returned by the server. This
* version simply calls addRelationshipsToLinks() before invoking
* the RESTSerializer's version.
*
* @method normalize
* @param {subclass of DS.Model} typeClass
* @param {Object} hash
* @param {String} prop
* @return {Object}
*/
normalize: function(typeClass, hash, prop) {
this.addRelationshipsToLinks(typeClass, hash);
return this._super(typeClass, hash, prop);
},
export default DS.JSONSerializer.extend({
// Remove this in our 2.0 release.
isNewSerializerAPI: true,

/**
* Adds relationships to the links hash as expected by the RESTSerializer.
* Returns the resource's relationships formatted as a JSON-API "relationships object".
*
* @method addRelationshipsToLinks
* @private
* @param {subclass of DS.Model} typeClass
* @param {Object} hash
* http://jsonapi.org/format/#document-resource-object-relationships
*
* This version adds a 'links'hash with relationship urls before invoking the
* JSONSerializer's version.
*
* @method extractRelationships
* @param {Object} modelClass
* @param {Object} resourceHash
* @return {Object}
*/
addRelationshipsToLinks: function(typeClass, hash) {
if (!hash.hasOwnProperty('links')) {
hash['links'] = {};
extractRelationships: function (modelClass, resourceHash) {
if (!resourceHash.hasOwnProperty('links')) {
resourceHash['links'] = {};
}

typeClass.eachRelationship(function(key, relationship) {
modelClass.eachRelationship(function(key, relationshipMeta) {
let payloadRelKey = this.keyForRelationship(key);
if (!hash.hasOwnProperty(payloadRelKey)) {

if (!resourceHash.hasOwnProperty(payloadRelKey)) {
return;
}
if (relationship.kind === 'hasMany' || relationship.kind === 'belongsTo') {

if (relationshipMeta.kind === 'hasMany' || relationshipMeta.kind === 'belongsTo') {
// Matches strings starting with: https://, http://, //, /
var payloadRel = hash[payloadRelKey];
var payloadRel = resourceHash[payloadRelKey];
if (!Ember.isNone(payloadRel) && !Ember.isNone(payloadRel.match) &&
typeof(payloadRel.match) === 'function' && payloadRel.match(/^((https?:)?\/\/|\/)\w/)) {
hash['links'][key] = hash[payloadRelKey];
delete hash[payloadRelKey];
resourceHash['links'][key] = resourceHash[payloadRelKey];
delete resourceHash[payloadRelKey];
}
}
}, this);

return this._super(modelClass, resourceHash);
},

/**
Expand All @@ -77,70 +73,40 @@ export default DS.RESTSerializer.extend({
},

/**
* `extractMeta` is used to deserialize any meta information in the
* adapter payload. By default Ember Data expects meta information to
* be located on the `meta` property of the payload object.
* Normalizes server responses for array or list data using the JSONSerializer's version
* of this function.
*
* @method extractMeta
* @param {DS.Store} store
* @param {subclass of DS.Model} type
* @param {Object} payload
*/
extractMeta: function(store, type, payload) {
if (payload && payload.results) {
// Sets the metadata for the type.
store.setMetadataFor(type, {
count: payload.count,
next: this.extractPageNumber(payload.next),
previous: this.extractPageNumber(payload.previous)
});

// Keep ember data from trying to parse the metadata as a records
delete payload.count;
delete payload.next;
delete payload.previous;
}
},

/**
* `extractSingle` is used to deserialize a single record returned
* from the adapter.
* If the payload has a results property, all properties that aren't in the results
* are added to the 'meta' hash so that Ember Data can use these properties for metadata.
* The next and previous pagination URLs are parsed to make it easier to paginate data
* in applications.
*
* @method extractSingle
* @method normalizeArrayResponse
* @param {DS.Store} store
* @param {subclass of DS.Model} type
* @param {DS.Model} primaryModelClass
* @param {Object} payload
* @param {String or Number} id
* @return {Object} json The deserialized payload
* @param {String|Number} id
* @param {String} requestType
* @return {Object} JSON-API Document
*/
extractSingle: function(store, type, payload, id) {
// Convert payload to json format expected by the RESTSerializer.
var convertedPayload = {};
convertedPayload[type.modelName] = payload;
return this._super(store, type, convertedPayload, id);
},
normalizeArrayResponse: function(store, primaryModelClass, payload, id, requestType) {
if (!Ember.isNone(payload) && payload.hasOwnProperty('results')) {
// Move DRF metadata to the meta hash.
let modifiedPayload = payload.results;
delete payload.results;
modifiedPayload['meta'] = payload;

/**
* `extractArray` is used to deserialize an array of records
* returned from the adapter.
*
* @method extractArray
* @param {DS.Store} store
* @param {subclass of DS.Model} type
* @param {Object} payload
* @return {Array} array An array of deserialized objects
*/
extractArray: function(store, type, payload) {
// Convert payload to json format expected by the RESTSerializer.
// This function is being overridden instead of normalizePayload()
// because the `results` hash is only in lists of records.
var convertedPayload = {};
if (payload.results) {
convertedPayload[type.modelName] = payload.results;
} else {
convertedPayload[type.modelName] = payload;
// The next and previous pagination URLs are parsed to make it easier to paginate data in applications.
if (!Ember.isNone(modifiedPayload.meta['next'])) {
modifiedPayload.meta['next'] = this.extractPageNumber(payload.next);
}
if (!Ember.isNone(modifiedPayload.meta['previous'])) {
modifiedPayload.meta['previous'] = this.extractPageNumber(payload.previous);
}
return this._super(store, primaryModelClass, modifiedPayload, id, requestType);
}
return this._super(store, type, convertedPayload);

return this._super(store, primaryModelClass, payload, id, requestType);
},

/**
Expand Down
2 changes: 1 addition & 1 deletion docs/hyperlinked-related-fields.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ related comments instead of one URL per related record:
}
```

*Note:* It is also possible to use the [Coalesce Find Requests](coalesce-find-requests.md)
**Note:** It is also possible to use the [Coalesce Find Requests](coalesce-find-requests.md)
feature to retrieve related records in a single request, however, this is the preferred
solution.

Expand Down
3 changes: 2 additions & 1 deletion docs/non-field-errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,5 @@ In case of several errors, the InvalidError.errors attribute will include
{ detail: 'error 2', meta { key: 'non_field_errors' } } //or whatever key name you configured
```

**note** we store the key for non-field errors in a meta object as this is non standard in the error object defined by the jsonapi spec
**Note** We store the key for non-field errors in a meta object as this is non standard in the error
object defined by the JSON API spec.
2 changes: 1 addition & 1 deletion docs/pagination.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Or you can access the metadata just for this query:
var meta = result.get("content.meta");
```

**NB** Running a find request against a paginated list view without query params will
**Note** Running a find request against a paginated list view without query params will
retrieve the first page with metadata set in only `store.metadataFor`. This is how
metadata works in Ember Data.

Expand Down
6 changes: 3 additions & 3 deletions tests/acceptance/crud-failure-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ module('Acceptance: CRUD Failure', {
beforeEach: function() {
application = startApp();

store = application.__container__.lookup('store:main');
store = application.__container__.lookup('service:store');

server = new Pretender(function() {

Expand Down Expand Up @@ -174,10 +174,10 @@ test('Update field errors', function(assert) {

return store.findRecord('post', 3).then(function(post) {
assert.ok(post);
assert.equal(post.get('isDirty'), false);
assert.equal(post.get('hasDirtyAttributes'), false);
post.set('postTitle', 'Lorem ipsum dolor sit amet, consectetur adipiscing el');
post.set('body', '');
assert.equal(post.get('isDirty'), true);
assert.equal(post.get('hasDirtyAttributes'), true);

post.save().then({}, function(response) {
const postTitleErrors = post.get('errors.postTitle'),
Expand Down
8 changes: 4 additions & 4 deletions tests/acceptance/crud-success-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ module('Acceptance: CRUD Success', {
beforeEach: function() {
application = startApp();

store = application.__container__.lookup('store:main');
store = application.__container__.lookup('service:store');

server = new Pretender(function() {

Expand Down Expand Up @@ -152,18 +152,18 @@ test('Update record', function(assert) {
return store.findRecord('post', 1).then(function(post) {

assert.ok(post);
assert.equal(post.get('isDirty'), false);
assert.equal(post.get('hasDirtyAttributes'), false);

return Ember.run(function() {

post.set('postTitle', 'new post title');
post.set('body', 'new post body');
assert.equal(post.get('isDirty'), true);
assert.equal(post.get('hasDirtyAttributes'), true);

return post.save().then(function(post) {

assert.ok(post);
assert.equal(post.get('isDirty'), false);
assert.equal(post.get('hasDirtyAttributes'), false);
assert.equal(post.get('postTitle'), 'new post title');
assert.equal(post.get('body'), 'new post body');
});
Expand Down
56 changes: 17 additions & 39 deletions tests/acceptance/pagination-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ module('Acceptance: Pagination', {
beforeEach: function() {
application = startApp();

store = application.__container__.lookup('store:main');
store = application.__container__.lookup('service:store');

// The implementation of the paginated Pretender server is dynamic
// so it can be used with all of the pagination tests. Otherwise,
Expand Down Expand Up @@ -111,9 +111,9 @@ module('Acceptance: Pagination', {
});

test('Retrieve list of paginated records', function(assert) {
assert.expect(8);
assert.expect(7);

return store.findAll('post').then(function(response) {
return store.query('post', {page: 1}).then(function(response) {
assert.ok(response);

assert.equal(response.get('length'), 4);
Expand All @@ -123,75 +123,53 @@ test('Retrieve list of paginated records', function(assert) {
assert.equal(post.get('postTitle'), 'post title 2');
assert.equal(post.get('body'), 'post body 2');

// Test the type metadata.
var metadata = store.metadataFor('post');
var metadata = response.get('meta');
assert.equal(metadata.count, 6);
assert.equal(metadata.next, 2);
assert.equal(metadata.previous, null);

// No metadata on results when using find without query params.
assert.ok(!response.get('meta'));
});
});


test("Type metadata doesn't have previous", function(assert) {
assert.expect(5);
assert.expect(4);

return store.findAll('post').then(function(response) {
return store.query('post', {page: 1}).then(function(response) {
assert.ok(response);

// Test the type metadata.
var metadata = store.metadataFor('post');
var metadata = response.get('meta');
assert.equal(metadata.count, 6);
assert.equal(metadata.next, 2);
assert.equal(metadata.previous, null);

// No metadata on results when using findAll.
assert.ok(!response.get('meta'));
});
});


test("Type metadata doesn't have next", function(assert) {
assert.expect(8);
assert.expect(5);

return store.query('post', {page: 2}).then(function(response) {
assert.ok(response);
assert.equal(response.get('length'), 2);

// Test the type metadata.
var typeMetadata = store.metadataFor('post');
assert.equal(typeMetadata.count, 6);
assert.equal(typeMetadata.next, null);
assert.equal(typeMetadata.previous, 1);

// Test the results metadata.
var resultsMetadata = response.get('meta');
assert.equal(resultsMetadata.count, 6);
assert.equal(resultsMetadata.next, null);
assert.equal(resultsMetadata.previous, 1);
var metadata = response.get('meta');
assert.equal(metadata.count, 6);
assert.equal(metadata.next, null);
assert.equal(metadata.previous, 1);
});
});


test("Test page_size query param", function(assert) {
assert.expect(8);
assert.expect(5);

return store.query('post', {page: 2, page_size: 2}).then(function(response) {
assert.ok(response);
assert.equal(response.get('length'), 2);

// Test the type metadata.
var typeMetadata = store.metadataFor('post');
assert.equal(typeMetadata.count, 6);
assert.equal(typeMetadata.previous, 1);
assert.equal(typeMetadata.next, 3);

// Test the results metadata.
var resultsMetadata = response.get('meta');
assert.equal(resultsMetadata.count, 6);
assert.equal(resultsMetadata.previous, 1);
assert.equal(resultsMetadata.next, 3);
var metadata = response.get('meta');
assert.equal(metadata.count, 6);
assert.equal(metadata.previous, 1);
assert.equal(metadata.next, 3);
});
});
4 changes: 1 addition & 3 deletions tests/acceptance/relationship-links-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,11 @@ var comments = [
}
];


module('Acceptance: Relationship Links', {
beforeEach: function() {
application = startApp();

store = application.__container__.lookup('store:main');
store = application.__container__.lookup('service:store');

server = new Pretender(function() {
this.get('/test-api/posts/:id/', function(request) {
Expand Down Expand Up @@ -96,7 +95,6 @@ test('belongsTo', function(assert) {
});
});


test('hasMany', function(assert) {
assert.expect(9);

Expand Down
2 changes: 1 addition & 1 deletion tests/acceptance/relationships-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ module('Acceptance: Relationships', {
beforeEach: function() {
application = startApp();

store = application.__container__.lookup('store:main');
store = application.__container__.lookup('service:store');

server = new Pretender(function() {

Expand Down
Loading

0 comments on commit 4e04404

Please sign in to comment.