Skip to content

Commit de6dc86

Browse files
author
guylabs
committed
Update ignores and add dist directory with 0.2.0 release.
1 parent 463dbc0 commit de6dc86

File tree

4 files changed

+398
-9
lines changed

4 files changed

+398
-9
lines changed

.gitignore

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
dist/
2-
node_modules/
1+
node_modules
2+
bower_components
3+
npm-debug.log
34
.idea
45
*.iml

bower.json

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
11
{
22
"name": "angular-spring-data-rest",
33
"description": "An AngularJS module to ease the work with a Spring Data REST backend.",
4-
"main": "dist/angular-spring-data-rest.js",
4+
"main": "./dist/angular-spring-data-rest.js",
55
"license": "MIT",
66
"ignore": [
7-
"**/.*",
8-
"node_modules",
9-
"bower_components",
10-
"dist",
11-
".idea",
12-
"*.iml"
7+
"node_modules"
138
],
149
"keywords": [
1510
"angular",

dist/angular-spring-data-rest.js

Lines changed: 311 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,311 @@
1+
/**
2+
* @module spring-data-rest
3+
* @version 0.2.0
4+
*
5+
* An AngularJS module to ease the work with a Spring Data REST backend.
6+
*/
7+
angular.module("spring-data-rest", ["ngResource"]);
8+
9+
/**
10+
* @module spring-data-rest
11+
* @version 0.2.0
12+
*
13+
* Provider for the SpringDataRestAdapter which is the core of this module.
14+
*/
15+
angular.module("spring-data-rest").provider("SpringDataRestAdapter", function () {
16+
17+
/**
18+
* Default configuration for spring data rest defaults
19+
*/
20+
var config = {
21+
'links': {
22+
'key': '_links'
23+
},
24+
'embedded': {
25+
'key': '_embedded',
26+
'value': '_embeddedItems'
27+
},
28+
'hrefKey': 'href',
29+
'resourcesKey': '_resources',
30+
'resourcesFunction': undefined
31+
};
32+
33+
return {
34+
35+
/**
36+
* Sets and gets the configuration object.
37+
*
38+
* @param {object} newConfig the new configuration to be set
39+
* @returns {object} the configuration object
40+
*/
41+
config: function (newConfig) {
42+
// if the configuration object is 'undefined' then return the configuration object
43+
if (typeof newConfig !== 'undefined') {
44+
// throw an error if the given configuration is not an object
45+
if (!angular.isObject(newConfig)) {
46+
throw new Error("The given configuration '" + newConfig + "' is not an object.");
47+
}
48+
49+
// check if the given resource function is not undefined and is of type function
50+
if (newConfig.resourcesFunction != undefined && typeof(newConfig.resourcesFunction) != "function") {
51+
throw new Error("The given resource function '" + newConfig.resourcesFunction + "' is not of type function.")
52+
}
53+
54+
// override the default configuration properties with the given new configuration
55+
config = deepExtend(config, newConfig);
56+
}
57+
return config;
58+
},
59+
60+
$get: ["$injector", function ($injector) {
61+
62+
/**
63+
* Returns the Angular $resource method which is configured with the given parameters.
64+
*
65+
* @param {string} url the url at which the resource is available
66+
* @param {object} paramDefaults optional $resource method parameter defaults
67+
* @param {object} actions optional $resource method actions
68+
* @param {object} options additional $resource method options
69+
* @returns {*}
70+
*/
71+
function callBackend(url, paramDefaults, actions, options) {
72+
if (config.resourcesFunction == undefined) {
73+
return $injector.get("$resource")(url, paramDefaults, actions, options);
74+
} else {
75+
return config.resourcesFunction(url, paramDefaults, actions, options);
76+
}
77+
}
78+
79+
/**
80+
* The actual adapter method which processes the given JSON data object and adds
81+
* the wrapped resource property to all embedded elements where resources are available.
82+
*
83+
* @param {object} data the given JSON data
84+
* @returns {object} the processed JSON data
85+
*/
86+
var SpringDataRestAdapter = function (data) {
87+
88+
/**
89+
* Wraps the Angular $resource method and adds the ability to retrieve the available resources. If no
90+
* parameter is given it will return an array with the available resources in this object.
91+
*
92+
* @param {string|object} resourceObject the resource name to be retrieved or an object which holds the
93+
* resource name and the parameters
94+
* @param {object} paramDefaults optional $resource method parameter defaults
95+
* @param {object} actions optional $resource method actions
96+
* @param {object} options additional $resource method options
97+
* @returns {object} the result of the $resource method or the available resources as a resource object array
98+
*
99+
* @see https://docs.angularjs.org/api/ngResource/service/$resource
100+
*/
101+
var resources = function (resourceObject, paramDefaults, actions, options) {
102+
var resources = this[config.links.key];
103+
104+
// if a resource object is given process it
105+
if (angular.isObject(resourceObject)) {
106+
if (!resourceObject.name) {
107+
throw new Error("The provided resource object must contain a name property.");
108+
}
109+
110+
var parameters = paramDefaults;
111+
var resourceObjectParameters = resourceObject.parameters;
112+
113+
// if the default parameters and the resource object parameters are objects, then merge these two objects
114+
// if not use the objects themselves as parameters
115+
if (paramDefaults && angular.isObject(paramDefaults)) {
116+
if (resourceObjectParameters && angular.isObject(resourceObjectParameters)) {
117+
parameters = angular.extend(angular.copy(paramDefaults), angular.copy(resourceObjectParameters));
118+
} else {
119+
parameters = angular.copy(paramDefaults);
120+
}
121+
} else {
122+
if (resourceObjectParameters && angular.isObject(resourceObjectParameters)) {
123+
parameters = angular.copy(resourceObjectParameters);
124+
}
125+
}
126+
127+
return callBackend(extractUrl(data[config.links.key][resourceObject.name][config.hrefKey],
128+
data[config.links.key][resourceObject.name].templated), parameters, actions, options);
129+
130+
} else if (resourceObject in resources) {
131+
// get the url out of the resource name and return the backend function
132+
return callBackend(extractUrl(data[config.links.key][resourceObject][config.hrefKey],
133+
data[config.links.key][resourceObject].templated), paramDefaults, actions, options);
134+
}
135+
136+
// return the available resources as resource object array if the resource object parameter is not set
137+
var availableResources = [];
138+
angular.forEach(resources, function (value, key) {
139+
if (value.templated) {
140+
var templateParameters = extractTemplateParameters(value[config.hrefKey]);
141+
availableResources.push({"name": key, "parameters": templateParameters});
142+
} else {
143+
availableResources.push({"name": key});
144+
}
145+
});
146+
return availableResources;
147+
};
148+
149+
// throw an exception if given data parameter is not of type object
150+
if (!angular.isObject(data) || data instanceof Array) {
151+
throw new Error("Given data '" + data + "' is not of type object.");
152+
}
153+
154+
var processedData = undefined;
155+
156+
// only add the resource method to the object if the links key is present
157+
if (config.links.key in data) {
158+
159+
// add Angular resources property to object
160+
var resourcesObject = {};
161+
resourcesObject[config.resourcesKey] = resources;
162+
processedData = angular.extend(this, angular.copy(data), resourcesObject);
163+
}
164+
165+
// only move the embedded values to a top level property if the embedded key is present
166+
if (config.embedded.key in data) {
167+
168+
// make a defensive copy if the processedData variable is undefined
169+
if (!processedData) {
170+
processedData = angular.copy(data);
171+
}
172+
173+
// process the embedded key and move it to an embedded value key
174+
processedData = moveArray(processedData, config.embedded.key, config.embedded.value);
175+
176+
// recursively process all contained objects in the embedded value array
177+
angular.forEach(processedData[config.embedded.value], function (value, key) {
178+
processedData[config.embedded.value][key] = new SpringDataRestAdapter(value);
179+
});
180+
}
181+
182+
// return the original data object if no processing is done
183+
return processedData ? processedData : data;
184+
};
185+
return SpringDataRestAdapter;
186+
}]
187+
};
188+
189+
});
190+
191+
/**
192+
* @module spring-data-rest
193+
* @version 0.2.0
194+
*
195+
* Provider for the interceptor which wraps the SpringDataRestAdapter around the response object.
196+
*/
197+
angular.module("spring-data-rest").provider("SpringDataRestInterceptor",
198+
["$httpProvider", "SpringDataRestAdapterProvider",
199+
function ($httpProvider) {
200+
return {
201+
202+
apply: function () {
203+
$httpProvider.interceptors.push("SpringDataRestInterceptor");
204+
},
205+
206+
$get: ["SpringDataRestAdapter", "$q", function (SpringDataRestAdapter, $q) {
207+
208+
return {
209+
response: function (response) {
210+
if (response && angular.isObject(response.data)) {
211+
response.data = new SpringDataRestAdapter(response.data);
212+
}
213+
return response || $q.when(response);
214+
}
215+
};
216+
}]
217+
218+
};
219+
220+
}]
221+
);
222+
223+
/**
224+
* Makes a deep extend of the given destination object and the source objects.
225+
*
226+
* @param {object} destination the destination object
227+
* @returns {object} a copy of the extended destination object
228+
*/
229+
function deepExtend(destination) {
230+
angular.forEach(arguments, function (obj) {
231+
if (obj !== destination) {
232+
angular.forEach(obj, function (value, key) {
233+
if (destination[key] && destination[key].constructor && destination[key].constructor === Object) {
234+
deepExtend(destination[key], value);
235+
} else {
236+
destination[key] = value;
237+
}
238+
});
239+
}
240+
});
241+
return angular.copy(destination);
242+
}
243+
244+
/**
245+
* Moves a key with an array value to the destination key.
246+
*
247+
* @param {object} object the object in which the source key exists and destination key is created
248+
* @param {string} sourceKey the source key from which the array is moved
249+
* @param {string} destinationKey the destination key to which the array is moved
250+
* @returns {object} the processed object
251+
*/
252+
var moveArray = function (object, sourceKey, destinationKey) {
253+
var embeddedObject = object[sourceKey];
254+
if (embeddedObject) {
255+
var key = Object.keys(embeddedObject)[0];
256+
var processedData = {};
257+
processedData[destinationKey] = embeddedObject[key];
258+
259+
object = angular.extend(object, processedData);
260+
delete object[sourceKey];
261+
}
262+
return object;
263+
};
264+
265+
/**
266+
* Extracts the url out of a url string. If template parameters exist, they will be removed from the
267+
* returned url.
268+
*
269+
* @param {string} url the url string from which to extract the url
270+
* @param {boolean} templated true if the url is templated
271+
* @returns {string} the url of the resource object
272+
*/
273+
function extractUrl(url, templated) {
274+
if (templated) {
275+
url = removeTemplateParameters(url)
276+
}
277+
return url;
278+
}
279+
280+
/**
281+
* Removes the template parameters of the given url. e.g. from this url
282+
* 'http://localhost:8080/categories{?page,size,sort}' it will remove the curly braces
283+
* and everything within.
284+
*
285+
* @param {string} url the url with the template parameters
286+
* @returns {string} the url without the template parameters
287+
*/
288+
var removeTemplateParameters = function (url) {
289+
return url.replace(/{.*}/g, '');
290+
};
291+
292+
/**
293+
* Returns the template parameters of the given url as array. e.g. from this url
294+
* 'http://localhost:8080/categories{?page,size,sort}' it will return the following array:
295+
* ['page', 'size', 'sort']
296+
*
297+
* @param {string} url the url with the template parameters
298+
* @returns {object} the array containing the template parameters
299+
*/
300+
var extractTemplateParameters = function (url) {
301+
var templateParametersObject = {};
302+
303+
var regexp = /{\?(.*)}/g;
304+
var templateParametersArray = regexp.exec(url)[1].split(',');
305+
306+
angular.forEach(templateParametersArray, function (value) {
307+
templateParametersObject[value] = undefined;
308+
});
309+
310+
return templateParametersObject;
311+
};

0 commit comments

Comments
 (0)