From f4e3e1b966159a7418e2acb9b5bcd7476fec28e0 Mon Sep 17 00:00:00 2001 From: Stefan Date: Wed, 3 Apr 2019 13:54:34 +0200 Subject: [PATCH 1/5] feat: deserialize function for relationships --- lib/JSONAPISerializer.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/JSONAPISerializer.js b/lib/JSONAPISerializer.js index afcf2b6..ab67ea4 100644 --- a/lib/JSONAPISerializer.js +++ b/lib/JSONAPISerializer.js @@ -61,6 +61,7 @@ module.exports = class JSONAPISerializer { schema: joi.string().default('default'), links: joi.alternatives([joi.func(), joi.object()]).default({}), meta: joi.alternatives([joi.func(), joi.object()]).default({}), + deserialize: joi.func() })).default({}), topLevelLinks: joi.alternatives([joi.func(), joi.object()]).default({}), topLevelMeta: joi.alternatives([joi.func(), joi.object()]).default({}), @@ -484,8 +485,14 @@ module.exports = class JSONAPISerializer { // Support alternativeKey options for relationships let relationshipKey = relationshipProperty; - if (resourceOpts.relationships[relationshipKey] && resourceOpts.relationships[relationshipKey].alternativeKey) { - relationshipKey = resourceOpts.relationships[relationshipKey].alternativeKey; + let deserializeFunction; + if (resourceOpts.relationships[relationshipKey]) { + if (resourceOpts.relationships[relationshipKey].alternativeKey) { + relationshipKey = resourceOpts.relationships[relationshipKey].alternativeKey; + } + if (resourceOpts.relationships[relationshipKey].deserialize) { + deserializeFunction = resourceOpts.relationships[relationshipKey].deserialize + } } if (relationship.data !== undefined) { @@ -493,7 +500,7 @@ module.exports = class JSONAPISerializer { // Array data _set(deserializedData, relationshipKey, relationship.data.map(d => (included ? this.deserializeIncluded(d.type, d.id, resourceOpts.relationships[relationshipProperty], included) - : d.id))); + : deserializeFunction ? deserializeFunction(d) : d.id))); } else if (relationship.data === null) { // null data _set(deserializedData, relationshipKey, null); @@ -501,7 +508,7 @@ module.exports = class JSONAPISerializer { // Object data _set(deserializedData, relationshipKey, included ? this.deserializeIncluded(relationship.data.type, relationship.data.id, resourceOpts.relationships[relationshipProperty], included) - : relationship.data.id); + : deserializeFunction ? deserializeFunction(relationship.data) : relationship.data.id); } } }); From bb32c887b7a401d356436277048e2193ab40fbb2 Mon Sep 17 00:00:00 2001 From: Stefan Date: Fri, 12 Apr 2019 16:43:40 +0200 Subject: [PATCH 2/5] fix: Wrong relationshipKey for deserialize when alternativeKey is defined --- lib/JSONAPISerializer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/JSONAPISerializer.js b/lib/JSONAPISerializer.js index ab67ea4..1cbbb64 100644 --- a/lib/JSONAPISerializer.js +++ b/lib/JSONAPISerializer.js @@ -490,8 +490,8 @@ module.exports = class JSONAPISerializer { if (resourceOpts.relationships[relationshipKey].alternativeKey) { relationshipKey = resourceOpts.relationships[relationshipKey].alternativeKey; } - if (resourceOpts.relationships[relationshipKey].deserialize) { - deserializeFunction = resourceOpts.relationships[relationshipKey].deserialize + if (resourceOpts.relationships[relationshipProperty].deserialize) { + deserializeFunction = resourceOpts.relationships[relationshipProperty].deserialize } } From f865388b771fd9578d4f541a4e4660ac7b39f0ae Mon Sep 17 00:00:00 2001 From: Stefan Date: Fri, 12 Apr 2019 16:45:42 +0200 Subject: [PATCH 3/5] test: Add test for deserialize property --- test/unit/JSONAPISerializer.test.js | 37 +++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/test/unit/JSONAPISerializer.test.js b/test/unit/JSONAPISerializer.test.js index f807dfc..4dffb2f 100644 --- a/test/unit/JSONAPISerializer.test.js +++ b/test/unit/JSONAPISerializer.test.js @@ -1520,6 +1520,43 @@ describe('JSONAPISerializer', function() { done(); }); + it('should deserialize with \'deserialize\' option as a function', function(done) { + const Serializer = new JSONAPISerializer(); + Serializer.register('articles', { + relationships: { + author: { + type: 'people', + deserialize: (data) => ({id: data.id, type: data.type}) + } + } + }); + + const data = { + data: { + type: 'article', + id: '1', + attributes: { + title: 'JSON API paints my bikeshed!', + body: 'The shortest article. Ever.', + created: '2015-05-22T14:56:29.000Z' + }, + relationships: { + author: { + data: { + type: 'people', + id: '1' + } + } + } + } + }; + + const deserializedData = Serializer.deserialize('articles', data); + expect(deserializedData.author).to.have.property('id'); + expect(deserializedData.author).to.have.property('type'); + done(); + }) + it('should deserialize with \'unconvertCase\' options', function(done) { const Serializer = new JSONAPISerializer(); Serializer.register('articles', { From 1fde11839ebe5ed858a8fdc5fed6655c1fe742c3 Mon Sep 17 00:00:00 2001 From: Stefan Date: Fri, 12 Apr 2019 17:05:07 +0200 Subject: [PATCH 4/5] refactor: No nested ternary expressions --- lib/JSONAPISerializer.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/JSONAPISerializer.js b/lib/JSONAPISerializer.js index 1cbbb64..0fb4566 100644 --- a/lib/JSONAPISerializer.js +++ b/lib/JSONAPISerializer.js @@ -61,7 +61,7 @@ module.exports = class JSONAPISerializer { schema: joi.string().default('default'), links: joi.alternatives([joi.func(), joi.object()]).default({}), meta: joi.alternatives([joi.func(), joi.object()]).default({}), - deserialize: joi.func() + deserialize: joi.func(), })).default({}), topLevelLinks: joi.alternatives([joi.func(), joi.object()]).default({}), topLevelMeta: joi.alternatives([joi.func(), joi.object()]).default({}), @@ -485,22 +485,22 @@ module.exports = class JSONAPISerializer { // Support alternativeKey options for relationships let relationshipKey = relationshipProperty; - let deserializeFunction; - if (resourceOpts.relationships[relationshipKey]) { - if (resourceOpts.relationships[relationshipKey].alternativeKey) { - relationshipKey = resourceOpts.relationships[relationshipKey].alternativeKey; - } - if (resourceOpts.relationships[relationshipProperty].deserialize) { - deserializeFunction = resourceOpts.relationships[relationshipProperty].deserialize - } + if (resourceOpts.relationships[relationshipKey] && resourceOpts.relationships[relationshipKey].alternativeKey) { + relationshipKey = resourceOpts.relationships[relationshipKey].alternativeKey; } + const deserializeFunction = (relationshipData) => { + if (resourceOpts.relationships[relationshipKey] && resourceOpts.relationships[relationshipProperty].deserialize) { + return resourceOpts.relationships[relationshipProperty].deserialize(relationshipData); + } + return relationshipData.id; + }; if (relationship.data !== undefined) { if (Array.isArray(relationship.data)) { // Array data _set(deserializedData, relationshipKey, relationship.data.map(d => (included ? this.deserializeIncluded(d.type, d.id, resourceOpts.relationships[relationshipProperty], included) - : deserializeFunction ? deserializeFunction(d) : d.id))); + : deserializeFunction(d)))); } else if (relationship.data === null) { // null data _set(deserializedData, relationshipKey, null); @@ -508,7 +508,7 @@ module.exports = class JSONAPISerializer { // Object data _set(deserializedData, relationshipKey, included ? this.deserializeIncluded(relationship.data.type, relationship.data.id, resourceOpts.relationships[relationshipProperty], included) - : deserializeFunction ? deserializeFunction(relationship.data) : relationship.data.id); + : deserializeFunction(relationship.data)); } } }); From 81933717878b0a72e1c29ab0b89403d94ef2e8f4 Mon Sep 17 00:00:00 2001 From: stefanvanherwijnen Date: Mon, 15 Apr 2019 14:06:32 +0200 Subject: [PATCH 5/5] Update README.md Add deserialize function documentation. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 37781d5..4b7d04e 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,8 @@ Serializer.register(type, options); * **meta** (optional): Describes meta that contains non-standard meta-information about the relationship. It can be: * An _object_ (values can be string or function). * A _function_ with one argument `function(data) { ... }` or with two arguments `function(data, extraData) { ... }` + * **deserialize** (optional): Describes the function which should be used to deserialize a related property which is not included in the JSON:API document. It should be: + * A _function_ with one argument `function(data) { ... }`which defines the format to which a relation should be deserialized. By default, the ID of the related object is returned, which would be equal to `function(data) {return data.id}`. See [issue #65](https://github.com/danivek/json-api-serializer/issues/65). * **convertCase** (optional): Case conversion for serializing data. Value can be : `kebab-case`, `snake_case`, `camelCase` **Deserialization options:**