Skip to content

Commit 7778b59

Browse files
committed
generate tests for query
1 parent 1aa3656 commit 7778b59

File tree

237 files changed

+1795
-279
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

237 files changed

+1795
-279
lines changed

.gitignore

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ report.json
1212
.compiled-sources
1313
expansions.yml
1414
.nvmrc
15-
.vscode
16-
!.vscode/extentions.json
15+
.vscode/settings.json
1716
.migration-cache
1817
lerna-debug.log
1918
packages/**/*.tgz
@@ -28,4 +27,4 @@ coverage
2827
env-vars.sh
2928
mongocryptd.pid
3029
mongodb-csfle
31-
.esm-wrapper.mjs
30+
.esm-wrapper.mjs
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
{
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"type": "node",
9+
"request": "launch",
10+
"name": "Run CLI",
11+
"skipFiles": ["<node_internals>/**"],
12+
"program": "${workspaceFolder}/bin/runner.js",
13+
"args": ["${input:command}"],
14+
"preLaunchTask": "npm: compile",
15+
"outFiles": ["${workspaceFolder}/dist/**/*.js"]
16+
},
17+
{
18+
"type": "node",
19+
"request": "launch",
20+
"name": "Run CLI with filters",
21+
"skipFiles": ["<node_internals>/**"],
22+
"program": "${workspaceFolder}/bin/runner.js",
23+
"args": [
24+
"${input:command}",
25+
"--category",
26+
"${input:categoryFilter}",
27+
"--operator",
28+
"${input:operatorFilter}"
29+
],
30+
"preLaunchTask": "npm: compile",
31+
"outFiles": ["${workspaceFolder}/dist/**/*.js"]
32+
}
33+
],
34+
"inputs": [
35+
{
36+
"id": "command",
37+
"type": "pickString",
38+
"description": "Select the command to run.",
39+
"options": ["schema", "driver-schema", "tests"],
40+
"default": "schema"
41+
},
42+
{
43+
"id": "categoryFilter",
44+
"type": "pickString",
45+
"description": "Select the category filter to apply.",
46+
"options": ["accumulator", "expression", "query", "search", "stage"]
47+
},
48+
{
49+
"id": "operatorFilter",
50+
"type": "promptString",
51+
"description": "Enter the operator filter to apply"
52+
}
53+
]
54+
}

packages/mql-typescript/out/schema.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import type * as bson from 'bson';
22
import { FilterOperators } from 'mongodb';
33

4-
type Condition<T> = AlternativeType<T> | FilterOperators<T>;
4+
type Condition<T> = AlternativeType<T> | FilterOperators<T> | QueryOperator<T>;
55
type AlternativeType<T> =
66
T extends ReadonlyArray<infer U> ? T | RegExpOrString<U> : RegExpOrString<T>;
7-
type RegExpOrString<T> = T extends string ? bson.BSONRegExp | RegExp | T : T;
7+
type RegExpOrString<T> = T extends string ? Regex | T : T;
88
type KeysOfAType<T, Type> = {
99
[k in keyof T]: NonNullable<T[k]> extends Type ? k : never;
1010
}[keyof T];
@@ -3675,7 +3675,7 @@ export namespace Aggregation.Query {
36753675
* Matches values that are equal to a specified value.
36763676
* @see {@link https://www.mongodb.com/docs/manual/reference/operator/query/eq/}
36773677
*/
3678-
$eq: any;
3678+
$eq: Expression<S>;
36793679
}
36803680

36813681
/**

packages/mql-typescript/src/cli.ts

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import yargs from 'yargs';
22
import { SchemaGenerator } from './schemaGenerator';
33
import { TestGenerator } from './testGenerator/testGenerator';
44
import { DriverSchemaGenerator } from './driverSchema/driverSchemaGenerator';
5+
import { GeneratorBase } from './generator';
56

67
async function main() {
78
const argv = await yargs
@@ -13,36 +14,46 @@ async function main() {
1314
.command(
1415
'driver-schema',
1516
'Updates the php driver definitions with the schema for the tests',
17+
{
18+
category: {
19+
type: 'string',
20+
choices: ['accumulator', 'expression', 'query', 'search', 'stage'],
21+
description:
22+
'The category of the operator to update. If not provided, all categories will be updated.',
23+
},
24+
operator: {
25+
type: 'string',
26+
description:
27+
'The operator to update the schema for. If not provided, all operators will be updated.',
28+
},
29+
},
1630
)
1731
.demandCommand(1, 'A command must be provided')
1832
.help().argv;
1933

2034
const [command] = argv._.map(String);
2135

36+
const categoryFilter = argv.category as string | undefined;
37+
const operatorFilter = argv.operator as string | undefined;
38+
39+
let generator: GeneratorBase;
2240
switch (command) {
2341
case 'schema':
24-
{
25-
const schemaGenerator = new SchemaGenerator();
26-
await schemaGenerator.generate();
27-
}
42+
generator = new SchemaGenerator();
2843
break;
2944
case 'tests':
30-
{
31-
const testGenerator = new TestGenerator();
32-
await testGenerator.generate();
33-
}
45+
generator = new TestGenerator();
3446
break;
3547
case 'driver-schema':
36-
{
37-
const driverSchemaGenerator = new DriverSchemaGenerator();
38-
await driverSchemaGenerator.generate();
39-
}
48+
generator = new DriverSchemaGenerator();
4049
break;
4150
default:
4251
throw new Error(
4352
`Unknown command: ${command}. See '${argv.$0} --help' for more information.`,
4453
);
4554
}
55+
56+
await generator.generate(categoryFilter, operatorFilter);
4657
}
4758

4859
main().catch((err) => {

packages/mql-typescript/src/driverSchema/docsCrawler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ class IsoDateProcessor extends RegexCustomTypeProcessor {
5858
s || '00'
5959
}.${ms || '000'}${tz || 'Z'}`;
6060
const date = new Date(normalized);
61-
// Make surd we're in the range 0000-01-01T00:00:00.000Z - 9999-12-31T23:59:59.999Z
61+
// Make sure we're in the range 0000-01-01T00:00:00.000Z - 9999-12-31T23:59:59.999Z
6262
if (
6363
date.getTime() >= -62167219200000 &&
6464
date.getTime() <= 253402300799999

packages/mql-typescript/src/driverSchema/staticSchemas.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,15 @@ const inventorySchema: SchemaInfo = {
8181
qty: {
8282
types: [{ bsonType: 'Int32' }, { bsonType: 'Undefined' }],
8383
},
84+
quantity: {
85+
types: [{ bsonType: 'Int32' }, { bsonType: 'Undefined' }],
86+
},
8487
sale: {
8588
types: [{ bsonType: 'Boolean' }],
8689
},
90+
tags: {
91+
types: [{ bsonType: 'Array', types: [{ bsonType: 'String' }] }],
92+
},
8793
},
8894
};
8995

@@ -1458,11 +1464,18 @@ const staticSchemas: SchemaMap = {
14581464
},
14591465
query: {
14601466
and: inventorySchema,
1461-
exists: {
1462-
['Exists and Not Equal To']: inventorySchema,
1467+
eq: {
1468+
['Regex Match Behaviour']: {
1469+
collectionName: 'companies',
1470+
schema: {
1471+
_id: { types: [{ bsonType: 'Int32' }] },
1472+
company: { types: [{ bsonType: 'String' }] },
1473+
},
1474+
},
14631475
},
1476+
exists: inventorySchema,
14641477
geoIntersects: geoPolygonSchema,
1465-
geoWithin: geoPointSchema,
1478+
geoWithin: geoPolygonSchema,
14661479
jsonSchema: {
14671480
collectionName: 'TestCollection',
14681481
schema: {

packages/mql-typescript/src/generator.ts

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ export abstract class GeneratorBase {
3232
private outputStream?: NodeJS.WritableStream;
3333

3434
constructor() {
35+
// The default YAML schema will represent BsonDate using the Date representation because
36+
// it's a subclass of Date. We find the implicit type for Date and modify it to use predicate
37+
// instead of instanceOf, so it will only match Date instances that are not BsonDate.
3538
if ('implicit' in yaml.DEFAULT_SCHEMA) {
3639
const implicit = yaml.DEFAULT_SCHEMA.implicit as yaml.Type[];
3740
const timestamp = implicit.find((type) => type.instanceOf === Date);
@@ -178,14 +181,16 @@ export abstract class GeneratorBase {
178181
'config',
179182
);
180183

181-
private async *listCategories(): AsyncIterable<{
184+
private async *listCategories(
185+
filterRegex: RegExp | undefined,
186+
): AsyncIterable<{
182187
category: string;
183188
folder: string;
184189
}> {
185190
for await (const folder of await fs.readdir(this.configDir, {
186191
withFileTypes: true,
187192
})) {
188-
if (folder.isDirectory()) {
193+
if (folder.isDirectory() && filterRegex?.test(folder.name) !== false) {
189194
yield {
190195
category: folder.name,
191196
folder: path.join(folder.parentPath, folder.name),
@@ -194,18 +199,27 @@ export abstract class GeneratorBase {
194199
}
195200
}
196201

197-
private async *listSourceYAMLFiles(): AsyncIterable<{
202+
private async *listSourceYAMLFiles(
203+
categoryRegex: RegExp | undefined,
204+
operatorRegex: RegExp | undefined,
205+
): AsyncIterable<{
198206
category: string;
199207
operators: () => AsyncIterable<{ yaml: unknown; path: string }>;
200208
}> {
201-
for await (const { category, folder } of this.listCategories()) {
209+
for await (const { category, folder } of this.listCategories(
210+
categoryRegex,
211+
)) {
202212
yield {
203213
category,
204214
operators: async function* () {
205215
for await (const file of await fs.readdir(folder, {
206216
withFileTypes: true,
207217
})) {
208-
if (file.isFile() && file.name.endsWith('.yaml')) {
218+
if (
219+
file.isFile() &&
220+
file.name.endsWith('.yaml') &&
221+
operatorRegex?.test(file.name) !== false
222+
) {
209223
const filePath = path.join(file.parentPath, file.name);
210224
const content = await fs.readFile(filePath, 'utf8');
211225
const parsed = yaml.load(content, GeneratorBase.loadOptions);
@@ -261,8 +275,18 @@ export abstract class GeneratorBase {
261275

262276
protected abstract generateImpl(iterable: YamlFiles): Promise<void>;
263277

264-
public generate(): Promise<void> {
265-
const files = this.listSourceYAMLFiles();
278+
public generate(
279+
categoryFilter?: string,
280+
operatorFilter?: string,
281+
): Promise<void> {
282+
const categoryRegex = categoryFilter
283+
? new RegExp(categoryFilter)
284+
: undefined;
285+
const operatorRegex = operatorFilter
286+
? new RegExp(operatorFilter)
287+
: undefined;
288+
289+
const files = this.listSourceYAMLFiles(categoryRegex, operatorRegex);
266290
return this.generateImpl(files);
267291
}
268292
}

packages/mql-typescript/src/schemaGenerator.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,10 +227,10 @@ export class SchemaGenerator extends GeneratorBase {
227227
import type * as bson from 'bson';
228228
import { FilterOperators } from 'mongodb';
229229
230-
type Condition<T> = AlternativeType<T> | FilterOperators<T>;
230+
type Condition<T> = AlternativeType<T> | FilterOperators<T> | QueryOperator<T>;
231231
type AlternativeType<T> =
232232
T extends ReadonlyArray<infer U> ? T | RegExpOrString<U> : RegExpOrString<T>;
233-
type RegExpOrString<T> = T extends string ? bson.BSONRegExp | RegExp | T : T;
233+
type RegExpOrString<T> = T extends string ? Regex | T : T;
234234
type KeysOfAType<T, Type> = {
235235
[k in keyof T]: NonNullable<T[k]> extends Type ? k : never;
236236
}[keyof T];

0 commit comments

Comments
 (0)