Skip to content

Commit 71f19ec

Browse files
committed
Add support for giving back total count via header, make populate return array only
1 parent fc43360 commit 71f19ec

File tree

11 files changed

+128
-20
lines changed

11 files changed

+128
-20
lines changed

lib/action-util.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const internals = {};
1010
*
1111
* @type {Object}
1212
*/
13-
module.exports = (request, options) => {
13+
module.exports = (request, options, h) => {
1414

1515
return {
1616

@@ -194,6 +194,15 @@ module.exports = (request, options) => {
194194
const userId = Hoek.reach(request.auth.credentials, options.userIdProperty);
195195

196196
return userId;
197+
},
198+
199+
replyWithRange: (model, rangeStart, rangeEnd, total, results) => {
200+
if (options.totalCountHeader === 'content-range') {
201+
return h.response(results).header('content-range', `${model} ${rangeStart}-${rangeStart + results.length}/${total.total}`);
202+
}
203+
204+
return h.response(results).header(options.totalCountHeader, String(total.total));
205+
197206
}
198207
};
199208
};

lib/actions/add.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ module.exports = function addToCollection(route, options) {
2020

2121
return async (request, h) => {
2222

23-
const actionUtil = Actions(request, options);
23+
const actionUtil = Actions(request, options, h);
2424

2525
// Ensure a model and alias can be deduced from the request.
2626
const Model = actionUtil.modelFromParam(options.model);
@@ -32,7 +32,7 @@ module.exports = function addToCollection(route, options) {
3232
return Boom.notFound('No record found with the specified `id`.');
3333
}
3434

35-
//if a key was specified for the relation, we're linking an exsiting.
35+
//if a key was specified for the relation, we're linking an existing.
3636
if (keys.child.value) {
3737

3838
const updatedTokenId = await foundModel.$relatedQuery(options.associationAttr)

lib/actions/create.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ module.exports = function createRecord(route, options) {
1616

1717
return async (request, h) => {
1818

19-
const actionUtil = Actions(request, options);
19+
const actionUtil = Actions(request, options, h);
2020
const Model = actionUtil.parseModel();
2121

2222
return h.response(await Model.query().insertAndFetch(request.payload)).code(201);

lib/actions/destroy.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ module.exports = function destroyOneRecord(route, options) {
1717

1818
return async (request, h) => {
1919

20-
const actionUtil = Actions(request, options);
20+
const actionUtil = Actions(request, options, h);
2121

2222
const Model = actionUtil.parseModel();
2323
const keys = actionUtil.getKeys();

lib/actions/find-by-id.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ const Actions = require('../action-util');
1515

1616
module.exports = function findOneRecord(route, options) {
1717

18-
return async (request) => {
18+
return async (request, h) => {
1919

20-
const actionUtil = Actions(request, options);
20+
const actionUtil = Actions(request, options, h);
2121

2222
const Model = actionUtil.modelFromParam(options.model);
2323
const keys = actionUtil.getKeys();

lib/actions/find.js

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,16 @@ const Actions = require('../action-util');
2121

2222
module.exports = function findRecords(route, options) {
2323

24-
return async (request) => {
24+
return async (request, h) => {
2525

26-
const actionUtil = Actions(request, options);
26+
const actionUtil = Actions(request, options, h);
2727
// Look up the model
2828
const Model = actionUtil.parseModel();
2929
// Lookup for records that match the specified criteria. Are we just counting?
3030
if (options._private.count) {
3131

32-
const modelCount = await Model.query().count().first();
33-
return modelCount[Object.keys(modelCount)[0]];
32+
const modelCount = await Model.query().count({ total: '*' }).first();
33+
return modelCount.total;
3434
}
3535

3636
const limit = actionUtil.parseLimit();
@@ -39,18 +39,30 @@ module.exports = function findRecords(route, options) {
3939
const rangeEnd = rangeStart ? rangeStart + limit : limit;
4040
const where = actionUtil.parseWhere(Model);
4141

42-
const foundModelsQuery = Model.query().range(rangeStart, rangeEnd).limit(limit);
42+
const foundModelsQuery = Model.query();
4343

4444
if (where) {
4545
foundModelsQuery.where(where);
4646
}
4747

48+
let total;
49+
50+
if (options.includeTotalCount) {
51+
total = await foundModelsQuery.clone().count({ total: '*' }).first();
52+
}
53+
4854
if (sort) {
4955
foundModelsQuery.orderByRaw(sort);
5056
}
5157

58+
foundModelsQuery.range(rangeStart, rangeEnd).limit(limit);
59+
5260
const foundModels = await foundModelsQuery;
5361

62+
if (total) {
63+
return actionUtil.replyWithRange(options.model, rangeStart, rangeEnd, total, foundModels.results);
64+
}
65+
5466
return foundModels.results;
5567

5668
};

lib/actions/populate.js

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ const Actions = require('../action-util');
66
/**
77
* Populate an association
88
*
9-
* get /model/:parentid/relation
10-
* get /model/:parentid/relation/count
11-
* get /model/:parentid/relation/:id
9+
* get /model/:parentid/:relation
10+
* get /model/:parentid/:relation/count
11+
* get /model/:parentid/:relation/:id
1212
*
1313
* @param {Object} where - the find criteria (passed directly to the ORM)
1414
* @param {Integer} limit - the maximum number of records to send back (useful for pagination)
@@ -21,7 +21,7 @@ module.exports = function expand(route, options) {
2121

2222
return async (request, h) => {
2323

24-
const actionUtil = Actions(request, options);
24+
const actionUtil = Actions(request, options, h);
2525

2626
const Model = actionUtil.modelFromParam(options.model);
2727
const relation = options.associationAttr;
@@ -37,6 +37,8 @@ module.exports = function expand(route, options) {
3737
const rangeStart = actionUtil.parseSkip();
3838
const rangeEnd = rangeStart + limit;
3939

40+
let total;
41+
4042
const modelFullQuery = Model.query().findById(keys.parent.value)
4143
.withGraphFetched(relation)
4244
.modifyGraph(relation, (builder) => {
@@ -45,6 +47,12 @@ module.exports = function expand(route, options) {
4547
builder.where(Ref(RelationModel.tableName + '.' + keys.child.key), '=', keys.child.value);
4648
}
4749

50+
if (options.includeTotalCount) {
51+
// we need to wrap this in an async iffe to trigger the query,
52+
// as otherwise the main query gets borked
53+
total = (async () => await builder.clone().count({ total: Ref(RelationModel.tableName + '.' + keys.child.key) }).first())();
54+
}
55+
4856
builder.range(rangeStart, rangeEnd).limit(limit);
4957

5058
if (sort) {
@@ -66,10 +74,14 @@ module.exports = function expand(route, options) {
6674
return Boom.notFound();
6775
}
6876

77+
if (total) {
78+
return actionUtil.replyWithRange(options.associationAttr, rangeStart, rangeEnd, await total, modelFull[options.associationAttr]);
79+
}
80+
6981
if (options._private.count) {
7082
return modelFull[options.associationAttr].length;
7183
}
7284

73-
return modelFull;
85+
return modelFull[options.associationAttr];
7486
};
7587
};

lib/actions/remove.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ module.exports = function remove(route, options) {
1414

1515
return async (request, h) => {
1616

17-
const actionUtil = Actions(request, options);
17+
const actionUtil = Actions(request, options, h);
1818

1919
const Model = actionUtil.modelFromParam(options.model);
2020
const keys = actionUtil.getKeys();

lib/actions/update.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ const Actions = require('../action-util');
1313

1414
module.exports = function updateOneRecord(route, options) {
1515

16-
return async (request) => {
16+
return async (request, h) => {
1717

18-
const actionUtil = Actions(request, options);
18+
const actionUtil = Actions(request, options, h);
1919

2020
// Look up the model
2121
const Model = actionUtil.parseModel();

lib/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ internals.defaults = {
7272
userModel: 'Users', // since it's not in the url
7373
userIdProperty: 'id', // on auth credentials
7474
prefix: '',
75+
includeTotalCount: false,
76+
totalCountHeader: 'content-range',
7577
_private: {
7678
actAsUserModifiedPath: false,
7779
count: false

0 commit comments

Comments
 (0)