@depup/mongoose 9.1.3-depup.0 → 9.1.5-depup.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/lib/cursor/queryCursor.js +3 -0
- package/lib/document.js +7 -1
- package/lib/helpers/clone.js +15 -1
- package/lib/helpers/discriminator/mergeDiscriminatorSchema.js +5 -0
- package/lib/helpers/document/compile.js +3 -0
- package/lib/schema/array.js +3 -0
- package/lib/schema/map.js +5 -9
- package/lib/types/map.js +10 -61
- package/lib/types/subdocument.js +4 -29
- package/package.json +4 -4
- package/types/inferrawdoctype.d.ts +19 -4
|
@@ -599,6 +599,9 @@ function _nextDoc(ctx, doc, pop, callback) {
|
|
|
599
599
|
if (err != null) {
|
|
600
600
|
return callback(err);
|
|
601
601
|
}
|
|
602
|
+
if (options.session != null) {
|
|
603
|
+
doc.$session(options.session);
|
|
604
|
+
}
|
|
602
605
|
ctx.model.hooks.execPost('find', ctx.query, [[doc]]).then(() => callback(null, doc), err => callback(err));
|
|
603
606
|
});
|
|
604
607
|
}
|
package/lib/document.js
CHANGED
|
@@ -2824,7 +2824,13 @@ function _getPathsToValidate(doc, pathsToValidate, pathsToSkip, isNestedValidate
|
|
|
2824
2824
|
|
|
2825
2825
|
// Optimization: if primitive path with no validators, or array of primitives
|
|
2826
2826
|
// with no validators, skip validating this path entirely.
|
|
2827
|
-
if (!_pathType.schema &&
|
|
2827
|
+
if (!_pathType.schema &&
|
|
2828
|
+
!_pathType.embeddedSchemaType &&
|
|
2829
|
+
_pathType.validators.length === 0 &&
|
|
2830
|
+
!_pathType.$parentSchemaDocArray &&
|
|
2831
|
+
// gh-15957: skip this optimization for SchemaMap as maps can contain subdocuments
|
|
2832
|
+
// that need validation even if the map itself has no validators
|
|
2833
|
+
!_pathType.$isSchemaMap) {
|
|
2828
2834
|
paths.delete(path);
|
|
2829
2835
|
} else if (_pathType.$isMongooseArray &&
|
|
2830
2836
|
!_pathType.$isMongooseDocumentArray && // Skip document arrays...
|
package/lib/helpers/clone.js
CHANGED
|
@@ -51,11 +51,20 @@ function clone(obj, options, isArrayChild) {
|
|
|
51
51
|
clonedDoc.__index = obj.__index;
|
|
52
52
|
}
|
|
53
53
|
if (obj.__parentArray != null) {
|
|
54
|
-
clonedDoc.__parentArray = obj.__parentArray;
|
|
54
|
+
clonedDoc.__parentArray = options.parentArray ?? obj.__parentArray;
|
|
55
55
|
}
|
|
56
56
|
clonedDoc.$__setParent(options.parentDoc ?? obj.$__parent);
|
|
57
57
|
return clonedDoc;
|
|
58
58
|
}
|
|
59
|
+
if (options.retainDocuments && obj.$isMongooseMap) {
|
|
60
|
+
const clonedParent = options.parentDoc ?? obj.$__parent;
|
|
61
|
+
const MongooseMap = obj.constructor;
|
|
62
|
+
const ret = new MongooseMap({}, obj.$__path, clonedParent, obj.$__schemaType);
|
|
63
|
+
for (const [key, value] of obj) {
|
|
64
|
+
ret.$__set(key, clone(value, options));
|
|
65
|
+
}
|
|
66
|
+
return ret;
|
|
67
|
+
}
|
|
59
68
|
}
|
|
60
69
|
|
|
61
70
|
if (isPOJO(obj) && obj.$__ != null && obj._doc != null) {
|
|
@@ -187,6 +196,11 @@ function cloneArray(arr, options) {
|
|
|
187
196
|
}
|
|
188
197
|
|
|
189
198
|
arr = isMongooseArray(arr) ? arr.__array : arr;
|
|
199
|
+
if (ret.isMongooseDocumentArray) {
|
|
200
|
+
// Create new options object to avoid mutating the shared options.
|
|
201
|
+
// Subdocs need parentArray to point to their own cloned array.
|
|
202
|
+
options = { ...options, parentArray: ret };
|
|
203
|
+
}
|
|
190
204
|
for (i = 0; i < len; ++i) {
|
|
191
205
|
ret[i] = clone(arr[i], options, true);
|
|
192
206
|
}
|
|
@@ -46,6 +46,11 @@ module.exports = function mergeDiscriminatorSchema(to, from, path, seen) {
|
|
|
46
46
|
if (specialProperties.has(key)) {
|
|
47
47
|
continue;
|
|
48
48
|
}
|
|
49
|
+
if (key === 'parentSchema') {
|
|
50
|
+
// Skip parentSchema to avoid merging parent schema multiple times
|
|
51
|
+
// through child paths' back-references (gh-15966)
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
49
54
|
if (to[key] == null) {
|
|
50
55
|
to[key] = from[key];
|
|
51
56
|
} else if (isObject(from[key])) {
|
package/lib/schema/array.js
CHANGED
|
@@ -398,6 +398,9 @@ SchemaArray.prototype.cast = function(value, doc, init, prev, options) {
|
|
|
398
398
|
if (options.hydratedPopulatedDocs) {
|
|
399
399
|
opts.hydratedPopulatedDocs = options.hydratedPopulatedDocs;
|
|
400
400
|
}
|
|
401
|
+
if (options.virtuals) {
|
|
402
|
+
opts.virtuals = options.virtuals;
|
|
403
|
+
}
|
|
401
404
|
rawValue[i] = caster.applySetters(rawValue[i], doc, init, void 0, opts);
|
|
402
405
|
}
|
|
403
406
|
} catch (e) {
|
package/lib/schema/map.js
CHANGED
|
@@ -58,14 +58,10 @@ class SchemaMap extends SchemaType {
|
|
|
58
58
|
return val;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
const path = this.path;
|
|
61
|
+
const path = options?.path ?? this.path;
|
|
62
62
|
|
|
63
63
|
if (init) {
|
|
64
|
-
const map = new MongooseMap({}, path, doc, this.$__schemaType
|
|
65
|
-
|
|
66
|
-
// Use the map's path for passing to nested casts.
|
|
67
|
-
// If map's parent is a subdocument, use the relative path so nested casts get relative paths.
|
|
68
|
-
const mapPath = map.$__pathRelativeToParent != null ? map.$__pathRelativeToParent : map.$__path;
|
|
64
|
+
const map = new MongooseMap({}, path, doc, this.$__schemaType);
|
|
69
65
|
|
|
70
66
|
if (val instanceof global.Map) {
|
|
71
67
|
for (const key of val.keys()) {
|
|
@@ -73,7 +69,7 @@ class SchemaMap extends SchemaType {
|
|
|
73
69
|
if (_val == null) {
|
|
74
70
|
_val = map.$__schemaType._castNullish(_val);
|
|
75
71
|
} else {
|
|
76
|
-
_val = map.$__schemaType.cast(_val, doc, true, null, { ...options, path:
|
|
72
|
+
_val = map.$__schemaType.cast(_val, doc, true, null, { ...options, path: path + '.' + key });
|
|
77
73
|
}
|
|
78
74
|
map.$init(key, _val);
|
|
79
75
|
}
|
|
@@ -83,7 +79,7 @@ class SchemaMap extends SchemaType {
|
|
|
83
79
|
if (_val == null) {
|
|
84
80
|
_val = map.$__schemaType._castNullish(_val);
|
|
85
81
|
} else {
|
|
86
|
-
_val = map.$__schemaType.cast(_val, doc, true, null, { ...options, path:
|
|
82
|
+
_val = map.$__schemaType.cast(_val, doc, true, null, { ...options, path: path + '.' + key });
|
|
87
83
|
}
|
|
88
84
|
map.$init(key, _val);
|
|
89
85
|
}
|
|
@@ -92,7 +88,7 @@ class SchemaMap extends SchemaType {
|
|
|
92
88
|
return map;
|
|
93
89
|
}
|
|
94
90
|
|
|
95
|
-
return new MongooseMap(val, path, doc, this.$__schemaType
|
|
91
|
+
return new MongooseMap(val, path, doc, this.$__schemaType);
|
|
96
92
|
}
|
|
97
93
|
|
|
98
94
|
/**
|
package/lib/types/map.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const Mixed = require('../schema/mixed');
|
|
3
4
|
const MongooseError = require('../error/mongooseError');
|
|
4
5
|
const clone = require('../helpers/clone');
|
|
5
6
|
const deepEqual = require('../utils').deepEqual;
|
|
@@ -17,30 +18,14 @@ const populateModelSymbol = require('../helpers/symbols').populateModelSymbol;
|
|
|
17
18
|
*/
|
|
18
19
|
|
|
19
20
|
class MongooseMap extends Map {
|
|
20
|
-
constructor(v, path, doc, schemaType
|
|
21
|
+
constructor(v, path, doc, schemaType) {
|
|
21
22
|
if (getConstructorName(v) === 'Object') {
|
|
22
23
|
v = Object.keys(v).reduce((arr, key) => arr.concat([[key, v[key]]]), []);
|
|
23
24
|
}
|
|
24
25
|
super(v);
|
|
25
26
|
this.$__parent = doc?.$__ != null ? doc : null;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
// Priority: parent.$basePath (from subdoc) > options.path (from parent map/structure) > path (schema path)
|
|
29
|
-
// Subdocuments have the most up-to-date path info, so prefer that over options.path
|
|
30
|
-
if (this.$__parent?.$isSingleNested && this.$__parent.$basePath) {
|
|
31
|
-
this.$__path = this.$__parent.$basePath + '.' + path;
|
|
32
|
-
// Performance optimization: store path relative to parent subdocument
|
|
33
|
-
// to avoid string operations in set() hot path
|
|
34
|
-
this.$__pathRelativeToParent = path;
|
|
35
|
-
} else if (options?.path) {
|
|
36
|
-
this.$__path = options.path;
|
|
37
|
-
this.$__pathRelativeToParent = null;
|
|
38
|
-
} else {
|
|
39
|
-
this.$__path = path;
|
|
40
|
-
this.$__pathRelativeToParent = null;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
this.$__schemaType = schemaType;
|
|
27
|
+
this.$__path = path;
|
|
28
|
+
this.$__schemaType = schemaType == null ? new Mixed(path) : schemaType;
|
|
44
29
|
|
|
45
30
|
this.$__runDeferred();
|
|
46
31
|
}
|
|
@@ -52,14 +37,6 @@ class MongooseMap extends Map {
|
|
|
52
37
|
|
|
53
38
|
if (value?.$isSingleNested) {
|
|
54
39
|
value.$basePath = this.$__path + '.' + key;
|
|
55
|
-
// Store the path relative to parent subdoc for efficient markModified()
|
|
56
|
-
if (this.$__pathRelativeToParent != null) {
|
|
57
|
-
// Map's parent is a subdocument, store path relative to that subdoc
|
|
58
|
-
value.$pathRelativeToParent = this.$__pathRelativeToParent + '.' + key;
|
|
59
|
-
} else {
|
|
60
|
-
// Map's parent is root document, store the full path
|
|
61
|
-
value.$pathRelativeToParent = this.$__path + '.' + key;
|
|
62
|
-
}
|
|
63
40
|
}
|
|
64
41
|
}
|
|
65
42
|
|
|
@@ -159,16 +136,9 @@ class MongooseMap extends Map {
|
|
|
159
136
|
}
|
|
160
137
|
} else {
|
|
161
138
|
try {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
// For subdocuments, also pass the relative path to avoid string operations
|
|
166
|
-
if (this.$__schemaType.$isSingleNested) {
|
|
167
|
-
options.pathRelativeToParent = this.$__pathRelativeToParent != null ?
|
|
168
|
-
this.$__pathRelativeToParent + '.' + key :
|
|
169
|
-
this.$__path + '.' + key;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
139
|
+
const options = this.$__schemaType.$isMongooseDocumentArray || this.$__schemaType.$isSingleNested || this.$__schemaType.$isMongooseArray || this.$__schemaType.$isSchemaMap ?
|
|
140
|
+
{ path: fullPath.call(this) } :
|
|
141
|
+
null;
|
|
172
142
|
value = this.$__schemaType.applySetters(
|
|
173
143
|
value,
|
|
174
144
|
this.$__parent,
|
|
@@ -187,34 +157,13 @@ class MongooseMap extends Map {
|
|
|
187
157
|
|
|
188
158
|
super.set(key, value);
|
|
189
159
|
|
|
190
|
-
// Set relative path on subdocuments to avoid string operations in markModified()
|
|
191
|
-
// The path should be relative to the parent subdocument (if any), not just the key
|
|
192
|
-
if (value?.$isSingleNested) {
|
|
193
|
-
if (this.$__pathRelativeToParent != null) {
|
|
194
|
-
// Map's parent is a subdocument, store path relative to that subdoc (e.g., 'items.i2')
|
|
195
|
-
value.$pathRelativeToParent = this.$__pathRelativeToParent + '.' + key;
|
|
196
|
-
} else {
|
|
197
|
-
// Map's parent is root document, store just the full path
|
|
198
|
-
value.$pathRelativeToParent = this.$__path + '.' + key;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
160
|
if (parent?.$__ != null && !deepEqual(value, priorVal)) {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
let pathToMark;
|
|
206
|
-
if (this.$__pathRelativeToParent != null) {
|
|
207
|
-
// Parent is a subdocument - use precalculated relative path (e.g., 'items.i1')
|
|
208
|
-
pathToMark = this.$__pathRelativeToParent + '.' + key;
|
|
209
|
-
} else {
|
|
210
|
-
// Parent is root document or map - use full path
|
|
211
|
-
pathToMark = fullPath.call(this);
|
|
212
|
-
}
|
|
213
|
-
parent.markModified(pathToMark);
|
|
161
|
+
const path = fullPath.call(this);
|
|
162
|
+
parent.markModified(path);
|
|
214
163
|
// If overwriting the full document array or subdoc, make sure to clean up any paths that were modified
|
|
215
164
|
// before re: #15108
|
|
216
165
|
if (this.$__schemaType.$isMongooseDocumentArray || this.$__schemaType.$isSingleNested) {
|
|
217
|
-
cleanModifiedSubpaths(parent,
|
|
166
|
+
cleanModifiedSubpaths(parent, path);
|
|
218
167
|
}
|
|
219
168
|
}
|
|
220
169
|
|
package/lib/types/subdocument.js
CHANGED
|
@@ -26,21 +26,7 @@ function Subdocument(value, fields, parent, options) {
|
|
|
26
26
|
if (options?.path != null) {
|
|
27
27
|
this.$basePath = options.path;
|
|
28
28
|
}
|
|
29
|
-
|
|
30
|
-
this.$pathRelativeToParent = options.pathRelativeToParent;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Don't pass `path` to Document constructor: path is used for storing the
|
|
34
|
-
// absolute path to this schematype relative to the top-level document, but
|
|
35
|
-
// subdocuments use relative paths (relative to the parent document) to track changes.
|
|
36
|
-
// This avoids the subdocument's fields receiving the subdocument's path as options.path.
|
|
37
|
-
let documentOptions = options;
|
|
38
|
-
if (options?.path != null) {
|
|
39
|
-
documentOptions = Object.assign({}, options);
|
|
40
|
-
delete documentOptions.path;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
Document.call(this, value, fields, documentOptions);
|
|
29
|
+
Document.call(this, value, fields, options);
|
|
44
30
|
|
|
45
31
|
delete this.$__.priorDoc;
|
|
46
32
|
}
|
|
@@ -125,12 +111,6 @@ Subdocument.prototype.$__fullPath = function(path) {
|
|
|
125
111
|
*/
|
|
126
112
|
|
|
127
113
|
Subdocument.prototype.$__pathRelativeToParent = function(p) {
|
|
128
|
-
// If this subdocument has a stored relative path (set by map when subdoc is created),
|
|
129
|
-
// use it directly to avoid string operations
|
|
130
|
-
if (this.$pathRelativeToParent != null) {
|
|
131
|
-
return p == null ? this.$pathRelativeToParent : this.$pathRelativeToParent + '.' + p;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
114
|
if (p == null) {
|
|
135
115
|
return this.$basePath;
|
|
136
116
|
}
|
|
@@ -183,13 +163,9 @@ Subdocument.prototype.$isValid = function(path) {
|
|
|
183
163
|
Subdocument.prototype.markModified = function(path) {
|
|
184
164
|
Document.prototype.markModified.call(this, path);
|
|
185
165
|
const parent = this.$parent();
|
|
166
|
+
const fullPath = this.$__pathRelativeToParent(path);
|
|
186
167
|
|
|
187
|
-
if (parent == null) {
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
const pathToMark = this.$__pathRelativeToParent(path);
|
|
192
|
-
if (pathToMark == null) {
|
|
168
|
+
if (parent == null || fullPath == null) {
|
|
193
169
|
return;
|
|
194
170
|
}
|
|
195
171
|
|
|
@@ -197,8 +173,7 @@ Subdocument.prototype.markModified = function(path) {
|
|
|
197
173
|
if (parent.isDirectModified(myPath) || this.isNew) {
|
|
198
174
|
return;
|
|
199
175
|
}
|
|
200
|
-
|
|
201
|
-
this.$__parent.markModified(pathToMark, this);
|
|
176
|
+
this.$__parent.markModified(fullPath, this);
|
|
202
177
|
};
|
|
203
178
|
|
|
204
179
|
/*!
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@depup/mongoose",
|
|
3
3
|
"description": "Mongoose MongoDB ODM",
|
|
4
|
-
"version": "9.1.
|
|
4
|
+
"version": "9.1.5-depup.0",
|
|
5
5
|
"author": "Guillermo Rauch <guillermo@learnboost.com>",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"mongodb",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@ark/attest": "0.56.0",
|
|
32
|
-
"@mongodb-js/mongodb-downloader": "^1.1.
|
|
32
|
+
"@mongodb-js/mongodb-downloader": "^1.1.6",
|
|
33
33
|
"acquit": "1.4.0",
|
|
34
34
|
"acquit-ignore": "^0.2.2",
|
|
35
35
|
"acquit-require": "0.1.1",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"mocha": "11.7.5",
|
|
52
52
|
"moment": "2.30.1",
|
|
53
53
|
"mongodb-memory-server": "11.0.1",
|
|
54
|
-
"mongodb-runner": "^6.5.
|
|
54
|
+
"mongodb-runner": "^6.5.4",
|
|
55
55
|
"mongodb-client-encryption": "~7.0",
|
|
56
56
|
"ncp": "^2.0.0",
|
|
57
57
|
"nyc": "^17.1.0",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"sinon": "21.0.1",
|
|
60
60
|
"tsd": "0.33.0",
|
|
61
61
|
"typescript": "5.9.3",
|
|
62
|
-
"typescript-eslint": "^8.53.
|
|
62
|
+
"typescript-eslint": "^8.53.1",
|
|
63
63
|
"uuid": "^13.0.0"
|
|
64
64
|
},
|
|
65
65
|
"directories": {
|
|
@@ -29,7 +29,9 @@ declare module 'mongoose' {
|
|
|
29
29
|
SchemaDefinition,
|
|
30
30
|
TSchemaOptions extends Record<any, any> = DefaultSchemaOptions,
|
|
31
31
|
TTransformOptions = { bufferToBinary: false }
|
|
32
|
-
> =
|
|
32
|
+
> = TSchemaOptions extends { _id: false }
|
|
33
|
+
? InferRawDocTypeWithout_id<SchemaDefinition, TSchemaOptions, TTransformOptions>
|
|
34
|
+
: Require_id<InferRawDocTypeWithout_id<SchemaDefinition, TSchemaOptions, TTransformOptions>>;
|
|
33
35
|
|
|
34
36
|
/**
|
|
35
37
|
* @summary Allows users to optionally choose their own type for a schema field for stronger typing.
|
|
@@ -88,12 +90,25 @@ declare module 'mongoose' {
|
|
|
88
90
|
> =
|
|
89
91
|
IsNotNever<TypeHint> extends true ? TypeHint
|
|
90
92
|
: [PathValueType] extends [neverOrAny] ? PathValueType
|
|
91
|
-
|
|
93
|
+
: PathValueType extends Schema<infer RawDocType, any, any, any, any, any, infer TSchemaOptions, infer DocType, any, infer TSchemaDefinition> ?
|
|
94
|
+
IsItRecordAndNotAny<RawDocType> extends true ?
|
|
95
|
+
RawDocType :
|
|
96
|
+
string extends keyof TSchemaDefinition ?
|
|
97
|
+
TSchemaOptions extends { _id: false } ?
|
|
98
|
+
FlattenMaps<SubdocsToPOJOs<DocType>> :
|
|
99
|
+
Require_id<FlattenMaps<SubdocsToPOJOs<DocType>>> :
|
|
100
|
+
InferRawDocType<TSchemaDefinition, TSchemaOptions & Record<any, any>, TTransformOptions>
|
|
92
101
|
: PathValueType extends ReadonlyArray<infer Item> ?
|
|
93
102
|
IfEquals<Item, never> extends true ? any[]
|
|
94
|
-
: Item extends Schema<infer RawDocType, any, any, any, any, any,
|
|
103
|
+
: Item extends Schema<infer RawDocType, any, any, any, any, any, infer TSchemaOptions, infer DocType, any, infer TSchemaDefinition> ?
|
|
95
104
|
// If Item is a schema, infer its type.
|
|
96
|
-
Array<IsItRecordAndNotAny<RawDocType> extends true ?
|
|
105
|
+
Array<IsItRecordAndNotAny<RawDocType> extends true ?
|
|
106
|
+
RawDocType :
|
|
107
|
+
string extends keyof TSchemaDefinition ?
|
|
108
|
+
TSchemaOptions extends { _id: false } ?
|
|
109
|
+
FlattenMaps<SubdocsToPOJOs<DocType>> :
|
|
110
|
+
Require_id<FlattenMaps<SubdocsToPOJOs<DocType>>> :
|
|
111
|
+
InferRawDocType<TSchemaDefinition, TSchemaOptions & Record<any, any>, TTransformOptions>>
|
|
97
112
|
: TypeKey extends keyof Item ?
|
|
98
113
|
Item[TypeKey] extends Function | String ?
|
|
99
114
|
// If Item has a type key that's a string or a callable, it must be a scalar,
|