mongoose 9.9.2 → 9.9.3
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/cast/double.js +6 -0
- package/lib/cast/int32.js +6 -0
- package/lib/document.js +65 -31
- package/lib/internal.js +2 -0
- package/package.json +1 -1
package/lib/cast/double.js
CHANGED
|
@@ -30,6 +30,12 @@ module.exports = function castDouble(val) {
|
|
|
30
30
|
assert.ok(false);
|
|
31
31
|
}
|
|
32
32
|
} else if (typeof val === 'object') {
|
|
33
|
+
if (Array.isArray(val)) {
|
|
34
|
+
// `[5].valueOf()` returns the array itself, so without this guard a
|
|
35
|
+
// single-element or empty array would fall through to `Number(tempVal)`
|
|
36
|
+
// below and silently coerce instead of throwing.
|
|
37
|
+
assert.ok(false);
|
|
38
|
+
}
|
|
33
39
|
const tempVal = val.valueOf() ?? val.toString();
|
|
34
40
|
// ex: { a: 'im an object, valueOf: () => 'helloworld' } // throw an error
|
|
35
41
|
if (typeof tempVal === 'string') {
|
package/lib/cast/int32.js
CHANGED
|
@@ -20,6 +20,12 @@ module.exports = function castInt32(val) {
|
|
|
20
20
|
if (val === '') {
|
|
21
21
|
return null;
|
|
22
22
|
}
|
|
23
|
+
if (Array.isArray(val)) {
|
|
24
|
+
// `Number([5])` is `5` and `Number([])` is `0`, so without this guard a
|
|
25
|
+
// single-element or empty array would silently coerce instead of throwing,
|
|
26
|
+
// unlike every other array input and unlike `castNumber()`'s own guard.
|
|
27
|
+
assert.ok(false);
|
|
28
|
+
}
|
|
23
29
|
|
|
24
30
|
const coercedVal = isBsonType(val, 'Long') ? val.toNumber() : Number(val);
|
|
25
31
|
|
package/lib/document.js
CHANGED
|
@@ -2570,25 +2570,15 @@ Document.prototype.isSelected = function isSelected(path) {
|
|
|
2570
2570
|
return path.some(p => this.$__isSelected(p));
|
|
2571
2571
|
}
|
|
2572
2572
|
|
|
2573
|
-
const
|
|
2574
|
-
|
|
2573
|
+
const index = _getProjectionIndex(this);
|
|
2574
|
+
const paths = index.paths;
|
|
2575
|
+
const inclusive = index.inclusive;
|
|
2575
2576
|
|
|
2576
|
-
if (
|
|
2577
|
+
if (index.onlyId) {
|
|
2577
2578
|
// only _id was selected.
|
|
2578
2579
|
return this.$__.selected._id === 0;
|
|
2579
2580
|
}
|
|
2580
2581
|
|
|
2581
|
-
for (const cur of paths) {
|
|
2582
|
-
if (cur === '_id') {
|
|
2583
|
-
continue;
|
|
2584
|
-
}
|
|
2585
|
-
if (!isDefiningProjection(this.$__.selected[cur])) {
|
|
2586
|
-
continue;
|
|
2587
|
-
}
|
|
2588
|
-
inclusive = !!this.$__.selected[cur];
|
|
2589
|
-
break;
|
|
2590
|
-
}
|
|
2591
|
-
|
|
2592
2582
|
if (inclusive === null) {
|
|
2593
2583
|
return true;
|
|
2594
2584
|
}
|
|
@@ -2599,6 +2589,25 @@ Document.prototype.isSelected = function isSelected(path) {
|
|
|
2599
2589
|
|
|
2600
2590
|
const pathHasDot = path.indexOf('.') !== -1;
|
|
2601
2591
|
|
|
2592
|
+
if (!index.hasNestedKey) {
|
|
2593
|
+
// No projection key is nested, so no key can start with `path + '.'` and
|
|
2594
|
+
// only the "is an ancestor of `path` projected?" check below can match.
|
|
2595
|
+
// Every ancestor that matches returns the same value, so we can walk
|
|
2596
|
+
// `path`'s ancestors instead of scanning every projection key. This keeps
|
|
2597
|
+
// `isSelected()` O(depth of path) rather than O(number of projected paths),
|
|
2598
|
+
// which matters because `toObject({ getters: true })` calls this once per
|
|
2599
|
+
// schema path. Re: gh-16373
|
|
2600
|
+
if (pathHasDot) {
|
|
2601
|
+
for (let dot = path.indexOf('.'); dot !== -1; dot = path.indexOf('.', dot + 1)) {
|
|
2602
|
+
const ancestor = path.slice(0, dot);
|
|
2603
|
+
if (ancestor !== '_id' && Object.hasOwn(this.$__.selected, ancestor)) {
|
|
2604
|
+
return inclusive;
|
|
2605
|
+
}
|
|
2606
|
+
}
|
|
2607
|
+
}
|
|
2608
|
+
return !inclusive;
|
|
2609
|
+
}
|
|
2610
|
+
|
|
2602
2611
|
for (const cur of paths) {
|
|
2603
2612
|
if (cur === '_id') {
|
|
2604
2613
|
continue;
|
|
@@ -2615,6 +2624,43 @@ Document.prototype.isSelected = function isSelected(path) {
|
|
|
2615
2624
|
return !inclusive;
|
|
2616
2625
|
};
|
|
2617
2626
|
|
|
2627
|
+
/*!
|
|
2628
|
+
* Computes and caches the derived properties of `doc.$__.selected` that
|
|
2629
|
+
* `isSelected()` and `isDirectSelected()` would otherwise recompute on every
|
|
2630
|
+
* call. `$__.selected` is assigned once in the Document constructor and never
|
|
2631
|
+
* mutated afterwards, so this can safely be cached for the document's lifetime.
|
|
2632
|
+
*/
|
|
2633
|
+
|
|
2634
|
+
function _getProjectionIndex(doc) {
|
|
2635
|
+
if (doc.$__.selectedIndex !== undefined) {
|
|
2636
|
+
return doc.$__.selectedIndex;
|
|
2637
|
+
}
|
|
2638
|
+
|
|
2639
|
+
const selected = doc.$__.selected;
|
|
2640
|
+
const paths = Object.keys(selected);
|
|
2641
|
+
let inclusive = null;
|
|
2642
|
+
let hasNestedKey = false;
|
|
2643
|
+
|
|
2644
|
+
for (const cur of paths) {
|
|
2645
|
+
if (cur === '_id') {
|
|
2646
|
+
continue;
|
|
2647
|
+
}
|
|
2648
|
+
if (cur.indexOf('.') !== -1) {
|
|
2649
|
+
hasNestedKey = true;
|
|
2650
|
+
}
|
|
2651
|
+
if (inclusive === null && isDefiningProjection(selected[cur])) {
|
|
2652
|
+
inclusive = !!selected[cur];
|
|
2653
|
+
}
|
|
2654
|
+
}
|
|
2655
|
+
|
|
2656
|
+
return (doc.$__.selectedIndex = {
|
|
2657
|
+
paths,
|
|
2658
|
+
inclusive,
|
|
2659
|
+
hasNestedKey,
|
|
2660
|
+
onlyId: paths.length === 1 && paths[0] === '_id'
|
|
2661
|
+
});
|
|
2662
|
+
}
|
|
2663
|
+
|
|
2618
2664
|
Document.prototype.$__isSelected = Document.prototype.isSelected;
|
|
2619
2665
|
|
|
2620
2666
|
/**
|
|
@@ -2650,34 +2696,22 @@ Document.prototype.isDirectSelected = function isDirectSelected(path) {
|
|
|
2650
2696
|
return path.some(p => this.isDirectSelected(p));
|
|
2651
2697
|
}
|
|
2652
2698
|
|
|
2653
|
-
const
|
|
2654
|
-
let inclusive = null;
|
|
2699
|
+
const index = _getProjectionIndex(this);
|
|
2655
2700
|
|
|
2656
|
-
if (
|
|
2701
|
+
if (index.onlyId) {
|
|
2657
2702
|
// only _id was selected.
|
|
2658
2703
|
return this.$__.selected._id === 0;
|
|
2659
2704
|
}
|
|
2660
2705
|
|
|
2661
|
-
|
|
2662
|
-
if (cur === '_id') {
|
|
2663
|
-
continue;
|
|
2664
|
-
}
|
|
2665
|
-
if (!isDefiningProjection(this.$__.selected[cur])) {
|
|
2666
|
-
continue;
|
|
2667
|
-
}
|
|
2668
|
-
inclusive = !!this.$__.selected[cur];
|
|
2669
|
-
break;
|
|
2670
|
-
}
|
|
2671
|
-
|
|
2672
|
-
if (inclusive === null) {
|
|
2706
|
+
if (index.inclusive === null) {
|
|
2673
2707
|
return true;
|
|
2674
2708
|
}
|
|
2675
2709
|
|
|
2676
2710
|
if (Object.hasOwn(this.$__.selected, path)) {
|
|
2677
|
-
return inclusive;
|
|
2711
|
+
return index.inclusive;
|
|
2678
2712
|
}
|
|
2679
2713
|
|
|
2680
|
-
return !inclusive;
|
|
2714
|
+
return !index.inclusive;
|
|
2681
2715
|
};
|
|
2682
2716
|
|
|
2683
2717
|
/**
|
package/lib/internal.js
CHANGED
|
@@ -17,6 +17,8 @@ InternalCache.prototype.strictMode = true;
|
|
|
17
17
|
|
|
18
18
|
InternalCache.prototype.fullPath = undefined;
|
|
19
19
|
InternalCache.prototype.selected = undefined;
|
|
20
|
+
// Lazily computed index over `selected`, see `_getProjectionIndex()` in document.js
|
|
21
|
+
InternalCache.prototype.selectedIndex = undefined;
|
|
20
22
|
InternalCache.prototype.shardval = undefined;
|
|
21
23
|
InternalCache.prototype.saveError = undefined;
|
|
22
24
|
InternalCache.prototype.validationError = undefined;
|