adminmate-express-mongoose 1.3.3 → 1.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,494 +2,517 @@ const mongoose = require('mongoose');
2
2
  const { serializeError } = require('serialize-error');
3
3
  const _ = require('lodash');
4
4
  const moment = require('moment');
5
-
6
5
  const pjson = require('../../package.json');
7
6
 
8
- const getModelProperties = model => {
9
- let modelFields = [];
10
- const modelProps = model.schema.paths;
7
+ module.exports = _conf => {
8
+ const getModelProperties = model => {
9
+ let modelFields = [];
10
+ const modelProps = model.schema.paths;
11
11
 
12
- Object.keys(modelProps).forEach(key => {
13
- if (key === '__v') {
14
- return;
15
- }
16
- let property = {
17
- path: key,
18
- type: modelProps[key].instance
19
- };
12
+ Object.keys(modelProps).forEach(key => {
13
+ if (key === '__v') {
14
+ return;
15
+ }
16
+ let property = {
17
+ path: key,
18
+ type: modelProps[key].instance
19
+ };
20
20
 
21
- if (property.type === 'Array') {
22
- const optionsTypes = modelProps[key].options.type;
23
- if (optionsTypes && optionsTypes[0] && typeof optionsTypes[0] === 'function') {
24
- property.type = `ArrayOf${optionsTypes[0].name}`;
21
+ if (property.type === 'Array') {
22
+ const optionsTypes = modelProps[key].options.type;
23
+ if (optionsTypes && optionsTypes[0] && typeof optionsTypes[0] === 'function') {
24
+ property.type = `ArrayOf${optionsTypes[0].name}`;
25
+ }
26
+ else if (optionsTypes && optionsTypes[0] && optionsTypes[0].type && typeof optionsTypes[0].type === 'function') {
27
+ property.type = `ArrayOf${optionsTypes[0].type.name}`;
28
+ }
29
+ else {
30
+ property.type = 'ArrayOfObject';
31
+ }
25
32
  }
26
- else if (optionsTypes && optionsTypes[0] && optionsTypes[0].type && typeof optionsTypes[0].type === 'function') {
27
- property.type = `ArrayOf${optionsTypes[0].type.name}`;
33
+
34
+ // Required option
35
+ if (modelProps[key].options.required) {
36
+ property.required = true;
28
37
  }
29
- else {
30
- property.type = 'ArrayOfObject';
38
+
39
+ // Default value option
40
+ if (typeof modelProps[key].options.default !== 'undefined') {
41
+ if (typeof modelProps[key].options.default === 'function') {
42
+ property.default = modelProps[key].options.default();
43
+ }
44
+ else {
45
+ property.default = modelProps[key].options.default;
46
+ }
31
47
  }
32
- }
33
48
 
34
- // Required option
35
- if (modelProps[key].options.required) {
36
- property.required = true;
37
- }
49
+ // Enum option
50
+ if (modelProps[key].options.enum) {
51
+ if (modelProps[key].enumValues) {
52
+ property.enum = modelProps[key].enumValues;
53
+ }
54
+ else if (modelProps[key].options.enum.values) {
55
+ property.enum = modelProps[key].options.enum.values
56
+ }
57
+ }
38
58
 
39
- // Default value option
40
- if (typeof modelProps[key].options.default !== 'undefined') {
41
- if (typeof modelProps[key].options.default === 'function') {
42
- property.default = modelProps[key].options.default();
59
+ // Ref option
60
+ if (modelProps[key].options.ref) {
61
+ property.ref = modelProps[key].options.ref;
43
62
  }
44
- else {
45
- property.default = modelProps[key].options.default;
63
+
64
+ // RefPath option
65
+ if (modelProps[key].options.refPath) {
66
+ property.refPath = modelProps[key].options.refPath;
46
67
  }
47
- }
48
68
 
49
- // Enum option
50
- if (modelProps[key].options.enum) {
51
- if (modelProps[key].enumValues) {
52
- property.enum = modelProps[key].enumValues;
69
+ if (key === '_id') {
70
+ modelFields.unshift(property);
53
71
  }
54
- else if (modelProps[key].options.enum.values) {
55
- property.enum = modelProps[key].options.enum.values
72
+ else {
73
+ modelFields.push(property);
56
74
  }
57
- }
75
+ });
58
76
 
59
- // Ref option
60
- if (modelProps[key].options.ref) {
61
- property.ref = modelProps[key].options.ref;
62
- }
77
+ return modelFields;
78
+ };
63
79
 
64
- // RefPath option
65
- if (modelProps[key].options.refPath) {
66
- property.refPath = modelProps[key].options.refPath;
67
- }
80
+ // Return real mongoose model name
81
+ const getModelRealname = model => {
82
+ return model.modelName;
83
+ };
68
84
 
69
- if (key === '_id') {
70
- modelFields.unshift(property);
71
- }
72
- else {
73
- modelFields.push(property);
85
+ // To be used in this file
86
+ const permutations = list => {
87
+ if (list.length <= 1) {
88
+ return list.slice();
74
89
  }
75
- });
76
-
77
- return modelFields;
78
- };
79
90
 
80
- module.exports.getModelProperties = getModelProperties;
81
-
82
- // Return real mongoose model name
83
- const getModelRealname = model => {
84
- return model.modelName;
85
- };
86
-
87
- module.exports.getModelRealname = getModelRealname;
88
-
89
- // To be used in this file
90
- const permutations = list => {
91
- if (list.length <= 1) {
92
- return list.slice();
93
- }
94
-
95
- let result = [],
96
- i = 0,
97
- j,
98
- current,
99
- rest;
100
-
101
- for(; i < list.length; i++) {
102
- rest = list.slice(); // make a copy of list
103
- current = rest.splice(i, 1);
104
- permutationsRest = permutations(rest);
105
- for(j = 0; j < permutationsRest.length; j++) {
106
- result.push(current.concat(permutationsRest[j]));
107
- }
108
- }
109
- return result;
110
- };
91
+ let result = [],
92
+ i = 0,
93
+ j,
94
+ current,
95
+ rest;
96
+
97
+ for(; i < list.length; i++) {
98
+ rest = list.slice(); // make a copy of list
99
+ current = rest.splice(i, 1);
100
+ permutationsRest = permutations(rest);
101
+ for(j = 0; j < permutationsRest.length; j++) {
102
+ result.push(current.concat(permutationsRest[j]));
103
+ }
104
+ }
105
+ return result;
106
+ };
111
107
 
112
- module.exports.permutations = permutations;
108
+ // To be used in this file
109
+ const cleanString = string => {
110
+ return string.toLowerCase().replace(/\W/g, '');
111
+ };
113
112
 
114
- // To be used in this file
115
- const cleanString = string => {
116
- return string.toLowerCase().replace(/\W/g, '');
117
- };
113
+ const queryRule = rule => {
114
+ if (rule.type === 'group') {
115
+ return queryRuleSet(rule);
116
+ }
117
+ let q = {};
118
+ if (rule.operator === 'is') {
119
+ // In order that aggregate queries to work well
120
+ const value = mongoose.isValidObjectId(rule.value) ? new mongoose.Types.ObjectId(rule.value) : rule.value;
121
+ q[rule.field] = { $eq: value };
122
+ }
123
+ else if (rule.operator === 'is_not') {
124
+ // In order that aggregate queries to work well
125
+ const value = mongoose.isValidObjectId(rule.value) ? new mongoose.Types.ObjectId(rule.value) : rule.value;
126
+ q[rule.field] = { $ne: value };
127
+ }
128
+ // Date
129
+ else if (rule.operator === 'is_before') {
130
+ // In order that aggregate queries to work well
131
+ q[rule.field] = { $lt: new Date(moment(rule.value)) };
132
+ }
133
+ else if (rule.operator === 'is_after') {
134
+ // In order that aggregate queries to work well
135
+ q[rule.field] = { $gt: new Date(moment(rule.value)) };
136
+ }
137
+ else if (rule.operator === 'is_today') {
138
+ q[rule.field] = {
139
+ $gte: moment().startOf('day'),
140
+ $lte: moment().endOf('day')
141
+ };
142
+ }
143
+ else if (rule.operator === 'was_yesterday') {
144
+ q[rule.field] = {
145
+ $gte: moment().startOf('day').subtract(1, 'day'),
146
+ $lte: moment().endOf('day').subtract(1, 'day')
147
+ };
148
+ }
149
+ else if (rule.operator === 'was_in_previous_week') {
150
+ q[rule.field] = {
151
+ $gte: moment().subtract(1, 'week').startOf('week'),
152
+ $lte: moment().subtract(1, 'week').endOf('week')
153
+ };
154
+ }
155
+ else if (rule.operator === 'was_in_previous_month') {
156
+ q[rule.field] = {
157
+ $gte: moment().subtract(1, 'month').startOf('month'),
158
+ $lte: moment().subtract(1, 'month').endOf('month')
159
+ };
160
+ }
161
+ else if (rule.operator === 'was_in_previous_year') {
162
+ q[rule.field] = {
163
+ $gte: moment().subtract(1, 'year').startOf('year'),
164
+ $lte: moment().subtract(1, 'year').endOf('year')
165
+ };
166
+ }
167
+ // Number
168
+ else if (rule.operator === 'is_greater_than') {
169
+ q[rule.field] = { $gt: rule.value };
170
+ }
171
+ else if (rule.operator === 'is_less_than') {
172
+ q[rule.field] = { $lt: rule.value };
173
+ }
174
+ // Boolean
175
+ else if (rule.operator === 'is_true') {
176
+ q[rule.field] = { $eq: true };
177
+ }
178
+ else if (rule.operator === 'is_false') {
179
+ q[rule.field] = { $eq: false };
180
+ }
181
+ // Exists
182
+ else if (rule.operator === 'is_present') {
183
+ q[rule.field] = { $exists: true };
184
+ }
185
+ else if (rule.operator === 'is_blank') {
186
+ q[rule.field] = { $exists: false };
187
+ }
188
+ // String comparison
189
+ else if (rule.operator === 'starts_with') {
190
+ const regexp = new RegExp(`^${rule.value}`);
191
+ q[rule.field] = { $regex: regexp, $options: 'i' };
192
+ }
193
+ else if (rule.operator === 'ends_with') {
194
+ const regexp = new RegExp(`${rule.value}$`);
195
+ q[rule.field] = { $regex: regexp, $options: 'i' };
196
+ }
197
+ else if (rule.operator === 'contains') {
198
+ const regexp = new RegExp(`${rule.value}`);
199
+ q[rule.field] = { $regex: regexp, $options: 'i' };
200
+ }
201
+ else if (rule.operator === 'not_contains') {
202
+ const regexp = new RegExp(`^((?!${rule.value}).)*$`);
203
+ q[rule.field] = { $regex: regexp, $options: 'i' };
204
+ }
205
+ return q;
206
+ };
118
207
 
119
- module.exports.cleanString = cleanString;
120
-
121
- const queryRule = rule => {
122
- if (rule.type === 'group') {
123
- return queryRuleSet(rule);
124
- }
125
- let q = {};
126
- if (rule.operator === 'is') {
127
- q[rule.field] = { $eq: rule.value };
128
- }
129
- else if (rule.operator === 'is_not') {
130
- q[rule.field] = { $ne: rule.value };
131
- }
132
- // Date
133
- else if (rule.operator === 'is_before') {
134
- q[rule.field] = { $lt: rule.value };
135
- }
136
- else if (rule.operator === 'is_after') {
137
- q[rule.field] = { $gt: rule.value };
138
- }
139
- else if (rule.operator === 'is_today') {
140
- q[rule.field] = {
141
- $gte: moment().startOf('day'),
142
- $lte: moment().endOf('day')
143
- };
144
- }
145
- else if (rule.operator === 'was_yesterday') {
146
- q[rule.field] = {
147
- $gte: moment().startOf('day').subtract(1, 'day'),
148
- $lte: moment().endOf('day').subtract(1, 'day')
149
- };
150
- }
151
- else if (rule.operator === 'was_in_previous_week') {
152
- q[rule.field] = {
153
- $gte: moment().subtract(1, 'week').startOf('week'),
154
- $lte: moment().subtract(1, 'week').endOf('week')
155
- };
156
- }
157
- else if (rule.operator === 'was_in_previous_month') {
158
- q[rule.field] = {
159
- $gte: moment().subtract(1, 'month').startOf('month'),
160
- $lte: moment().subtract(1, 'month').endOf('month')
161
- };
162
- }
163
- else if (rule.operator === 'was_in_previous_year') {
164
- q[rule.field] = {
165
- $gte: moment().subtract(1, 'year').startOf('year'),
166
- $lte: moment().subtract(1, 'year').endOf('year')
208
+ const queryRuleSet = ruleSet => {
209
+ const conditions = {
210
+ 'and': '$and',
211
+ 'or': '$or'
167
212
  };
168
- }
169
- // Number
170
- else if (rule.operator === 'is_greater_than') {
171
- q[rule.field] = { $gt: rule.value };
172
- }
173
- else if (rule.operator === 'is_less_than') {
174
- q[rule.field] = { $lt: rule.value };
175
- }
176
- // Boolean
177
- else if (rule.operator === 'is_true') {
178
- q[rule.field] = { $eq: true };
179
- }
180
- else if (rule.operator === 'is_false') {
181
- q[rule.field] = { $eq: false };
182
- }
183
- // Exists
184
- else if (rule.operator === 'is_present') {
185
- q[rule.field] = { $exists: true };
186
- }
187
- else if (rule.operator === 'is_blank') {
188
- q[rule.field] = { $exists: false };
189
- }
190
- // String comparison
191
- else if (rule.operator === 'starts_with') {
192
- const regexp = new RegExp(`^${rule.value}`);
193
- q[rule.field] = { $regex: regexp, $options: 'i' };
194
- }
195
- else if (rule.operator === 'ends_with') {
196
- const regexp = new RegExp(`${rule.value}$`);
197
- q[rule.field] = { $regex: regexp, $options: 'i' };
198
- }
199
- else if (rule.operator === 'contains') {
200
- const regexp = new RegExp(`${rule.value}`);
201
- q[rule.field] = { $regex: regexp, $options: 'i' };
202
- }
203
- else if (rule.operator === 'not_contains') {
204
- const regexp = new RegExp(`^((?!${rule.value}).)*$`);
205
- q[rule.field] = { $regex: regexp, $options: 'i' };
206
- }
207
- return q;
208
- };
209
213
 
210
- const queryRuleSet = ruleSet => {
211
- const conditions = {
212
- 'and': '$and',
213
- 'or': '$or'
214
+ return {
215
+ [conditions[ruleSet.operator]]: ruleSet.list.map(
216
+ rule => rule.list ? queryRuleSet(rule) : queryRule(rule)
217
+ )
218
+ }
214
219
  };
215
220
 
216
- return {
217
- [conditions[ruleSet.operator]]: ruleSet.list.map(
218
- rule => rule.list ? queryRuleSet(rule) : queryRule(rule)
219
- )
220
- }
221
- };
222
-
223
- module.exports.toFixedIfNecessary = (value, dp) => {
224
- return +parseFloat(value).toFixed(dp);
225
- };
221
+ const toFixedIfNecessary = (value, dp) => {
222
+ return +parseFloat(value).toFixed(dp);
223
+ };
226
224
 
227
- module.exports.constructQuery = jsonQuery => {
228
- if (jsonQuery.operator && jsonQuery.list && jsonQuery.list.length) {
229
- return queryRuleSet(jsonQuery);
230
- }
231
- return null;
232
- };
225
+ const constructQuery = jsonQuery => {
226
+ if (jsonQuery.operator && jsonQuery.list && jsonQuery.list.length) {
227
+ return queryRuleSet(jsonQuery);
228
+ }
229
+ return null;
230
+ };
233
231
 
234
- module.exports.fieldsToValues = (string, values) => {
235
- return string.replace(/[a-z._]+/gi, word => {
236
- return _.get(values, word);
237
- });
238
- };
232
+ const fieldsToValues = (string, values) => {
233
+ return string.replace(/[a-z._]+/gi, word => {
234
+ return _.get(values, word);
235
+ });
236
+ };
239
237
 
240
- module.exports.refFields = (item, fieldsToPopulate) => {
241
- const attributes = Object.keys(item);
242
- attributes.forEach(attr => {
238
+ const refFields = (item, fieldsToPopulate) => {
239
+ const attributes = Object.keys(item);
240
+ attributes.forEach(attr => {
243
241
 
244
- // Set to empty instead of undefined
245
- item[attr] = typeof item[attr] === 'undefined' ? '' : item[attr];
242
+ // Set to empty instead of undefined
243
+ item[attr] = typeof item[attr] === 'undefined' ? '' : item[attr];
246
244
 
247
- // Manage populate fields
248
- const matchingField = fieldsToPopulate.find(field => field.path === attr);
245
+ // Manage populate fields
246
+ const matchingField = fieldsToPopulate.find(field => field.path === attr);
249
247
 
250
- if (matchingField) {
251
- let fieldsList = '';
252
- if (matchingField.multipleRefField && matchingField.multipleValues) {
253
- const modelToCheck = item[matchingField.multipleRefField];
254
- if (modelToCheck && matchingField.multipleValues[modelToCheck]) {
255
- fieldsList = matchingField.multipleValues[modelToCheck];
248
+ if (matchingField) {
249
+ let fieldsList = '';
250
+ if (matchingField.multipleRefField && matchingField.multipleValues) {
251
+ const modelToCheck = item[matchingField.multipleRefField];
252
+ if (modelToCheck && matchingField.multipleValues[modelToCheck]) {
253
+ fieldsList = matchingField.multipleValues[modelToCheck];
254
+ }
255
+ else {
256
+ fieldsList = '_id';
257
+ }
256
258
  }
257
259
  else {
258
- fieldsList = '_id';
260
+ fieldsList = matchingField.select;
259
261
  }
260
- }
261
- else {
262
- fieldsList = matchingField.select;
263
- }
264
262
 
265
- const label = fieldsList.replace(/[a-z._]+/gi, word => {
266
- return _.get(item, `${attr}.${word}`);
267
- });
263
+ const label = fieldsList.replace(/[a-z._]+/gi, word => {
264
+ return _.get(item, `${attr}.${word}`);
265
+ });
268
266
 
269
- if (item[attr]) {
270
- item[attr] = {
271
- type: 'ref',
272
- id: item[attr]._id,
273
- label
274
- };
275
- }
276
- else {
277
- item[attr] = '(deleted)';
267
+ if (item[attr]) {
268
+ item[attr] = {
269
+ type: 'ref',
270
+ id: item[attr]._id,
271
+ label
272
+ };
273
+ }
274
+ else {
275
+ item[attr] = '(deleted)';
276
+ }
278
277
  }
279
- }
280
- });
281
- return item;
282
- };
278
+ });
279
+ return item;
280
+ };
283
281
 
284
- module.exports.getFieldsToPopulate = (keys, fieldsToFetch, refFields = {}) => {
285
- // Create query populate config
286
- let fieldsToPopulate = [];
287
- fieldsToFetch.forEach(field => {
288
- const matchingField = keys.find(k => k.path === field);
289
- if (matchingField && matchingField.type === 'ObjectID' && (matchingField.ref || matchingField.refPath)) {
290
-
291
- let fieldToSelect = '_id';
292
- let toPush = {
293
- path: field,
294
- select: '_id'
295
- };
282
+ const getFieldsToPopulate = (keys, fieldsToFetch, refFields = {}) => {
283
+ // Create query populate config
284
+ let fieldsToPopulate = [];
285
+ fieldsToFetch.forEach(field => {
286
+ const matchingField = keys.find(k => k.path === field);
287
+ if (matchingField && matchingField.type === 'ObjectID' && (matchingField.ref || matchingField.refPath)) {
288
+
289
+ let fieldToSelect = '_id';
290
+ let toPush = {
291
+ path: field,
292
+ select: '_id'
293
+ };
296
294
 
297
- // For ref attributes
298
- if (matchingField.ref) {
299
- const matchingModel = global._amConfig.models.find(m => m.model.modelName === matchingField.ref);
300
- if (matchingModel && matchingModel.slug && refFields[matchingModel.slug]) {
301
- toPush.select = refFields[matchingModel.slug];
295
+ // For ref attributes
296
+ if (matchingField.ref) {
297
+ const matchingModel = _conf.models.find(m => m.model.modelName === matchingField.ref);
298
+ if (matchingModel && matchingModel.slug && refFields[matchingModel.slug]) {
299
+ toPush.select = refFields[matchingModel.slug];
300
+ }
302
301
  }
303
- }
304
- // For refPath attributes
305
- else if (matchingField.refPath) {
306
- const multipleValues = {};
307
- const refPathField = keys.find(k => k.path === matchingField.refPath);
308
- if (refPathField && refPathField.enum) {
309
- refPathField.enum.forEach(modelName => {
310
- multipleValues[modelName] = '_id';
311
- const matchingModel = global._amConfig.models.find(m => m.model.modelName === modelName);
312
- if (matchingModel && matchingModel.slug && refFields[matchingModel.slug]) {
313
- // Merge all ref models fields
314
- fieldToSelect += ` ${refFields[matchingModel.slug]}`;
315
- multipleValues[modelName] = refFields[matchingModel.slug];
316
- }
317
- });
318
- toPush.select = fieldToSelect || '_id';
319
- toPush.multipleRefField = matchingField.refPath;
320
- toPush.multipleValues = multipleValues;
302
+ // For refPath attributes
303
+ else if (matchingField.refPath) {
304
+ const multipleValues = {};
305
+ const refPathField = keys.find(k => k.path === matchingField.refPath);
306
+ if (refPathField && refPathField.enum) {
307
+ refPathField.enum.forEach(modelName => {
308
+ multipleValues[modelName] = '_id';
309
+ const matchingModel = _conf.models.find(m => m.model.modelName === modelName);
310
+ if (matchingModel && matchingModel.slug && refFields[matchingModel.slug]) {
311
+ // Merge all ref models fields
312
+ fieldToSelect += ` ${refFields[matchingModel.slug]}`;
313
+ multipleValues[modelName] = refFields[matchingModel.slug];
314
+ }
315
+ });
316
+ toPush.select = fieldToSelect || '_id';
317
+ toPush.multipleRefField = matchingField.refPath;
318
+ toPush.multipleValues = multipleValues;
319
+ }
321
320
  }
321
+
322
+ fieldsToPopulate.push(toPush);
322
323
  }
324
+ });
323
325
 
324
- fieldsToPopulate.push(toPush);
325
- }
326
- });
326
+ return fieldsToPopulate;
327
+ };
327
328
 
328
- return fieldsToPopulate;
329
- };
329
+ const constructSearch = (search, fieldsToSearchIn, fieldsToPopulate = []) => {
330
+ params = { $or: [] };
330
331
 
331
- module.exports.constructSearch = (search, fieldsToSearchIn, fieldsToPopulate = []) => {
332
- params = { $or: [] };
332
+ fieldsToSearchIn.map(field => {
333
+ params.$or.push({ [field]: { '$regex': `${search}`, '$options': 'i' } });
334
+ });
333
335
 
334
- fieldsToSearchIn.map(field => {
335
- params.$or.push({ [field]: { '$regex': `${search}`, '$options': 'i' } });
336
- });
336
+ // If the search is a valid mongodb _id
337
+ // An object id's only defining feature is that its 12 bytes long
338
+ if (mongoose.isValidObjectId(search)) {
339
+ params.$or.push({ _id: search });
340
+ fieldsToPopulate.map(field => {
341
+ params.$or.push({ [field.path]: search });
342
+ });
343
+ }
337
344
 
338
- // If the search is a valid mongodb _id
339
- // An object id's only defining feature is that its 12 bytes long
340
- if (mongoose.Types.ObjectId.isValid(search)) {
341
- params.$or.push({ _id: search });
342
- fieldsToPopulate.map(field => {
343
- params.$or.push({ [field.path]: search });
344
- });
345
- }
346
-
347
- // If the search terms contains multiple words and there is multiple fields to search in
348
- if (/\s/.test(search) && fieldsToSearchIn.length > 1) {
349
- // Create all search combinaisons for $regexMatch
350
- const searchPieces = search.split(' ');
351
- const searchCombinaisons = permutations(searchPieces)
352
- .map(comb => cleanString(comb.join('')))
353
- .join('|');
354
- const concatFields = fieldsToSearchIn.map(field => `$${field}`);
355
-
356
- params.$or.push({
357
- $expr: {
358
- $regexMatch: {
359
- input: {
360
- $concat: concatFields
361
- },
362
- regex: new RegExp(searchCombinaisons),
363
- options: 'i'
345
+ // If the search terms contains multiple words and there is multiple fields to search in
346
+ if (/\s/.test(search) && fieldsToSearchIn.length > 1) {
347
+ // Create all search combinaisons for $regexMatch
348
+ const searchPieces = search.split(' ');
349
+ const searchCombinaisons = permutations(searchPieces)
350
+ .map(comb => cleanString(comb.join('')))
351
+ .join('|');
352
+ const concatFields = fieldsToSearchIn.map(field => `$${field}`);
353
+
354
+ params.$or.push({
355
+ $expr: {
356
+ $regexMatch: {
357
+ input: {
358
+ $concat: concatFields
359
+ },
360
+ regex: new RegExp(searchCombinaisons),
361
+ options: 'i'
362
+ }
364
363
  }
365
- }
366
- });
367
- }
364
+ });
365
+ }
368
366
 
369
- return params;
370
- };
367
+ return params;
368
+ };
371
369
 
372
- module.exports.getModelWhereClause = (model, idsArray) => {
373
- return { _id: idsArray };
374
- };
370
+ const getModelWhereClause = (model, idsArray) => {
371
+ return { _id: idsArray };
372
+ };
375
373
 
376
- module.exports.getModelPrimaryKeys = model => {
377
- return ['_id'];
378
- };
374
+ const getModelPrimaryKeys = model => {
375
+ return ['_id'];
376
+ };
379
377
 
380
- module.exports.getModelAssociations = model => {
381
- // Get current model mongoose realname
382
- const currentModelRealName = getModelRealname(model);
383
-
384
- if (!currentModelRealName) {
385
- return [];
386
- }
387
-
388
- // List all the models that reference the current model
389
- const associationsList = [];
390
- global._amConfig.models
391
- .filter(mc => getModelRealname(mc.model) !== currentModelRealName)
392
- .forEach(mc => {
393
- const modelProperties = getModelProperties(mc.model);
394
- if (modelProperties && modelProperties.length) {
395
- modelProperties.forEach(mp => {
396
- if (mp.ref === currentModelRealName) {
397
- associationsList.push({
398
- model: mc.model,
399
- model_slug: mc.slug,
400
- slug: `${mc.slug}_${mp.path}`,
401
- ref_field: mp.path
402
- });
403
- }
404
- })
405
- }
406
- });
378
+ const getModelAssociations = model => {
379
+ // Get current model mongoose realname
380
+ const currentModelRealName = getModelRealname(model);
407
381
 
408
- return associationsList;
409
- };
382
+ if (!currentModelRealName) {
383
+ return [];
384
+ }
410
385
 
411
- const getModel = modelCode => {
412
- if (!modelCode) {
413
- return null;
414
- }
386
+ // List all the models that reference the current model
387
+ const associationsList = [];
388
+ _conf.models
389
+ .filter(mc => !!mc.model && getModelRealname(mc.model) !== currentModelRealName)
390
+ .forEach(mc => {
391
+ const modelProperties = getModelProperties(mc.model);
392
+ if (modelProperties && modelProperties.length) {
393
+ modelProperties.forEach(mp => {
394
+ if (mp.ref === currentModelRealName) {
395
+ associationsList.push({
396
+ model: mc.model,
397
+ model_slug: mc.slug,
398
+ slug: `${mc.slug}_${mp.path}`,
399
+ ref_field: mp.path
400
+ });
401
+ }
402
+ })
403
+ }
404
+ });
415
405
 
416
- const currentModel = global._amConfig.models.find(m => m.slug === modelCode);
406
+ return associationsList;
407
+ };
417
408
 
418
- return currentModel;
419
- };
409
+ const getModel = modelCode => {
410
+ if (!modelCode) {
411
+ return null;
412
+ }
420
413
 
421
- module.exports.getModelObject = modelCode => {
422
- const currentModel = getModel(modelCode);
423
- if (!currentModel) {
424
- return null;
425
- }
414
+ const currentModel = _conf.models.find(m => m.slug === modelCode);
426
415
 
427
- return currentModel.model;
428
- };
416
+ return currentModel;
417
+ };
429
418
 
430
- module.exports.getModelSegments = modelCode => {
431
- const currentModel = getModel(modelCode);
432
- if (!currentModel) {
433
- return null;
434
- }
419
+ const getModelObject = modelCode => {
420
+ const currentModel = getModel(modelCode);
421
+ if (!currentModel) {
422
+ return null;
423
+ }
435
424
 
436
- return currentModel.segments;
437
- };
425
+ return currentModel.model;
426
+ };
438
427
 
439
- module.exports.getModelSegment = (modelCode, segmentCode) => {
440
- const currentModel = getModel(modelCode);
441
- if (!currentModel || !currentModel.segments || currentModel.segments.length === 0) {
442
- return null;
443
- }
428
+ const getModelSegments = modelCode => {
429
+ const currentModel = getModel(modelCode);
430
+ if (!currentModel) {
431
+ return null;
432
+ }
444
433
 
445
- return currentModel.segments
446
- .find(s => s.code === segmentCode);
447
- };
434
+ return currentModel.segments;
435
+ };
448
436
 
449
- module.exports.buildError = (e, defaultMessage) => {
450
- if (e && e.errors) {
451
- let arr = [];
452
- Object.entries(e.errors).forEach(value => {
453
- arr.push({ field: value[0], message: value[1].message });
454
- });
455
- return { message: defaultMessage, error_details: arr };
456
- }
457
- else if (e && e.message) {
458
- const errorObject = serializeError(e);
459
- const arr = [{
460
- message: errorObject.stack
461
- }];
462
- return { message: defaultMessage, error_details: arr };
463
- }
464
- return { message: defaultMessage };
465
- };
437
+ const getModelSegment = (modelCode, segmentCode) => {
438
+ const currentModel = getModel(modelCode);
439
+ if (!currentModel || !currentModel.segments || currentModel.segments.length === 0) {
440
+ return null;
441
+ }
442
+
443
+ return currentModel.segments
444
+ .find(s => s.code === segmentCode);
445
+ };
446
+
447
+ const buildError = (e, defaultMessage) => {
448
+ if (e && e.errors) {
449
+ let arr = [];
450
+ Object.entries(e.errors).forEach(value => {
451
+ arr.push({ field: value[0], message: value[1].message });
452
+ });
453
+ return { message: defaultMessage, error_details: arr };
454
+ }
455
+ else if (e && e.message) {
456
+ const errorObject = serializeError(e);
457
+ const arr = [{
458
+ message: errorObject.stack
459
+ }];
460
+ return { message: defaultMessage, error_details: arr };
461
+ }
462
+ return { message: defaultMessage };
463
+ };
464
+
465
+ const validateOrderStructure = orderConfig => {
466
+ let bool = true;
467
+ if (orderConfig && Array.isArray(orderConfig)) {
468
+ orderConfig.forEach(oc => {
469
+ if (!Array.isArray(oc) || oc.length !== 2 && !['ASC', 'DESC'].includes(oc[1])) {
470
+ bool = false;
471
+ }
472
+ });
473
+ }
474
+ else {
475
+ bool = false;
476
+ }
477
+ return bool;
478
+ };
466
479
 
467
- module.exports.validateOrderStructure = orderConfig => {
468
- let bool = true;
469
- if (orderConfig && Array.isArray(orderConfig)) {
480
+ const getCleanOrderStructure = orderConfig => {
481
+ const order = {};
470
482
  orderConfig.forEach(oc => {
471
- if (!Array.isArray(oc) || oc.length !== 2 && !['ASC', 'DESC'].includes(oc[1])) {
472
- bool = false;
473
- }
483
+ order[oc[0]] = oc[1];
474
484
  });
475
- }
476
- else {
477
- bool = false;
478
- }
479
- return bool;
480
- };
485
+ return order;
486
+ };
481
487
 
482
- module.exports.getCleanOrderStructure = orderConfig => {
483
- const order = {};
484
- orderConfig.forEach(oc => {
485
- order[oc[0]] = oc[1];
486
- });
487
- return order;
488
- };
488
+ const getAppConfig = () => {
489
+ return {
490
+ package: pjson.name,
491
+ version: pjson.version
492
+ };
493
+ };
489
494
 
490
- module.exports.getAppConfig = () => {
491
495
  return {
492
- package: pjson.name,
493
- version: pjson.version
496
+ getAppConfig,
497
+ getCleanOrderStructure,
498
+ validateOrderStructure,
499
+ getModelSegment,
500
+ getModelSegments,
501
+ getModelObject,
502
+ getModelAssociations,
503
+ getModelPrimaryKeys,
504
+ getModelWhereClause,
505
+ getModelRealname,
506
+ getModelProperties,
507
+ constructSearch,
508
+ getFieldsToPopulate,
509
+ getFieldsToPopulate,
510
+ refFields,
511
+ fieldsToValues,
512
+ constructQuery,
513
+ toFixedIfNecessary,
514
+ cleanString,
515
+ buildError,
516
+ permutations
494
517
  };
495
- };
518
+ };