diff --git a/addon/serializer.js b/addon/serializer.js index ec933d4..9a37fe1 100644 --- a/addon/serializer.js +++ b/addon/serializer.js @@ -2,6 +2,7 @@ import DS from "ember-data"; import Ember from 'ember'; let {JSONAPISerializer} = DS; +let {get} = Ember; // Reserved keys, per the HAL spec let halReservedKeys = ['_embedded', '_links'], @@ -269,5 +270,93 @@ export default JSONAPISerializer.extend({ } return relationships; + }, + + serialize(snapshot, options){ + var json = {}; + + if (options && options.includeId) { + var id = snapshot.id; + + if (id) { + json[get(this, 'primaryKey')] = id; + } + } + + snapshot.eachAttribute((key, attribute) => { + this.serializeAttribute(snapshot, json, key, attribute, options); + }); + + snapshot.eachRelationship((key, relationship) => { + if (relationship.kind === 'belongsTo') { + this.serializeBelongsTo(snapshot, json, relationship, options); + } else if (relationship.kind === 'hasMany') { + this.serializeHasMany(snapshot, json, relationship, options); + } + }); + + return json; + }, + + serializeAttribute(snapshot, json, key, attribute/*, options */) { + var type = attribute.type; + + if (this._canSerialize(key)) { + var value = snapshot.attr(key); + if (type) { + var transform = this.transformFor(type); + value = transform.serialize(value); + } + + var payloadKey = this._getMappedKey(key); + + if (payloadKey === key && this.keyForAttribute) { + payloadKey = this.keyForAttribute(key, 'serialize'); + } + + json[payloadKey] = value; + } + }, + + serializeBelongsTo(snapshot, json, relationship, options) { + var key = relationship.key; + + if (this._canSerialize(key)) { + var belongsTo = snapshot.belongsTo(key); + if (belongsTo !== undefined) { + + + var payloadKey = this._getMappedKey(key); + if (payloadKey === key) { + payloadKey = this.keyForRelationship(key, 'belongsTo', 'serialize'); + } + + if (belongsTo) { + json._embedded = json._embedded || {}; + json._embedded[key] = this.serialize(belongsTo, options); + } + } + } + }, + serializeHasMany(snapshot, json, relationship, options) { + var key = relationship.key; + + if (this._shouldSerializeHasMany(snapshot, key, relationship)) { + var hasMany = snapshot.hasMany(key); + if (hasMany !== undefined) { + + json._embedded = json._embedded || {}; + json._embedded[key] = json._embedded[key] || []; + + var payloadKey = this._getMappedKey(key); + if (payloadKey === key && this.keyForRelationship) { + payloadKey = this.keyForRelationship(key, 'hasMany', 'serialize'); + } + + hasMany.forEach((item) => { + json._embedded[key].push(this.serialize(item, options)); + }); + } + } } }); diff --git a/tests/dummy/app/models/user.js b/tests/dummy/app/models/user.js new file mode 100644 index 0000000..b3ac39b --- /dev/null +++ b/tests/dummy/app/models/user.js @@ -0,0 +1,12 @@ +import DS from 'ember-data'; + +let {attr} = DS; + +export default DS.Model.extend({ + email: attr('string'), + user_type: attr('string'), + profile: attr(), + _updated: attr('string'), + _created: attr('string'), + _etag: attr('string') +}); diff --git a/tests/dummy/app/serializers/application.js b/tests/dummy/app/serializers/application.js index e5ce4cd..429dd85 100644 --- a/tests/dummy/app/serializers/application.js +++ b/tests/dummy/app/serializers/application.js @@ -2,6 +2,11 @@ import HalSerializer from "ember-data-hal-9000/serializer"; import Ember from 'ember'; export default HalSerializer.extend({ + attrs: { + attributes: {serialize: true}, + owner: {serialize: true} + }, + keyForRelationship(key) { return Ember.String.underscore(key); } diff --git a/tests/unit/models/serialize-test.js b/tests/unit/models/serialize-test.js new file mode 100644 index 0000000..068afba --- /dev/null +++ b/tests/unit/models/serialize-test.js @@ -0,0 +1,113 @@ +import { + test, + moduleForModel +} from "ember-qunit"; +import { stubRequest } from 'ember-cli-fake-server'; +import Ember from "ember"; + +let {extend} = Ember.$; +let {RSVP} = Ember; + +moduleForModel('car', 'serialize', { + needs: ['serializer:application', 'adapter:application', 'transform:temperature', + 'model:attribute', 'model:user', 'model:team', 'model:wheel', 'model:owner'] +}); + +test('serializes loaded record relationships (hasMany, belongsTo) with `serialize: true`', function (assert) { + assert.expect(1); + const INPUT = { + id: 1, + make: 'foo', + model: 'bar', + + _links: { + self: {href: '/cars/1'}, + attributes: {href: '/cars/1/attributes'}, + owner: {href: '/cars/1/owner'} + } + }; + + stubRequest('get', `/cars/${INPUT.id}`, (request) => + request.ok(INPUT)); + + stubRequest('get', `/cars/${INPUT.id}/owner`, (request) => + request.ok({ + id: 'owner1', + name: 'owner #1', + _links: { + self: { href: "/owners/owner1" } + } + })); + + stubRequest('get', '/cars/1/attributes', (request) => { + request.ok({ + _links: {self: {href: '/cars/1/attributes'}}, + _embedded: { + attributes: [{ + id: 'some-attribute', + attributes: 2 + }] + } + }); + }); + + stubRequest('patch', `/cars/${INPUT.id}`, (request) => { + assert.deepEqual(JSON.parse(request.requestBody), { + "_embedded": { + "attributes": [{ + "attributes": 2, + "id": "some-attribute" + }], + "owner": { + "id": "owner1", + "name": "owner #1" + } + }, + "id": "1", + "make": "foo", + "model": "bar" + }); + request.ok(INPUT); + }); + + const store = this.store(); + return Ember.run(() => + store.findRecord('car', INPUT.id).then((car) => + RSVP.all([ + car.get('attributes'), + car.get('owner') + ]).then(() => { + return car.save(); + }))); +}); + +test('serializes record correctly', function (assert) { + assert.expect(2); + const INPUT = { + "id": "55b21c520fabf0ba57bf0631", + "email": "user@site.com", + "user_type": "power", + "profile": { + "nickname": "SuperJoe", + "bio": null + }, + "_updated": "Fri, 24 Jul 2015 11:06:58 GMT", + "_created": "Fri, 24 Jul 2015 11:06:58 GMT", + "_etag": "f6687527bd6a10205d7c1462109e6193b58c8ae9" + }; + + stubRequest('get', `/users/${INPUT.id}`, (request) => + request.ok(INPUT)); + + stubRequest('patch', `/users/${INPUT.id}`, (request) => { + assert.deepEqual(JSON.parse(request.requestBody), INPUT); + request.ok(INPUT); + }); + + const store = this.store(); + return Ember.run(() => + store.findRecord('user', INPUT.id).then((user) => { + assert.deepEqual(user.toJSON({includeId: true}), INPUT); + user.save(); + })); +}); diff --git a/tests/unit/models/transformers-test.js b/tests/unit/models/transformers-test.js index 78a30c7..e7ad20c 100644 --- a/tests/unit/models/transformers-test.js +++ b/tests/unit/models/transformers-test.js @@ -25,7 +25,7 @@ test('transforms attributes using transformers', function(assert){ stubRequest('patch', '/requirements/1', (request) => { let body = JSON.parse(request.requestBody); - assert.strictEqual(body.data.attributes.temperature, 50); + assert.strictEqual(body.temperature, 50); request.noContent(); });