Skip to content

Commit 3fd3c5b

Browse files
GoldenChrysusdynamiccast
authored andcommitted
Write populate blueprint (#49)
* Adding base support for "populate." Writing tests after. * Method info clarification. * Comment correction and improvement. * Forgot to add support for queries on non-ID requests. * Add basic initial tests. * Finalized and verified relationship tests. * Enabling pluralization in dummy test Sails config. * HOTFIX add symlink in dummy app node_modules to refer to current module code * Delete sails-json-api-blueprints * Accidentally removed symlink thanks to Windows. * Updated formatting of changes to meet repo guidelines.
1 parent 8757b19 commit 3fd3c5b

File tree

7 files changed

+222
-6
lines changed

7 files changed

+222
-6
lines changed

lib/api/blueprints/_util/actionUtil.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
/**
2+
* Module dependencies
3+
*/
4+
let pluralize = require("pluralize");
5+
16
/**
27
* Utility methods used in built-in blueprint actions.
38
*
@@ -83,6 +88,43 @@ module.exports = {
8388
return pk;
8489
},
8590

91+
/**
92+
* Parse parent key value for use in a Waterline criteria
93+
* (e.g. for `populate`)
94+
*
95+
* @param {Request} req
96+
* @return {Integer|String}
97+
*/
98+
parseParentId: function(req) {
99+
return req.options.parentid || req.param("parentid");
100+
},
101+
102+
/**
103+
* Parse relationship alias for use in a Waterline criteria
104+
* (e.g. for `populate`)
105+
*
106+
* @param {Request} req
107+
* @return {String}
108+
*/
109+
parseAlias: function(req) {
110+
return req.options.alias;
111+
},
112+
113+
/**
114+
* Parse relationship alias model name for use in a Waterline criteria
115+
* (e.g. for `populate`)
116+
*
117+
* @param {Request} req
118+
* @return {String}
119+
*/
120+
parseAliasModelName: function(req) {
121+
let Model = module.exports.parseModel(req);
122+
let alias = module.exports.parseAlias(req);
123+
let attribute = Model.attributes[alias];
124+
125+
return (attribute) ? pluralize(attribute.model || attribute.collection) : false;
126+
},
127+
86128
/**
87129
* Parse a JSON API request and set query to be populated with all defined relationships
88130
*

lib/api/blueprints/populate.js

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,58 @@
1+
/**
2+
* Module dependencies
3+
*/
4+
let actionUtil = require("./_util/actionUtil");
5+
let pluralize = require("pluralize");
6+
7+
/**
8+
* Populate Relationships
9+
*
10+
* get /:modelIdentity/:parentid/:alias
11+
* get /:modelIdentity/:parentid/:alias/:id
12+
*
13+
* An API call to find and return relationship instances from the data adapter
14+
* using the specified criteria.
15+
*
16+
* Required:
17+
* @param {Integer|String} parentid - the unique ID of the particular parent model you'd like to look up
18+
* @param {String} alias - the collection alias used to look up relationships
19+
*
20+
* Optional:
21+
* @param {Integer|String} id - the unique ID of the particular relationship model you'd like to look up *
22+
*
23+
*/
24+
125
module.exports = function findRecords(req, res) {
26+
let Model = actionUtil.parseModel(req);
27+
let alias = actionUtil.parseAlias(req);
28+
let parent_id = actionUtil.parseParentId(req);
29+
let pk = actionUtil.parsePk(req);
30+
let query_params = JsonApiService.deserialize(req.query.filter) || null;
31+
let query = Model.findOne(parent_id).populate(alias, pk || query_params);
32+
33+
query.exec((err, result) => {
34+
if (err) {
35+
return res.serverError(err);
36+
}
37+
38+
if (!result) {
39+
return res.ok(result);
40+
}
41+
42+
let sub_results = result[alias];
43+
44+
if
45+
(
46+
pk &&
47+
(
48+
!sub_results ||
49+
(Array.isArray(sub_results) && (!sub_results || sub_results.length === 0)) ||
50+
(sub_results !== null && typeof sub_results === "object" && Object.keys(sub_results).length === 0)
51+
)
52+
) {
53+
return res.notFound("No record found with the specified ID.");
54+
}
255

3-
res.status(501); // Not implemented
4-
return res.send(null);
56+
return res.ok(sub_results);
57+
});
558
};

lib/api/responses/ok.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
/**
2+
* Module dependencies
3+
*/
4+
let actionUtil = require("../blueprints/_util/actionUtil");
15
var pluralize = require('pluralize');
26

37
/**
@@ -19,7 +23,7 @@ module.exports = function sendOK(data, options) {
1923
var req = this.req;
2024
var res = this.res;
2125
var sails = req._sails;
22-
var type = pluralize(req.options.model || req.options.controller);
26+
var type = pluralize(actionUtil.parseAliasModelName(req) || req.options.model || req.options.controller);
2327

2428
data = JsonApiService.serialize(type, data);
2529

tests/dummy/api/models/Husband.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,8 @@ module.exports = {
1212
model: 'wife',
1313
unique: true
1414
}
15-
}
15+
},
16+
17+
autoUpdatedAt : false,
18+
autoCreatedAt : false
1619
};

tests/dummy/api/models/Wife.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,8 @@ module.exports = {
1515
collection: 'husband',
1616
via: 'wife'
1717
}
18-
}
18+
},
19+
20+
autoUpdatedAt : false,
21+
autoCreatedAt : false
1922
};

tests/dummy/config/blueprints.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ module.exports.blueprints = {
126126
* *
127127
***************************************************************************/
128128

129-
// pluralize: false,
129+
pluralize: true,
130130

131131
/***************************************************************************
132132
* *

tests/dummy/test/integration/controllers/Relationships.test.js

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,4 +217,115 @@ describe("Has many through relationships", function() {
217217
})
218218
})
219219

220+
describe("GET /husbands/:parentid/wife, GET /wives/:parentid/husband", function() {
221+
let husband_id = null;
222+
let wife_id = null;
223+
224+
before("Populate some data", function(done) {
225+
Husband.create({})
226+
.then((husband) => {
227+
husband_id = husband.id;
228+
229+
Wife.create({
230+
maidenName: 'Doe',
231+
husband: husband
232+
})
233+
.then((wife) => {
234+
wife_id = wife.id;
235+
236+
done();
237+
});
238+
})
239+
});
240+
241+
it("Should return the husband's wife", function(done) {
242+
request(sails.hooks.http.app)
243+
.get(`/husbands/${husband_id}/wife`)
244+
.expect(200)
245+
.expect(validateJSONapi)
246+
.expect({
247+
data : {
248+
type : "wives",
249+
id : `${wife_id}`,
250+
attributes : {
251+
"maiden-name" : "Doe"
252+
}
253+
}
254+
})
255+
.end(done);
256+
});
257+
258+
it("Should return the wife's husbands", function(done) {
259+
request(sails.hooks.http.app)
260+
.get(`/wives/${wife_id}/husband`)
261+
.expect(200)
262+
.expect(validateJSONapi)
263+
.expect({
264+
data : [{
265+
type : "husbands",
266+
id : `${husband_id}`,
267+
attributes : {
268+
wife : `${wife_id}`
269+
}
270+
}]
271+
})
272+
.end(done);
273+
});
274+
});
275+
276+
describe("GET /husbands/:parentid/wife/:id, GET /wives/:parentid/husband/:id", function() {
277+
let husband_id = null;
278+
let wife_id = null;
279+
280+
before("Populate some data", function(done) {
281+
Husband.create({})
282+
.then((husband) => {
283+
husband_id = husband.id;
284+
285+
Wife.create({
286+
maidenName: 'Doe',
287+
husband: husband
288+
})
289+
.then((wife) => {
290+
wife_id = wife.id;
291+
292+
done();
293+
});
294+
});
295+
});
296+
297+
it("Should return the husband's wife", function(done) {
298+
request(sails.hooks.http.app)
299+
.get(`/husbands/${husband_id}/wife/${wife_id}`)
300+
.expect(200)
301+
.expect(validateJSONapi)
302+
.expect({
303+
data : {
304+
type : "wives",
305+
id : `${wife_id}`,
306+
attributes : {
307+
"maiden-name" : "Doe"
308+
}
309+
}
310+
})
311+
.end(done);
312+
});
313+
314+
it("Should return the wife's husbands", function(done) {
315+
request(sails.hooks.http.app)
316+
.get(`/wives/${wife_id}/husband/${husband_id}`)
317+
.expect(200)
318+
.expect(validateJSONapi)
319+
.expect({
320+
data : [{
321+
type : "husbands",
322+
id : `${husband_id}`,
323+
attributes : {
324+
wife : `${wife_id}`
325+
}
326+
}]
327+
})
328+
.end(done);
329+
});
330+
});
220331
});

0 commit comments

Comments
 (0)