Skip to content

Commit 2f4131d

Browse files
author
Thomas Reggi
committed
force from master
1 parent 054838f commit 2f4131d

File tree

13 files changed

+215
-200
lines changed

13 files changed

+215
-200
lines changed

src/collection.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ import {
4141
EstimatedDocumentCountOperation,
4242
EstimatedDocumentCountOptions
4343
} from './operations/estimated_document_count';
44-
import { FindOperation, FindOptions, Sort } from './operations/find';
44+
import { FindOperation, FindOptions } from './operations/find';
4545
import { FindOneOperation } from './operations/find_one';
4646
import {
4747
FindAndModifyOperation,
@@ -86,6 +86,7 @@ import type { PkFactory } from './mongo_client';
8686
import type { Topology } from './sdam/topology';
8787
import type { Logger, LoggerOptions } from './logger';
8888
import type { OperationParent } from './operations/command';
89+
import type { Sort } from './sort';
8990

9091
/** @public */
9192
export interface Collection {

src/cursor/aggregation_cursor.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Cursor, CursorOptions } from './cursor';
33
import { CursorState } from './core_cursor';
44
import type { AggregateOperation, AggregateOptions } from '../operations/aggregate';
55
import type { Document } from '../bson';
6-
import type { Sort } from '../operations/find';
6+
import type { Sort } from '../sort';
77
import type { Topology } from '../sdam/topology';
88

99
/** @public */

src/cursor/cursor.ts

Lines changed: 8 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,16 @@ import {
1212
CursorCloseOptions,
1313
DocumentTransforms
1414
} from './core_cursor';
15-
import { maybePromise, formattedOrderClause, Callback } from '../utils';
15+
import { maybePromise, Callback } from '../utils';
1616
import { executeOperation } from '../operations/execute_operation';
1717
import { each, EachCallback } from '../operations/cursor_ops';
1818
import { CountOperation, CountOptions } from '../operations/count';
1919
import type { Logger } from '../logger';
2020
import type { Topology } from '../sdam/topology';
2121
import type { CollationOptions } from '../cmap/wire_protocol/write_command';
22-
import type { Sort, SortDirection } from '../operations/find';
2322
import type { Hint, OperationBase } from '../operations/operation';
2423
import type { Document } from '../bson';
24+
import { Sort, SortDirection, formatSort } from '../sort';
2525

2626
/** @public Flags allowed for cursor */
2727
export const FLAGS = [
@@ -52,6 +52,7 @@ export interface CursorOptions extends CoreCursorOptions {
5252
topology?: Topology;
5353
/** Session to use for the operation */
5454
numberOfRetries?: number;
55+
sort?: Sort;
5556
}
5657

5758
const kCursor = Symbol('cursor');
@@ -237,6 +238,10 @@ export class Cursor<
237238
this.addCursorFlag('noCursorTimeout', true);
238239
}
239240

241+
if (this.options.sort) {
242+
this.cmd.sort = formatSort(this.options.sort);
243+
}
244+
240245
// Set the batch size
241246
this.cursorBatchSize = batchSize;
242247
}
@@ -303,14 +308,6 @@ export class Cursor<
303308
return;
304309
}
305310

306-
if (this.s.state === CursorState.INIT && this.cmd.sort) {
307-
try {
308-
this.cmd.sort = formattedOrderClause(this.cmd.sort);
309-
} catch (err) {
310-
return cb(err);
311-
}
312-
}
313-
314311
this._next((err, doc) => {
315312
if (err) return cb(err);
316313
this.s.state = CursorState.OPEN;
@@ -587,37 +584,7 @@ export class Cursor<
587584
throw new MongoError('Cursor is closed');
588585
}
589586

590-
let order = sort;
591-
592-
// We have an array of arrays, we need to preserve the order of the sort
593-
// so we will us a Map
594-
if (Array.isArray(order) && Array.isArray(order[0])) {
595-
this.cmd.sort = new Map<string, unknown>(
596-
(order as [string, SortDirection][]).map(([key, dir]) => {
597-
if (dir === 'asc') {
598-
return [key, 1];
599-
} else if (dir === 'desc') {
600-
return [key, -1];
601-
} else if (dir === 1 || dir === -1 || dir.$meta) {
602-
return [key, dir];
603-
} else {
604-
throw new MongoError(
605-
"Illegal sort clause, must be of the form [['field1', '(ascending|descending)'], ['field2', '(ascending|descending)']]"
606-
);
607-
}
608-
609-
return [key, null];
610-
})
611-
);
612-
613-
return this;
614-
}
615-
616-
if (direction != null) {
617-
order = [[sort as string, direction]];
618-
}
619-
620-
this.cmd.sort = order;
587+
this.cmd.sort = formatSort(sort, direction);
621588
return this;
622589
}
623590

src/gridfs-stream/download.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { Readable } from 'stream';
22
import type { AnyError } from '../error';
33
import type { Document } from '../bson';
4-
import type { FindOptions, Sort } from '../operations/find';
4+
import type { FindOptions } from '../operations/find';
5+
import type { Sort } from '../sort';
56
import type { Cursor } from './../cursor/cursor';
67
import type { Callback } from '../utils';
78
import type { Collection } from '../collection';

src/gridfs-stream/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ import type { Db } from '../db';
1313
import type { ReadPreference } from '../read_preference';
1414
import type { Collection } from '../collection';
1515
import type { Cursor } from './../cursor/cursor';
16-
import type { FindOptions, Sort } from './../operations/find';
16+
import type { FindOptions } from './../operations/find';
17+
import type { Sort } from '../sort';
1718
import type { Logger } from '../logger';
1819

1920
const DEFAULT_GRIDFS_BUCKET_OPTIONS: {

src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,8 @@ export type { DistinctOptions } from './operations/distinct';
210210
export type { DropCollectionOptions, DropDatabaseOptions } from './operations/drop';
211211
export type { EstimatedDocumentCountOptions } from './operations/estimated_document_count';
212212
export type { EvalOptions } from './operations/eval';
213-
export type { FindOptions, Sort, SortDirection } from './operations/find';
213+
export type { FindOptions } from './operations/find';
214+
export type { Sort, SortDirection } from './sort';
214215
export type { FindAndModifyOptions } from './operations/find_and_modify';
215216
export type {
216217
IndexSpecification,

src/operations/common_functions.ts

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,5 @@
11
import { MongoError } from '../error';
2-
import { CursorState, Cursor } from '../cursor';
3-
import {
4-
applyRetryableWrites,
5-
applyWriteConcern,
6-
decorateWithCollation,
7-
formattedOrderClause,
8-
Callback
9-
} from '../utils';
2+
import { applyRetryableWrites, applyWriteConcern, decorateWithCollation, Callback } from '../utils';
103
import type { Document } from '../bson';
114
import type { Db } from '../db';
125
import type { ClientSession } from '../sessions';
@@ -106,28 +99,6 @@ export function prepareDocs(
10699
});
107100
}
108101

109-
// Get the next available document from the cursor, returns null if no more documents are available.
110-
export function nextObject(cursor: Cursor, callback: Callback): void {
111-
if (cursor.s.state === CursorState.CLOSED || (cursor.isDead && cursor.isDead())) {
112-
return callback(MongoError.create({ message: 'Cursor is closed', driver: true }));
113-
}
114-
115-
if (cursor.s.state === CursorState.INIT && cursor.cmd && cursor.cmd.sort) {
116-
try {
117-
cursor.cmd.sort = formattedOrderClause(cursor.cmd.sort);
118-
} catch (err) {
119-
return callback(err);
120-
}
121-
}
122-
123-
// Get the next object
124-
cursor._next((err, doc) => {
125-
cursor.s.state = CursorState.OPEN;
126-
if (err) return callback(err);
127-
callback(undefined, doc);
128-
});
129-
}
130-
131102
export function removeDocuments(server: Server, coll: Collection, callback?: Callback): void;
132103
export function removeDocuments(
133104
server: Server,

src/operations/find.ts

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,14 @@
11
import { Aspect, defineAspects, Hint } from './operation';
22
import { ReadPreference } from '../read_preference';
3-
import {
4-
maxWireVersion,
5-
MongoDBNamespace,
6-
Callback,
7-
formattedOrderClause,
8-
normalizeHintField
9-
} from '../utils';
3+
import { maxWireVersion, MongoDBNamespace, Callback, normalizeHintField } from '../utils';
104
import { MongoError } from '../error';
115
import type { Document } from '../bson';
126
import type { Server } from '../sdam/server';
137
import type { Collection } from '../collection';
148
import type { CollationOptions } from '../cmap/wire_protocol/write_command';
159
import type { QueryOptions } from '../cmap/wire_protocol/query';
1610
import { CommandOperation, CommandOperationOptions } from './command';
17-
18-
/** @public */
19-
export type SortDirection = 1 | -1 | 'asc' | 'desc' | { $meta: string };
20-
/** @public */
21-
export type Sort =
22-
| { [key: string]: SortDirection }
23-
| [string, SortDirection][]
24-
| [string, SortDirection];
11+
import { Sort, formatSort } from '../sort';
2512

2613
/** @public */
2714
export interface FindOptions extends QueryOptions, CommandOperationOptions {
@@ -153,9 +140,8 @@ export class FindOperation extends CommandOperation<FindOptions, Document> {
153140
const findCommand: Document = Object.assign({}, this.cmd);
154141

155142
if (options.sort) {
156-
findCommand.sort = formattedOrderClause(options.sort);
143+
findCommand.sort = formatSort(options.sort);
157144
}
158-
159145
if (options.projection || options.fields) {
160146
let projection = options.projection || options.fields;
161147
if (projection && !Buffer.isBuffer(projection) && Array.isArray(projection)) {

src/operations/find_and_modify.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import {
44
applyRetryableWrites,
55
decorateWithCollation,
66
applyWriteConcern,
7-
formattedOrderClause,
87
hasAtomicOperators,
98
Callback
109
} from '../utils';
@@ -14,7 +13,7 @@ import { defineAspects, Aspect } from './operation';
1413
import type { Document } from '../bson';
1514
import type { Server } from '../sdam/server';
1615
import type { Collection } from '../collection';
17-
import type { Sort } from './find';
16+
import { Sort, formatSort } from '../sort';
1817

1918
/** @public */
2019
export interface FindAndModifyOptions extends CommandOperationOptions {
@@ -69,7 +68,7 @@ export class FindAndModifyOperation extends CommandOperation<FindAndModifyOption
6968
execute(server: Server, callback: Callback<Document>): void {
7069
const coll = this.collection;
7170
const query = this.query;
72-
const sort = formattedOrderClause(this.sort);
71+
const sort = formatSort(this.sort);
7372
const doc = this.doc;
7473
let options = this.options;
7574

src/operations/map_reduce.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { ReadPreference, ReadPreferenceMode } from '../read_preference';
1111
import { CommandOperation, CommandOperationOptions } from './command';
1212
import type { Server } from '../sdam/server';
1313
import type { Collection } from '../collection';
14-
import type { Sort } from './find';
14+
import type { Sort } from '../sort';
1515
import { MongoError } from '../error';
1616
import type { ObjectId } from '../bson';
1717

src/sort.ts

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/** @public */
2+
export type SortDirection =
3+
| 1
4+
| -1
5+
| 'asc'
6+
| 'desc'
7+
| 'ascending'
8+
| 'descending'
9+
| { $meta: string };
10+
11+
/** @public */
12+
export type Sort =
13+
| string
14+
| string[]
15+
| { [key: string]: SortDirection }
16+
| [string, SortDirection][]
17+
| [string, SortDirection];
18+
19+
/** Below stricter types were created for sort that correspond with type that the cmd takes */
20+
21+
/** @internal */
22+
type SortDirectionForCmd = 1 | -1 | { $meta: string };
23+
24+
/** @internal */
25+
type SortForCmd = { [key: string]: SortDirectionForCmd };
26+
27+
/** @internal */
28+
class SortDigest {
29+
static prepareDirection(direction: any = 1): SortDirectionForCmd {
30+
const value = ('' + direction).toLowerCase();
31+
if (SortDigest.isMeta(direction)) return direction;
32+
switch (value) {
33+
case 'ascending':
34+
case 'asc':
35+
case '1':
36+
return 1;
37+
case 'descending':
38+
case 'desc':
39+
case '-1':
40+
return -1;
41+
default:
42+
throw new Error(`Invalid sort direction: ${JSON.stringify(direction)}`);
43+
}
44+
}
45+
static isMeta(t: SortDirection): t is { $meta: string } {
46+
return typeof t === 'object' && t !== null && '$meta' in t && typeof t.$meta === 'string';
47+
}
48+
static isPair(t: Sort): t is [string, SortDirection] {
49+
if (Array.isArray(t) && t.length === 2) {
50+
try {
51+
SortDigest.prepareDirection(t[1]);
52+
return true;
53+
} catch (e) {
54+
return false;
55+
}
56+
}
57+
return false;
58+
}
59+
static pairToObject(v: [string, SortDirection]): SortForCmd {
60+
return { [v[0]]: SortDigest.prepareDirection(v[1]) };
61+
}
62+
static isDeep(t: Sort): t is [string, SortDirection][] {
63+
return Array.isArray(t) && Array.isArray(t[0]);
64+
}
65+
static deepToObject(t: [string, SortDirection][]): SortForCmd {
66+
return t.reduce((acq, i) => {
67+
return { ...acq, ...SortDigest.pairToObject(i) };
68+
}, {});
69+
}
70+
static stringsToObject(t: string[]): SortForCmd {
71+
return t.reduce((acq, key) => {
72+
return { ...acq, [key]: 1 };
73+
}, {});
74+
}
75+
static validate(t: { [key: string]: SortDirection }): SortForCmd {
76+
return Object.keys(t).reduce((acq, key) => {
77+
return { ...acq, [key]: SortDigest.prepareDirection(t[key]) };
78+
}, {});
79+
}
80+
static prepare(sort: Sort | undefined, direction?: SortDirection): SortForCmd | undefined {
81+
if (sort == null) return undefined;
82+
if (Array.isArray(sort) && !sort.length) return undefined;
83+
if (typeof sort === 'object' && !Object.keys(sort).length) return undefined;
84+
if (typeof sort === 'string') return { [sort]: SortDigest.prepareDirection(direction) };
85+
if (SortDigest.isPair(sort)) return SortDigest.pairToObject(sort);
86+
if (SortDigest.isDeep(sort)) return SortDigest.deepToObject(sort);
87+
if (Array.isArray(sort)) return SortDigest.stringsToObject(sort);
88+
if (typeof sort === 'object') return SortDigest.validate(sort);
89+
throw new Error(`Invalid sort format: ${JSON.stringify(sort)}`);
90+
}
91+
}
92+
93+
/** converts a Sort type into a type that is valid for the server (SortForCmd) */
94+
export const formatSort = SortDigest.prepare;

0 commit comments

Comments
 (0)