-
Notifications
You must be signed in to change notification settings - Fork 6
/
cursor.ts
143 lines (129 loc) · 4.39 KB
/
cursor.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/**
* Created by tsturzl on 4/11/17.
*/
import Datastore from "./datastore";
import { isEmpty, mergeSort, getSortType, flatten, rmArrDups} from "./utils";
export interface ICursor {
sort(sort: any): this;
skip(skip: number): this;
limit(limit: number): this;
exec(): Promise<any[] | number>;
}
export interface I$and {
$and: any[];
}
export interface Ioptions {
sort?: any;
skip?: number;
limit?: number;
}
/**
* Database Cursor
*/
export default class Cursor implements ICursor {
/** Reference to Datastore object */
private datastore: Datastore;
/** Query passed from `Datastore.find` or `count` */
private query: any;
/** Options for `exec` */
private options: Ioptions;
/** Is this a count operation? */
private count: boolean;
/**
* Constructor
* @param datastore - Datastore reference
* @param query - query for search
* @param count - is this a count operation? Default: false
*/
constructor(datastore: Datastore, query: any = {}, count?: boolean) {
this.datastore = datastore;
this.query = query;
this.count = count || false;
this.options = {};
}
/**
* Sort order for fields
* @param sort - sort object `{fieldName: 1 | -1}`
*/
public sort(sort: any): this {
this.options.sort = sort;
return this;
}
/**
* Set how many results to skip
* @param skip - how many results to skip
*/
public skip(skip: number): this {
this.options.skip = skip;
return this;
}
/**
* Limit result size
* @param limit - how many results
*/
public limit(limit: number): this {
this.options.limit = limit;
return this;
}
/**
* Execute the Cursor
*/
public exec(): Promise<any[] | number> {
return new Promise<any[] | number>((resolve, reject) => {
const promisesGetIds: Array<Promise<string[]>> = [];
if (isEmpty(this.query)) {
promisesGetIds.push(this.datastore.search());
} else {
const searchKeys = Object.keys(this.query);
if (searchKeys.indexOf("$or") !== -1 || searchKeys.indexOf("$and") !== -1) {
for (const field in this.query) {
if (this.query.hasOwnProperty(field)) {
promisesGetIds.push(this.datastore.search(field, this.query[field]));
}
}
} else {
const searchValues = Object.values(this.query);
const newQuery: I$and = {$and: []};
searchKeys.forEach((v: any, i: number) => {
const obj: any = {};
obj[v] = searchValues[i];
newQuery.$and.push(obj);
});
promisesGetIds.push(this.datastore.search("$and", newQuery.$and));
}
}
const joined: any = Promise.all(promisesGetIds); // confusing type issues*
joined
.then((idsArr: string[][]): number | Promise<any[]> => {
idsArr = flatten(idsArr);
const ids = rmArrDups(idsArr);
if (this.count) {
return ids.length;
} else {
return this.datastore.getDocs(this.options, ids);
}
})
.then((res: any[]) => {
if (this.options.sort) {
try {
const sortKey = Object.keys(this.options.sort)[0];
const sortValue = this.options.sort[sortKey];
const sortType = getSortType(res, sortKey);
if (sortType === "") {
// can't sort null or undefined
return res;
} else {
return mergeSort(res, sortKey, sortValue, sortType);
}
} catch (e) {
return reject(e);
}
} else {
return res;
}
})
.then(resolve)
.catch(reject);
});
}
}