Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(base): add support to set default immutable for createdAt globally #11888

Merged
merged 5 commits into from
Jun 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 4 additions & 1 deletion lib/helpers/timestamps/setupTimestamps.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,11 @@ module.exports = function setupTimestamps(schema, timestamps) {
}

if (createdAt && !schema.paths[createdAt]) {
schemaAdditions[createdAt] = { [schema.options.typeKey || 'type']: Date, immutable: true };
const baseImmutableCreatedAt = schema.base.get('timestamps.createdAt.immutable');
const immutable = baseImmutableCreatedAt != null ? baseImmutableCreatedAt : true;
schemaAdditions[createdAt] = { [schema.options.typeKey || 'type']: Date, immutable };
}

schema.add(schemaAdditions);

schema.pre('save', function(next) {
Expand Down
29 changes: 15 additions & 14 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,23 +153,24 @@ Mongoose.prototype.driver = driver;
* mongoose.set('debug', function(collectionName, methodName, ...methodArgs) {}); // use custom function to log collection methods + arguments
*
* Currently supported options are:
* - 'debug': If `true`, prints the operations mongoose sends to MongoDB to the console. If a writable stream is passed, it will log to that stream, without colorization. If a callback function is passed, it will receive the collection name, the method name, then all arugments passed to the method. For example, if you wanted to replicate the default logging, you could output from the callback `Mongoose: ${collectionName}.${methodName}(${methodArgs.join(', ')})`.
* - 'returnOriginal': If `false`, changes the default `returnOriginal` option to `findOneAndUpdate()`, `findByIdAndUpdate`, and `findOneAndReplace()` to false. This is equivalent to setting the `new` option to `true` for `findOneAndX()` calls by default. Read our [`findOneAndUpdate()` tutorial](/docs/tutorials/findoneandupdate.html) for more information.
* - 'applyPluginsToChildSchemas': `true` by default. Set to false to skip applying global plugins to child schemas
* - 'applyPluginsToDiscriminators': `false` by default. Set to true to apply global plugins to discriminator schemas. This typically isn't necessary because plugins are applied to the base schema and discriminators copy all middleware, methods, statics, and properties from the base schema.
* - 'autoCreate': Set to `true` to make Mongoose call [`Model.createCollection()`](/docs/api/model.html#model_Model.createCollection) automatically when you create a model with `mongoose.model()` or `conn.model()`. This is useful for testing transactions, change streams, and other features that require the collection to exist.
* - 'autoIndex': `true` by default. Set to false to disable automatic index creation for all models associated with this Mongoose instance.
* - 'bufferCommands': enable/disable mongoose's buffering mechanism for all connections and models
* - 'cloneSchemas': false by default. Set to `true` to `clone()` all schemas before compiling into a model.
* - 'applyPluginsToDiscriminators': false by default. Set to true to apply global plugins to discriminator schemas. This typically isn't necessary because plugins are applied to the base schema and discriminators copy all middleware, methods, statics, and properties from the base schema.
* - 'applyPluginsToChildSchemas': true by default. Set to false to skip applying global plugins to child schemas
* - 'objectIdGetter': true by default. Mongoose adds a getter to MongoDB ObjectId's called `_id` that returns `this` for convenience with populate. Set this to false to remove the getter.
* - 'runValidators': false by default. Set to true to enable [update validators](/docs/validation.html#update-validators) for all validators by default.
* - 'toObject': `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toObject()`](/docs/api.html#document_Document-toObject)
* - 'toJSON': `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toJSON()`](/docs/api.html#document_Document-toJSON), for determining how Mongoose documents get serialized by `JSON.stringify()`
* - 'strict': true by default, may be `false`, `true`, or `'throw'`. Sets the default strict mode for schemas.
* - 'strictQuery': same value as 'strict' by default (`true`), may be `false`, `true`, or `'throw'`. Sets the default [strictQuery](/docs/guide.html#strictQuery) mode for schemas.
* - 'selectPopulatedPaths': true by default. Set to false to opt out of Mongoose adding all fields that you `populate()` to your `select()`. The schema-level option `selectPopulatedPaths` overwrites this one.
* - 'cloneSchemas': `false` by default. Set to `true` to `clone()` all schemas before compiling into a model.
* - 'debug': If `true`, prints the operations mongoose sends to MongoDB to the console. If a writable stream is passed, it will log to that stream, without colorization. If a callback function is passed, it will receive the collection name, the method name, then all arugments passed to the method. For example, if you wanted to replicate the default logging, you could output from the callback `Mongoose: ${collectionName}.${methodName}(${methodArgs.join(', ')})`.
* - 'timestamps.createdAt.immutable': `true` by default. If `false`, it will change the `createdAt` field to be [`immutable: false`](https://mongoosejs.com/docs/api/schematype.html#schematype_SchemaType-immutable) which means you can update the `createdAt`
* - 'maxTimeMS': If set, attaches [maxTimeMS](https://docs.mongodb.com/manual/reference/operator/meta/maxTimeMS/) to every query
* - 'autoIndex': true by default. Set to false to disable automatic index creation for all models associated with this Mongoose instance.
* - 'autoCreate': Set to `true` to make Mongoose call [`Model.createCollection()`](/docs/api/model.html#model_Model.createCollection) automatically when you create a model with `mongoose.model()` or `conn.model()`. This is useful for testing transactions, change streams, and other features that require the collection to exist.
* - 'objectIdGetter': `true` by default. Mongoose adds a getter to MongoDB ObjectId's called `_id` that returns `this` for convenience with populate. Set this to false to remove the getter.
* - 'overwriteModels': Set to `true` to default to overwriting models with the same name when calling `mongoose.model()`, as opposed to throwing an `OverwriteModelError`.
* - 'returnOriginal': If `false`, changes the default `returnOriginal` option to `findOneAndUpdate()`, `findByIdAndUpdate`, and `findOneAndReplace()` to false. This is equivalent to setting the `new` option to `true` for `findOneAndX()` calls by default. Read our [`findOneAndUpdate()` tutorial](/docs/tutorials/findoneandupdate.html) for more information.
* - 'runValidators': `false` by default. Set to true to enable [update validators](/docs/validation.html#update-validators) for all validators by default.
* - 'selectPopulatedPaths': `true` by default. Set to false to opt out of Mongoose adding all fields that you `populate()` to your `select()`. The schema-level option `selectPopulatedPaths` overwrites this one.
* - 'strict': `true` by default, may be `false`, `true`, or `'throw'`. Sets the default strict mode for schemas.
* - 'strictQuery': same value as 'strict' by default (`true`), may be `false`, `true`, or `'throw'`. Sets the default [strictQuery](/docs/guide.html#strictQuery) mode for schemas.
* - 'toJSON': `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toJSON()`](/docs/api.html#document_Document-toJSON), for determining how Mongoose documents get serialized by `JSON.stringify()`
* - 'toObject': `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toObject()`](/docs/api.html#document_Document-toObject)
*
* @param {String} key
* @param {String|Function|Boolean} value
Expand Down
1 change: 1 addition & 0 deletions lib/validoptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const VALID_OPTIONS = Object.freeze([
'bufferTimeoutMS',
'cloneSchemas',
'debug',
'timestamps.createdAt.immutable',
'maxTimeMS',
'objectIdGetter',
'overwriteModels',
Expand Down
24 changes: 24 additions & 0 deletions test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1019,5 +1019,29 @@ describe('mongoose module:', function() {
assert.equal(optionsSentToMongo.allowDiskUse, false);
});
});
describe('global `timestamps.createdAt.immutable` (gh-10139)', () => {
it('is `true` by default', () => {
// Arrange
const m = new mongoose.Mongoose();

// Act
const userSchema = new m.Schema({ name: String }, { timestamps: true });

// Assert
assert.equal(userSchema.path('createdAt').options.immutable, true);
});

it('can be overridden to `false`', () => {
// Arrange
const m = new mongoose.Mongoose();
m.set('timestamps.createdAt.immutable', false);

// Act
const userSchema = new m.Schema({ name: String }, { timestamps: true });

// Assert
assert.equal(userSchema.path('createdAt').options.immutable, false);
});
});
});
});
4 changes: 4 additions & 0 deletions test/types/base.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,8 @@ function connectionStates() {
function gh11478() {
mongoose.set('allowDiskUse', false);
mongoose.set('allowDiskUse', true);
}

function gh10139() {
mongoose.set('timestamps.createdAt.immutable', false);
}
8 changes: 8 additions & 0 deletions types/mongooseoptions.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,14 @@ declare module 'mongoose' {
| stream.Writable
| ((collectionName: string, methodName: string, ...methodArgs: any[]) => void);

/**
* If `false`, it will change the `createdAt` field to be [`immutable: false`](https://mongoosejs.com/docs/api/schematype.html#schematype_SchemaType-immutable)
* which means you can update the `createdAt`.
*
* @default true
*/
'timestamps.createdAt.immutable'?: boolean

/** If set, attaches [maxTimeMS](https://docs.mongodb.com/manual/reference/operator/meta/maxTimeMS/) to every query */
maxTimeMS?: number;

Expand Down