-
Notifications
You must be signed in to change notification settings - Fork 4
/
filter.ts
192 lines (184 loc) · 4.99 KB
/
filter.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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
// Copyright DataStax, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import type { SomeDoc } from '@/src/data-api';
import type { IdOf, NoId, ToDotNotation } from '@/src/data-api/types';
import { IsDate, IsNum } from '@/src/data-api/types/utils';
/**
* Represents some filter operation for a given document schema.
*
* **If you want stricter type-checking and full auto-complete, see {@link StrictFilter}.**
*
* This is a more relaxed version of {@link StrictFilter} that doesn't type-check nested fields.
*
* @example
* ```
* interface BasicSchema {
* arr: string[],
* num: number,
* }
*
* db.collection<BasicSchema>('coll_name').findOne({
* $and: [
* { _id: { $in: ['abc', 'def'] } },
* { $not: { arr: { $size: 0 } } },
* ]
* });
* ```
*
* @see StrictFilter
*
* @public
*/
export type Filter<Schema extends SomeDoc> = {
[K in keyof NoId<Schema>]?: FilterExpr<NoId<Schema>[K]>
} & {
_id?: FilterExpr<IdOf<Schema>>,
$and?: Filter<Schema>[],
$or?: Filter<Schema>[],
$not?: Filter<Schema>,
} & {
[key: string]: any,
}
/**
* Represents some filter operation for a given document schema.
*
* **If you want relaxed type-checking, see {@link Filter}.**
*
* This is a stricter version of {@link Filter} that type-checks nested fields.
*
* You can use it anywhere by using the `satisfies` keyword, or by creating a temporary const with the StrictFilter type.
*
* @example
* ```
* interface BasicSchema {
* arr: string[],
* num: number,
* }
*
* db.collection<BasicSchema>('coll_name').findOne({
* $and: [
* { _id: { $in: ['abc', 'def'] } },
* { $not: { arr: { $size: 0 } } },
* ]
* } satisfies StrictFilter<BasicSchema>);
* ```
*
* @see Filter
*
* @public
*/
export type StrictFilter<Schema extends SomeDoc> = {
[K in keyof ToDotNotation<NoId<Schema>>]?: FilterExpr<ToDotNotation<NoId<Schema>>[K]>
} & {
_id?: FilterExpr<IdOf<Schema>>,
$and?: StrictFilter<Schema>[],
$or?: StrictFilter<Schema>[],
$not?: StrictFilter<Schema>,
}
/**
* Represents an expression in a filter statement, such as an exact value, or a filter operator
*
* @public
*/
export type FilterExpr<Elem> = Elem | FilterOps<Elem>;
/**
* Represents filter operators such as `$eq` and `$in` (but not statements like `$and`)
*
* @public
*/
export type FilterOps<Elem> = {
$eq?: Elem,
$ne?: Elem,
$in?: Elem[],
$nin?: Elem[] /* I can't un-see this as 'Nine-Inch Nails'... */,
$exists?: boolean,
} & (
// eslint-disable-next-line @typescript-eslint/ban-types -- Intersection w/ {} is a "noop" here
IsNum<Elem> extends false ? {} : NumFilterOps
) & (
// eslint-disable-next-line @typescript-eslint/ban-types -- Intersection w/ {} is a "noop" here
IsDate<Elem> extends false ? {} : (DateFilterOps | Date)
) & (
// eslint-disable-next-line @typescript-eslint/ban-types -- Intersection w/ {} is a "noop" here
any[] extends Elem ? ArrayFilterOps<Elem> : {}
)
/**
* Represents filter operations exclusive to number (or dynamically typed) fields
*
* @public
*/
export interface NumFilterOps {
/**
* Less than (exclusive) some number
*/
$lt?: number | bigint,
/**
* Less than or equal to some number
*/
$lte?: number | bigint,
/**
* Greater than (exclusive) some number
*/
$gt?: number | bigint,
/**
* Greater than or equal to some number
*/
$gte?: number | bigint,
}
/**
* Represents filter operations exclusive to Dates (or dynamically typed) fields
*
* @public
*/
export interface DateFilterOps {
/**
* Less than (exclusive) some date.
*
* `{ $date: number }` can be replaced with `new Date(number)`.
*/
$lt?: Date,
/**
* Less than or equal to some date.
*
* `{ $date: number }` can be replaced with `new Date(number)`.
*/
$lte?: Date,
/**
* Greater than (exclusive) some date.
*
* `{ $date: number }` can be replaced with `new Date(number)`.
*/
$gt?: Date,
/**
* Greater than or equal to some date.
*
* `{ $date: number }` can be replaced with `new Date(number)`.
*/
$gte?: Date,
}
/**
* Represents filter operations exclusive to array (or dynamically typed) fields
*
* @public
*/
export interface ArrayFilterOps<Elem> {
/**
* Checks if the array is of a certain size.
*/
$size?: number,
/**
* Checks if the array contains all the specified elements.
*/
$all?: Elem,
}