forked from fullcube/loopback-ds-paginate-mixin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
169 lines (136 loc) · 4.45 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
var debug = require('debug')('loopback-ds-paginate-mixin');
var utils = require('loopback-datasource-juggler/lib/utils');
var assert = require('assert');
var _ = require('lodash');
function Paginate(Model, options) {
'use strict';
var mixinName = 'Paginate';
var modelName = Model.definition.name;
var debugPrefix = mixinName + ': ' + modelName + ': ';
debug(debugPrefix + 'Loading with config %o', options);
Model.paginate = function(query, cb) {
cb = cb || utils.createPromiseCallback();
if (_.isUndefined(query)) {
query = {};
}
assert(typeof query, 'object', 'Page should always be an object');
debug(debugPrefix + 'paginate: query: %o', query);
// Check if limit is passed otherwise set to mixin config or default
if (_.isUndefined(query.limit)) {
query.limit = options.config.limit || 10;
debug(debugPrefix + 'paginate: limit undefined, using default:', query.limit);
} else {
debug(debugPrefix + 'paginate: limit defined: %s', query.limit);
}
// Check if skip is passed otherwise default to 1
if (!query.skip) {
debug(debugPrefix + 'paginate: skip undefined');
query.skip = 0;
} else {
debug(debugPrefix + 'paginate: skip defined: %s', query.skip);
}
// Do some assertions
// TODO: These values should never be negative
assert(typeof query.limit, 'number', 'Limit should always be a number');
// Define the initial params object
var params = {
skip: query.skip,
limit: query.limit
};
// Check if additional query parameters are passed
if (!_.isUndefined(query)) {
// Check each of the following properties and add to params object
var queryParams = ['fields', 'include', 'where', 'order'];
queryParams.map(function(queryParam) {
if (!_.isUndefined(query[queryParam])) {
params[queryParam] = query[queryParam];
debug(debugPrefix + 'paginate: adding param: %s = %o', queryParam,
query[queryParam]);
}
});
}
// Handle the passed search terms
if (!_.isEmpty(query.searchTerms)) {
debug(debugPrefix + 'query.searchTerms: %o', query.searchTerms);
// Create a new 'and' query
params.where = {
and: []
};
// Loop through the search terms
_.mapKeys(query.searchTerms, function(term, key) {
// Handle wildcard search
if (key === '*') {
params.where.or = [];
// Add an 'or' item for each property
Object.keys(Model.definition.properties).map(function(key) {
var bit = {};
bit[key] = {
like: term,
options: 'i'
};
params.where.or.push(bit);
});
} else {
// Add an 'and' item for each key
var bit = {};
bit[key] = {
like: term,
options: 'i'
};
params.where.and.push(bit);
}
});
}
if (!_.isEmpty(query.sortOrder)) {
debug(debugPrefix + 'query.sortOrder: %o', query.sortOrder);
this.sortOrder = (query.sortOrder.reverse === true) ? 'DESC' : 'ASC';
this.sortBy = query.sortOrder.predicate;
params.order = this.sortBy + ' ' + this.sortOrder;
}
debug(debugPrefix + 'paginate: params: %o', params);
// Define where query used for counter
var countWhere = params.where || {};
// Get all the objects based on the params
Model.all(params).then(function(items) {
// Get total number of objects based on countWhere
Model.count(countWhere).then(function(count) {
// Format the result
var result = {
counters: {
itemsFrom: query.skip,
itemsTo: query.skip + items.length,
itemsTotal: count,
itemsPerPage: query.limit,
pageTotal: Math.ceil(count / query.limit)
},
items: items
};
debug(debugPrefix + 'paginate: result: %o', result);
cb(null, result);
}).catch(cb);
}).catch(cb);
return cb.promise;
};
Model.remoteMethod('paginate', {
accepts: [{
arg: 'query',
type: 'object',
required: false,
http: {
source: 'body'
}
}],
returns: {
arg: 'result',
type: 'string',
root: true
},
http: {
path: '/paginate',
verb: 'post'
}
});
}
module.exports = function mixin(app) {
app.loopback.modelBuilder.mixins.define('Paginate', Paginate);
};