@bedrockio/model 0.1.32 → 0.2.0
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.
- package/README.md +323 -109
- package/dist/cjs/const.js +2 -4
- package/dist/cjs/delete-hooks.js +351 -0
- package/dist/cjs/disallowed.js +0 -14
- package/dist/cjs/env.js +1 -2
- package/dist/cjs/include.js +11 -3
- package/dist/cjs/query.js +21 -0
- package/dist/cjs/schema.js +6 -3
- package/dist/cjs/search.js +12 -23
- package/dist/cjs/serialization.js +5 -3
- package/dist/cjs/soft-delete.js +226 -51
- package/dist/cjs/validation.js +1 -2
- package/package.json +5 -5
- package/src/delete-hooks.js +343 -0
- package/src/disallowed.js +0 -29
- package/src/include.js +10 -1
- package/src/query.js +15 -0
- package/src/schema.js +9 -4
- package/src/search.js +15 -27
- package/src/serialization.js +5 -1
- package/src/soft-delete.js +248 -55
- package/types/delete-hooks.d.ts +2 -0
- package/types/delete-hooks.d.ts.map +1 -0
- package/types/disallowed.d.ts.map +1 -1
- package/types/load.d.ts +67 -1
- package/types/load.d.ts.map +1 -1
- package/types/query.d.ts +2 -0
- package/types/query.d.ts.map +1 -0
- package/types/schema.d.ts +15 -9
- package/types/schema.d.ts.map +1 -1
- package/types/search.d.ts.map +1 -1
- package/types/serialization.d.ts.map +1 -1
- package/types/soft-delete.d.ts.map +1 -1
- package/types/testing.d.ts +1 -1
- package/types/testing.d.ts.map +1 -1
- package/dist/cjs/references.js +0 -104
- package/src/references.js +0 -101
package/dist/cjs/const.js
CHANGED
|
@@ -4,13 +4,11 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.SEARCH_DEFAULTS = exports.POPULATE_MAX_DEPTH = void 0;
|
|
7
|
-
const SEARCH_DEFAULTS = {
|
|
7
|
+
const SEARCH_DEFAULTS = exports.SEARCH_DEFAULTS = {
|
|
8
8
|
limit: 50,
|
|
9
9
|
sort: {
|
|
10
10
|
field: 'createdAt',
|
|
11
11
|
order: 'desc'
|
|
12
12
|
}
|
|
13
13
|
};
|
|
14
|
-
exports.
|
|
15
|
-
const POPULATE_MAX_DEPTH = 5;
|
|
16
|
-
exports.POPULATE_MAX_DEPTH = POPULATE_MAX_DEPTH;
|
|
14
|
+
const POPULATE_MAX_DEPTH = exports.POPULATE_MAX_DEPTH = 5;
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.applyDeleteHooks = applyDeleteHooks;
|
|
7
|
+
var _mongoose = _interopRequireDefault(require("mongoose"));
|
|
8
|
+
var _lodash = require("lodash");
|
|
9
|
+
var _errors = require("./errors");
|
|
10
|
+
var _utils = require("./utils");
|
|
11
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
12
|
+
const {
|
|
13
|
+
ObjectId: SchemaObjectId
|
|
14
|
+
} = _mongoose.default.Schema.Types;
|
|
15
|
+
function applyDeleteHooks(schema, definition) {
|
|
16
|
+
let {
|
|
17
|
+
onDelete: deleteHooks
|
|
18
|
+
} = definition;
|
|
19
|
+
if (!deleteHooks) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const cleanLocal = validateCleanLocal(deleteHooks, schema);
|
|
23
|
+
const cleanForeign = validateCleanForeign(deleteHooks);
|
|
24
|
+
const errorHook = validateError(deleteHooks);
|
|
25
|
+
let references;
|
|
26
|
+
const deleteFn = schema.methods.delete;
|
|
27
|
+
const restoreFn = schema.methods.restore;
|
|
28
|
+
schema.method('delete', async function () {
|
|
29
|
+
if (errorHook) {
|
|
30
|
+
references ||= getAllReferences(this);
|
|
31
|
+
await errorOnForeignReferences(this, {
|
|
32
|
+
errorHook,
|
|
33
|
+
cleanForeign,
|
|
34
|
+
references
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
await deleteLocalReferences(this, cleanLocal);
|
|
39
|
+
await deleteForeignReferences(this, cleanForeign);
|
|
40
|
+
} catch (error) {
|
|
41
|
+
await restoreLocalReferences(this, cleanLocal);
|
|
42
|
+
await restoreForeignReferences(this);
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
await deleteFn.apply(this, arguments);
|
|
46
|
+
});
|
|
47
|
+
schema.method('restore', async function () {
|
|
48
|
+
await restoreLocalReferences(this, cleanLocal);
|
|
49
|
+
await restoreForeignReferences(this);
|
|
50
|
+
await restoreFn.apply(this, arguments);
|
|
51
|
+
});
|
|
52
|
+
schema.add({
|
|
53
|
+
deletedRefs: [{
|
|
54
|
+
_id: 'ObjectId',
|
|
55
|
+
ref: 'String'
|
|
56
|
+
}]
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Clean Hook
|
|
61
|
+
|
|
62
|
+
function validateCleanLocal(deleteHooks, schema) {
|
|
63
|
+
let {
|
|
64
|
+
local
|
|
65
|
+
} = deleteHooks.clean || {};
|
|
66
|
+
if (!local) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (typeof local !== 'string' && !Array.isArray(local)) {
|
|
70
|
+
throw new Error('Local delete hook must be an array.');
|
|
71
|
+
}
|
|
72
|
+
if (typeof local === 'string') {
|
|
73
|
+
local = [local];
|
|
74
|
+
}
|
|
75
|
+
for (let name of local) {
|
|
76
|
+
const pathType = schema.pathType(name);
|
|
77
|
+
if (pathType !== 'real') {
|
|
78
|
+
throw new Error(`Delete hook has invalid local reference "${name}".`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return local;
|
|
82
|
+
}
|
|
83
|
+
function validateCleanForeign(deleteHooks) {
|
|
84
|
+
const {
|
|
85
|
+
foreign
|
|
86
|
+
} = deleteHooks.clean || {};
|
|
87
|
+
if (!foreign) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (typeof foreign !== 'object') {
|
|
91
|
+
throw new Error('Foreign delete hook must be an object.');
|
|
92
|
+
}
|
|
93
|
+
for (let [modelName, arg] of Object.entries(foreign)) {
|
|
94
|
+
if (typeof arg === 'object') {
|
|
95
|
+
const {
|
|
96
|
+
$and,
|
|
97
|
+
$or
|
|
98
|
+
} = arg;
|
|
99
|
+
if ($and && $or) {
|
|
100
|
+
throw new Error(`Cannot define both $or and $and in a delete hook for model ${modelName}.`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return foreign;
|
|
105
|
+
}
|
|
106
|
+
function validateError(deleteHooks) {
|
|
107
|
+
let {
|
|
108
|
+
errorOnReferenced
|
|
109
|
+
} = deleteHooks;
|
|
110
|
+
if (!errorOnReferenced) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (errorOnReferenced === true) {
|
|
114
|
+
errorOnReferenced = {};
|
|
115
|
+
}
|
|
116
|
+
return errorOnReferenced;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Error on references
|
|
120
|
+
|
|
121
|
+
async function errorOnForeignReferences(doc, options) {
|
|
122
|
+
const {
|
|
123
|
+
errorHook,
|
|
124
|
+
cleanForeign,
|
|
125
|
+
references
|
|
126
|
+
} = options;
|
|
127
|
+
if (!errorHook) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
const {
|
|
131
|
+
only,
|
|
132
|
+
except
|
|
133
|
+
} = errorHook;
|
|
134
|
+
assertModelNames(only);
|
|
135
|
+
assertModelNames(except);
|
|
136
|
+
const results = [];
|
|
137
|
+
for (let {
|
|
138
|
+
model,
|
|
139
|
+
paths
|
|
140
|
+
} of references) {
|
|
141
|
+
if (referenceIsAllowed(errorHook, model)) {
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
const $or = paths.filter(path => {
|
|
145
|
+
if (cleanForeign) {
|
|
146
|
+
return cleanForeign[model.modelName] !== path;
|
|
147
|
+
}
|
|
148
|
+
return true;
|
|
149
|
+
}).map(path => {
|
|
150
|
+
return {
|
|
151
|
+
[path]: doc.id
|
|
152
|
+
};
|
|
153
|
+
});
|
|
154
|
+
if (!$or.length) {
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
const docs = await model.find({
|
|
158
|
+
$or
|
|
159
|
+
}, {
|
|
160
|
+
_id: 1
|
|
161
|
+
}).lean();
|
|
162
|
+
if (docs.length > 0) {
|
|
163
|
+
const ids = docs.map(doc => {
|
|
164
|
+
return String(doc._id);
|
|
165
|
+
});
|
|
166
|
+
results.push({
|
|
167
|
+
ids,
|
|
168
|
+
model,
|
|
169
|
+
count: ids.length
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
if (results.length) {
|
|
174
|
+
const {
|
|
175
|
+
modelName
|
|
176
|
+
} = doc.constructor;
|
|
177
|
+
const refNames = results.map(reference => {
|
|
178
|
+
return reference.model.modelName;
|
|
179
|
+
});
|
|
180
|
+
throw new _errors.ReferenceError(`Refusing to delete ${modelName} referenced by ${refNames}.`, results);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
function referenceIsAllowed(errorHook, model) {
|
|
184
|
+
const {
|
|
185
|
+
only,
|
|
186
|
+
except
|
|
187
|
+
} = errorHook;
|
|
188
|
+
if (only) {
|
|
189
|
+
return !only.includes(model.modelName);
|
|
190
|
+
} else if (except) {
|
|
191
|
+
return except.includes(model.modelName);
|
|
192
|
+
} else {
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
function assertModelNames(arr = []) {
|
|
197
|
+
for (let val of arr) {
|
|
198
|
+
if (!_mongoose.default.models[val]) {
|
|
199
|
+
throw new Error(`Unknown model "${val}".`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
function getAllReferences(doc) {
|
|
204
|
+
const targetName = doc.constructor.modelName;
|
|
205
|
+
return Object.values(_mongoose.default.models).map(model => {
|
|
206
|
+
const paths = getModelReferences(model, targetName);
|
|
207
|
+
return {
|
|
208
|
+
model,
|
|
209
|
+
paths
|
|
210
|
+
};
|
|
211
|
+
}).filter(({
|
|
212
|
+
paths
|
|
213
|
+
}) => {
|
|
214
|
+
return paths.length > 0;
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
function getModelReferences(model, targetName) {
|
|
218
|
+
const paths = [];
|
|
219
|
+
model.schema.eachPath((schemaPath, schemaType) => {
|
|
220
|
+
if (schemaType instanceof SchemaObjectId && schemaPath[0] !== '_') {
|
|
221
|
+
const {
|
|
222
|
+
ref,
|
|
223
|
+
refPath
|
|
224
|
+
} = schemaType.options;
|
|
225
|
+
let refs;
|
|
226
|
+
if (ref) {
|
|
227
|
+
refs = [ref];
|
|
228
|
+
} else if (refPath) {
|
|
229
|
+
refs = model.schema.path(refPath).options.enum;
|
|
230
|
+
} else {
|
|
231
|
+
throw new Error(`Cannot derive refs for ${model.modelName}#${schemaPath}.`);
|
|
232
|
+
}
|
|
233
|
+
if (refs.includes(targetName)) {
|
|
234
|
+
paths.push(schemaPath);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
return paths;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Deletion
|
|
242
|
+
|
|
243
|
+
async function deleteLocalReferences(doc, arr) {
|
|
244
|
+
if (!arr) {
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
for (let name of arr) {
|
|
248
|
+
await doc.populate(name);
|
|
249
|
+
const value = doc.get(name);
|
|
250
|
+
const arr = Array.isArray(value) ? value : [value];
|
|
251
|
+
for (let sub of arr) {
|
|
252
|
+
await sub.delete();
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
async function deleteForeignReferences(doc, refs) {
|
|
257
|
+
if (!refs) {
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
const {
|
|
261
|
+
id
|
|
262
|
+
} = doc;
|
|
263
|
+
if (!id) {
|
|
264
|
+
throw new Error(`Refusing to apply delete hook to document without id.`);
|
|
265
|
+
}
|
|
266
|
+
for (let [modelName, arg] of Object.entries(refs)) {
|
|
267
|
+
const Model = _mongoose.default.models[modelName];
|
|
268
|
+
if (typeof arg === 'string') {
|
|
269
|
+
await runDeletes(Model, doc, {
|
|
270
|
+
[arg]: id
|
|
271
|
+
});
|
|
272
|
+
} else {
|
|
273
|
+
const {
|
|
274
|
+
$and,
|
|
275
|
+
$or
|
|
276
|
+
} = arg;
|
|
277
|
+
if ($and) {
|
|
278
|
+
await runDeletes(Model, doc, {
|
|
279
|
+
$and: mapArrayQuery($and, id)
|
|
280
|
+
});
|
|
281
|
+
} else if ($or) {
|
|
282
|
+
await runDeletes(Model, doc, {
|
|
283
|
+
$or: mapArrayQuery($or, id)
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
async function runDeletes(Model, refDoc, query) {
|
|
290
|
+
const docs = await Model.find(query);
|
|
291
|
+
for (let doc of docs) {
|
|
292
|
+
await doc.delete();
|
|
293
|
+
refDoc.deletedRefs.push({
|
|
294
|
+
_id: doc.id,
|
|
295
|
+
ref: doc.constructor.modelName
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
function mapArrayQuery(arr, id) {
|
|
300
|
+
return arr.map(refName => {
|
|
301
|
+
return {
|
|
302
|
+
[refName]: id
|
|
303
|
+
};
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Restore
|
|
308
|
+
|
|
309
|
+
async function restoreLocalReferences(refDoc, arr) {
|
|
310
|
+
if (!arr) {
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
for (let name of arr) {
|
|
314
|
+
const {
|
|
315
|
+
ref
|
|
316
|
+
} = (0, _utils.getInnerField)(refDoc.constructor.schema.obj, name);
|
|
317
|
+
const value = refDoc.get(name);
|
|
318
|
+
const ids = Array.isArray(value) ? value : [value];
|
|
319
|
+
const Model = _mongoose.default.models[ref];
|
|
320
|
+
|
|
321
|
+
// @ts-ignore
|
|
322
|
+
const docs = await Model.findDeleted({
|
|
323
|
+
_id: {
|
|
324
|
+
$in: ids
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
for (let doc of docs) {
|
|
328
|
+
await doc.restore();
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
async function restoreForeignReferences(refDoc) {
|
|
333
|
+
const grouped = (0, _lodash.groupBy)(refDoc.deletedRefs, 'ref');
|
|
334
|
+
for (let [modelName, refs] of Object.entries(grouped)) {
|
|
335
|
+
const ids = refs.map(ref => {
|
|
336
|
+
return ref._id;
|
|
337
|
+
});
|
|
338
|
+
const Model = _mongoose.default.models[modelName];
|
|
339
|
+
|
|
340
|
+
// @ts-ignore
|
|
341
|
+
const docs = await Model.findDeleted({
|
|
342
|
+
_id: {
|
|
343
|
+
$in: ids
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
for (let doc of docs) {
|
|
347
|
+
await doc.restore();
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
refDoc.deletedRefs = [];
|
|
351
|
+
}
|
package/dist/cjs/disallowed.js
CHANGED
|
@@ -7,24 +7,10 @@ exports.applyDisallowed = applyDisallowed;
|
|
|
7
7
|
var _warn = _interopRequireDefault(require("./warn"));
|
|
8
8
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
9
9
|
function applyDisallowed(schema) {
|
|
10
|
-
schema.method('remove', function () {
|
|
11
|
-
(0, _warn.default)('The "remove" method on documents is disallowed due to ambiguity.', 'To permanently delete a document use "destroy", otherwise "delete".');
|
|
12
|
-
throw new Error('Method not allowed.');
|
|
13
|
-
}, {
|
|
14
|
-
suppressWarning: true
|
|
15
|
-
});
|
|
16
|
-
schema.method('update', function () {
|
|
17
|
-
(0, _warn.default)('The "update" method on documents is deprecated. Use "updateOne" instead.');
|
|
18
|
-
throw new Error('Method not allowed.');
|
|
19
|
-
});
|
|
20
10
|
schema.method('deleteOne', function () {
|
|
21
11
|
(0, _warn.default)('The "deleteOne" method on documents is disallowed due to ambiguity', 'Use either "delete" or "deleteOne" on the model.');
|
|
22
12
|
throw new Error('Method not allowed.');
|
|
23
13
|
});
|
|
24
|
-
schema.static('remove', function () {
|
|
25
|
-
(0, _warn.default)('The "remove" method on models is disallowed due to ambiguity.', 'To permanently delete a document use "destroyMany", otherwise "deleteMany".');
|
|
26
|
-
throw new Error('Method not allowed.');
|
|
27
|
-
});
|
|
28
14
|
schema.static('findOneAndRemove', function () {
|
|
29
15
|
(0, _warn.default)('The "findOneAndRemove" method on models is disallowed due to ambiguity.', 'To permanently delete a document use "findOneAndDestroy", otherwise "findOneAndDelete".');
|
|
30
16
|
throw new Error('Method not allowed.');
|
package/dist/cjs/env.js
CHANGED
package/dist/cjs/include.js
CHANGED
|
@@ -24,10 +24,9 @@ _mongoose.default.Query.prototype.include = function include(arg) {
|
|
|
24
24
|
return this;
|
|
25
25
|
};
|
|
26
26
|
const DESCRIPTION = 'Field to be selected or populated.';
|
|
27
|
-
const INCLUDE_FIELD_SCHEMA = _yada.default.object({
|
|
27
|
+
const INCLUDE_FIELD_SCHEMA = exports.INCLUDE_FIELD_SCHEMA = _yada.default.object({
|
|
28
28
|
include: _yada.default.allow(_yada.default.string().description(DESCRIPTION), _yada.default.array(_yada.default.string().description(DESCRIPTION)))
|
|
29
29
|
});
|
|
30
|
-
exports.INCLUDE_FIELD_SCHEMA = INCLUDE_FIELD_SCHEMA;
|
|
31
30
|
function applyInclude(schema) {
|
|
32
31
|
// Query Includes
|
|
33
32
|
|
|
@@ -243,7 +242,16 @@ function setNodePath(node, options) {
|
|
|
243
242
|
node[key] = null;
|
|
244
243
|
}
|
|
245
244
|
} else if (type === 'virtual') {
|
|
246
|
-
node[key]
|
|
245
|
+
node[key] ||= {};
|
|
246
|
+
const virtual = schema.virtual(key);
|
|
247
|
+
setNodePath(node[key], {
|
|
248
|
+
// @ts-ignore
|
|
249
|
+
modelName: virtual.options.ref,
|
|
250
|
+
path: path.slice(parts.length),
|
|
251
|
+
depth: depth + 1,
|
|
252
|
+
exclude
|
|
253
|
+
});
|
|
254
|
+
halt = true;
|
|
247
255
|
} else if (type !== 'nested') {
|
|
248
256
|
throw new Error(`Unknown path on ${modelName}: ${key}.`);
|
|
249
257
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.wrapQuery = wrapQuery;
|
|
7
|
+
// Wrapper that allows a mongoose query object to be returned
|
|
8
|
+
// to access chained methods while still resolving with a
|
|
9
|
+
// transformed value. Allows methods to behave like other find
|
|
10
|
+
// methods and importantly allow custom population with the same API.
|
|
11
|
+
function wrapQuery(query, fn) {
|
|
12
|
+
const runQuery = query.then.bind(query);
|
|
13
|
+
query.then = async (resolve, reject) => {
|
|
14
|
+
try {
|
|
15
|
+
resolve(await fn(runQuery()));
|
|
16
|
+
} catch (err) {
|
|
17
|
+
reject(err);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
return query;
|
|
21
|
+
}
|
package/dist/cjs/schema.js
CHANGED
|
@@ -13,8 +13,8 @@ var _slug = require("./slug");
|
|
|
13
13
|
var _search = require("./search");
|
|
14
14
|
var _assign = require("./assign");
|
|
15
15
|
var _include = require("./include");
|
|
16
|
-
var _references = require("./references");
|
|
17
16
|
var _softDelete = require("./soft-delete");
|
|
17
|
+
var _deleteHooks = require("./delete-hooks");
|
|
18
18
|
var _disallowed = require("./disallowed");
|
|
19
19
|
var _validation = require("./validation");
|
|
20
20
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
@@ -45,10 +45,13 @@ function createSchema(definition, options = {}) {
|
|
|
45
45
|
toObject: _serialization.serializeOptions,
|
|
46
46
|
...options
|
|
47
47
|
});
|
|
48
|
+
|
|
49
|
+
// Soft Delete needs to be applied
|
|
50
|
+
// first for hooks to work correctly.
|
|
51
|
+
(0, _softDelete.applySoftDelete)(schema);
|
|
48
52
|
(0, _validation.applyValidation)(schema, definition);
|
|
53
|
+
(0, _deleteHooks.applyDeleteHooks)(schema, definition);
|
|
49
54
|
(0, _search.applySearch)(schema, definition);
|
|
50
|
-
(0, _softDelete.applySoftDelete)(schema);
|
|
51
|
-
(0, _references.applyReferences)(schema);
|
|
52
55
|
(0, _disallowed.applyDisallowed)(schema);
|
|
53
56
|
(0, _include.applyInclude)(schema);
|
|
54
57
|
(0, _assign.applyAssign)(schema);
|
package/dist/cjs/search.js
CHANGED
|
@@ -13,6 +13,7 @@ var _utils = require("./utils");
|
|
|
13
13
|
var _const = require("./const");
|
|
14
14
|
var _validation = require("./validation");
|
|
15
15
|
var _env = require("./env");
|
|
16
|
+
var _query = require("./query");
|
|
16
17
|
var _warn = _interopRequireDefault(require("./warn"));
|
|
17
18
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
18
19
|
const {
|
|
@@ -49,29 +50,17 @@ function applySearch(schema, definition) {
|
|
|
49
50
|
_logger.default.info(`Search query for ${this.modelName}:\n`, JSON.stringify(query, null, 2));
|
|
50
51
|
}
|
|
51
52
|
const mQuery = this.find(query).sort(resolveSort(sort, schema)).skip(skip).limit(limit);
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
data,
|
|
64
|
-
meta: {
|
|
65
|
-
total,
|
|
66
|
-
skip,
|
|
67
|
-
limit
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
} catch (err) {
|
|
71
|
-
reject(err);
|
|
72
|
-
}
|
|
73
|
-
};
|
|
74
|
-
return mQuery;
|
|
53
|
+
return (0, _query.wrapQuery)(mQuery, async promise => {
|
|
54
|
+
const [data, total] = await Promise.all([promise, this.countDocuments(query)]);
|
|
55
|
+
return {
|
|
56
|
+
data,
|
|
57
|
+
meta: {
|
|
58
|
+
total,
|
|
59
|
+
skip,
|
|
60
|
+
limit
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
});
|
|
75
64
|
});
|
|
76
65
|
}
|
|
77
66
|
function searchValidation(options = {}) {
|
|
@@ -8,7 +8,8 @@ var _lodash = require("lodash");
|
|
|
8
8
|
var _include = require("./include");
|
|
9
9
|
var _access = require("./access");
|
|
10
10
|
var _utils = require("./utils");
|
|
11
|
-
const
|
|
11
|
+
const DISALLOWED_FIELDS = ['deleted', 'deletedRefs'];
|
|
12
|
+
const serializeOptions = exports.serializeOptions = {
|
|
12
13
|
getters: true,
|
|
13
14
|
versionKey: false,
|
|
14
15
|
transform: (doc, ret, options) => {
|
|
@@ -17,11 +18,12 @@ const serializeOptions = {
|
|
|
17
18
|
transformField(ret, doc.schema.obj, options);
|
|
18
19
|
}
|
|
19
20
|
};
|
|
20
|
-
exports.serializeOptions = serializeOptions;
|
|
21
21
|
function transformField(obj, field, options) {
|
|
22
22
|
if (Array.isArray(obj)) {
|
|
23
23
|
for (let el of obj) {
|
|
24
24
|
transformField(el, field, options);
|
|
25
|
+
// Delete ids in array elements.
|
|
26
|
+
delete el.id;
|
|
25
27
|
}
|
|
26
28
|
} else if ((0, _lodash.isPlainObject)(obj)) {
|
|
27
29
|
for (let [key, val] of Object.entries(obj)) {
|
|
@@ -37,7 +39,7 @@ function isAllowedField(key, field, options) {
|
|
|
37
39
|
if (key[0] === '_') {
|
|
38
40
|
// Strip internal keys like _id and __v
|
|
39
41
|
return false;
|
|
40
|
-
} else if (key
|
|
42
|
+
} else if (DISALLOWED_FIELDS.includes(key)) {
|
|
41
43
|
// Strip "deleted" field which defaults
|
|
42
44
|
// to false and should not be exposed.
|
|
43
45
|
return false;
|