From 44dea532b86909d64a91d40576feddbb98540bf9 Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Tue, 24 Jan 2023 09:34:45 +0100 Subject: [PATCH] feat: added Schema.prototype.omit() function fix #12931 --- lib/schema.js | 42 +++++++++++++++++++++++++ test/schema.test.js | 75 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+) diff --git a/lib/schema.js b/lib/schema.js index 20471d40e59..c77c27d03d5 100644 --- a/lib/schema.js +++ b/lib/schema.js @@ -478,6 +478,48 @@ Schema.prototype.pick = function(paths, options) { return newSchema; }; +/** + * Returns a new schema that has the `paths` from the original schema, minus the omitted ones. + * + * This method is analagous to [Lodash's `omit()` function](https://lodash.com/docs/#omit) for Mongoose schemas. + * + * #### Example: + * + * const schema = Schema({ name: String, age: Number }); + * // Creates a new schema omitting the `age` path + * const newSchema = schema.omit(['age']); + * + * newSchema.path('name'); // SchemaString { ... } + * newSchema.path('age'); // undefined + * + * @param {String[]} paths List of Paths to omit for the new Schema + * @param {Object} [options] Options to pass to the new Schema Constructor (same as `new Schema(.., Options)`). Defaults to `this.options` if not set. + * @return {Schema} + * @api public + */ + +Schema.prototype.omit = function(paths, options) { + const newSchema = new Schema(this, options || this.options); + if (!Array.isArray(paths)) { + throw new MongooseError( + 'Schema#omit() only accepts an array argument, ' + + 'got "' + + typeof paths + + '"' + ); + } + + newSchema.remove(paths); + + for (const nested in newSchema.singleNestedPaths) { + if (paths.includes(nested)) { + delete newSchema.singleNestedPaths[nested]; + } + } + + return newSchema; +}; + /** * Returns default options for this schema, merged with `options`. * diff --git a/test/schema.test.js b/test/schema.test.js index dec8be82d56..f5934e2a821 100644 --- a/test/schema.test.js +++ b/test/schema.test.js @@ -2339,6 +2339,81 @@ describe('schema', function() { }); }); + describe('omit() (gh-12931)', function() { + it('works with nested paths', function() { + const schema = Schema({ + name: { + first: { + type: String, + required: true + }, + last: { + type: String, + required: true + } + }, + age: { + type: Number, + index: true + } + }); + assert.ok(schema.path('name.first')); + assert.ok(schema.path('name.last')); + + let newSchema = schema.omit(['name.first']); + assert.ok(!newSchema.path('name.first')); + assert.ok(newSchema.path('age')); + assert.ok(newSchema.path('age').index); + + newSchema = schema.omit(['age']); + assert.ok(newSchema.path('name.first')); + assert.ok(newSchema.path('name.first').required); + assert.ok(newSchema.path('name.last')); + assert.ok(newSchema.path('name.last').required); + assert.ok(!newSchema.path('age')); + + newSchema = schema.omit(['name.last', 'age']); + assert.ok(newSchema.path('name.first')); + assert.ok(newSchema.path('name.first').required); + assert.ok(!newSchema.path('name.last')); + assert.ok(!newSchema.path('age')); + }); + + it('with single nested paths', function() { + const schema = Schema({ + name: Schema({ + first: { + type: String, + required: true + }, + last: { + type: String, + required: true + } + }), + age: { + type: Number, + index: true + } + }); + assert.ok(schema.path('name.first')); + assert.ok(schema.path('name.last')); + + let newSchema = schema.omit(['age']); + assert.ok(newSchema.path('name.first')); + assert.ok(newSchema.path('name.first').required); + assert.ok(newSchema.path('name.last')); + assert.ok(newSchema.path('name.last').required); + assert.ok(!newSchema.path('age')); + + newSchema = schema.omit(['name.last', 'age']); + assert.ok(newSchema.path('name.first')); + assert.ok(newSchema.path('name.first').required); + assert.ok(!newSchema.path('name.last')); + assert.ok(!newSchema.path('age')); + }); + }); + describe('path-level custom cast (gh-8300)', function() { it('with numbers', function() { const schema = Schema({