Skip to content

Commit 72c4cac

Browse files
author
guylabs
committed
Add ability to have multiple embedded items with embeddedResourceName set to true.
1 parent c8b8c1d commit 72c4cac

7 files changed

+158
-59
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,8 @@ The `SpringDataRestAdapter` is designed to be configurable and you are able to c
442442
* `linksSelfLinkName` (default: `self`): the name of the self link in the links object.
443443
* `embeddedKey` (default: `_embedded`): the property name where the embedded items are stored.
444444
* `embeddedNewKey` (default: `_embeddedItems`): the property name where the array of embedded items are stored.
445-
* `embeddedNamedResources` (default: `false`): true if the embedded resources names should be left as is, false if they should be removed
445+
* `embeddedNamedResources` (default: `false`): true if the embedded resources names (can be more than one) should be
446+
left as is, false if they should be removed and be replaced by the value of the first embedded resource
446447
* Example if set to true:
447448
```json
448449
{

dist/angular-spring-data-rest.js

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ angular.module("spring-data-rest").provider("SpringDataRestAdapter", function ()
2727
'linksSelfLinkName': 'self',
2828
'embeddedKey': '_embedded',
2929
'embeddedNewKey': '_embeddedItems',
30+
'embeddedNamedResources': false,
3031
'resourcesKey': '_resources',
3132
'resourcesFunction': undefined,
3233
'fetchFunction': undefined,
@@ -251,11 +252,23 @@ angular.module("spring-data-rest").provider("SpringDataRestAdapter", function ()
251252
}
252253

253254
// process the embedded key and move it to an embedded value key
254-
processedData = moveArray(processedData, config.embeddedKey, config.embeddedNewKey);
255+
processedData = moveArray(processedData, config.embeddedKey, config.embeddedNewKey, config.embeddedNamedResources);
255256

256257
// recursively process all contained objects in the embedded value array
257258
angular.forEach(processedData[config.embeddedNewKey], function (value, key) {
258-
processedData[config.embeddedNewKey][key] = processDataFunction(value, fetchLinkNames, recursive);
259+
260+
// if the embeddedResourceName config variable is set to true, process each resource name array
261+
if (value instanceof Array) {
262+
var processedDataArray = [];
263+
angular.forEach(value, function (arrayValue, arrayKey) {
264+
processedDataArray[arrayKey] = processDataFunction(arrayValue, fetchLinkNames, recursive);
265+
});
266+
processedData[config.embeddedNewKey][key] = processedDataArray;
267+
}
268+
else {
269+
// single objects are processed directly
270+
processedData[config.embeddedNewKey][key] = processDataFunction(value, fetchLinkNames, recursive);
271+
}
259272
});
260273
}
261274

@@ -372,19 +385,32 @@ function deepExtend(destination) {
372385
}
373386

374387
/**
375-
* Moves a key with an array value to the destination key.
388+
* Moves a key with an array value to the destination key. It is also possible to specify to use the value of the
389+
* first key of the object[sourceKey] object instead of the same object.
376390
*
377391
* @param {object} object the object in which the source key exists and destination key is created
378392
* @param {string} sourceKey the source key from which the array is moved
379393
* @param {string} destinationKey the destination key to which the array is moved
394+
* @param {boolean} useSameObject true if the same object is used for the destinationKey, false if the value of the
395+
* first key is used
380396
* @returns {object} the processed object
381397
*/
382-
function moveArray(object, sourceKey, destinationKey) {
398+
function moveArray(object, sourceKey, destinationKey, useSameObject) {
383399
var embeddedObject = object[sourceKey];
384400
if (embeddedObject) {
385-
var key = Object.keys(embeddedObject)[0];
386401
var processedData = {};
387-
processedData[destinationKey] = embeddedObject[key];
402+
processedData[destinationKey] = {};
403+
404+
if (useSameObject === true) {
405+
// loop over all items in the embedded object and add them to the processed data
406+
angular.forEach(Object.keys(embeddedObject), function (key) {
407+
processedData[destinationKey][key] = embeddedObject[key];
408+
});
409+
} else {
410+
// remove the key and replace it with the value of it
411+
var key = Object.keys(embeddedObject)[0];
412+
processedData[destinationKey] = embeddedObject[key];
413+
}
388414

389415
object = angular.extend(object, processedData);
390416
delete object[sourceKey];
@@ -420,7 +446,7 @@ function extractUrl(url, templated) {
420446
function checkUrl(url, resourceName, hrefKey) {
421447
if (url == undefined || !url) {
422448
throw new Error("The provided resource name '" + resourceName + "' has no valid URL in the '" +
423-
hrefKey + "' property.");
449+
hrefKey + "' property.");
424450
}
425451
return url
426452
}

dist/angular-spring-data-rest.min.js

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*!
22
* angular-spring-data-rest 0.3.1
3-
* Copyright 2014 Guy Brûlé (@guy_labs)
3+
* Copyright 2015 Guy Brûlé (@guy_labs)
44
* https://github.com/guylabs/angular-spring-data-rest
55
*/
66
!function () {
@@ -13,11 +13,17 @@
1313
}), angular.copy(b)
1414
}
1515

16-
function b(a, b, c) {
17-
var d = a[b];
18-
if (d) {
19-
var e = Object.keys(d)[0], f = {};
20-
f[c] = d[e], a = angular.extend(a, f), delete a[b]
16+
function b(a, b, c, d) {
17+
var e = a[b];
18+
if (e) {
19+
var f = {};
20+
if (f[c] = {}, d === !0)angular.forEach(Object.keys(e), function (a) {
21+
f[c][a] = e[a]
22+
}); else {
23+
var g = Object.keys(e)[0];
24+
f[c] = e[g]
25+
}
26+
a = angular.extend(a, f), delete a[b]
2127
}
2228
return a
2329
}
@@ -49,6 +55,7 @@
4955
linksSelfLinkName: "self",
5056
embeddedKey: "_embedded",
5157
embeddedNewKey: "_embeddedItems",
58+
embeddedNamedResources: !1,
5259
resourcesKey: "_resources",
5360
resourcesFunction: void 0,
5461
fetchFunction: void 0,
@@ -109,8 +116,13 @@
109116
c != e.linksSelfLinkName && (i == e.fetchAllKey || "string" == typeof i && c == i || i instanceof Array && i.indexOf(c) >= 0) && h(l(a, c), c, n, i, j)
110117
}))
111118
}
112-
return e.embeddedKey in a && (n || (n = angular.copy(a)), n = b(n, e.embeddedKey, e.embeddedNewKey), angular.forEach(n[e.embeddedNewKey], function (a, b) {
113-
n[e.embeddedNewKey][b] = k(a, i, j)
119+
return e.embeddedKey in a && (n || (n = angular.copy(a)), n = b(n, e.embeddedKey, e.embeddedNewKey, e.embeddedNamedResources), angular.forEach(n[e.embeddedNewKey], function (a, b) {
120+
if (a instanceof Array) {
121+
var c = [];
122+
angular.forEach(a, function (a, b) {
123+
c[b] = k(a, i, j)
124+
}), n[e.embeddedNewKey][b] = c
125+
} else n[e.embeddedNewKey][b] = k(a, i, j)
114126
})), n ? n : a
115127
}, j = function (b, c, d) {
116128
var e = a.get("$q").when(b), f = a.get("$q").defer();

src/angular-spring-data-rest-utils.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,17 @@ function deepExtend(destination) {
3333
function moveArray(object, sourceKey, destinationKey, useSameObject) {
3434
var embeddedObject = object[sourceKey];
3535
if (embeddedObject) {
36-
var key = Object.keys(embeddedObject)[0];
3736
var processedData = {};
37+
processedData[destinationKey] = {};
3838

3939
if (useSameObject === true) {
40-
processedData[destinationKey] = embeddedObject;
40+
// loop over all items in the embedded object and add them to the processed data
41+
angular.forEach(Object.keys(embeddedObject), function (key) {
42+
processedData[destinationKey][key] = embeddedObject[key];
43+
});
4144
} else {
45+
// remove the key and replace it with the value of it
46+
var key = Object.keys(embeddedObject)[0];
4247
processedData[destinationKey] = embeddedObject[key];
4348
}
4449

test/angular-spring-data-rest-provider.embedded-named-resources.spec.js

Lines changed: 0 additions & 41 deletions
This file was deleted.

test/angular-spring-data-rest-provider.embedded.spec.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,44 @@ describe("the response with the embedded values", function () {
6060
}
6161
});
6262

63+
it("must have the named resources if the embeddedNamedResources is set to true", function () {
64+
// set the new fetch function which throws an error if it is called
65+
springDataRestAdapterProvider.config({
66+
'embeddedNamedResources': true
67+
});
68+
this.response = SpringDataRestAdapter.process(this.rawResponse);
69+
70+
// expect that the first key of the embedded items is categories
71+
var key = Object.keys(this.response[this.config.embeddedNewKey])[0];
72+
expect(key).toBe("categories");
73+
74+
// expect that the embedded key value is an array of the size 2
75+
expect(this.response[this.config.embeddedNewKey]['categories'] instanceof Array).toBe(true);
76+
expect(this.response[this.config.embeddedNewKey]['categories'].length).toBe(2);
77+
});
78+
79+
it("must have multiple named resources if the embeddedNamedResources is set to true", function () {
80+
// set the new fetch function which throws an error if it is called
81+
springDataRestAdapterProvider.config({
82+
'embeddedNamedResources': true
83+
});
84+
this.response = SpringDataRestAdapter.process(mockDataWithoutLinksKeyAndMultipleEmbeddedKeys());
85+
86+
// expect that the first key of the embedded items is categories
87+
var key = Object.keys(this.response[this.config.embeddedNewKey])[0];
88+
expect(key).toBe("categories");
89+
90+
// expect that the second key of the embedded items is item
91+
var secondKey = Object.keys(this.response[this.config.embeddedNewKey])[1];
92+
expect(secondKey).toBe("item");
93+
94+
// expect that the first embedded key value is an array of the size 2
95+
expect(this.response[this.config.embeddedNewKey]['categories'] instanceof Array).toBe(true);
96+
expect(this.response[this.config.embeddedNewKey]['categories'].length).toBe(2);
97+
98+
// expect that the second embedded key value is an object
99+
expect(this.response[this.config.embeddedNewKey]['item'] instanceof Object).toBe(true);
100+
expect(this.response[this.config.embeddedNewKey]['item'].name).toBe('Test item 1');
101+
});
102+
63103
});

test/angular-spring-data-rest.helper.spec.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,62 @@ var mockDataWithoutLinksKey = function () {
164164
);
165165
};
166166

167+
var mockDataWithoutLinksKeyAndMultipleEmbeddedKeys = function () {
168+
return angular.copy(
169+
{
170+
"_embedded": {
171+
"categories": [
172+
{
173+
"version": 0,
174+
"creationDate": 1406219870650,
175+
"modificationDate": 1406219870650,
176+
"name": "Test category 1",
177+
"_links": {
178+
"self": {
179+
"href": "http://localhost:8080/categories/f974f5ef-a951-43b4-9027-4d2163216e54"
180+
},
181+
"parentCategory": {
182+
"href": "http://localhost:8080/categories/f974f5ef-a951-43b4-9027-4d2163216e54/parentCategory"
183+
}
184+
}
185+
},
186+
{
187+
"version": 0,
188+
"creationDate": 1406219884502,
189+
"modificationDate": 1406219884502,
190+
"name": "Test category 2",
191+
"_links": {
192+
"self": {
193+
"href": "http://localhost:8080/categories/b5ba38d5-98d3-4579-8709-a28549406697"
194+
},
195+
"parentCategory": {
196+
"href": "http://localhost:8080/categories/b5ba38d5-98d3-4579-8709-a28549406697/parentCategory"
197+
}
198+
}
199+
}
200+
],
201+
"item": {
202+
"version": 0,
203+
"creationDate": 1406219870650,
204+
"modificationDate": 1406219870650,
205+
"name": "Test item 1",
206+
"_links": {
207+
"self": {
208+
"href": "http://localhost:8080/item/f974f5ef-a951-43b4-9027-4d2163216e54"
209+
}
210+
}
211+
}
212+
},
213+
"page": {
214+
"size": 20,
215+
"totalElements": 2,
216+
"totalPages": 1,
217+
"number": 0
218+
}
219+
}
220+
);
221+
};
222+
167223
var mockDataWithoutEmbeddedKey = function () {
168224
return angular.copy(
169225
{

0 commit comments

Comments
 (0)