diff --git a/etc/notes/CHANGES_5.0.0.md b/etc/notes/CHANGES_5.0.0.md index 11fb49d7a50..6ef21c17888 100644 --- a/etc/notes/CHANGES_5.0.0.md +++ b/etc/notes/CHANGES_5.0.0.md @@ -124,3 +124,33 @@ cursor.closed // true Everywhere the driver sends a `hello` command (initial handshake and monitoring), it will now pass the command value as `1` instead of the previous `true` for spec compliance. + +### Removed `Collection.insert`, `Collection.update`, and `Collection.remove` + +Three legacy operation helpers on the collection class have been removed: + +| Removed API | API to migrate to | +|------------------------------------------------|----------------------------------------------------| +| `insert(document)` | `insertOne(document)` | +| `insert(arrayOfDocuments)` | `insertMany(arrayOfDocuments)` | +| `update(filter)` | `updateMany(filter)` | +| `remove(filter)` | `deleteMany(filter)` | + +The `insert` method accepted an array of documents for multi-document inserts and a single document for single document inserts. `insertOne` should now be used for single-document inserts and `insertMany` should be used for multi-document inserts. + +```ts +// Single document insert: +await collection.insert({ name: 'spot' }); +// Migration: +await collection.insertOne({ name: 'spot' }); + +// Multi-document insert: +await collection.insert([{ name: 'fido' }, { name: 'luna' }]) +// Migration: +await collection.insertMany([{ name: 'fido' }, { name: 'luna' }]) +``` + +### Removed `keepGoing` option from `BulkWriteOptions` + +The `keepGoing` option was a legacy name for setting `ordered` to `false` for bulk inserts. +It was only supported by the legacy `collection.insert()` method which is now removed as noted above. diff --git a/src/collection.ts b/src/collection.ts index 5897587dd77..1689ad03e30 100644 --- a/src/collection.ts +++ b/src/collection.ts @@ -1630,77 +1630,6 @@ export class Collection { return this.s.db.s.logger; } - /** - * Inserts a single document or a an array of documents into MongoDB. If documents passed in do not contain the **_id** field, - * one will be added to each of the documents missing it by the driver, mutating the document. This behavior - * can be overridden by setting the **forceServerObjectId** flag. - * - * @deprecated Use insertOne, insertMany or bulkWrite instead. Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance - * @param docs - The documents to insert - * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided - */ - insert( - docs: OptionalUnlessRequiredId[], - options: BulkWriteOptions, - callback: Callback> - ): Promise> | void { - emitWarningOnce( - 'collection.insert is deprecated. Use insertOne, insertMany or bulkWrite instead.' - ); - if (typeof options === 'function') (callback = options), (options = {}); - options = options || { ordered: false }; - docs = !Array.isArray(docs) ? [docs] : docs; - - return this.insertMany(docs, options, callback); - } - - /** - * Updates documents. - * - * @deprecated use updateOne, updateMany or bulkWrite. Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance - * @param filter - The filter for the update operation. - * @param update - The update operations to be applied to the documents - * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided - */ - update( - filter: Filter, - update: UpdateFilter, - options: UpdateOptions, - callback: Callback - ): Promise | void { - emitWarningOnce( - 'collection.update is deprecated. Use updateOne, updateMany, or bulkWrite instead.' - ); - if (typeof options === 'function') (callback = options), (options = {}); - options = options ?? {}; - - return this.updateMany(filter, update, options, callback); - } - - /** - * Remove documents. - * - * @deprecated use deleteOne, deleteMany or bulkWrite. Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance - * @param filter - The filter for the remove operation. - * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided - */ - remove( - filter: Filter, - options: DeleteOptions, - callback: Callback - ): Promise | void { - emitWarningOnce( - 'collection.remove is deprecated. Use deleteOne, deleteMany, or bulkWrite instead.' - ); - if (typeof options === 'function') (callback = options), (options = {}); - options = options ?? {}; - - return this.deleteMany(filter, options, callback); - } - /** * An estimated count of matching documents in the db to a filter. * diff --git a/test/integration/collection-management/collection.test.ts b/test/integration/collection-management/collection.test.ts index 15e5a8d2fc0..f15d772b2d9 100644 --- a/test/integration/collection-management/collection.test.ts +++ b/test/integration/collection-management/collection.test.ts @@ -227,28 +227,6 @@ describe('Collection', function () { ); }); - it('should perform collection remove with no callback', function (done) { - const collection = db.collection('remove_with_no_callback_bug_test'); - collection.insertOne({ a: 1 }, configuration.writeConcernMax(), err => { - expect(err).to.not.exist; - collection.insertOne({ b: 1 }, configuration.writeConcernMax(), err => { - expect(err).to.not.exist; - collection.insertOne({ c: 1 }, configuration.writeConcernMax(), err => { - expect(err).to.not.exist; - collection.remove({ a: 1 }, configuration.writeConcernMax(), err => { - expect(err).to.not.exist; - // Let's perform a count - collection.countDocuments((err, count) => { - expect(err).to.not.exist; - expect(count).to.equal(2); - done(); - }); - }); - }); - }); - }); - }); - it('should correctly read back document with null', function (done) { db.createCollection('shouldCorrectlyReadBackDocumentWithNull', {}, (err, collection) => { // Insert a document with a date diff --git a/test/integration/crud/crud_api.test.ts b/test/integration/crud/crud_api.test.ts index d5e077faca1..026c02d32e7 100644 --- a/test/integration/crud/crud_api.test.ts +++ b/test/integration/crud/crud_api.test.ts @@ -655,71 +655,6 @@ describe('CRUD API', function () { } }); - it('should correctly execute remove methods using crud api', { - // Add a tag that our runner can trigger on - // in this case we are setting that node needs to be higher than 0.10.X to run - metadata: { - requires: { topology: ['single', 'replicaset', 'sharded', 'ssl', 'heap', 'wiredtiger'] } - }, - - test: function (done) { - client.connect(function (err, client) { - const db = client.db(); - - // - // Legacy update method - // ------------------------------------------------- - const legacyRemove = function () { - deleteOne(); - }; - - // - // Update one method - // ------------------------------------------------- - const deleteOne = function () { - db.collection('t4_2').insertMany( - [{ a: 1 }, { a: 1 }], - { writeConcern: { w: 1 } }, - (err, r) => { - expect(err).to.not.exist; - expect(r).property('insertedCount').to.equal(2); - - db.collection('t4_2').deleteOne({ a: 1 }, (err, r) => { - expect(err).to.not.exist; - expect(r).property('deletedCount').to.equal(1); - - deleteMany(); - }); - } - ); - }; - - // - // Update many method - // ------------------------------------------------- - const deleteMany = function () { - db.collection('t4_3').insertMany( - [{ a: 1 }, { a: 1 }], - { writeConcern: { w: 1 } }, - (err, r) => { - expect(err).to.not.exist; - expect(r).property('insertedCount').to.equal(2); - - db.collection('t4_3').deleteMany({ a: 1 }, (err, r) => { - expect(err).to.not.exist; - expect(r).property('deletedCount').to.equal(2); - - client.close(done); - }); - } - ); - }; - - legacyRemove(); - }); - } - }); - it('should correctly execute findAndModify methods using crud api', { // Add a tag that our runner can trigger on // in this case we are setting that node needs to be higher than 0.10.X to run diff --git a/test/integration/crud/find.test.js b/test/integration/crud/find.test.js index e677bfdfbb1..806bd0f1117 100644 --- a/test/integration/crud/find.test.js +++ b/test/integration/crud/find.test.js @@ -1,13 +1,18 @@ 'use strict'; -const { assert: test, setupDatabase } = require('../shared'); +const { assert: test } = require('../shared'); const { expect } = require('chai'); const sinon = require('sinon'); const { setTimeout } = require('timers'); const { Code, ObjectId, Long, Binary, ReturnDocument } = require('../../../src'); describe('Find', function () { - before(function () { - return setupDatabase(this.configuration); + let client; + beforeEach(async function () { + client = this.configuration.newClient(); + }); + + afterEach(async function () { + await client.close(); }); /** @@ -786,83 +791,96 @@ describe('Find', function () { test: function (done) { var configuration = this.configuration; - var client = configuration.newClient(configuration.writeConcernMax(), { maxPoolSize: 1 }); - client.connect(function (err, client) { - var db = client.db(configuration.db); - db.createCollection('test_find_and_modify_a_document_1', function (err, collection) { - // Test return new document on change - collection.insert({ a: 1, b: 2 }, configuration.writeConcernMax(), function (err) { + var db = client.db(configuration.db); + db.dropCollection('test_find_and_modify_a_document_1') + .catch(() => null) + .finally(() => { + db.createCollection('test_find_and_modify_a_document_1', function (err, collection) { expect(err).to.not.exist; - // Let's modify the document in place - collection.findOneAndUpdate( - { a: 1 }, - { $set: { b: 3 } }, - { returnDocument: ReturnDocument.AFTER }, - function (err, updated_doc) { - test.equal(1, updated_doc.value.a); - test.equal(3, updated_doc.value.b); + // Test return new document on change + collection.insert({ a: 1, b: 2 }, configuration.writeConcernMax(), function (err) { + expect(err).to.not.exist; - // Test return old document on change - collection.insert({ a: 2, b: 2 }, configuration.writeConcernMax(), function (err) { + // Let's modify the document in place + collection.findOneAndUpdate( + { a: 1 }, + { $set: { b: 3 } }, + { returnDocument: ReturnDocument.AFTER }, + function (err, updated_doc) { expect(err).to.not.exist; + test.equal(1, updated_doc.value.a); + test.equal(3, updated_doc.value.b); - // Let's modify the document in place - collection.findOneAndUpdate( - { a: 2 }, - { $set: { b: 3 } }, + // Test return old document on change + collection.insert( + { a: 2, b: 2 }, configuration.writeConcernMax(), - function (err, result) { - test.equal(2, result.value.a); - test.equal(2, result.value.b); + function (err) { + expect(err).to.not.exist; - // Test remove object on change - collection.insert( - { a: 3, b: 2 }, + // Let's modify the document in place + collection.findOneAndUpdate( + { a: 2 }, + { $set: { b: 3 } }, configuration.writeConcernMax(), - function (err) { + function (err, result) { expect(err).to.not.exist; - // Let's modify the document in place - collection.findOneAndUpdate( - { a: 3 }, - { $set: { b: 3 } }, - { remove: true }, - function (err, updated_doc) { - test.equal(3, updated_doc.value.a); - test.equal(2, updated_doc.value.b); - - // Let's upsert! + test.equal(2, result.value.a); + test.equal(2, result.value.b); + + // Test remove object on change + collection.insert( + { a: 3, b: 2 }, + configuration.writeConcernMax(), + function (err) { + expect(err).to.not.exist; + // Let's modify the document in place collection.findOneAndUpdate( - { a: 4 }, + { a: 3 }, { $set: { b: 3 } }, - { returnDocument: ReturnDocument.AFTER, upsert: true }, + { remove: true }, function (err, updated_doc) { - test.equal(4, updated_doc.value.a); - test.equal(3, updated_doc.value.b); - - // Test selecting a subset of fields - collection.insert( - { a: 100, b: 101 }, - configuration.writeConcernMax(), - function (err, r) { + expect(err).to.not.exist; + test.equal(3, updated_doc.value.a); + test.equal(2, updated_doc.value.b); + + // Let's upsert! + collection.findOneAndUpdate( + { a: 4 }, + { $set: { b: 3 } }, + { returnDocument: ReturnDocument.AFTER, upsert: true }, + function (err, updated_doc) { expect(err).to.not.exist; - - collection.findOneAndUpdate( - { a: 100 }, - { $set: { b: 5 } }, - { - returnDocument: ReturnDocument.AFTER, - projection: { b: 1 } - }, - function (err, updated_doc) { - test.equal(2, Object.keys(updated_doc.value).length); - test.equal( - r.insertedIds[0].toHexString(), - updated_doc.value._id.toHexString() + test.equal(4, updated_doc.value.a); + test.equal(3, updated_doc.value.b); + + // Test selecting a subset of fields + collection.insert( + { a: 100, b: 101 }, + configuration.writeConcernMax(), + function (err, r) { + expect(err).to.not.exist; + + collection.findOneAndUpdate( + { a: 100 }, + { $set: { b: 5 } }, + { + returnDocument: ReturnDocument.AFTER, + projection: { b: 1 } + }, + function (err, updated_doc) { + expect(err).to.not.exist; + test.equal(2, Object.keys(updated_doc.value).length); + test.equal( + r.insertedIds[0].toHexString(), + updated_doc.value._id.toHexString() + ); + test.equal(5, updated_doc.value.b); + test.equal('undefined', typeof updated_doc.value.a); + client.close(done); + } ); - test.equal(5, updated_doc.value.b); - test.equal('undefined', typeof updated_doc.value.a); - client.close(done); } ); } @@ -875,12 +893,11 @@ describe('Find', function () { ); } ); - }); - } - ); + } + ); + }); }); }); - }); } }); @@ -926,44 +943,41 @@ describe('Find', function () { test: function (done) { var configuration = this.configuration; - var client = configuration.newClient(configuration.writeConcernMax(), { maxPoolSize: 1 }); - client.connect(function (err, client) { - var db = client.db(configuration.db); - db.createCollection( - 'shouldCorrectlyExecuteFindOneWithAnInSearchTag', - function (err, collection) { - // Test return new document on change - collection.insert( - { - title: 'Tobi', - author: 'Brian', - newTitle: 'Woot', - meta: { visitors: 0 } - }, - configuration.writeConcernMax(), - function (err, r) { - // Fetch the id - var id = r.insertedIds[0]; + var db = client.db(configuration.db); + db.createCollection( + 'shouldCorrectlyExecuteFindOneWithAnInSearchTag', + function (err, collection) { + // Test return new document on change + collection.insert( + { + title: 'Tobi', + author: 'Brian', + newTitle: 'Woot', + meta: { visitors: 0 } + }, + configuration.writeConcernMax(), + function (err, r) { + // Fetch the id + var id = r.insertedIds[0]; - collection.update( - { _id: id }, - { $inc: { 'meta.visitors': 1 } }, - configuration.writeConcernMax(), - function (err, r) { - expect(r).property('matchedCount').to.equal(1); - expect(err).to.not.exist; + collection.update( + { _id: id }, + { $inc: { 'meta.visitors': 1 } }, + configuration.writeConcernMax(), + function (err, r) { + expect(r).property('matchedCount').to.equal(1); + expect(err).to.not.exist; - collection.findOne({ _id: id }, function (err, item) { - test.equal(1, item.meta.visitors); - client.close(done); - }); - } - ); - } - ); - } - ); - }); + collection.findOne({ _id: id }, function (err, item) { + test.equal(1, item.meta.visitors); + client.close(done); + }); + } + ); + } + ); + } + ); } }); @@ -1458,58 +1472,55 @@ describe('Find', function () { test: function (done) { var configuration = this.configuration; - var client = configuration.newClient(configuration.writeConcernMax(), { maxPoolSize: 1 }); - client.connect(function (err, client) { - var db = client.db(configuration.db); - var transaction = {}; - transaction.document = {}; - transaction.document.type = 'documentType'; - transaction.document.id = new ObjectId(); - transaction.transactionId = new ObjectId(); - transaction.amount = 12.3333; - - var transactions = []; - transactions.push(transaction); - // Wrapping object - var wrapingObject = { - funds: { - remaining: 100.5 - }, - - transactions: transactions - }; + var db = client.db(configuration.db); + var transaction = {}; + transaction.document = {}; + transaction.document.type = 'documentType'; + transaction.document.id = new ObjectId(); + transaction.transactionId = new ObjectId(); + transaction.amount = 12.3333; + + var transactions = []; + transactions.push(transaction); + // Wrapping object + var wrapingObject = { + funds: { + remaining: 100.5 + }, + + transactions: transactions + }; + + db.createCollection('find_and_modify_generate_correct_bson', function (err, collection) { + expect(err).to.not.exist; - db.createCollection('find_and_modify_generate_correct_bson', function (err, collection) { + collection.insert(wrapingObject, configuration.writeConcernMax(), function (err, r) { expect(err).to.not.exist; - collection.insert(wrapingObject, configuration.writeConcernMax(), function (err, r) { - expect(err).to.not.exist; + collection.findOne( + { + _id: r.insertedIds[0], + 'funds.remaining': { $gte: 3.0 }, + 'transactions.id': { $ne: transaction.transactionId } + }, + function (err, item) { + test.ok(item != null); - collection.findOne( - { - _id: r.insertedIds[0], - 'funds.remaining': { $gte: 3.0 }, - 'transactions.id': { $ne: transaction.transactionId } - }, - function (err, item) { - test.ok(item != null); - - collection.findOneAndUpdate( - { - _id: r.insertedIds[0], - 'funds.remaining': { $gte: 3.0 }, - 'transactions.id': { $ne: transaction.transactionId } - }, - { $push: { transactions: transaction } }, - { returnDocument: ReturnDocument.AFTER, safe: true }, - function (err) { - expect(err).to.not.exist; - client.close(done); - } - ); - } - ); - }); + collection.findOneAndUpdate( + { + _id: r.insertedIds[0], + 'funds.remaining': { $gte: 3.0 }, + 'transactions.id': { $ne: transaction.transactionId } + }, + { $push: { transactions: transaction } }, + { returnDocument: ReturnDocument.AFTER, safe: true }, + function (err) { + expect(err).to.not.exist; + client.close(done); + } + ); + } + ); }); }); } diff --git a/test/integration/crud/insert.test.js b/test/integration/crud/insert.test.js index 8bbdc301cec..7f19b52d1cc 100644 --- a/test/integration/crud/insert.test.js +++ b/test/integration/crud/insert.test.js @@ -323,7 +323,7 @@ describe('crud - insert', function () { db.createCollection( 'users', getResult(function (user_collection) { - user_collection.remove({}, configuration.writeConcernMax(), function (err) { + user_collection.deleteMany({}, configuration.writeConcernMax(), function (err) { expect(err).to.not.exist; //first, create a user object @@ -572,29 +572,26 @@ describe('crud - insert', function () { test: function (done) { var configuration = this.configuration; - var client = configuration.newClient(configuration.writeConcernMax(), { maxPoolSize: 1 }); - client.connect(function (err, client) { - var db = client.db(configuration.db); - var collection = db.collection('test_should_throw_error_if_serializing_function'); - var func = function () { - return 1; - }; - // Insert the update - collection.insert( - { i: 1, z: func }, - { writeConcern: { w: 1 }, serializeFunctions: true }, - function (err, result) { - expect(err).to.not.exist; + var db = client.db(configuration.db); + var collection = db.collection('test_should_throw_error_if_serializing_function'); + var func = function () { + return 1; + }; + // Insert the update + collection.insert( + { i: 1, z: func }, + { writeConcern: { w: 1 }, serializeFunctions: true }, + function (err, result) { + expect(err).to.not.exist; - collection.findOne({ _id: result.insertedIds[0] }, function (err, object) { - expect(err).to.not.exist; - test.equal(normalizedFunctionString(func), object.z.code); - test.equal(1, object.i); - client.close(done); - }); - } - ); - }); + collection.findOne({ _id: result.insertedIds[0] }, function (err, object) { + expect(err).to.not.exist; + test.equal(normalizedFunctionString(func), object.z.code); + test.equal(1, object.i); + client.close(done); + }); + } + ); } }); @@ -607,29 +604,26 @@ describe('crud - insert', function () { test: function (done) { var configuration = this.configuration; - var client = configuration.newClient(configuration.writeConcernMax(), { maxPoolSize: 1 }); - client.connect(function (err, client) { - var db = client.db(configuration.db); - var collection = db.collection('test_should_throw_error_if_serializing_function_1'); - var func = function () { - return 1; - }; - // Insert the update - collection.insert( - { i: 1, z: func }, - { writeConcern: { w: 1 }, serializeFunctions: true, ordered: false }, - function (err, result) { - expect(err).to.not.exist; + var db = client.db(configuration.db); + var collection = db.collection('test_should_throw_error_if_serializing_function_1'); + var func = function () { + return 1; + }; + // Insert the update + collection.insert( + { i: 1, z: func }, + { writeConcern: { w: 1 }, serializeFunctions: true, ordered: false }, + function (err, result) { + expect(err).to.not.exist; - collection.findOne({ _id: result.insertedIds[0] }, function (err, object) { - expect(err).to.not.exist; - test.equal(normalizedFunctionString(func), object.z.code); - test.equal(1, object.i); - client.close(done); - }); - } - ); - }); + collection.findOne({ _id: result.insertedIds[0] }, function (err, object) { + expect(err).to.not.exist; + test.equal(normalizedFunctionString(func), object.z.code); + test.equal(1, object.i); + client.close(done); + }); + } + ); } }); @@ -810,7 +804,7 @@ describe('crud - insert', function () { expect(err).to.not.exist; test.ok(result); - collection.remove( + collection.deleteMany( { a: 2 }, configuration.writeConcernMax(), function (err, result) { @@ -1526,7 +1520,7 @@ describe('crud - insert', function () { client.connect(function (err, client) { var db = client.db(configuration.db); var collection = db.collection('gh-completely1'); - collection.remove({ a: 1 }, { writeConcern: { w: 0 } }, cb); + collection.deleteMany({ a: 1 }, { writeConcern: { w: 0 } }, cb); }); } }); diff --git a/test/integration/crud/remove.test.js b/test/integration/crud/remove.test.js index 04ad2275f21..327f55fbc38 100644 --- a/test/integration/crud/remove.test.js +++ b/test/integration/crud/remove.test.js @@ -1,10 +1,14 @@ 'use strict'; const { expect } = require('chai'); -const { setupDatabase } = require('../shared'); describe('Remove', function () { - before(function () { - return setupDatabase(this.configuration); + let client; + beforeEach(async function () { + client = this.configuration.newClient(); + }); + + afterEach(async function () { + await client.close(); }); it('should correctly clear out collection', { @@ -13,42 +17,34 @@ describe('Remove', function () { }, test: function (done) { - const self = this; - const client = self.configuration.newClient(self.configuration.writeConcernMax(), { - maxPoolSize: 1 - }); + const db = client.db(); - client.connect(function (err, client) { - const db = client.db(self.configuration.db); + db.createCollection('test_clear', function (err) { expect(err).to.not.exist; - db.createCollection('test_clear', function (err) { - expect(err).to.not.exist; + const collection = db.collection('test_clear'); - const collection = db.collection('test_clear'); + collection.insert({ i: 1 }, { writeConcern: { w: 1 } }, function (err) { + expect(err).to.not.exist; - collection.insert({ i: 1 }, { writeConcern: { w: 1 } }, function (err) { + collection.insert({ i: 2 }, { writeConcern: { w: 1 } }, function (err) { expect(err).to.not.exist; - collection.insert({ i: 2 }, { writeConcern: { w: 1 } }, function (err) { + collection.count(function (err, count) { expect(err).to.not.exist; + expect(count).to.equal(2); - collection.count(function (err, count) { + // Clear the collection + collection.deleteMany({}, { writeConcern: { w: 1 } }, function (err, r) { expect(err).to.not.exist; - expect(count).to.equal(2); + expect(r).property('deletedCount').to.equal(2); - // Clear the collection - collection.remove({}, { writeConcern: { w: 1 } }, function (err, r) { + collection.count(function (err, count) { expect(err).to.not.exist; - expect(r).property('deletedCount').to.equal(2); + expect(count).to.equal(0); - collection.count(function (err, count) { - expect(err).to.not.exist; - expect(count).to.equal(0); - - // Let's close the db - client.close(done); - }); + // Let's close the db + client.close(done); }); }); }); @@ -85,7 +81,7 @@ describe('Remove', function () { expect(err).to.not.exist; // Clear the collection - collection.remove( + collection.deleteMany( { address: /485 7th ave/ }, { writeConcern: { w: 1 } }, function (err, r) { diff --git a/test/integration/node-specific/auto_connect.test.ts b/test/integration/node-specific/auto_connect.test.ts index 74d55208f83..39ef0e181b9 100644 --- a/test/integration/node-specific/auto_connect.test.ts +++ b/test/integration/node-specific/auto_connect.test.ts @@ -482,15 +482,6 @@ describe('When executing an operation for the first time', () => { }); }); - describe(`#insert()`, () => { - it('should connect the client', async () => { - const c = client.db().collection('test'); - // @ts-expect-error: deprecated API - await c.insert({ a: 1 }); - expect(client).to.have.property('topology').that.is.instanceOf(Topology); - }); - }); - describe(`#insertMany()`, () => { it('should connect the client', async () => { const c = client.db().collection('test'); @@ -541,15 +532,6 @@ describe('When executing an operation for the first time', () => { }); }); - describe(`#remove()`, () => { - it('should connect the client', async () => { - const c = client.db().collection('test'); - // @ts-expect-error: deprecated API - await c.remove({ a: 1 }); - expect(client).to.have.property('topology').that.is.instanceOf(Topology); - }); - }); - describe(`#rename()`, () => { it('should connect the client', async () => { const c = client.db().collection('test0'); @@ -574,15 +556,6 @@ describe('When executing an operation for the first time', () => { }); }); - describe(`#update()`, () => { - it('should connect the client', async () => { - const c = client.db().collection('test'); - // @ts-expect-error: deprecated API - await c.update({ a: 1 }, { $set: { a: 2 } }); - expect(client).to.have.property('topology').that.is.instanceOf(Topology); - }); - }); - describe(`#updateMany()`, () => { it('should connect the client', async () => { const c = client.db().collection('test'); diff --git a/test/integration/node-specific/operation_examples.test.ts b/test/integration/node-specific/operation_examples.test.ts index 59667ec385a..357e09f8802 100644 --- a/test/integration/node-specific/operation_examples.test.ts +++ b/test/integration/node-specific/operation_examples.test.ts @@ -1802,77 +1802,6 @@ describe('Operations', function () { } }); - /** - * Example of using keepGoing to allow batch insert using a Promise to complete even when there are illegal documents in the batch - * - * example-class Collection - * example-method insert - */ - it('Should correctly execute insert with keepGoing option on mongod >= 1.9.1 With Promises', { - // Add a tag that our runner can trigger on - // in this case we are setting that node needs to be higher than 0.10.X to run - metadata: { requires: { mongodb: '>1.9.1', topology: ['single'] } }, - - test: function () { - const configuration = this.configuration; - const client = configuration.newClient(configuration.writeConcernMax(), { maxPoolSize: 1 }); - - return client.connect().then(function (client) { - const db = client.db(configuration.db); - // LINE var MongoClient = require('mongodb').MongoClient, - // LINE test = require('assert'); - // LINE const client = new MongoClient('mongodb://localhost:27017/test'); - // LINE client.connect().then(() => { - // LINE var db = client.db('test); - // REPLACE configuration.writeConcernMax() WITH {w:1} - // REMOVE-LINE done(); - // BEGIN - - // Create a collection - const collection = db.collection('keepGoingExample_with_promise'); - - return collection - .drop() - .catch(() => null) - .then(function () { - // Add an unique index to title to force errors in the batch insert - return collection.createIndex({ title: 1 }, { unique: true }); - }) - .then(function (indexName) { - expect(indexName).to.exist; - - // Insert some intial data into the collection - return collection.insertMany( - [{ name: 'Jim' }, { name: 'Sarah', title: 'Princess' }], - configuration.writeConcernMax() - ); - }) - .then(function (result) { - expect(result).to.exist; - - // Force keep going flag, ignoring unique index issue - return collection.insert( - [ - { name: 'Jim' }, - { name: 'Sarah', title: 'Princess' }, - { name: 'Gump', title: 'Gump' } - ], - { writeConcern: { w: 1 }, ordered: false } - ); - }) - .catch(function () { - // Count the number of documents left (should not include the duplicates) - return collection.count(); - }) - .then(function (count) { - expect(count).to.equal(3); - return client.close(); - }); - }); - // END - } - }); - /** * An example showing how to establish if it's a capped collection using a Promise. * diff --git a/test/integration/objectid.test.js b/test/integration/objectid.test.js index 19ae6350485..1c7baf726f6 100644 --- a/test/integration/objectid.test.js +++ b/test/integration/objectid.test.js @@ -1,92 +1,43 @@ 'use strict'; var test = require('./shared').assert; const { expect } = require('chai'); -var setupDatabase = require('./shared').setupDatabase; const { ObjectId } = require('../../src'); -const { clearInterval, setInterval } = require('timers'); const { sleep } = require('../tools/utils'); describe('ObjectId', function () { - before(function () { - return setupDatabase(this.configuration); + let client; + beforeEach(async function () { + client = this.configuration.newClient(); }); - it('shouldCorrectlyGenerateObjectId', { - metadata: { - requires: { topology: ['single', 'replicaset', 'sharded', 'ssl', 'heap', 'wiredtiger'] } - }, + afterEach(async function () { + await client.close(); + }); - test: function (done) { - var configuration = this.configuration; - var client = configuration.newClient(configuration.writeConcernMax(), { maxPoolSize: 1 }); - var db = client.db(configuration.db); - var number_of_tests_done = 0; - - var collection = db.collection('test_object_id_generation.data'); - // Insert test documents (creates collections and test fetch by query) - collection.insertMany( - [{ name: 'Fred', age: 42 }], - { writeConcern: { w: 1 } }, - function (err, r) { - expect(r).property('insertedCount').to.equal(1); - - const id = r.insertedIds[0]; - expect(id.toHexString().length).to.equal(24); - // Locate the first document inserted - collection.findOne({ name: 'Fred' }, function (err, document) { - expect(err).to.not.exist; - expect(id.toHexString()).to.equal(document._id.toHexString()); - number_of_tests_done++; - }); - } - ); - - // Insert another test document and collect using ObjectId - collection.insert({ name: 'Pat', age: 21 }, { writeConcern: { w: 1 } }, function (err, r) { - expect(r).property('insertedCount').to.equal(1); - - const id = r.insertedIds[0]; - expect(id.toHexString().length).to.equal(24); - - // Locate the first document inserted - collection.findOne(id, function (err, document) { - expect(err).to.not.exist; - expect(id.toHexString()).to.equal(document._id.toHexString()); - number_of_tests_done++; - }); - }); + it('generates new ObjectId for documents without _id property', async function () { + const db = client.db(); + const collection = db.collection('test_object_id_generation'); + await collection.drop().catch(() => null); - // Manually created id - var objectId = new ObjectId(null); - // Insert a manually created document with generated oid - collection.insert( - { _id: objectId, name: 'Donald', age: 95 }, - { writeConcern: { w: 1 } }, - function (err, r) { - expect(err).to.not.exist; - expect(r).property('insertedCount').to.equal(1); - - const id = r.insertedIds[0]; - expect(id.toHexString().length).to.equal(24); - expect(id.toHexString()).to.equal(objectId.toHexString()); - - // Locate the first document inserted - collection.findOne(id, function (err, document) { - expect(err).to.not.exist; - expect(id.toHexString()).to.equal(document._id.toHexString()); - expect(objectId.toHexString()).to.equal(document._id.toHexString()); - number_of_tests_done++; - }); - } - ); - - var intervalId = setInterval(function () { - if (number_of_tests_done === 3) { - clearInterval(intervalId); - client.close(done); - } - }, 100); - } + const documents = [{ a: 1 }, { a: 1 }, { a: 1 }]; + + const parallelInserts = await Promise.all([ + collection.insertOne(documents[0]), + collection.insertOne(documents[1]), + collection.insertOne(documents[2]) + ]); + + expect(parallelInserts).to.have.lengthOf(3); + + // Input documents are modified + expect(documents[0]).to.have.deep.property('_id', parallelInserts[0].insertedId); + expect(documents[1]).to.have.deep.property('_id', parallelInserts[1].insertedId); + expect(documents[2]).to.have.deep.property('_id', parallelInserts[2].insertedId); + + // ObjectIds are generated in a predictable order + expect(documents[0]._id.id.compare(documents[1]._id.id)).to.equal(-1); + expect(documents[1]._id.id.compare(documents[2]._id.id)).to.equal(-1); + expect(documents[2]._id.id.compare(documents[0]._id.id)).to.equal(1); }); it('shouldCorrectlyRetrieve24CharacterHexStringFromToString', { diff --git a/test/mocha_mongodb.json b/test/mocha_mongodb.json index a553bec88f4..6203eea2b1d 100644 --- a/test/mocha_mongodb.json +++ b/test/mocha_mongodb.json @@ -5,9 +5,13 @@ "ts-node/register", "test/tools/runner/chai-addons.js", "test/tools/runner/hooks/configuration.js", - "test/tools/runner/hooks/leak_checker.ts" + "test/tools/runner/hooks/leak_checker.ts", + "test/tools/runner/hooks/legacy_crud_shims.ts" + ], + "extension": [ + "js", + "ts" ], - "extension": ["js", "ts"], "ui": "test/tools/runner/metadata_ui.js", "recursive": true, "timeout": 60000, diff --git a/test/tools/runner/hooks/legacy_crud_shims.ts b/test/tools/runner/hooks/legacy_crud_shims.ts new file mode 100644 index 00000000000..357b0a6d503 --- /dev/null +++ b/test/tools/runner/hooks/legacy_crud_shims.ts @@ -0,0 +1,51 @@ +import { expect } from 'chai'; + +import { Collection } from '../../../../src'; + +// Setup legacy shims for tests that use removed or changed APIs +const legacyUsageCounts = { + insert: 0, + update: 0 +}; + +const legacyUsageMaximums = { + insert: 340, + update: 25 +}; + +// @ts-expect-error: Method no longer exists on Collection +Collection.prototype.insert = function (docs, options, callback) { + legacyUsageCounts.insert += 1; + callback = + typeof callback === 'function' ? callback : typeof options === 'function' ? options : undefined; + options = options != null && typeof options === 'object' ? options : { ordered: false }; + + docs = Array.isArray(docs) ? docs : [docs]; + + return this.insertMany(docs, options, callback); +}; + +// @ts-expect-error: Method no longer exists on Collection +Collection.prototype.update = function (filter, update, options, callback) { + legacyUsageCounts.update += 1; + callback = + typeof callback === 'function' ? callback : typeof options === 'function' ? options : undefined; + options = options != null && typeof options === 'object' ? options : {}; + + return this.updateMany(filter, update, options, callback); +}; + +function assertLegacyAPIUsageDoesNotIncrease() { + expect( + legacyUsageCounts.insert, + 'Please do not use more instance of the legacy CRUD API: insert' + ).is.lessThanOrEqual(legacyUsageMaximums.insert); + expect( + legacyUsageCounts.update, + 'Please do not use more instance of the legacy CRUD API: update' + ).is.lessThanOrEqual(legacyUsageMaximums.update); +} + +export const mochaHooks = { + afterAll: [assertLegacyAPIUsageDoesNotIncrease] +}; diff --git a/test/types/mongodb.test-d.ts b/test/types/mongodb.test-d.ts index 2987d1b8c1c..5c17b23a7ee 100644 --- a/test/types/mongodb.test-d.ts +++ b/test/types/mongodb.test-d.ts @@ -7,9 +7,6 @@ import type { AggregationCursor, ChangeStreamDocument } from '../mongodb'; import { Collection, FindCursor, MongoClient } from '../mongodb'; // We wish to keep these APIs but continue to ensure they are marked as deprecated. -expectDeprecated(Collection.prototype.insert); -expectDeprecated(Collection.prototype.update); -expectDeprecated(Collection.prototype.remove); expectDeprecated(Collection.prototype.count); expectDeprecated(Collection.prototype.mapReduce); expectDeprecated(FindCursor.prototype.count); diff --git a/test/unit/assorted/bulk_write.test.js b/test/unit/assorted/bulk_write.test.js deleted file mode 100644 index 8e32673ffca..00000000000 --- a/test/unit/assorted/bulk_write.test.js +++ /dev/null @@ -1,67 +0,0 @@ -'use strict'; - -const { expect } = require('chai'); -const mock = require('../../tools/mongodb-mock/index'); -const { MongoClient } = require('../../../src'); -const { isHello } = require('../../mongodb'); - -describe('Bulk Writes', function () { - const test = {}; - - let documents; - before(() => { - documents = new Array(20000).fill('').map(() => ({ - arr: new Array(19).fill('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa') - })); - }); - - beforeEach(() => { - return mock.createServer().then(server => { - test.server = server; - }); - }); - afterEach(() => mock.cleanup()); - - it('should propagate errors', function (done) { - const client = new MongoClient(`mongodb://${test.server.uri()}/test`); - - let close = e => { - close = () => {}; - client.close(() => done(e)); - }; - - let hasErrored = false; - - test.server.setMessageHandler(request => { - const doc = request.document; - if (isHello(doc)) { - request.reply(Object.assign({}, mock.HELLO)); - } else if (doc.endSessions) { - request.reply({ ok: 1 }); - } else if (doc.insert) { - if (hasErrored) { - return request.reply({ ok: 1 }); - } - hasErrored = true; - return request.reply({ ok: 0 }); - } else { - close(`Received unknown command ${doc}`); - } - }); - - client.connect(function (err) { - expect(err).to.not.exist; - - const coll = client.db('foo').collection('bar'); - - coll.insert(documents, { ordered: false }, function (err) { - try { - expect(err).to.be.an.instanceOf(Error); - close(); - } catch (e) { - close(e); - } - }); - }); - }); -}); diff --git a/test/unit/assorted/sessions_collection.test.js b/test/unit/assorted/sessions_collection.test.js index cc63137f9b4..e72120a0023 100644 --- a/test/unit/assorted/sessions_collection.test.js +++ b/test/unit/assorted/sessions_collection.test.js @@ -33,21 +33,19 @@ describe('Sessions - unit/sessions', function () { }); const client = new MongoClient(`mongodb://${test.server.uri()}/test`); - return client.connect().then(client => { - const session = client.startSession({ causalConsistency: true }); - const coll = client.db('foo').collection('bar'); + const session = client.startSession({ causalConsistency: true }); + const coll = client.db('foo').collection('bar'); - return coll - .insert({ a: 42 }, { session: session }) - .then(() => coll.findOne({}, { session: session, readConcern: { level: 'majority' } })) - .then(() => { - expect(findCommand.readConcern).to.have.keys(['level', 'afterClusterTime']); - expect(findCommand.readConcern.afterClusterTime).to.eql(insertOperationTime); + return coll + .insertOne({ a: 42 }, { session: session }) + .then(() => coll.findOne({}, { session: session, readConcern: { level: 'majority' } })) + .then(() => { + expect(findCommand.readConcern).to.have.keys(['level', 'afterClusterTime']); + expect(findCommand.readConcern.afterClusterTime).to.eql(insertOperationTime); - session.endSession({ skipCommand: true }); - return client.close(); - }); - }); + session.endSession({ skipCommand: true }); + return client.close(); + }); }); it('does not mutate command options', function () {