@bedrockio/model 0.3.2 → 0.4.1
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/dist/cjs/hydrate.js +33 -0
- package/dist/cjs/query.js +17 -0
- package/dist/cjs/schema.js +2 -0
- package/dist/cjs/search.js +13 -6
- package/dist/cjs/validation.js +5 -2
- package/package.json +3 -3
- package/src/hydrate.js +28 -0
- package/src/query.js +13 -0
- package/src/schema.js +2 -0
- package/src/search.js +11 -10
- package/src/validation.js +5 -2
- package/types/hydrate.d.ts +2 -0
- package/types/hydrate.d.ts.map +1 -0
- package/types/include.d.ts +1 -1
- package/types/query.d.ts +1 -0
- package/types/query.d.ts.map +1 -1
- package/types/schema.d.ts +0 -4
- package/types/schema.d.ts.map +1 -1
- package/types/search.d.ts +1 -1
- package/types/search.d.ts.map +1 -1
- package/types/validation.d.ts +1 -2
- package/types/validation.d.ts.map +1 -1
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.applyHydrate = applyHydrate;
|
|
7
|
+
var _mongoose = require("mongoose");
|
|
8
|
+
// Patching mongoose hydrate method to be less useless
|
|
9
|
+
// as it sets all input fields on the resulting document.
|
|
10
|
+
// Compare this to creating a new model which will only
|
|
11
|
+
// set the fields known to the schema. This results in:
|
|
12
|
+
//
|
|
13
|
+
// 1. Sending too much data down the wire
|
|
14
|
+
// 2. Potentially leaking sensitive data in aggregations.
|
|
15
|
+
|
|
16
|
+
function applyHydrate(schema) {
|
|
17
|
+
schema.static('hydrate', function hydrate(obj) {
|
|
18
|
+
return _mongoose.Model.hydrate.call(this, obj, getProjection(schema));
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Note that the mongoose docs imply that an array of
|
|
23
|
+
// strings will work for the projection, however this
|
|
24
|
+
// does not seem to work.
|
|
25
|
+
// https://mongoosejs.com/docs/7.x/docs/api/model.html
|
|
26
|
+
function getProjection(schema) {
|
|
27
|
+
const keys = Object.keys(schema.paths);
|
|
28
|
+
const result = {};
|
|
29
|
+
for (let key of keys) {
|
|
30
|
+
result[key] = true;
|
|
31
|
+
}
|
|
32
|
+
return result;
|
|
33
|
+
}
|
package/dist/cjs/query.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
+
exports.mergeQuery = mergeQuery;
|
|
6
7
|
exports.wrapQuery = wrapQuery;
|
|
7
8
|
// Wrapper that allows a mongoose query object to be returned
|
|
8
9
|
// to access chained methods while still resolving with a
|
|
@@ -18,4 +19,20 @@ function wrapQuery(query, fn) {
|
|
|
18
19
|
}
|
|
19
20
|
};
|
|
20
21
|
return query;
|
|
22
|
+
}
|
|
23
|
+
function mergeQuery(target, source) {
|
|
24
|
+
const result = Object.assign({}, target, source);
|
|
25
|
+
if (target.$or && source.$or) {
|
|
26
|
+
const {
|
|
27
|
+
$or
|
|
28
|
+
} = target;
|
|
29
|
+
result.$or = source.$or.map(conditions => {
|
|
30
|
+
return {
|
|
31
|
+
$and: [conditions, {
|
|
32
|
+
$or
|
|
33
|
+
}]
|
|
34
|
+
};
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
return result;
|
|
21
38
|
}
|
package/dist/cjs/schema.js
CHANGED
|
@@ -12,6 +12,7 @@ var _serialization = require("./serialization");
|
|
|
12
12
|
var _slug = require("./slug");
|
|
13
13
|
var _search = require("./search");
|
|
14
14
|
var _assign = require("./assign");
|
|
15
|
+
var _hydrate = require("./hydrate");
|
|
15
16
|
var _include = require("./include");
|
|
16
17
|
var _softDelete = require("./soft-delete");
|
|
17
18
|
var _deleteHooks = require("./delete-hooks");
|
|
@@ -54,6 +55,7 @@ function createSchema(definition, options = {}) {
|
|
|
54
55
|
(0, _search.applySearch)(schema, definition);
|
|
55
56
|
(0, _disallowed.applyDisallowed)(schema);
|
|
56
57
|
(0, _include.applyInclude)(schema);
|
|
58
|
+
(0, _hydrate.applyHydrate)(schema);
|
|
57
59
|
(0, _assign.applyAssign)(schema);
|
|
58
60
|
(0, _slug.applySlug)(schema);
|
|
59
61
|
return schema;
|
package/dist/cjs/search.js
CHANGED
|
@@ -25,10 +25,14 @@ const {
|
|
|
25
25
|
function applySearch(schema, definition) {
|
|
26
26
|
validateDefinition(definition);
|
|
27
27
|
applySearchCache(schema, definition);
|
|
28
|
+
const {
|
|
29
|
+
query: searchQuery,
|
|
30
|
+
fields: searchFields
|
|
31
|
+
} = definition.search || {};
|
|
28
32
|
schema.static('search', function search(body = {}) {
|
|
29
33
|
const options = {
|
|
30
34
|
..._const.SEARCH_DEFAULTS,
|
|
31
|
-
...
|
|
35
|
+
...searchQuery,
|
|
32
36
|
...body
|
|
33
37
|
};
|
|
34
38
|
const {
|
|
@@ -39,16 +43,19 @@ function applySearch(schema, definition) {
|
|
|
39
43
|
sort,
|
|
40
44
|
...rest
|
|
41
45
|
} = options;
|
|
42
|
-
|
|
46
|
+
let query = normalizeQuery(rest, schema.obj);
|
|
43
47
|
if (ids?.length) {
|
|
44
|
-
query
|
|
45
|
-
|
|
48
|
+
query = {
|
|
49
|
+
...query,
|
|
50
|
+
_id: {
|
|
51
|
+
$in: ids
|
|
52
|
+
}
|
|
46
53
|
};
|
|
47
54
|
}
|
|
48
55
|
if (keyword) {
|
|
49
|
-
|
|
56
|
+
const keywordQuery = buildKeywordQuery(schema, keyword, searchFields);
|
|
57
|
+
query = (0, _query.mergeQuery)(query, keywordQuery);
|
|
50
58
|
}
|
|
51
|
-
Object.assign(query, normalizeQuery(rest, schema.obj));
|
|
52
59
|
if (_env.debug) {
|
|
53
60
|
_logger.default.info(`Search query for ${this.modelName}:\n`, JSON.stringify(query, null, 2));
|
|
54
61
|
}
|
package/dist/cjs/validation.js
CHANGED
|
@@ -282,11 +282,14 @@ function getSchemaForTypedef(typedef, options = {}) {
|
|
|
282
282
|
schema = getObjectSchema(type, options);
|
|
283
283
|
} else {
|
|
284
284
|
schema = getSchemaForType(type, options);
|
|
285
|
+
|
|
286
|
+
// Unsetting only allowed for primitive types.
|
|
287
|
+
if (allowUnset(typedef, options)) {
|
|
288
|
+
schema = _yada.default.allow(null, '', schema);
|
|
289
|
+
}
|
|
285
290
|
}
|
|
286
291
|
if (isRequired(typedef, options)) {
|
|
287
292
|
schema = schema.required();
|
|
288
|
-
} else if (allowUnset(typedef, options)) {
|
|
289
|
-
schema = _yada.default.allow(null, '', schema);
|
|
290
293
|
}
|
|
291
294
|
if (typedef.default && options.allowDefaultTags) {
|
|
292
295
|
// Tag the default value to allow OpenAPI description
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bedrockio/model",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Bedrock utilities for model creation.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
33
|
"@bedrockio/yada": "^1.0.40",
|
|
34
|
-
"mongoose": "^7.6.
|
|
34
|
+
"mongoose": "^7.6.13"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@babel/cli": "^7.20.7",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"jest": "^29.4.1",
|
|
46
46
|
"jest-environment-node": "^29.4.1",
|
|
47
47
|
"mongodb": "^6.5.0",
|
|
48
|
-
"mongoose": "
|
|
48
|
+
"mongoose": "7.6.13",
|
|
49
49
|
"prettier-eslint": "^15.0.1",
|
|
50
50
|
"typescript": "^4.9.5"
|
|
51
51
|
},
|
package/src/hydrate.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Model } from 'mongoose';
|
|
2
|
+
|
|
3
|
+
// Patching mongoose hydrate method to be less useless
|
|
4
|
+
// as it sets all input fields on the resulting document.
|
|
5
|
+
// Compare this to creating a new model which will only
|
|
6
|
+
// set the fields known to the schema. This results in:
|
|
7
|
+
//
|
|
8
|
+
// 1. Sending too much data down the wire
|
|
9
|
+
// 2. Potentially leaking sensitive data in aggregations.
|
|
10
|
+
|
|
11
|
+
export function applyHydrate(schema) {
|
|
12
|
+
schema.static('hydrate', function hydrate(obj) {
|
|
13
|
+
return Model.hydrate.call(this, obj, getProjection(schema));
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Note that the mongoose docs imply that an array of
|
|
18
|
+
// strings will work for the projection, however this
|
|
19
|
+
// does not seem to work.
|
|
20
|
+
// https://mongoosejs.com/docs/7.x/docs/api/model.html
|
|
21
|
+
function getProjection(schema) {
|
|
22
|
+
const keys = Object.keys(schema.paths);
|
|
23
|
+
const result = {};
|
|
24
|
+
for (let key of keys) {
|
|
25
|
+
result[key] = true;
|
|
26
|
+
}
|
|
27
|
+
return result;
|
|
28
|
+
}
|
package/src/query.js
CHANGED
|
@@ -13,3 +13,16 @@ export function wrapQuery(query, fn) {
|
|
|
13
13
|
};
|
|
14
14
|
return query;
|
|
15
15
|
}
|
|
16
|
+
|
|
17
|
+
export function mergeQuery(target, source) {
|
|
18
|
+
const result = Object.assign({}, target, source);
|
|
19
|
+
if (target.$or && source.$or) {
|
|
20
|
+
const { $or } = target;
|
|
21
|
+
result.$or = source.$or.map((conditions) => {
|
|
22
|
+
return {
|
|
23
|
+
$and: [conditions, { $or }],
|
|
24
|
+
};
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
return result;
|
|
28
|
+
}
|
package/src/schema.js
CHANGED
|
@@ -7,6 +7,7 @@ import { serializeOptions } from './serialization';
|
|
|
7
7
|
import { applySlug } from './slug';
|
|
8
8
|
import { applySearch } from './search';
|
|
9
9
|
import { applyAssign } from './assign';
|
|
10
|
+
import { applyHydrate } from './hydrate';
|
|
10
11
|
import { applyInclude } from './include';
|
|
11
12
|
import { applySoftDelete } from './soft-delete';
|
|
12
13
|
import { applyDeleteHooks } from './delete-hooks';
|
|
@@ -58,6 +59,7 @@ export function createSchema(definition, options = {}) {
|
|
|
58
59
|
applySearch(schema, definition);
|
|
59
60
|
applyDisallowed(schema);
|
|
60
61
|
applyInclude(schema);
|
|
62
|
+
applyHydrate(schema);
|
|
61
63
|
applyAssign(schema);
|
|
62
64
|
applySlug(schema);
|
|
63
65
|
|
package/src/search.js
CHANGED
|
@@ -15,7 +15,7 @@ import { isDateField, isNumberField, getField } from './utils';
|
|
|
15
15
|
import { SEARCH_DEFAULTS } from './const';
|
|
16
16
|
import { OBJECT_ID_SCHEMA } from './validation';
|
|
17
17
|
import { debug } from './env';
|
|
18
|
-
import { wrapQuery } from './query';
|
|
18
|
+
import { mergeQuery, wrapQuery } from './query';
|
|
19
19
|
|
|
20
20
|
import warn from './warn';
|
|
21
21
|
|
|
@@ -26,30 +26,31 @@ export function applySearch(schema, definition) {
|
|
|
26
26
|
validateDefinition(definition);
|
|
27
27
|
applySearchCache(schema, definition);
|
|
28
28
|
|
|
29
|
+
const { query: searchQuery, fields: searchFields } = definition.search || {};
|
|
30
|
+
|
|
29
31
|
schema.static('search', function search(body = {}) {
|
|
30
32
|
const options = {
|
|
31
33
|
...SEARCH_DEFAULTS,
|
|
32
|
-
...
|
|
34
|
+
...searchQuery,
|
|
33
35
|
...body,
|
|
34
36
|
};
|
|
35
37
|
|
|
36
38
|
const { ids, keyword, skip = 0, limit, sort, ...rest } = options;
|
|
37
39
|
|
|
38
|
-
|
|
40
|
+
let query = normalizeQuery(rest, schema.obj);
|
|
39
41
|
|
|
40
42
|
if (ids?.length) {
|
|
41
|
-
query
|
|
43
|
+
query = {
|
|
44
|
+
...query,
|
|
45
|
+
_id: { $in: ids },
|
|
46
|
+
};
|
|
42
47
|
}
|
|
43
48
|
|
|
44
49
|
if (keyword) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
buildKeywordQuery(schema, keyword, definition.search?.fields)
|
|
48
|
-
);
|
|
50
|
+
const keywordQuery = buildKeywordQuery(schema, keyword, searchFields);
|
|
51
|
+
query = mergeQuery(query, keywordQuery);
|
|
49
52
|
}
|
|
50
53
|
|
|
51
|
-
Object.assign(query, normalizeQuery(rest, schema.obj));
|
|
52
|
-
|
|
53
54
|
if (debug) {
|
|
54
55
|
logger.info(
|
|
55
56
|
`Search query for ${this.modelName}:\n`,
|
package/src/validation.js
CHANGED
|
@@ -297,12 +297,15 @@ function getSchemaForTypedef(typedef, options = {}) {
|
|
|
297
297
|
schema = getObjectSchema(type, options);
|
|
298
298
|
} else {
|
|
299
299
|
schema = getSchemaForType(type, options);
|
|
300
|
+
|
|
301
|
+
// Unsetting only allowed for primitive types.
|
|
302
|
+
if (allowUnset(typedef, options)) {
|
|
303
|
+
schema = yd.allow(null, '', schema);
|
|
304
|
+
}
|
|
300
305
|
}
|
|
301
306
|
|
|
302
307
|
if (isRequired(typedef, options)) {
|
|
303
308
|
schema = schema.required();
|
|
304
|
-
} else if (allowUnset(typedef, options)) {
|
|
305
|
-
schema = yd.allow(null, '', schema);
|
|
306
309
|
}
|
|
307
310
|
|
|
308
311
|
if (typedef.default && options.allowDefaultTags) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hydrate.d.ts","sourceRoot":"","sources":["../src/hydrate.js"],"names":[],"mappings":"AAUA,gDAIC"}
|
package/types/include.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export const INCLUDE_FIELD_SCHEMA: {
|
|
|
14
14
|
meta: {};
|
|
15
15
|
required(): any;
|
|
16
16
|
default(arg: any): any;
|
|
17
|
-
custom(
|
|
17
|
+
custom(...args: import("@bedrockio/yada/types/Schema").CustomSignature): any;
|
|
18
18
|
strip(strip: any): any;
|
|
19
19
|
allow(...set: any[]): any;
|
|
20
20
|
reject(...set: any[]): any;
|
package/types/query.d.ts
CHANGED
package/types/query.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../src/query.js"],"names":[],"mappings":"AAIA,oDAUC"}
|
|
1
|
+
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../src/query.js"],"names":[],"mappings":"AAIA,oDAUC;AAED,0DAWC"}
|
package/types/schema.d.ts
CHANGED
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
*/
|
|
9
9
|
export function createSchema(definition: object, options?: mongoose.SchemaOptions): mongoose.Schema<any, mongoose.Model<any, any, any, any, any, any>, any, any, any, any, {
|
|
10
10
|
autoIndex?: boolean;
|
|
11
|
-
autoSearchIndex?: boolean;
|
|
12
11
|
autoCreate?: boolean;
|
|
13
12
|
bufferCommands?: boolean;
|
|
14
13
|
bufferTimeoutMS?: number;
|
|
@@ -31,9 +30,6 @@ export function createSchema(definition: object, options?: mongoose.SchemaOption
|
|
|
31
30
|
optimisticConcurrency?: boolean;
|
|
32
31
|
pluginTags?: string[];
|
|
33
32
|
read?: string;
|
|
34
|
-
readConcern?: {
|
|
35
|
-
level: "local" | "available" | "majority" | "snapshot" | "linearizable";
|
|
36
|
-
};
|
|
37
33
|
writeConcern?: mongoose.mongo.WriteConcern;
|
|
38
34
|
safe?: boolean | {
|
|
39
35
|
w?: string | number;
|
package/types/schema.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.js"],"names":[],"mappings":"AAqBA;;;;;;;GAOG;AACH,yCAJW,MAAM,YACN,SAAS,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAwChC;AAED,iEAsBC"}
|
package/types/search.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export function searchValidation(options?: {}): {
|
|
|
11
11
|
meta: {};
|
|
12
12
|
required(): any;
|
|
13
13
|
default(arg: any): any;
|
|
14
|
-
custom(
|
|
14
|
+
custom(...args: import("@bedrockio/yada/types/Schema").CustomSignature): any;
|
|
15
15
|
strip(strip: any): any;
|
|
16
16
|
allow(...set: any[]): any;
|
|
17
17
|
reject(...set: any[]): any;
|
package/types/search.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../src/search.js"],"names":[],"mappings":"AAwBA,
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../src/search.js"],"names":[],"mappings":"AAwBA,gEAwDC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyBC"}
|
package/types/validation.d.ts
CHANGED
|
@@ -11,7 +11,6 @@ export function getTupleValidator(types: any): {
|
|
|
11
11
|
};
|
|
12
12
|
export const OBJECT_ID_SCHEMA: {
|
|
13
13
|
required(): any;
|
|
14
|
-
allowEmpty(): any;
|
|
15
14
|
length(length: number): any;
|
|
16
15
|
min(length: number): any;
|
|
17
16
|
max(length: number): any;
|
|
@@ -73,7 +72,7 @@ export const OBJECT_ID_SCHEMA: {
|
|
|
73
72
|
assertions: any[];
|
|
74
73
|
meta: {};
|
|
75
74
|
default(arg: any): any;
|
|
76
|
-
custom(
|
|
75
|
+
custom(...args: import("@bedrockio/yada/types/Schema").CustomSignature): any;
|
|
77
76
|
strip(strip: any): any;
|
|
78
77
|
allow(...set: any[]): any;
|
|
79
78
|
reject(...set: any[]): any;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.js"],"names":[],"mappings":"AAkFA,kDAEC;AAED,oEA8FC;AAsBD,wEA2BC;
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.js"],"names":[],"mappings":"AAkFA,kDAEC;AAED,oEA8FC;AAsBD,wEA2BC;AAmSD;;;EAEC;AAED;;;EAOC;AAjgBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAQK"}
|