@bedrockio/model 0.7.0 → 0.7.2
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 +5 -5
- package/dist/cjs/assign.js +1 -1
- package/dist/cjs/validation.js +60 -20
- package/package.json +5 -5
- package/src/assign.js +1 -1
- package/src/validation.js +55 -23
- package/types/validation.d.ts +1 -2
- package/types/validation.d.ts.map +1 -1
package/README.md
CHANGED
|
@@ -1579,11 +1579,11 @@ user.assign(ctx.request.body);
|
|
|
1579
1579
|
Object.assign(user, ctx.request.body);
|
|
1580
1580
|
```
|
|
1581
1581
|
|
|
1582
|
-
This is functionally identical to `Object.assign` with the exception that
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1582
|
+
This is functionally identical to `Object.assign` with the exception that fields
|
|
1583
|
+
can be unset by passing falsy values. This method is provided as `undefined`
|
|
1584
|
+
cannot be represented in JSON which requires using either a `null` or empty
|
|
1585
|
+
string, both of which would be stored in the database if naively assigned with
|
|
1586
|
+
`Object.assign`.
|
|
1587
1587
|
|
|
1588
1588
|
### Upsert
|
|
1589
1589
|
|
package/dist/cjs/assign.js
CHANGED
|
@@ -12,7 +12,7 @@ function applyAssign(schema) {
|
|
|
12
12
|
schema.method('assign', function assign(fields) {
|
|
13
13
|
unsetReferenceFields(fields, schema.obj);
|
|
14
14
|
for (let [path, value] of Object.entries(flattenObject(fields))) {
|
|
15
|
-
if (value === null) {
|
|
15
|
+
if (value === null || value === '') {
|
|
16
16
|
this.set(path, undefined);
|
|
17
17
|
} else {
|
|
18
18
|
this.set(path, value);
|
package/dist/cjs/validation.js
CHANGED
|
@@ -83,7 +83,7 @@ function applyValidation(schema, definition) {
|
|
|
83
83
|
model: this,
|
|
84
84
|
appendSchema,
|
|
85
85
|
allowInclude,
|
|
86
|
-
|
|
86
|
+
stripEmpty: true,
|
|
87
87
|
stripDeleted: true,
|
|
88
88
|
stripTimestamps: true,
|
|
89
89
|
allowDefaultTags: true,
|
|
@@ -106,7 +106,7 @@ function applyValidation(schema, definition) {
|
|
|
106
106
|
model: this,
|
|
107
107
|
appendSchema,
|
|
108
108
|
allowInclude,
|
|
109
|
-
|
|
109
|
+
allowNull: true,
|
|
110
110
|
skipRequired: true,
|
|
111
111
|
stripUnknown: true,
|
|
112
112
|
stripDeleted: true,
|
|
@@ -122,13 +122,6 @@ function applyValidation(schema, definition) {
|
|
|
122
122
|
})
|
|
123
123
|
});
|
|
124
124
|
});
|
|
125
|
-
schema.static('getDeleteValidation', function getDeleteValidation() {
|
|
126
|
-
const allowed = definition.access?.delete || 'all';
|
|
127
|
-
return validateAccess('delete', _yada.default, allowed, {
|
|
128
|
-
model: this,
|
|
129
|
-
message: 'You do not have permissions to delete this document.'
|
|
130
|
-
});
|
|
131
|
-
});
|
|
132
125
|
schema.static('getSearchValidation', function getSearchValidation(options = {}) {
|
|
133
126
|
const {
|
|
134
127
|
defaults,
|
|
@@ -138,6 +131,7 @@ function applyValidation(schema, definition) {
|
|
|
138
131
|
return getSchemaFromMongoose(schema, {
|
|
139
132
|
model: this,
|
|
140
133
|
allowNull: true,
|
|
134
|
+
stripEmpty: true,
|
|
141
135
|
allowSearch: true,
|
|
142
136
|
skipRequired: true,
|
|
143
137
|
allowInclude: true,
|
|
@@ -152,6 +146,13 @@ function applyValidation(schema, definition) {
|
|
|
152
146
|
})
|
|
153
147
|
});
|
|
154
148
|
});
|
|
149
|
+
schema.static('getDeleteValidation', function getDeleteValidation() {
|
|
150
|
+
const allowed = definition.access?.delete || 'all';
|
|
151
|
+
return validateAccess('delete', _yada.default, allowed, {
|
|
152
|
+
model: this,
|
|
153
|
+
message: 'You do not have permissions to delete this document.'
|
|
154
|
+
});
|
|
155
|
+
});
|
|
155
156
|
schema.static('getIncludeValidation', function getIncludeValidation() {
|
|
156
157
|
return _include.INCLUDE_FIELD_SCHEMA;
|
|
157
158
|
});
|
|
@@ -228,6 +229,7 @@ function getObjectSchema(arg, options) {
|
|
|
228
229
|
} else if (typeof arg === 'object') {
|
|
229
230
|
const {
|
|
230
231
|
stripUnknown,
|
|
232
|
+
stripEmpty,
|
|
231
233
|
expandDotSyntax
|
|
232
234
|
} = options;
|
|
233
235
|
const map = {};
|
|
@@ -242,6 +244,11 @@ function getObjectSchema(arg, options) {
|
|
|
242
244
|
stripUnknown: true
|
|
243
245
|
});
|
|
244
246
|
}
|
|
247
|
+
if (stripEmpty) {
|
|
248
|
+
schema = schema.options({
|
|
249
|
+
stripEmpty: true
|
|
250
|
+
});
|
|
251
|
+
}
|
|
245
252
|
if (expandDotSyntax) {
|
|
246
253
|
schema = schema.options({
|
|
247
254
|
expandDotSyntax: true
|
|
@@ -285,15 +292,24 @@ function getSchemaForTypedef(typedef, options = {}) {
|
|
|
285
292
|
} else {
|
|
286
293
|
schema = getSchemaForType(type, options);
|
|
287
294
|
|
|
288
|
-
//
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
295
|
+
// Null may be allowed to unset non-required fields
|
|
296
|
+
// in an update operation or to search for non-existent
|
|
297
|
+
// fields in a search operation.
|
|
298
|
+
if (allowNull(typedef, options)) {
|
|
292
299
|
schema = schema.nullable();
|
|
293
|
-
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Empty strings are allowed to unset non-required fields
|
|
303
|
+
// in an update operation. Technically this should be null,
|
|
304
|
+
// however empty strings are allowed here as well as they
|
|
305
|
+
// generally play nicer with front-end components. For
|
|
306
|
+
// ObjectId fields the empty string must be appended here.
|
|
307
|
+
if (disallowEmpty(typedef, options)) {
|
|
294
308
|
schema = schema.options({
|
|
295
|
-
allowEmpty:
|
|
309
|
+
allowEmpty: false
|
|
296
310
|
});
|
|
311
|
+
} else if (appendEmpty(typedef, options)) {
|
|
312
|
+
schema = _yada.default.allow(schema, '');
|
|
297
313
|
}
|
|
298
314
|
}
|
|
299
315
|
if (isRequired(typedef, options)) {
|
|
@@ -406,13 +422,37 @@ function isRequired(typedef, options) {
|
|
|
406
422
|
return typedef.required && !typedef.default && !options.skipRequired;
|
|
407
423
|
}
|
|
408
424
|
function allowNull(typedef, options) {
|
|
409
|
-
|
|
425
|
+
if (!options.allowNull) {
|
|
426
|
+
return false;
|
|
427
|
+
}
|
|
428
|
+
const {
|
|
429
|
+
required,
|
|
430
|
+
type
|
|
431
|
+
} = typedef;
|
|
432
|
+
return !required && type !== 'Boolean';
|
|
410
433
|
}
|
|
411
|
-
function
|
|
412
|
-
|
|
434
|
+
function disallowEmpty(typedef, options) {
|
|
435
|
+
if (!options.allowNull) {
|
|
436
|
+
return false;
|
|
437
|
+
}
|
|
438
|
+
const {
|
|
439
|
+
type
|
|
440
|
+
} = typedef;
|
|
441
|
+
if (type === 'String' || type === 'ObjectId') {
|
|
442
|
+
return typedef.required;
|
|
443
|
+
} else {
|
|
444
|
+
return false;
|
|
445
|
+
}
|
|
413
446
|
}
|
|
414
|
-
function
|
|
415
|
-
|
|
447
|
+
function appendEmpty(typedef, options) {
|
|
448
|
+
if (!options.allowNull) {
|
|
449
|
+
return false;
|
|
450
|
+
}
|
|
451
|
+
const {
|
|
452
|
+
required,
|
|
453
|
+
type
|
|
454
|
+
} = typedef;
|
|
455
|
+
return !required && type === 'ObjectId';
|
|
416
456
|
}
|
|
417
457
|
function isExcludedField(field, options) {
|
|
418
458
|
if ((0, _utils.isSchemaTypedef)(field)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bedrockio/model",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.2",
|
|
4
4
|
"description": "Bedrock utilities for model creation.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -30,22 +30,22 @@
|
|
|
30
30
|
"lodash": "^4.17.21"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
|
-
"@bedrockio/yada": "^1.
|
|
34
|
-
"mongoose": "^8.
|
|
33
|
+
"@bedrockio/yada": "^1.2.2",
|
|
34
|
+
"mongoose": "^8.6.2"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@babel/cli": "^7.20.7",
|
|
38
38
|
"@babel/core": "^7.20.12",
|
|
39
39
|
"@babel/preset-env": "^7.20.2",
|
|
40
40
|
"@bedrockio/prettier-config": "^1.0.2",
|
|
41
|
-
"@bedrockio/yada": "^1.
|
|
41
|
+
"@bedrockio/yada": "^1.2.2",
|
|
42
42
|
"@shelf/jest-mongodb": "^4.3.2",
|
|
43
43
|
"eslint": "^8.33.0",
|
|
44
44
|
"eslint-plugin-bedrock": "^1.0.26",
|
|
45
45
|
"jest": "^29.4.1",
|
|
46
46
|
"jest-environment-node": "^29.4.1",
|
|
47
47
|
"mongodb": "^6.5.0",
|
|
48
|
-
"mongoose": "^8.
|
|
48
|
+
"mongoose": "^8.6.2",
|
|
49
49
|
"prettier-eslint": "^15.0.1",
|
|
50
50
|
"typescript": "^4.9.5"
|
|
51
51
|
},
|
package/src/assign.js
CHANGED
|
@@ -7,7 +7,7 @@ export function applyAssign(schema) {
|
|
|
7
7
|
schema.method('assign', function assign(fields) {
|
|
8
8
|
unsetReferenceFields(fields, schema.obj);
|
|
9
9
|
for (let [path, value] of Object.entries(flattenObject(fields))) {
|
|
10
|
-
if (value === null) {
|
|
10
|
+
if (value === null || value === '') {
|
|
11
11
|
this.set(path, undefined);
|
|
12
12
|
} else {
|
|
13
13
|
this.set(path, value);
|
package/src/validation.js
CHANGED
|
@@ -95,7 +95,7 @@ export function applyValidation(schema, definition) {
|
|
|
95
95
|
model: this,
|
|
96
96
|
appendSchema,
|
|
97
97
|
allowInclude,
|
|
98
|
-
|
|
98
|
+
stripEmpty: true,
|
|
99
99
|
stripDeleted: true,
|
|
100
100
|
stripTimestamps: true,
|
|
101
101
|
allowDefaultTags: true,
|
|
@@ -119,7 +119,7 @@ export function applyValidation(schema, definition) {
|
|
|
119
119
|
model: this,
|
|
120
120
|
appendSchema,
|
|
121
121
|
allowInclude,
|
|
122
|
-
|
|
122
|
+
allowNull: true,
|
|
123
123
|
skipRequired: true,
|
|
124
124
|
stripUnknown: true,
|
|
125
125
|
stripDeleted: true,
|
|
@@ -137,22 +137,14 @@ export function applyValidation(schema, definition) {
|
|
|
137
137
|
}
|
|
138
138
|
);
|
|
139
139
|
|
|
140
|
-
schema.static('getDeleteValidation', function getDeleteValidation() {
|
|
141
|
-
const allowed = definition.access?.delete || 'all';
|
|
142
|
-
return validateAccess('delete', yd, allowed, {
|
|
143
|
-
model: this,
|
|
144
|
-
message: 'You do not have permissions to delete this document.',
|
|
145
|
-
});
|
|
146
|
-
});
|
|
147
|
-
|
|
148
140
|
schema.static(
|
|
149
141
|
'getSearchValidation',
|
|
150
142
|
function getSearchValidation(options = {}) {
|
|
151
143
|
const { defaults, includeDeleted, ...appendSchema } = options;
|
|
152
|
-
|
|
153
144
|
return getSchemaFromMongoose(schema, {
|
|
154
145
|
model: this,
|
|
155
146
|
allowNull: true,
|
|
147
|
+
stripEmpty: true,
|
|
156
148
|
allowSearch: true,
|
|
157
149
|
skipRequired: true,
|
|
158
150
|
allowInclude: true,
|
|
@@ -169,6 +161,14 @@ export function applyValidation(schema, definition) {
|
|
|
169
161
|
}
|
|
170
162
|
);
|
|
171
163
|
|
|
164
|
+
schema.static('getDeleteValidation', function getDeleteValidation() {
|
|
165
|
+
const allowed = definition.access?.delete || 'all';
|
|
166
|
+
return validateAccess('delete', yd, allowed, {
|
|
167
|
+
model: this,
|
|
168
|
+
message: 'You do not have permissions to delete this document.',
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
|
|
172
172
|
schema.static('getIncludeValidation', function getIncludeValidation() {
|
|
173
173
|
return INCLUDE_FIELD_SCHEMA;
|
|
174
174
|
});
|
|
@@ -239,7 +239,7 @@ function getObjectSchema(arg, options) {
|
|
|
239
239
|
} else if (Array.isArray(arg)) {
|
|
240
240
|
return getArraySchema(arg, options);
|
|
241
241
|
} else if (typeof arg === 'object') {
|
|
242
|
-
const { stripUnknown, expandDotSyntax } = options;
|
|
242
|
+
const { stripUnknown, stripEmpty, expandDotSyntax } = options;
|
|
243
243
|
const map = {};
|
|
244
244
|
for (let [key, field] of Object.entries(arg)) {
|
|
245
245
|
if (!isExcludedField(field, options)) {
|
|
@@ -254,6 +254,13 @@ function getObjectSchema(arg, options) {
|
|
|
254
254
|
stripUnknown: true,
|
|
255
255
|
});
|
|
256
256
|
}
|
|
257
|
+
|
|
258
|
+
if (stripEmpty) {
|
|
259
|
+
schema = schema.options({
|
|
260
|
+
stripEmpty: true,
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
|
|
257
264
|
if (expandDotSyntax) {
|
|
258
265
|
schema = schema.options({
|
|
259
266
|
expandDotSyntax: true,
|
|
@@ -300,15 +307,24 @@ function getSchemaForTypedef(typedef, options = {}) {
|
|
|
300
307
|
} else {
|
|
301
308
|
schema = getSchemaForType(type, options);
|
|
302
309
|
|
|
303
|
-
//
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
310
|
+
// Null may be allowed to unset non-required fields
|
|
311
|
+
// in an update operation or to search for non-existent
|
|
312
|
+
// fields in a search operation.
|
|
313
|
+
if (allowNull(typedef, options)) {
|
|
307
314
|
schema = schema.nullable();
|
|
308
|
-
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// Empty strings are allowed to unset non-required fields
|
|
318
|
+
// in an update operation. Technically this should be null,
|
|
319
|
+
// however empty strings are allowed here as well as they
|
|
320
|
+
// generally play nicer with front-end components. For
|
|
321
|
+
// ObjectId fields the empty string must be appended here.
|
|
322
|
+
if (disallowEmpty(typedef, options)) {
|
|
309
323
|
schema = schema.options({
|
|
310
|
-
allowEmpty:
|
|
324
|
+
allowEmpty: false,
|
|
311
325
|
});
|
|
326
|
+
} else if (appendEmpty(typedef, options)) {
|
|
327
|
+
schema = yd.allow(schema, '');
|
|
312
328
|
}
|
|
313
329
|
}
|
|
314
330
|
|
|
@@ -465,15 +481,31 @@ function isRequired(typedef, options) {
|
|
|
465
481
|
}
|
|
466
482
|
|
|
467
483
|
function allowNull(typedef, options) {
|
|
468
|
-
|
|
484
|
+
if (!options.allowNull) {
|
|
485
|
+
return false;
|
|
486
|
+
}
|
|
487
|
+
const { required, type } = typedef;
|
|
488
|
+
return !required && type !== 'Boolean';
|
|
469
489
|
}
|
|
470
490
|
|
|
471
|
-
function
|
|
472
|
-
|
|
491
|
+
function disallowEmpty(typedef, options) {
|
|
492
|
+
if (!options.allowNull) {
|
|
493
|
+
return false;
|
|
494
|
+
}
|
|
495
|
+
const { type } = typedef;
|
|
496
|
+
if (type === 'String' || type === 'ObjectId') {
|
|
497
|
+
return typedef.required;
|
|
498
|
+
} else {
|
|
499
|
+
return false;
|
|
500
|
+
}
|
|
473
501
|
}
|
|
474
502
|
|
|
475
|
-
function
|
|
476
|
-
|
|
503
|
+
function appendEmpty(typedef, options) {
|
|
504
|
+
if (!options.allowNull) {
|
|
505
|
+
return false;
|
|
506
|
+
}
|
|
507
|
+
const { required, type } = typedef;
|
|
508
|
+
return !required && type === 'ObjectId';
|
|
477
509
|
}
|
|
478
510
|
|
|
479
511
|
function isExcludedField(field, options) {
|
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;
|
|
@@ -68,7 +67,7 @@ export const OBJECT_ID_SCHEMA: {
|
|
|
68
67
|
eth(): any;
|
|
69
68
|
swift(): any;
|
|
70
69
|
mongo(): any;
|
|
71
|
-
format(name: any, fn: any):
|
|
70
|
+
format(name: any, fn: any): any;
|
|
72
71
|
toString(): any;
|
|
73
72
|
assertions: any[];
|
|
74
73
|
meta: {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.js"],"names":[],"mappings":"AAkFA,kDAEC;AAED,oEAgGC;AAsBD,wEA2BC;
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.js"],"names":[],"mappings":"AAkFA,kDAEC;AAED,oEAgGC;AAsBD,wEA2BC;AAkVD;;;EAEC;AAED;;;EAOC;AAljBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAQK"}
|