Skip to content

Commit eb223d9

Browse files
Resolve merge conflicts from main
2 parents 70685e0 + 55d1c5f commit eb223d9

File tree

78 files changed

+1465
-1209
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

78 files changed

+1465
-1209
lines changed

.eslintrc.json

+15
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,21 @@
2323
"es6": true
2424
},
2525
"rules": {
26+
"no-restricted-properties": [
27+
"error",
28+
{
29+
"object": "describe",
30+
"property": "only"
31+
},
32+
{
33+
"object": "it",
34+
"property": "only"
35+
},
36+
{
37+
"object": "context",
38+
"property": "only"
39+
}
40+
],
2641
"prettier/prettier": "error",
2742
"tsdoc/syntax": "warn",
2843
"no-console": "error",

.evergreen/run-serverless-tests.sh

+5-2
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,12 @@ if [ -z ${SERVERLESS_ATLAS_PASSWORD+omitted} ]; then echo "SERVERLESS_ATLAS_PASS
1313

1414
npx mocha --file test/tools/runner/index.js \
1515
test/integration/crud/crud.spec.test.js \
16+
test/integration/crud/crud.prose.test.js \
1617
test/integration/retryable-reads/retryable_reads.spec.test.js \
1718
test/integration/retryable-writes/retryable_writes.spec.test.js \
18-
test/functional/sessions.test.js \
19-
test/functional/transactions.test.js \
19+
test/integration/sessions/sessions.spec.test.js \
20+
test/integration/sessions/sessions.test.js \
21+
test/integration/transactions/transactions.spec.test.js \
22+
test/integration/transactions/transactions.test.js \
2023
test/integration/versioned-api/versioned_api.spec.test.js \
2124
test/integration/load-balancers/load_balancers.spec.test.js

src/collection.ts

+21-12
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import type { PkFactory } from './mongo_client';
1212
import type {
1313
Filter,
1414
Flatten,
15-
OptionalId,
15+
OptionalUnlessRequiredId,
1616
TODO_NODE_3286,
1717
UpdateFilter,
1818
WithId,
@@ -264,16 +264,22 @@ export class Collection<TSchema extends Document = Document> {
264264
* @param options - Optional settings for the command
265265
* @param callback - An optional callback, a Promise will be returned if none is provided
266266
*/
267-
insertOne(doc: OptionalId<TSchema>): Promise<InsertOneResult<TSchema>>;
268-
insertOne(doc: OptionalId<TSchema>, callback: Callback<InsertOneResult<TSchema>>): void;
269-
insertOne(doc: OptionalId<TSchema>, options: InsertOneOptions): Promise<InsertOneResult<TSchema>>;
267+
insertOne(doc: OptionalUnlessRequiredId<TSchema>): Promise<InsertOneResult<TSchema>>;
270268
insertOne(
271-
doc: OptionalId<TSchema>,
269+
doc: OptionalUnlessRequiredId<TSchema>,
270+
callback: Callback<InsertOneResult<TSchema>>
271+
): void;
272+
insertOne(
273+
doc: OptionalUnlessRequiredId<TSchema>,
274+
options: InsertOneOptions
275+
): Promise<InsertOneResult<TSchema>>;
276+
insertOne(
277+
doc: OptionalUnlessRequiredId<TSchema>,
272278
options: InsertOneOptions,
273279
callback: Callback<InsertOneResult<TSchema>>
274280
): void;
275281
insertOne(
276-
doc: OptionalId<TSchema>,
282+
doc: OptionalUnlessRequiredId<TSchema>,
277283
options?: InsertOneOptions | Callback<InsertOneResult<TSchema>>,
278284
callback?: Callback<InsertOneResult<TSchema>>
279285
): Promise<InsertOneResult<TSchema>> | void {
@@ -308,19 +314,22 @@ export class Collection<TSchema extends Document = Document> {
308314
* @param options - Optional settings for the command
309315
* @param callback - An optional callback, a Promise will be returned if none is provided
310316
*/
311-
insertMany(docs: OptionalId<TSchema>[]): Promise<InsertManyResult<TSchema>>;
312-
insertMany(docs: OptionalId<TSchema>[], callback: Callback<InsertManyResult<TSchema>>): void;
317+
insertMany(docs: OptionalUnlessRequiredId<TSchema>[]): Promise<InsertManyResult<TSchema>>;
318+
insertMany(
319+
docs: OptionalUnlessRequiredId<TSchema>[],
320+
callback: Callback<InsertManyResult<TSchema>>
321+
): void;
313322
insertMany(
314-
docs: OptionalId<TSchema>[],
323+
docs: OptionalUnlessRequiredId<TSchema>[],
315324
options: BulkWriteOptions
316325
): Promise<InsertManyResult<TSchema>>;
317326
insertMany(
318-
docs: OptionalId<TSchema>[],
327+
docs: OptionalUnlessRequiredId<TSchema>[],
319328
options: BulkWriteOptions,
320329
callback: Callback<InsertManyResult<TSchema>>
321330
): void;
322331
insertMany(
323-
docs: OptionalId<TSchema>[],
332+
docs: OptionalUnlessRequiredId<TSchema>[],
324333
options?: BulkWriteOptions | Callback<InsertManyResult<TSchema>>,
325334
callback?: Callback<InsertManyResult<TSchema>>
326335
): Promise<InsertManyResult<TSchema>> | void {
@@ -1526,7 +1535,7 @@ export class Collection<TSchema extends Document = Document> {
15261535
* @param callback - An optional callback, a Promise will be returned if none is provided
15271536
*/
15281537
insert(
1529-
docs: OptionalId<TSchema>[],
1538+
docs: OptionalUnlessRequiredId<TSchema>[],
15301539
options: BulkWriteOptions,
15311540
callback: Callback<InsertManyResult<TSchema>>
15321541
): Promise<InsertManyResult<TSchema>> | void {

src/constants.ts

+6
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,9 @@ export const MONGO_CLIENT_EVENTS = Object.freeze([
114114
...TOPOLOGY_EVENTS,
115115
...HEARTBEAT_EVENTS
116116
] as const);
117+
118+
/**
119+
* @internal
120+
* The legacy hello command that was deprecated in MongoDB 5.0.
121+
*/
122+
export const LEGACY_HELLO_COMMAND = 'ismaster';

src/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -288,11 +288,13 @@ export type {
288288
KeysOfOtherType,
289289
MatchKeysAndValues,
290290
NestedPaths,
291+
NonObjectIdLikeDocument,
291292
NotAcceptedFields,
292293
NumericType,
293294
OneOrMore,
294295
OnlyFieldsOfType,
295296
OptionalId,
297+
OptionalUnlessRequiredId,
296298
Projection,
297299
ProjectionOperators,
298300
PropertyType,

src/mongo_types.ts

+30-13
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { ObjectIdLike } from 'bson';
12
import { EventEmitter } from 'events';
23

34
import type {
@@ -17,13 +18,15 @@ import type { Sort } from './sort';
1718
export type TODO_NODE_3286 = any;
1819

1920
/** Given an object shaped type, return the type of the _id field or default to ObjectId @public */
20-
export type InferIdType<TSchema> = TSchema extends { _id: infer IdType } // user has defined a type for _id
21-
? // eslint-disable-next-line @typescript-eslint/ban-types
22-
{} extends IdType // TODO(NODE-3285): Improve type readability
23-
? // eslint-disable-next-line @typescript-eslint/ban-types
24-
Exclude<IdType, {}>
25-
: unknown extends IdType
26-
? ObjectId
21+
export type InferIdType<TSchema> = TSchema extends { _id: infer IdType }
22+
? // user has defined a type for _id
23+
Record<any, never> extends IdType
24+
? never // explicitly forbid empty objects as the type of _id
25+
: IdType
26+
: TSchema extends { _id?: infer IdType }
27+
? // optional _id defined - return ObjectId | IdType
28+
unknown extends IdType
29+
? ObjectId // infer the _id type as ObjectId if the type of _id is unknown
2730
: IdType
2831
: ObjectId; // user has not defined _id on schema
2932

@@ -33,17 +36,23 @@ export type WithId<TSchema> = EnhancedOmit<TSchema, '_id'> & { _id: InferIdType<
3336
/**
3437
* Add an optional _id field to an object shaped type
3538
* @public
39+
*/
40+
export type OptionalId<TSchema> = EnhancedOmit<TSchema, '_id'> & { _id?: InferIdType<TSchema> };
41+
42+
/**
43+
* Adds an optional _id field to an object shaped type, unless the _id field is requried on that type.
44+
* In the case _id is required, this method continues to require_id.
45+
*
46+
* @public
3647
*
3748
* @privateRemarks
3849
* `ObjectId extends TSchema['_id']` is a confusing ordering at first glance. Rather than ask
3950
* `TSchema['_id'] extends ObjectId` which translated to "Is the _id property ObjectId?"
4051
* we instead ask "Does ObjectId look like (have the same shape) as the _id?"
4152
*/
42-
export type OptionalId<TSchema> = TSchema extends { _id?: any }
43-
? ObjectId extends TSchema['_id'] // a Schema with ObjectId _id type or "any" or "indexed type" provided
44-
? EnhancedOmit<TSchema, '_id'> & { _id?: InferIdType<TSchema> } // a Schema provided but _id type is not ObjectId
45-
: WithId<TSchema>
46-
: EnhancedOmit<TSchema, '_id'> & { _id?: InferIdType<TSchema> }; // TODO(NODE-3285): Improve type readability
53+
export type OptionalUnlessRequiredId<TSchema> = TSchema extends { _id: any }
54+
? TSchema
55+
: OptionalId<TSchema>;
4756

4857
/** TypeScript Omit (Exclude to be specific) does not work for objects with an "any" indexed type, and breaks discriminated unions @public */
4958
export type EnhancedOmit<TRecordOrUnion, KeyUnion> = string extends keyof TRecordOrUnion
@@ -93,8 +102,16 @@ export interface RootFilterOperators<TSchema> extends Document {
93102
$comment?: string | Document;
94103
}
95104

105+
/**
106+
* @public
107+
* A type that extends Document but forbids anything that "looks like" an object id.
108+
*/
109+
export type NonObjectIdLikeDocument = {
110+
[key in keyof ObjectIdLike]?: never;
111+
} & Document;
112+
96113
/** @public */
97-
export interface FilterOperators<TValue> extends Document {
114+
export interface FilterOperators<TValue> extends NonObjectIdLikeDocument {
98115
// Comparison
99116
$eq?: TValue;
100117
$gt?: TValue;

src/operations/find.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export interface FindOptions<TSchema extends Document = Document> extends Comman
3636
timeout?: boolean;
3737
/** Specify if the cursor is tailable. */
3838
tailable?: boolean;
39-
/** Specify if the cursor is a a tailable-await cursor. Requires `tailable` to be true */
39+
/** Specify if the cursor is a tailable-await cursor. Requires `tailable` to be true */
4040
awaitData?: boolean;
4141
/** Set the batchSize for the getMoreCommand when iterating over the query results. */
4242
batchSize?: number;

src/utils.ts

+9
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { Document, ObjectId, resolveBSONOptions } from './bson';
77
import type { Connection } from './cmap/connection';
88
import { MAX_SUPPORTED_WIRE_VERSION } from './cmap/wire_protocol/constants';
99
import type { Collection } from './collection';
10+
import { LEGACY_HELLO_COMMAND } from './constants';
1011
import type { Db } from './db';
1112
import {
1213
AnyError,
@@ -1097,6 +1098,14 @@ export function isSuperset(set: Set<any> | any[], subset: Set<any> | any[]): boo
10971098
return true;
10981099
}
10991100

1101+
/**
1102+
* Checks if the document is a Hello request
1103+
* @internal
1104+
*/
1105+
export function isHello(doc: Document): boolean {
1106+
return doc[LEGACY_HELLO_COMMAND] || doc.hello ? true : false;
1107+
}
1108+
11001109
/** Returns the items that are uniquely in setA */
11011110
export function setDifference<T>(setA: Iterable<T>, setB: Iterable<T>): Set<T> {
11021111
const difference = new Set<T>(setA);

test/benchmarks/driverBench/index.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ const MongoBench = require('../mongoBench');
55
const Runner = MongoBench.Runner;
66
const commonHelpers = require('./common');
77

8+
const { LEGACY_HELLO_COMMAND } = require('../../../src/constants');
9+
810
let BSON = require('bson');
911

1012
try {
@@ -110,7 +112,9 @@ function runCommand(done) {
110112
if (_id > 10000) {
111113
return done();
112114
}
113-
return this.db.command({ ismaster: true }, err => (err ? done(err) : loop(_id + 1)));
115+
return this.db.command({ [LEGACY_HELLO_COMMAND]: true }, err =>
116+
err ? done(err) : loop(_id + 1)
117+
);
114118
};
115119

116120
return loop(1);

test/functional/collations.test.js

+13-12
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const setupDatabase = require('./shared').setupDatabase;
33
const mock = require('../tools/mongodb-mock/index');
44
const expect = require('chai').expect;
55
const { Long, Code } = require('../../src');
6+
const { isHello } = require('../../src/utils');
67

78
const testContext = {};
89
describe('Collation', function () {
@@ -26,7 +27,7 @@ describe('Collation', function () {
2627
let commandResult;
2728
testContext.server.setMessageHandler(request => {
2829
const doc = request.document;
29-
if (doc.ismaster || doc.hello) {
30+
if (isHello(doc)) {
3031
request.reply(primary[0]);
3132
} else if (doc.count) {
3233
commandResult = doc;
@@ -62,7 +63,7 @@ describe('Collation', function () {
6263
let commandResult;
6364
testContext.server.setMessageHandler(request => {
6465
const doc = request.document;
65-
if (doc.ismaster || doc.hello) {
66+
if (isHello(doc)) {
6667
request.reply(primary[0]);
6768
} else if (doc.aggregate) {
6869
commandResult = doc;
@@ -100,7 +101,7 @@ describe('Collation', function () {
100101
let commandResult;
101102
testContext.server.setMessageHandler(request => {
102103
var doc = request.document;
103-
if (doc.ismaster || doc.hello) {
104+
if (isHello(doc)) {
104105
request.reply(primary[0]);
105106
} else if (doc.distinct) {
106107
commandResult = doc;
@@ -136,7 +137,7 @@ describe('Collation', function () {
136137
let commandResult;
137138
testContext.server.setMessageHandler(request => {
138139
var doc = request.document;
139-
if (doc.ismaster || doc.hello) {
140+
if (isHello(doc)) {
140141
request.reply(primary[0]);
141142
} else if (doc.mapReduce) {
142143
commandResult = doc;
@@ -177,7 +178,7 @@ describe('Collation', function () {
177178
let commandResult;
178179
testContext.server.setMessageHandler(request => {
179180
var doc = request.document;
180-
if (doc.ismaster || doc.hello) {
181+
if (isHello(doc)) {
181182
request.reply(primary[0]);
182183
} else if (doc.delete) {
183184
commandResult = doc;
@@ -213,7 +214,7 @@ describe('Collation', function () {
213214
let commandResult;
214215
testContext.server.setMessageHandler(request => {
215216
const doc = request.document;
216-
if (doc.ismaster || doc.hello) {
217+
if (isHello(doc)) {
217218
request.reply(primary[0]);
218219
} else if (doc.update) {
219220
commandResult = doc;
@@ -251,7 +252,7 @@ describe('Collation', function () {
251252
let commandResult;
252253
testContext.server.setMessageHandler(request => {
253254
const doc = request.document;
254-
if (doc.ismaster || doc.hello) {
255+
if (isHello(doc)) {
255256
request.reply(primary[0]);
256257
} else if (doc.find) {
257258
commandResult = doc;
@@ -287,7 +288,7 @@ describe('Collation', function () {
287288
let commandResult;
288289
testContext.server.setMessageHandler(request => {
289290
const doc = request.document;
290-
if (doc.ismaster || doc.hello) {
291+
if (isHello(doc)) {
291292
request.reply(primary[0]);
292293
} else if (doc.find) {
293294
commandResult = doc;
@@ -325,7 +326,7 @@ describe('Collation', function () {
325326
let commandResult;
326327
testContext.server.setMessageHandler(request => {
327328
const doc = request.document;
328-
if (doc.ismaster || doc.hello) {
329+
if (isHello(doc)) {
329330
request.reply(primary[0]);
330331
} else if (doc.find) {
331332
commandResult = doc;
@@ -361,7 +362,7 @@ describe('Collation', function () {
361362
let commandResult;
362363
testContext.server.setMessageHandler(request => {
363364
const doc = request.document;
364-
if (doc.ismaster || doc.hello) {
365+
if (isHello(doc)) {
365366
request.reply(primary[0]);
366367
} else if (doc.listCollections) {
367368
request.reply({
@@ -403,7 +404,7 @@ describe('Collation', function () {
403404
let commandResult;
404405
testContext.server.setMessageHandler(request => {
405406
const doc = request.document;
406-
if (doc.ismaster || doc.hello) {
407+
if (isHello(doc)) {
407408
request.reply(primary[0]);
408409
} else if (doc.update) {
409410
commandResult = doc;
@@ -457,7 +458,7 @@ describe('Collation', function () {
457458
let commandResult;
458459
testContext.server.setMessageHandler(request => {
459460
const doc = request.document;
460-
if (doc.ismaster || doc.hello) {
461+
if (isHello(doc)) {
461462
request.reply(primary[0]);
462463
} else if (doc.createIndexes) {
463464
commandResult = doc;

test/functional/collection.test.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const sinonChai = require('sinon-chai');
77
const mock = require('../tools/mongodb-mock/index');
88

99
chai.use(sinonChai);
10+
const { isHello } = require('../../src/utils');
1011

1112
describe('Collection', function () {
1213
let configuration;
@@ -638,7 +639,7 @@ describe('Collection', function () {
638639
}
639640
}
640641

641-
if (doc.ismaster || doc.hello) {
642+
if (isHello(doc)) {
642643
request.reply(Object.assign({}, mock.HELLO));
643644
} else if (doc.endSessions) {
644645
request.reply({ ok: 1 });

0 commit comments

Comments
 (0)