mongoose 7.8.8 → 7.8.10

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/gh-16033.ts ADDED
@@ -0,0 +1,35 @@
1
+ import mongoose, { Schema, Model, PipelineStage } from 'mongoose';
2
+
3
+ // Simple Item schema
4
+ const itemSchema = new Schema({ text: String, published: Boolean });
5
+ const Item: Model<any> = mongoose.model('Item', itemSchema);
6
+
7
+ type UnionSubPipelineStage = Exclude<
8
+ PipelineStage,
9
+ PipelineStage.Out | PipelineStage.Merge
10
+ >;
11
+
12
+ function isUnionSubPipelineStage(stage: PipelineStage): stage is UnionSubPipelineStage {
13
+ return !('$out' in stage) && !('$merge' in stage);
14
+ }
15
+
16
+ function toUnionSubPipeline(stages: PipelineStage[]): UnionSubPipelineStage[] {
17
+ if (!stages.every(isUnionSubPipelineStage)) {
18
+ throw new Error('unionWith pipeline cannot include $out or $merge');
19
+ }
20
+ return stages; // already narrowed, no `as`
21
+ }
22
+
23
+ // Create base pipeline using aggregate builder
24
+ const basePipeline = Item.aggregate([
25
+ { $match: { published: true } },
26
+ { $out: 'test' }
27
+ ]);
28
+
29
+ // Try to reuse pipeline in unionWith - TypeScript error occurs here
30
+ const result = Item.aggregate()
31
+ .match({ text: 'example' })
32
+ .unionWith({
33
+ coll: 'other_items',
34
+ pipeline: toUnionSubPipeline(basePipeline.pipeline()) // ❌ TypeScript error
35
+ });
package/lib/document.js CHANGED
@@ -60,6 +60,7 @@ let MongooseArray;
60
60
  let Embedded;
61
61
 
62
62
  const specialProperties = utils.specialProperties;
63
+ const hasOwnProperty = utils.object.hasOwnProperty;
63
64
 
64
65
  const VERSION_INC = 2;
65
66
 
@@ -1880,7 +1881,9 @@ Document.prototype.get = function(path, type, options) {
1880
1881
 
1881
1882
  // Fast path if we know we're just accessing top-level path on the document:
1882
1883
  // just get the schema path, avoid `$__path()` because that does string manipulation
1883
- let schema = noDottedPath ? this.$__schema.paths[path] : this.$__path(path);
1884
+ let schema = noDottedPath ?
1885
+ hasOwnProperty(this.$__schema.paths, path) ? this.$__schema.paths[path] : undefined :
1886
+ this.$__path(path);
1884
1887
  if (schema == null) {
1885
1888
  schema = this.$__schema.virtualpath(path);
1886
1889
 
@@ -1890,7 +1893,7 @@ Document.prototype.get = function(path, type, options) {
1890
1893
  }
1891
1894
 
1892
1895
  if (noDottedPath) {
1893
- let obj = this._doc[path];
1896
+ let obj = hasOwnProperty(this._doc, path) ? this._doc[path] : undefined;
1894
1897
  if (adhoc) {
1895
1898
  obj = adhoc.cast(obj);
1896
1899
  }
@@ -1917,6 +1920,10 @@ Document.prototype.get = function(path, type, options) {
1917
1920
  }
1918
1921
 
1919
1922
  for (let i = 0, l = pieces.length; i < l; i++) {
1923
+ if (specialProperties.has(pieces[i])) {
1924
+ return undefined;
1925
+ }
1926
+
1920
1927
  if (obj && obj._doc) {
1921
1928
  obj = obj._doc;
1922
1929
  }
@@ -1938,7 +1945,7 @@ Document.prototype.get = function(path, type, options) {
1938
1945
 
1939
1946
  if (schema != null && options.getters !== false) {
1940
1947
  obj = schema.applyGetters(obj, this);
1941
- } else if (this.$__schema.nested[path] && options.virtuals) {
1948
+ } else if (hasOwnProperty(this.$__schema.nested, path) && options.virtuals) {
1942
1949
  // Might need to apply virtuals if this is a nested path
1943
1950
  return applyVirtuals(this, clone(obj) || {}, { path: path });
1944
1951
  }
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ const MongooseError = require('../../error/mongooseError');
3
4
  const hasDollarKeys = require('./hasDollarKeys');
4
5
  const { trustedSymbol } = require('./trusted');
5
6
 
@@ -17,12 +18,14 @@ module.exports = function sanitizeFilter(filter) {
17
18
  const filterKeys = Object.keys(filter);
18
19
  for (const key of filterKeys) {
19
20
  const value = filter[key];
20
- if (value != null && value[trustedSymbol]) {
21
+ if (value?.[trustedSymbol]) {
21
22
  continue;
22
23
  }
23
- if (key === '$and' || key === '$or') {
24
+ if (key === '$and' || key === '$or' || key === '$nor') {
24
25
  sanitizeFilter(value);
25
26
  continue;
27
+ } else if (key === '$jsonSchema' || key === '$where' || key === '$expr' || key === '$text') {
28
+ throw new MongooseError(key + ' is not allowed with sanitizeFilter');
26
29
  }
27
30
 
28
31
  if (hasDollarKeys(value)) {
@@ -5,7 +5,7 @@ const trustedSymbol = Symbol('mongoose#trustedSymbol');
5
5
  exports.trustedSymbol = trustedSymbol;
6
6
 
7
7
  exports.trusted = function trusted(obj) {
8
- if (obj == null || typeof obj !== 'object') {
8
+ if (obj == null || (typeof obj !== 'object' && typeof obj !== 'function')) {
9
9
  return obj;
10
10
  }
11
11
  obj[trustedSymbol] = true;
@@ -69,7 +69,7 @@ SchemaBigInt.setters = [];
69
69
  * #### Example:
70
70
  *
71
71
  * // Convert bigints to numbers
72
- * mongoose.Schema.BigInt.get(v => v == null ? v : Number(v));
72
+ * mongoose.Schema.Types.BigInt.get(v => typeof v === 'bigint' ? Number(v) : v);
73
73
  *
74
74
  * @param {Function} getter
75
75
  * @return {this}
@@ -77,11 +77,11 @@ SchemaBuffer.setters = [];
77
77
  *
78
78
  * #### Example:
79
79
  *
80
- * // Always convert to string when getting an ObjectId
81
- * mongoose.Schema.Types.Buffer.get(v => v.toString('hex'));
80
+ * // Always convert to string when getting a buffer
81
+ * mongoose.Schema.Types.Buffer.get(v => Buffer.isBuffer(v) ? v.toString('hex') : v);
82
82
  *
83
- * const Model = mongoose.model('Test', new Schema({ buf: Buffer } }));
84
- * typeof (new Model({ buf: Buffer.fromString('hello') }).buf); // 'string'
83
+ * const Model = mongoose.model('Test', new Schema({ buf: Buffer }));
84
+ * typeof (new Model({ buf: Buffer.from('hello') }).buf); // 'string'
85
85
  *
86
86
  * @param {Function} getter
87
87
  * @return {this}
@@ -78,7 +78,7 @@ SchemaDate.setters = [];
78
78
  * #### Example:
79
79
  *
80
80
  * // Always convert Dates to string
81
- * mongoose.Date.get(v => v.toString());
81
+ * mongoose.Date.get(v => v instanceof Date ? v.toString() : v);
82
82
  *
83
83
  * const Model = mongoose.model('Test', new Schema({ date: { type: Date, default: () => new Date() } }));
84
84
  * typeof (new Model({}).date); // 'string'
@@ -73,7 +73,7 @@ Decimal128.setters = [];
73
73
  * #### Example:
74
74
  *
75
75
  * // Automatically convert Decimal128s to Numbers
76
- * mongoose.Schema.Decimal128.get(v => v == null ? v : Number(v));
76
+ * mongoose.Schema.Types.Decimal128.get(v => v instanceof mongoose.Types.Decimal128 ? Number(v) : v);
77
77
  *
78
78
  * @param {Function} getter
79
79
  * @return {this}
@@ -32,7 +32,7 @@ function SchemaNumber(key, options) {
32
32
  * #### Example:
33
33
  *
34
34
  * // Make all numbers round down
35
- * mongoose.Number.get(function(v) { return Math.floor(v); });
35
+ * mongoose.Number.get(function(v) { return typeof v === 'number' ? Math.floor(v) : v; });
36
36
  *
37
37
  * const Model = mongoose.model('Test', new Schema({ test: Number }));
38
38
  * new Model({ test: 3.14 }).test; // 3
@@ -58,8 +58,9 @@ ObjectId.prototype.OptionsConstructor = SchemaObjectIdOptions;
58
58
  *
59
59
  * #### Example:
60
60
  *
61
- * // Always convert to string when getting an ObjectId
62
- * mongoose.ObjectId.get(v => v.toString());
61
+ * // Convert actual ObjectId values to strings when getting an ObjectId. Check for
62
+ * // instanceof ObjectId first so null/undefined values and populated documents are left as-is.
63
+ * mongoose.ObjectId.get(v => v instanceof mongoose.Types.ObjectId ? v.toString() : v);
63
64
  *
64
65
  * const Model = mongoose.model('Test', new Schema({}));
65
66
  * typeof (new Model({})._id); // 'string'
@@ -107,8 +107,9 @@ SchemaString._defaultCaster = v => {
107
107
  *
108
108
  * #### Example:
109
109
  *
110
- * // Make all numbers round down
111
- * mongoose.Schema.String.get(v => v.toLowerCase());
110
+ * // Make all strings lowercase. Check for string type before calling `toLowerCase()`
111
+ * // to account for null/undefined values as well as populated docs.
112
+ * mongoose.Schema.Types.String.get(v => typeof v === 'string' ? v.toLowerCase() : v);
112
113
  *
113
114
  * const Model = mongoose.model('Test', new Schema({ test: String }));
114
115
  * new Model({ test: 'FOO' }).test; // 'foo'
package/lib/schema.js CHANGED
@@ -996,7 +996,7 @@ reserved.collection = 1;
996
996
 
997
997
  Schema.prototype.path = function(path, obj) {
998
998
  if (obj === undefined) {
999
- if (this.paths[path] != null) {
999
+ if (Object.prototype.hasOwnProperty.call(this.paths, path)) {
1000
1000
  return this.paths[path];
1001
1001
  }
1002
1002
  // Convert to '.$' to check subpaths re: gh-6405
@@ -1024,9 +1024,15 @@ Schema.prototype.path = function(path, obj) {
1024
1024
  : undefined;
1025
1025
  }
1026
1026
 
1027
+ const subpaths = path.indexOf('.') === -1 ? [path] : path.split('.');
1028
+ const last = subpaths.pop();
1029
+ if (utils.specialProperties.has(last)) {
1030
+ throw new Error('Cannot set special property `' + last + '` on a schema');
1031
+ }
1032
+
1027
1033
  // some path names conflict with document methods
1028
- const firstPieceOfPath = path.split('.')[0];
1029
- if (reserved[firstPieceOfPath] && !this.options.suppressReservedKeysWarning) {
1034
+ const firstPieceOfPath = subpaths.length === 0 ? last : subpaths[0];
1035
+ if (Object.prototype.hasOwnProperty.call(reserved, firstPieceOfPath) && !this.options.suppressReservedKeysWarning) {
1030
1036
  const errorMessage = `\`${firstPieceOfPath}\` is a reserved schema pathname and may break some functionality. ` +
1031
1037
  'You are allowed to use it, but use at your own risk. ' +
1032
1038
  'To disable this warning pass `suppressReservedKeysWarning` as a schema option.';
@@ -1039,8 +1045,6 @@ Schema.prototype.path = function(path, obj) {
1039
1045
  }
1040
1046
 
1041
1047
  // update the tree
1042
- const subpaths = path.split(/\./);
1043
- const last = subpaths.pop();
1044
1048
  let branch = this.tree;
1045
1049
  let fullPath = '';
1046
1050
 
@@ -2702,7 +2706,7 @@ Schema.prototype._getPathType = function(path) {
2702
2706
  };
2703
2707
  }
2704
2708
  return { schema: foundschema, pathType: 'real' };
2705
- } else if (p === parts.length && schema.nested[trypath]) {
2709
+ } else if (p === parts.length && Object.prototype.hasOwnProperty.call(schema.nested, trypath)) {
2706
2710
  return { schema: schema, pathType: 'nested' };
2707
2711
  }
2708
2712
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mongoose",
3
3
  "description": "Mongoose MongoDB ODM",
4
- "version": "7.8.8",
4
+ "version": "7.8.10",
5
5
  "author": "Guillermo Rauch <guillermo@learnboost.com>",
6
6
  "keywords": [
7
7
  "mongodb",
package/startmdb.mjs ADDED
@@ -0,0 +1,19 @@
1
+ import { MongoMemoryReplSet } from 'mongodb-memory-server';
2
+
3
+ const replSet = await MongoMemoryReplSet.create({
4
+ binary: {
5
+ systemBinary: '/home/v/libs/mongodb-linux-x86_64-enterprise-ubuntu2404-8.2.0/bin/mongod'
6
+ },
7
+ instanceOpts: [
8
+ {
9
+ port: 27017
10
+ }
11
+ ],
12
+ replSet: {
13
+ storageEngine: 'inMemory',
14
+ count: 1
15
+ }
16
+ });
17
+
18
+ const uri = replSet.getUri();
19
+ console.log(uri);
package/step1.mjs ADDED
@@ -0,0 +1,44 @@
1
+ import { tool } from 'ai';
2
+ import { execFile } from 'node:child_process';
3
+ import { promisify } from 'node:util';
4
+ import { z } from 'zod';
5
+
6
+ const execFileAsync = promisify(execFile);
7
+
8
+ async function run(command, args) {
9
+ const { stdout } = await execFileAsync(command, args);
10
+ return stdout.trim();
11
+ }
12
+
13
+ function logToolCall(name, preview) {
14
+ console.log(`\n> ${name} ${preview}`);
15
+ }
16
+
17
+ const git = tool({
18
+ description: 'Run a git command like log or diff',
19
+ inputSchema: z.object({
20
+ subcommand: z.enum(['log', 'diff', 'show']),
21
+ args: z.array(z.string()).default([])
22
+ }),
23
+ execute: async({ subcommand, args }) => {
24
+ logToolCall('git', [subcommand, ...args].join(' '));
25
+ return run('git', [subcommand, ...args]);
26
+ }
27
+ });
28
+
29
+ import { generateText, stepCountIs } from 'ai';
30
+ import { createGoogleGenerativeAI } from '@ai-sdk/google';
31
+
32
+ const google = createGoogleGenerativeAI({
33
+ apiKey: process.env.GEMINI_API_KEY
34
+ });
35
+
36
+ const result = await generateText({
37
+ model: google('gemini-2.5-flash'),
38
+ stopWhen: stepCountIs(10),
39
+ system: 'Summarize recent git commits into a concise changelog entry. Focus on user-facing changes.',
40
+ prompt: 'Summarize the last 20 commits',
41
+ tools: { git }
42
+ });
43
+
44
+ console.log(result.text);