Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
c9fc786
chore: reuse parse work
nbbeeken May 9, 2024
91418d8
chore: turn back on cursorResponse
nbbeeken May 9, 2024
414cdfa
wip
nbbeeken May 9, 2024
cd29ba1
wip
nbbeeken May 10, 2024
a342412
feat(NODE-6136): parse cursor responses on demand
nbbeeken May 15, 2024
9eff48a
wip
nbbeeken May 10, 2024
4534ada
fix: FLE
nbbeeken May 17, 2024
0075729
test: needs fail points
nbbeeken May 17, 2024
79acc71
test: undo bench changes
nbbeeken May 17, 2024
dde8250
chore: cleanup
nbbeeken May 17, 2024
0b825f1
wip
nbbeeken Jun 3, 2024
e0c2250
wip
nbbeeken Jun 4, 2024
1c10a1f
chore: fix unit tests
nbbeeken Jun 4, 2024
be871b8
chore: fix wc throw location
nbbeeken Jun 4, 2024
6989a54
fix: add get overload properly
nbbeeken Jun 5, 2024
9e07ea8
chore: use serialize to make empty_v
nbbeeken Jun 6, 2024
6d081f4
docs: add comment about type crime
nbbeeken Jun 6, 2024
241a08e
cruft
nbbeeken Jun 6, 2024
de3c271
chore: type annotation
nbbeeken Jun 6, 2024
4743695
chore: move ExecutionResult and document
nbbeeken Jun 6, 2024
cba9c49
test: add match to expected errors
nbbeeken Jun 6, 2024
acbb323
test: uncomment wc error ctor tests
nbbeeken Jun 6, 2024
1ffa752
fix: super generic
nbbeeken Jun 7, 2024
fb7de90
Merge branch 'main' into NODE-6136-cursor-response
nbbeeken Jun 7, 2024
827e3f7
chore: fix nullish documents
nbbeeken Jun 7, 2024
00b90ea
fix: pass through options
nbbeeken Jun 7, 2024
e28dbbb
Merge branch 'main' into NODE-6136-cursor-response
nbbeeken Jun 7, 2024
e517ab3
refactor: move CountDocument logic into collection API (#4138)
nbbeeken Jun 10, 2024
9d75303
Revert "refactor: move CountDocument logic into collection API" (#4139)
nbbeeken Jun 10, 2024
b9cfb7c
Merge branch 'main' into NODE-6136-cursor-response
nbbeeken Jun 10, 2024
c1c8ba4
chore: only attach encryptedResponse to cursor response
nbbeeken Jun 10, 2024
d5214c8
chore: clean up TS for "required"
nbbeeken Jun 11, 2024
eb0b618
Merge branch 'main' into NODE-6136-cursor-response
baileympearson Jun 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
refactor: move CountDocument logic into collection API (#4138)
  • Loading branch information
nbbeeken authored Jun 10, 2024
commit e517ab39fbfe84777799160e6211dd972f4010fd
30 changes: 25 additions & 5 deletions src/collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import type {
import type { AggregateOptions } from './operations/aggregate';
import { BulkWriteOperation } from './operations/bulk_write';
import { CountOperation, type CountOptions } from './operations/count';
import { CountDocumentsOperation, type CountDocumentsOptions } from './operations/count_documents';
import {
DeleteManyOperation,
DeleteOneOperation,
Expand Down Expand Up @@ -94,6 +93,14 @@ import {
} from './utils';
import { WriteConcern, type WriteConcernOptions } from './write_concern';

/** @public */
export interface CountDocumentsOptions extends AggregateOptions {
/** The number of documents to skip. */
skip?: number;
/** The maximum amounts to count before aborting. */
limit?: number;
}

/** @public */
export interface ModifyResult<TSchema = Document> {
value: WithId<TSchema> | null;
Expand Down Expand Up @@ -764,10 +771,23 @@ export class Collection<TSchema extends Document = Document> {
filter: Filter<TSchema> = {},
options: CountDocumentsOptions = {}
): Promise<number> {
return await executeOperation(
this.client,
new CountDocumentsOperation(this as TODO_NODE_3286, filter, resolveOptions(this, options))
);
const pipeline = [];
pipeline.push({ $match: filter });

if (typeof options.skip === 'number') {
pipeline.push({ $skip: options.skip });
}

if (typeof options.limit === 'number') {
pipeline.push({ $limit: options.limit });
}

pipeline.push({ $group: { _id: 1, n: { $sum: 1 } } });

const cursor = this.aggregate<{ n: number }>(pipeline, options);
const doc = await cursor.next();
await cursor.close();
return doc?.n ?? 0;
}

/**
Expand Down
8 changes: 6 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,12 @@ export type {
MongoDBResponse,
MongoDBResponseConstructor
} from './cmap/wire_protocol/responses';
export type { CollectionOptions, CollectionPrivate, ModifyResult } from './collection';
export type {
CollectionOptions,
CollectionPrivate,
CountDocumentsOptions,
ModifyResult
} from './collection';
export type {
COMMAND_FAILED,
COMMAND_STARTED,
Expand Down Expand Up @@ -458,7 +463,6 @@ export type {
OperationParent
} from './operations/command';
export type { CountOptions } from './operations/count';
export type { CountDocumentsOptions } from './operations/count_documents';
export type {
ClusteredCollectionOptions,
CreateCollectionOptions,
Expand Down
42 changes: 0 additions & 42 deletions src/operations/count_documents.ts

This file was deleted.

5 changes: 0 additions & 5 deletions test/integration/crud/abstract_operation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,6 @@ describe('abstract operation', function () {
subclassType: mongodb.CountOperation,
correctCommandName: 'count'
},
{
subclassCreator: () => new mongodb.CountDocumentsOperation(collection, { a: 1 }, {}),
subclassType: mongodb.CountDocumentsOperation,
correctCommandName: 'aggregate'
},
{
subclassCreator: () => new mongodb.CreateCollectionOperation(db, 'name'),
subclassType: mongodb.CreateCollectionOperation,
Expand Down
95 changes: 88 additions & 7 deletions test/integration/crud/crud_api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,9 @@ describe('CRUD API', function () {
const spy = sinon.spy(Collection.prototype, 'find');
const result = await collection.findOne({});
expect(result).to.deep.equal({ _id: 1 });
expect(events.at(0)).to.be.instanceOf(CommandSucceededEvent);
expect(spy.returnValues.at(0)).to.have.property('closed', true);
expect(spy.returnValues.at(0)).to.have.nested.property('session.hasEnded', true);
expect(events[0]).to.be.instanceOf(CommandSucceededEvent);
expect(spy.returnValues[0]).to.have.property('closed', true);
expect(spy.returnValues[0]).to.have.nested.property('session.hasEnded', true);
});
});

Expand All @@ -117,7 +117,7 @@ describe('CRUD API', function () {
if (this.currentTest) {
this.currentTest.skipReason = `Cannot run fail points on server version: ${this.configuration.version}`;
}
return this.skip();
this.skip();
}

const failPoint: FailPoint = {
Expand Down Expand Up @@ -149,9 +149,90 @@ describe('CRUD API', function () {
const spy = sinon.spy(Collection.prototype, 'find');
const error = await collection.findOne({}).catch(error => error);
expect(error).to.be.instanceOf(MongoServerError);
expect(events.at(0)).to.be.instanceOf(CommandFailedEvent);
expect(spy.returnValues.at(0)).to.have.property('closed', true);
expect(spy.returnValues.at(0)).to.have.nested.property('session.hasEnded', true);
expect(events[0]).to.be.instanceOf(CommandFailedEvent);
expect(spy.returnValues[0]).to.have.property('closed', true);
expect(spy.returnValues[0]).to.have.nested.property('session.hasEnded', true);
});
});
});

describe('countDocuments()', () => {
let client: MongoClient;
let events;
let collection: Collection<{ _id: number }>;

beforeEach(async function () {
client = this.configuration.newClient({ monitorCommands: true });
events = [];
client.on('commandSucceeded', commandSucceeded =>
commandSucceeded.commandName === 'aggregate' ? events.push(commandSucceeded) : null
);
client.on('commandFailed', commandFailed =>
commandFailed.commandName === 'aggregate' ? events.push(commandFailed) : null
);

collection = client.db('countDocuments').collection('countDocuments');
await collection.drop().catch(() => null);
await collection.insertMany([{ _id: 1 }, { _id: 2 }]);
});

afterEach(async () => {
await collection.drop().catch(() => null);
await client.close();
});

describe('when the aggregation operation succeeds', () => {
it('the cursor for countDocuments is closed', async function () {
const spy = sinon.spy(Collection.prototype, 'aggregate');
const result = await collection.countDocuments({});
expect(result).to.deep.equal(2);
expect(events[0]).to.be.instanceOf(CommandSucceededEvent);
expect(spy.returnValues[0]).to.have.property('closed', true);
expect(spy.returnValues[0]).to.have.nested.property('session.hasEnded', true);
});
});

describe('when the aggregation operation fails', () => {
beforeEach(async function () {
if (semver.lt(this.configuration.version, '4.2.0')) {
if (this.currentTest) {
this.currentTest.skipReason = `Cannot run fail points on server version: ${this.configuration.version}`;
}
this.skip();
}

const failPoint: FailPoint = {
configureFailPoint: 'failCommand',
mode: 'alwaysOn',
data: {
failCommands: ['aggregate'],
// 1 == InternalError, but this value not important to the test
errorCode: 1
}
};
await client.db().admin().command(failPoint);
});

afterEach(async function () {
if (semver.lt(this.configuration.version, '4.2.0')) {
return;
}

const failPoint: FailPoint = {
configureFailPoint: 'failCommand',
mode: 'off',
data: { failCommands: ['aggregate'] }
};
await client.db().admin().command(failPoint);
});

it('the cursor for countDocuments is closed', async function () {
const spy = sinon.spy(Collection.prototype, 'aggregate');
const error = await collection.countDocuments({}).catch(error => error);
expect(error).to.be.instanceOf(MongoServerError);
expect(events[0]).to.be.instanceOf(CommandFailedEvent);
expect(spy.returnValues[0]).to.have.property('closed', true);
expect(spy.returnValues[0]).to.have.nested.property('session.hasEnded', true);
});
});
});
Expand Down
1 change: 0 additions & 1 deletion test/mongodb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,6 @@ export * from '../src/operations/bulk_write';
export * from '../src/operations/collections';
export * from '../src/operations/command';
export * from '../src/operations/count';
export * from '../src/operations/count_documents';
export * from '../src/operations/create_collection';
export * from '../src/operations/delete';
export * from '../src/operations/distinct';
Expand Down