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

Remove default connection if setting createInitialConnection to false after Mongoose instance created #14679

Merged
merged 7 commits into from
Jun 24, 2024
29 changes: 27 additions & 2 deletions lib/mongoose.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const SetOptionError = require('./error/setOptionError');
const applyEmbeddedDiscriminators = require('./helpers/discriminator/applyEmbeddedDiscriminators');

const defaultMongooseSymbol = Symbol.for('mongoose:default');
const defaultConnectionSymbol = Symbol('mongoose:defaultConnection');

require('./helpers/printJestWarning');

Expand Down Expand Up @@ -72,8 +73,7 @@ function Mongoose(options) {
}, options);
const createInitialConnection = utils.getOption('createInitialConnection', this.options) ?? true;
if (createInitialConnection && this.__driver != null) {
const conn = this.createConnection(); // default connection
conn.models = this.models;
_createDefaultConnection(this);
}

if (this.options.pluralization) {
Expand Down Expand Up @@ -292,6 +292,14 @@ Mongoose.prototype.set = function(key, value) {
} else if (!optionValue && _mongoose.transactionAsyncLocalStorage) {
delete _mongoose.transactionAsyncLocalStorage;
}
} else if (optionKey === 'createInitialConnection') {
if (optionValue && !_mongoose.connection) {
_createDefaultConnection(_mongoose);
} else if (optionValue === false && _mongoose.connection && _mongoose.connection[defaultConnectionSymbol]) {
if (_mongoose.connection.readyState === STATES.disconnected && Object.keys(_mongoose.connection.models).length === 0) {
_mongoose.connections.shift();
}
}
}
}

Expand Down Expand Up @@ -424,6 +432,9 @@ Mongoose.prototype.connect = async function connect(uri, options) {
}

const _mongoose = this instanceof Mongoose ? this : mongoose;
if (_mongoose.connection == null) {
_createDefaultConnection(_mongoose);
}
const conn = _mongoose.connection;

return conn.openUri(uri, options).then(() => _mongoose);
Expand Down Expand Up @@ -1315,6 +1326,20 @@ Mongoose.prototype.overwriteMiddlewareResult = Kareem.overwriteResult;

Mongoose.prototype.omitUndefined = require('./helpers/omitUndefined');

/*!
* Create a new default connection (`mongoose.connection`) for a Mongoose instance.
* No-op if there is already a default connection.
*/

function _createDefaultConnection(mongoose) {
if (mongoose.connection) {
return;
}
const conn = mongoose.createConnection(); // default connection
conn[defaultConnectionSymbol] = true;
conn.models = mongoose.models;
}

/**
* The exports object is an instance of Mongoose.
*
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([
'bufferCommands',
'bufferTimeoutMS',
'cloneSchemas',
'createInitialConnection',
'debug',
'id',
'timestamps.createdAt.immutable',
Expand Down
48 changes: 48 additions & 0 deletions test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1180,4 +1180,52 @@ describe('mongoose module:', function() {
}
});
});

describe('createInitialConnection (gh-8302)', function() {
let m;

beforeEach(function() {
m = new mongoose.Mongoose();
});

afterEach(async function() {
await m.disconnect();
});

it('should delete existing connection when setting createInitialConnection to false', function() {
assert.ok(m.connection);
m.set('createInitialConnection', false);
assert.strictEqual(m.connection, undefined);
});

it('should create connection when createConnection is called', function() {
m.set('createInitialConnection', false);
const conn = m.createConnection();
assert.equal(conn, m.connection);
});

it('should create a new connection automatically when connect() is called if no existing default connection', async function() {
assert.ok(m.connection);
m.set('createInitialConnection', false);
assert.strictEqual(m.connection, undefined);

await m.connect(start.uri);
assert.ok(m.connection);
});

it('should not delete default connection if it has models', async function() {
assert.ok(m.connection);
m.model('Test', new m.Schema({ name: String }));
m.set('createInitialConnection', false);
assert.ok(m.connection);
});

it('should not delete default connection if it is connected', async function() {
assert.ok(m.connection);
await m.connect(start.uri);
m.set('createInitialConnection', false);
assert.ok(m.connection);
assert.equal(m.connection.readyState, 1);
});
});
});