mongodb 6.18.0-dev.20250805.sha.ff9a7858 → 6.18.0-dev.20250806.sha.e628296a
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/beta.d.ts +2 -1
- package/lib/cmap/connection.js.map +1 -1
- package/lib/cursor/aggregation_cursor.js +2 -1
- package/lib/cursor/aggregation_cursor.js.map +1 -1
- package/lib/cursor/explainable_cursor.js +36 -0
- package/lib/cursor/explainable_cursor.js.map +1 -0
- package/lib/cursor/find_cursor.js +2 -1
- package/lib/cursor/find_cursor.js.map +1 -1
- package/lib/explain.js +1 -33
- package/lib/explain.js.map +1 -1
- package/lib/index.js +6 -6
- package/lib/index.js.map +1 -1
- package/lib/operations/aggregate.js +10 -8
- package/lib/operations/aggregate.js.map +1 -1
- package/lib/operations/command.js +0 -9
- package/lib/operations/command.js.map +1 -1
- package/lib/operations/execute_operation.js +2 -1
- package/lib/operations/execute_operation.js.map +1 -1
- package/lib/operations/find.js +13 -24
- package/lib/operations/find.js.map +1 -1
- package/lib/operations/get_more.js +11 -12
- package/lib/operations/get_more.js.map +1 -1
- package/lib/operations/indexes.js +8 -4
- package/lib/operations/indexes.js.map +1 -1
- package/lib/operations/kill_cursors.js +14 -16
- package/lib/operations/kill_cursors.js.map +1 -1
- package/lib/operations/list_collections.js +8 -7
- package/lib/operations/list_collections.js.map +1 -1
- package/lib/operations/operation.js +0 -1
- package/lib/operations/operation.js.map +1 -1
- package/lib/sdam/server.js +6 -12
- package/lib/sdam/server.js.map +1 -1
- package/lib/sdam/topology.js +3 -2
- package/lib/sdam/topology.js.map +1 -1
- package/mongodb.d.ts +2 -1
- package/package.json +1 -1
- package/src/cmap/connection.ts +0 -1
- package/src/cursor/aggregation_cursor.ts +1 -1
- package/src/cursor/explainable_cursor.ts +51 -0
- package/src/cursor/find_cursor.ts +1 -1
- package/src/explain.ts +0 -49
- package/src/index.ts +2 -2
- package/src/operations/aggregate.ts +21 -22
- package/src/operations/command.ts +1 -12
- package/src/operations/execute_operation.ts +2 -1
- package/src/operations/find.ts +28 -49
- package/src/operations/get_more.ts +18 -20
- package/src/operations/indexes.ts +13 -8
- package/src/operations/kill_cursors.ts +22 -23
- package/src/operations/list_collections.ts +15 -23
- package/src/operations/operation.ts +0 -3
- package/src/sdam/server.ts +8 -13
- package/src/sdam/topology.ts +4 -3
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import type { Long } from '../bson';
|
|
1
|
+
import type { Document, Long } from '../bson';
|
|
2
|
+
import { type Connection } from '../cmap/connection';
|
|
2
3
|
import { CursorResponse } from '../cmap/wire_protocol/responses';
|
|
3
4
|
import { MongoRuntimeError } from '../error';
|
|
4
|
-
import type { Server } from '../sdam/server';
|
|
5
|
-
import type { ClientSession } from '../sessions';
|
|
5
|
+
import type { Server, ServerCommandOptions } from '../sdam/server';
|
|
6
6
|
import { type TimeoutContext } from '../timeout';
|
|
7
7
|
import { maxWireVersion, type MongoDBNamespace } from '../utils';
|
|
8
|
-
import {
|
|
8
|
+
import { Aspect, defineAspects, ModernizedOperation, type OperationOptions } from './operation';
|
|
9
9
|
|
|
10
10
|
/** @internal */
|
|
11
11
|
export interface GetMoreOptions extends OperationOptions {
|
|
@@ -37,7 +37,8 @@ export interface GetMoreCommand {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
/** @internal */
|
|
40
|
-
export class GetMoreOperation extends
|
|
40
|
+
export class GetMoreOperation extends ModernizedOperation<CursorResponse> {
|
|
41
|
+
override SERVER_COMMAND_RESPONSE_TYPE = CursorResponse;
|
|
41
42
|
cursorId: Long;
|
|
42
43
|
override options: GetMoreOptions;
|
|
43
44
|
|
|
@@ -53,19 +54,8 @@ export class GetMoreOperation extends AbstractOperation {
|
|
|
53
54
|
override get commandName() {
|
|
54
55
|
return 'getMore' as const;
|
|
55
56
|
}
|
|
56
|
-
/**
|
|
57
|
-
* Although there is a server already associated with the get more operation, the signature
|
|
58
|
-
* for execute passes a server so we will just use that one.
|
|
59
|
-
*/
|
|
60
|
-
override async execute(
|
|
61
|
-
server: Server,
|
|
62
|
-
_session: ClientSession | undefined,
|
|
63
|
-
timeoutContext: TimeoutContext
|
|
64
|
-
): Promise<CursorResponse> {
|
|
65
|
-
if (server !== this.server) {
|
|
66
|
-
throw new MongoRuntimeError('Getmore must run on the same server operation began on');
|
|
67
|
-
}
|
|
68
57
|
|
|
58
|
+
override buildCommand(connection: Connection): Document {
|
|
69
59
|
if (this.cursorId == null || this.cursorId.isZero()) {
|
|
70
60
|
throw new MongoRuntimeError('Unable to iterate cursor with no id');
|
|
71
61
|
}
|
|
@@ -92,18 +82,26 @@ export class GetMoreOperation extends AbstractOperation {
|
|
|
92
82
|
|
|
93
83
|
// we check for undefined specifically here to allow falsy values
|
|
94
84
|
// eslint-disable-next-line no-restricted-syntax
|
|
95
|
-
if (this.options.comment !== undefined && maxWireVersion(
|
|
85
|
+
if (this.options.comment !== undefined && maxWireVersion(connection) >= 9) {
|
|
96
86
|
getMoreCmd.comment = this.options.comment;
|
|
97
87
|
}
|
|
98
88
|
|
|
99
|
-
|
|
89
|
+
return getMoreCmd;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
override buildOptions(timeoutContext: TimeoutContext): ServerCommandOptions {
|
|
93
|
+
return {
|
|
100
94
|
returnFieldSelector: null,
|
|
101
95
|
documentsReturnedIn: 'nextBatch',
|
|
102
96
|
timeoutContext,
|
|
103
97
|
...this.options
|
|
104
98
|
};
|
|
99
|
+
}
|
|
105
100
|
|
|
106
|
-
|
|
101
|
+
override handleOk(
|
|
102
|
+
response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>
|
|
103
|
+
): CursorResponse {
|
|
104
|
+
return response;
|
|
107
105
|
}
|
|
108
106
|
}
|
|
109
107
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Document } from '../bson';
|
|
2
|
+
import { type Connection } from '../cmap/connection';
|
|
2
3
|
import { CursorResponse } from '../cmap/wire_protocol/responses';
|
|
3
4
|
import type { Collection } from '../collection';
|
|
4
5
|
import { type AbstractCursorOptions } from '../cursor/abstract_cursor';
|
|
@@ -12,6 +13,7 @@ import {
|
|
|
12
13
|
type CollationOptions,
|
|
13
14
|
CommandOperation,
|
|
14
15
|
type CommandOperationOptions,
|
|
16
|
+
ModernizedCommandOperation,
|
|
15
17
|
type OperationParent
|
|
16
18
|
} from './command';
|
|
17
19
|
import { Aspect, defineAspects } from './operation';
|
|
@@ -366,7 +368,8 @@ export type ListIndexesOptions = AbstractCursorOptions & {
|
|
|
366
368
|
};
|
|
367
369
|
|
|
368
370
|
/** @internal */
|
|
369
|
-
export class ListIndexesOperation extends
|
|
371
|
+
export class ListIndexesOperation extends ModernizedCommandOperation<CursorResponse> {
|
|
372
|
+
override SERVER_COMMAND_RESPONSE_TYPE = CursorResponse;
|
|
370
373
|
/**
|
|
371
374
|
* @remarks WriteConcern can still be present on the options because
|
|
372
375
|
* we inherit options from the client/db/collection. The
|
|
@@ -389,12 +392,8 @@ export class ListIndexesOperation extends CommandOperation<CursorResponse> {
|
|
|
389
392
|
return 'listIndexes' as const;
|
|
390
393
|
}
|
|
391
394
|
|
|
392
|
-
override
|
|
393
|
-
|
|
394
|
-
session: ClientSession | undefined,
|
|
395
|
-
timeoutContext: TimeoutContext
|
|
396
|
-
): Promise<CursorResponse> {
|
|
397
|
-
const serverWireVersion = maxWireVersion(server);
|
|
395
|
+
override buildCommandDocument(connection: Connection): Document {
|
|
396
|
+
const serverWireVersion = maxWireVersion(connection);
|
|
398
397
|
|
|
399
398
|
const cursor = this.options.batchSize ? { batchSize: this.options.batchSize } : {};
|
|
400
399
|
|
|
@@ -406,7 +405,13 @@ export class ListIndexesOperation extends CommandOperation<CursorResponse> {
|
|
|
406
405
|
command.comment = this.options.comment;
|
|
407
406
|
}
|
|
408
407
|
|
|
409
|
-
return
|
|
408
|
+
return command;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
override handleOk(
|
|
412
|
+
response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>
|
|
413
|
+
): CursorResponse {
|
|
414
|
+
return response;
|
|
410
415
|
}
|
|
411
416
|
}
|
|
412
417
|
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import type { Long } from '../bson';
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
2
|
+
import { type Connection } from '../cmap/connection';
|
|
3
|
+
import { MongoDBResponse } from '../cmap/wire_protocol/responses';
|
|
4
|
+
import { type MongoError, MongoRuntimeError } from '../error';
|
|
5
|
+
import type { Server, ServerCommandOptions } from '../sdam/server';
|
|
4
6
|
import type { ClientSession } from '../sessions';
|
|
5
7
|
import { type TimeoutContext } from '../timeout';
|
|
6
|
-
import { type MongoDBNamespace
|
|
7
|
-
import {
|
|
8
|
+
import { type MongoDBNamespace } from '../utils';
|
|
9
|
+
import { Aspect, defineAspects, ModernizedOperation, type OperationOptions } from './operation';
|
|
8
10
|
|
|
9
11
|
/**
|
|
10
12
|
* https://www.mongodb.com/docs/manual/reference/command/killCursors/
|
|
@@ -16,7 +18,8 @@ interface KillCursorsCommand {
|
|
|
16
18
|
comment?: unknown;
|
|
17
19
|
}
|
|
18
20
|
|
|
19
|
-
export class KillCursorsOperation extends
|
|
21
|
+
export class KillCursorsOperation extends ModernizedOperation<void> {
|
|
22
|
+
override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
|
|
20
23
|
cursorId: Long;
|
|
21
24
|
|
|
22
25
|
constructor(cursorId: Long, ns: MongoDBNamespace, server: Server, options: OperationOptions) {
|
|
@@ -30,15 +33,7 @@ export class KillCursorsOperation extends AbstractOperation {
|
|
|
30
33
|
return 'killCursors' as const;
|
|
31
34
|
}
|
|
32
35
|
|
|
33
|
-
override
|
|
34
|
-
server: Server,
|
|
35
|
-
session: ClientSession | undefined,
|
|
36
|
-
timeoutContext: TimeoutContext
|
|
37
|
-
): Promise<void> {
|
|
38
|
-
if (server !== this.server) {
|
|
39
|
-
throw new MongoRuntimeError('Killcursor must run on the same server operation began on');
|
|
40
|
-
}
|
|
41
|
-
|
|
36
|
+
override buildCommand(_connection: Connection, _session?: ClientSession): KillCursorsCommand {
|
|
42
37
|
const killCursors = this.ns.collection;
|
|
43
38
|
if (killCursors == null) {
|
|
44
39
|
// Cursors should have adopted the namespace returned by MongoDB
|
|
@@ -50,15 +45,19 @@ export class KillCursorsOperation extends AbstractOperation {
|
|
|
50
45
|
killCursors,
|
|
51
46
|
cursors: [this.cursorId]
|
|
52
47
|
};
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
48
|
+
|
|
49
|
+
return killCursorsCommand;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
override buildOptions(timeoutContext: TimeoutContext): ServerCommandOptions {
|
|
53
|
+
return {
|
|
54
|
+
session: this.session,
|
|
55
|
+
timeoutContext
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
override handleError(_error: MongoError): void {
|
|
60
|
+
// The driver should never emit errors from killCursors, this is spec-ed behavior
|
|
62
61
|
}
|
|
63
62
|
}
|
|
64
63
|
|
|
@@ -1,13 +1,11 @@
|
|
|
1
|
+
import { type Connection } from '..';
|
|
1
2
|
import type { Binary, Document } from '../bson';
|
|
2
|
-
import { CursorResponse } from '../cmap/wire_protocol/responses';
|
|
3
|
+
import { CursorResponse, ExplainedCursorResponse } from '../cmap/wire_protocol/responses';
|
|
3
4
|
import { type CursorTimeoutContext, type CursorTimeoutMode } from '../cursor/abstract_cursor';
|
|
4
5
|
import type { Db } from '../db';
|
|
5
6
|
import { type Abortable } from '../mongo_types';
|
|
6
|
-
import type { Server } from '../sdam/server';
|
|
7
|
-
import type { ClientSession } from '../sessions';
|
|
8
|
-
import { type TimeoutContext } from '../timeout';
|
|
9
7
|
import { maxWireVersion } from '../utils';
|
|
10
|
-
import {
|
|
8
|
+
import { type CommandOperationOptions, ModernizedCommandOperation } from './command';
|
|
11
9
|
import { Aspect, defineAspects } from './operation';
|
|
12
10
|
|
|
13
11
|
/** @public */
|
|
@@ -28,7 +26,8 @@ export interface ListCollectionsOptions
|
|
|
28
26
|
}
|
|
29
27
|
|
|
30
28
|
/** @internal */
|
|
31
|
-
export class ListCollectionsOperation extends
|
|
29
|
+
export class ListCollectionsOperation extends ModernizedCommandOperation<CursorResponse> {
|
|
30
|
+
override SERVER_COMMAND_RESPONSE_TYPE = CursorResponse;
|
|
32
31
|
/**
|
|
33
32
|
* @remarks WriteConcern can still be present on the options because
|
|
34
33
|
* we inherit options from the client/db/collection. The
|
|
@@ -56,28 +55,15 @@ export class ListCollectionsOperation extends CommandOperation<CursorResponse> {
|
|
|
56
55
|
if (typeof this.options.batchSize === 'number') {
|
|
57
56
|
this.batchSize = this.options.batchSize;
|
|
58
57
|
}
|
|
58
|
+
|
|
59
|
+
this.SERVER_COMMAND_RESPONSE_TYPE = this.explain ? ExplainedCursorResponse : CursorResponse;
|
|
59
60
|
}
|
|
60
61
|
|
|
61
62
|
override get commandName() {
|
|
62
63
|
return 'listCollections' as const;
|
|
63
64
|
}
|
|
64
65
|
|
|
65
|
-
override
|
|
66
|
-
server: Server,
|
|
67
|
-
session: ClientSession | undefined,
|
|
68
|
-
timeoutContext: TimeoutContext
|
|
69
|
-
): Promise<CursorResponse> {
|
|
70
|
-
return await super.executeCommand(
|
|
71
|
-
server,
|
|
72
|
-
session,
|
|
73
|
-
this.generateCommand(maxWireVersion(server)),
|
|
74
|
-
timeoutContext,
|
|
75
|
-
CursorResponse
|
|
76
|
-
);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/* This is here for the purpose of unit testing the final command that gets sent. */
|
|
80
|
-
generateCommand(wireVersion: number): Document {
|
|
66
|
+
override buildCommandDocument(connection: Connection): Document {
|
|
81
67
|
const command: Document = {
|
|
82
68
|
listCollections: 1,
|
|
83
69
|
filter: this.filter,
|
|
@@ -88,12 +74,18 @@ export class ListCollectionsOperation extends CommandOperation<CursorResponse> {
|
|
|
88
74
|
|
|
89
75
|
// we check for undefined specifically here to allow falsy values
|
|
90
76
|
// eslint-disable-next-line no-restricted-syntax
|
|
91
|
-
if (
|
|
77
|
+
if (maxWireVersion(connection) >= 9 && this.options.comment !== undefined) {
|
|
92
78
|
command.comment = this.options.comment;
|
|
93
79
|
}
|
|
94
80
|
|
|
95
81
|
return command;
|
|
96
82
|
}
|
|
83
|
+
|
|
84
|
+
override handleOk(
|
|
85
|
+
response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>
|
|
86
|
+
): CursorResponse {
|
|
87
|
+
return response;
|
|
88
|
+
}
|
|
97
89
|
}
|
|
98
90
|
|
|
99
91
|
/** @public */
|
|
@@ -33,7 +33,6 @@ export interface OperationOptions extends BSONSerializeOptions {
|
|
|
33
33
|
|
|
34
34
|
/** @internal Hints to `executeOperation` that this operation should not unpin on an ended transaction */
|
|
35
35
|
bypassPinningCheck?: boolean;
|
|
36
|
-
omitReadPreference?: boolean;
|
|
37
36
|
|
|
38
37
|
/** @internal Hint to `executeOperation` to omit maxTimeMS */
|
|
39
38
|
omitMaxTimeMS?: boolean;
|
|
@@ -57,7 +56,6 @@ export abstract class AbstractOperation<TResult = any> {
|
|
|
57
56
|
readPreference: ReadPreference;
|
|
58
57
|
server!: Server;
|
|
59
58
|
bypassPinningCheck: boolean;
|
|
60
|
-
trySecondaryWrite: boolean;
|
|
61
59
|
|
|
62
60
|
// BSON serialization options
|
|
63
61
|
bsonOptions?: BSONSerializeOptions;
|
|
@@ -83,7 +81,6 @@ export abstract class AbstractOperation<TResult = any> {
|
|
|
83
81
|
|
|
84
82
|
this.options = options;
|
|
85
83
|
this.bypassPinningCheck = !!options.bypassPinningCheck;
|
|
86
|
-
this.trySecondaryWrite = false;
|
|
87
84
|
}
|
|
88
85
|
|
|
89
86
|
/** Must match the first key of the command object sent to the server.
|
package/src/sdam/server.ts
CHANGED
|
@@ -37,6 +37,7 @@ import {
|
|
|
37
37
|
} from '../error';
|
|
38
38
|
import type { ServerApi } from '../mongo_client';
|
|
39
39
|
import { type Abortable, TypedEventEmitter } from '../mongo_types';
|
|
40
|
+
import { AggregateOperation } from '../operations/aggregate';
|
|
40
41
|
import type { GetMoreOptions } from '../operations/get_more';
|
|
41
42
|
import { type ModernizedOperation } from '../operations/operation';
|
|
42
43
|
import type { ClientSession } from '../sessions';
|
|
@@ -68,6 +69,7 @@ import type {
|
|
|
68
69
|
} from './events';
|
|
69
70
|
import { Monitor, type MonitorOptions } from './monitor';
|
|
70
71
|
import { compareTopologyVersion, ServerDescription } from './server_description';
|
|
72
|
+
import { MIN_SECONDARY_WRITE_WIRE_VERSION } from './server_selection';
|
|
71
73
|
import type { Topology } from './topology';
|
|
72
74
|
|
|
73
75
|
const stateTransition = makeStateMachine({
|
|
@@ -111,6 +113,7 @@ export type ServerEvents = {
|
|
|
111
113
|
/** @internal */
|
|
112
114
|
export type ServerCommandOptions = Omit<CommandOptions, 'timeoutContext' | 'socketTimeoutMS'> & {
|
|
113
115
|
timeoutContext: TimeoutContext;
|
|
116
|
+
returnFieldSelector?: Document | null;
|
|
114
117
|
} & Abortable;
|
|
115
118
|
|
|
116
119
|
/** @internal */
|
|
@@ -310,11 +313,11 @@ export class Server extends TypedEventEmitter<ServerEvents> {
|
|
|
310
313
|
|
|
311
314
|
options.directConnection = this.topology.s.options.directConnection;
|
|
312
315
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
if (
|
|
316
|
+
const omitReadPreference =
|
|
317
|
+
operation instanceof AggregateOperation &&
|
|
318
|
+
operation.hasWriteStage &&
|
|
319
|
+
maxWireVersion(conn) < MIN_SECONDARY_WRITE_WIRE_VERSION;
|
|
320
|
+
if (omitReadPreference) {
|
|
318
321
|
delete options.readPreference;
|
|
319
322
|
}
|
|
320
323
|
|
|
@@ -401,14 +404,6 @@ export class Server extends TypedEventEmitter<ServerEvents> {
|
|
|
401
404
|
|
|
402
405
|
options.directConnection = this.topology.s.options.directConnection;
|
|
403
406
|
|
|
404
|
-
// There are cases where we need to flag the read preference not to get sent in
|
|
405
|
-
// the command, such as pre-5.0 servers attempting to perform an aggregate write
|
|
406
|
-
// with a non-primary read preference. In this case the effective read preference
|
|
407
|
-
// (primary) is not the same as the provided and must be removed completely.
|
|
408
|
-
if (options.omitReadPreference) {
|
|
409
|
-
delete options.readPreference;
|
|
410
|
-
}
|
|
411
|
-
|
|
412
407
|
if (this.description.iscryptd) {
|
|
413
408
|
options.omitMaxTimeMS = true;
|
|
414
409
|
}
|
package/src/sdam/topology.ts
CHANGED
|
@@ -46,7 +46,6 @@ import {
|
|
|
46
46
|
makeStateMachine,
|
|
47
47
|
noop,
|
|
48
48
|
now,
|
|
49
|
-
ns,
|
|
50
49
|
promiseWithResolvers,
|
|
51
50
|
shuffle
|
|
52
51
|
} from '../utils';
|
|
@@ -459,7 +458,7 @@ export class Topology extends TypedEventEmitter<TopologyEvents> {
|
|
|
459
458
|
waitQueueTimeoutMS: this.client.s.options.waitQueueTimeoutMS
|
|
460
459
|
});
|
|
461
460
|
const selectServerOptions = {
|
|
462
|
-
operationName: '
|
|
461
|
+
operationName: 'handshake',
|
|
463
462
|
...options,
|
|
464
463
|
timeoutContext
|
|
465
464
|
};
|
|
@@ -469,9 +468,11 @@ export class Topology extends TypedEventEmitter<TopologyEvents> {
|
|
|
469
468
|
readPreferenceServerSelector(readPreference),
|
|
470
469
|
selectServerOptions
|
|
471
470
|
);
|
|
471
|
+
|
|
472
472
|
const skipPingOnConnect = this.s.options.__skipPingOnConnect === true;
|
|
473
473
|
if (!skipPingOnConnect && this.s.credentials) {
|
|
474
|
-
await server.
|
|
474
|
+
const connection = await server.pool.checkOut({ timeoutContext: timeoutContext });
|
|
475
|
+
server.pool.checkIn(connection);
|
|
475
476
|
stateTransition(this, STATE_CONNECTED);
|
|
476
477
|
this.emit(Topology.OPEN, this);
|
|
477
478
|
this.emit(Topology.CONNECT, this);
|