|
1 | 1 | import { type Document } from '../bson'; |
2 | 2 | import { CursorResponse } from '../cmap/wire_protocol/responses'; |
3 | | -import { MongoInvalidArgumentError, MongoTailableCursorError } from '../error'; |
4 | | -import { type ExplainCommandOptions, type ExplainVerbosityLike } from '../explain'; |
| 3 | +import { MongoAPIError, MongoInvalidArgumentError, MongoTailableCursorError } from '../error'; |
| 4 | +import { |
| 5 | + Explain, |
| 6 | + type ExplainCommandOptions, |
| 7 | + type ExplainVerbosityLike, |
| 8 | + validateExplainTimeoutOptions |
| 9 | +} from '../explain'; |
5 | 10 | import type { MongoClient } from '../mongo_client'; |
6 | 11 | import type { CollationOptions } from '../operations/command'; |
7 | 12 | import { CountOperation, type CountOptions } from '../operations/count'; |
@@ -63,11 +68,21 @@ export class FindCursor<TSchema = any> extends AbstractCursor<TSchema> { |
63 | 68 |
|
64 | 69 | /** @internal */ |
65 | 70 | async _initialize(session: ClientSession): Promise<InitialCursorResponse> { |
66 | | - const findOperation = new FindOperation(this.namespace, this.cursorFilter, { |
| 71 | + const options = { |
67 | 72 | ...this.findOptions, // NOTE: order matters here, we may need to refine this |
68 | 73 | ...this.cursorOptions, |
69 | 74 | session |
70 | | - }); |
| 75 | + }; |
| 76 | + |
| 77 | + try { |
| 78 | + validateExplainTimeoutOptions(options, Explain.fromOptions(options)); |
| 79 | + } catch { |
| 80 | + throw new MongoAPIError( |
| 81 | + 'timeoutMS cannot be used with explain when explain is specified in findOptions' |
| 82 | + ); |
| 83 | + } |
| 84 | + |
| 85 | + const findOperation = new FindOperation(this.namespace, this.cursorFilter, options); |
71 | 86 |
|
72 | 87 | const response = await executeOperation(this.client, findOperation, this.timeoutContext); |
73 | 88 |
|
@@ -133,14 +148,43 @@ export class FindCursor<TSchema = any> extends AbstractCursor<TSchema> { |
133 | 148 | } |
134 | 149 |
|
135 | 150 | /** Execute the explain for the cursor */ |
136 | | - async explain(verbosity?: ExplainVerbosityLike | ExplainCommandOptions): Promise<Document> { |
| 151 | + async explain(): Promise<Document>; |
| 152 | + async explain(verbosity: ExplainVerbosityLike | ExplainCommandOptions): Promise<Document>; |
| 153 | + async explain(options: { timeoutMS?: number }): Promise<Document>; |
| 154 | + async explain( |
| 155 | + verbosity: ExplainVerbosityLike | ExplainCommandOptions, |
| 156 | + options: { timeoutMS?: number } |
| 157 | + ): Promise<Document>; |
| 158 | + async explain( |
| 159 | + verbosity?: ExplainVerbosityLike | ExplainCommandOptions | { timeoutMS?: number }, |
| 160 | + options?: { timeoutMS?: number } |
| 161 | + ): Promise<Document> { |
| 162 | + let explain: ExplainVerbosityLike | ExplainCommandOptions | undefined; |
| 163 | + let timeout: { timeoutMS?: number } | undefined; |
| 164 | + if (verbosity == null && options == null) { |
| 165 | + explain = true; |
| 166 | + timeout = undefined; |
| 167 | + } else if (verbosity != null && options == null) { |
| 168 | + explain = |
| 169 | + typeof verbosity !== 'object' |
| 170 | + ? verbosity |
| 171 | + : 'timeoutMS' in verbosity |
| 172 | + ? undefined |
| 173 | + : (verbosity as ExplainCommandOptions); |
| 174 | + timeout = typeof verbosity === 'object' && 'timeoutMS' in verbosity ? verbosity : undefined; |
| 175 | + } else { |
| 176 | + explain = verbosity as ExplainCommandOptions; |
| 177 | + timeout = options; |
| 178 | + } |
| 179 | + |
137 | 180 | return ( |
138 | 181 | await executeOperation( |
139 | 182 | this.client, |
140 | 183 | new FindOperation(this.namespace, this.cursorFilter, { |
141 | 184 | ...this.findOptions, // NOTE: order matters here, we may need to refine this |
142 | 185 | ...this.cursorOptions, |
143 | | - explain: verbosity ?? true |
| 186 | + ...timeout, |
| 187 | + explain: explain ?? true |
144 | 188 | }) |
145 | 189 | ) |
146 | 190 | ).shift(this.deserializationOptions); |
|
0 commit comments