Skip to content

Commit c514068

Browse files
authored
feat: internal to Standard JSON Schema conversion COMPASS-8700 (#219)
1 parent 530563f commit c514068

File tree

8 files changed

+2460
-54
lines changed

8 files changed

+2460
-54
lines changed

package-lock.json

Lines changed: 206 additions & 34 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
".esm-wrapper.mjs"
3434
],
3535
"scripts": {
36-
"test": "nyc mocha --timeout 5000 --colors -r ts-node/register test/*.ts src/**/*.test.ts",
36+
"test": "nyc mocha --timeout 5000 --colors -r ts-node/register test/**/*.ts src/**/*.test.ts",
3737
"test-example-parse-from-file": "ts-node examples/parse-from-file.ts",
3838
"test-example-parse-schema": "ts-node examples/parse-schema.ts",
3939
"test-time": "ts-node ./test/time-testing.ts",
@@ -60,6 +60,7 @@
6060
"@types/sinon": "^17.0.3",
6161
"@typescript-eslint/eslint-plugin": "^5.47.1",
6262
"@typescript-eslint/parser": "^5.47.1",
63+
"ajv": "^8.17.1",
6364
"bson": "^6.7.0",
6465
"coveralls": "^3.1.1",
6566
"depcheck": "^1.4.3",

src/schema-accessor.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,24 @@ export class InternalSchemaBasedAccessor implements SchemaAccessor {
3333
return this.internalSchema;
3434
}
3535

36+
/**
37+
* Get standard JSON Schema - as per
38+
* https://json-schema.org/draft/2020-12/schema
39+
*/
3640
async getStandardJsonSchema(options: Options = {}): Promise<StandardJSONSchema> {
3741
return this.standardJSONSchema ??= await convertors.internalSchemaToStandard(this.internalSchema, options);
3842
}
3943

44+
/**
45+
* Get MongoDB's $jsonSchema
46+
*/
4047
async getMongoDBJsonSchema(options: Options = {}): Promise<MongoDBJSONSchema> {
4148
return this.mongodbJSONSchema ??= await convertors.internalSchemaToMongoDB(this.internalSchema, options);
4249
}
4350

51+
/**
52+
* Get expanded JSON Schema - with additional properties
53+
*/
4454
async getExpandedJSONSchema(options: Options = {}): Promise<ExpandedJSONSchema> {
4555
return this.ExpandedJSONSchema ??= await convertors.internalSchemaToExpanded(this.internalSchema, options);
4656
}

src/schema-convertors/internalToMongoDB.ts

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1+
/**
2+
* Transforms the internal schema to $jsonSchema
3+
*/
14
import { ArraySchemaType, DocumentSchemaType, Schema as InternalSchema, SchemaType } from '../schema-analyzer';
25
import { MongoDBJSONSchema } from '../types';
6+
import { allowAbort } from './util';
37

4-
const InternalTypeToBsonTypeMap: Record<
8+
export const InternalTypeToBsonTypeMap: Record<
59
SchemaType['name'] | 'Double' | 'BSONSymbol',
610
string
711
> = {
@@ -36,15 +40,6 @@ const convertInternalType = (type: string) => {
3640
return bsonType;
3741
};
3842

39-
async function allowAbort(signal?: AbortSignal) {
40-
return new Promise<void>((resolve, reject) =>
41-
setTimeout(() => {
42-
if (signal?.aborted) return reject(signal?.reason || new Error('Operation aborted'));
43-
resolve();
44-
})
45-
);
46-
}
47-
4843
async function parseType(type: SchemaType, signal?: AbortSignal): Promise<MongoDBJSONSchema> {
4944
await allowAbort(signal);
5045
const schema: MongoDBJSONSchema = {
@@ -64,6 +59,10 @@ async function parseType(type: SchemaType, signal?: AbortSignal): Promise<MongoD
6459
return schema;
6560
}
6661

62+
function isPlainTypesOnly(types: MongoDBJSONSchema[]): types is { bsonType: string }[] {
63+
return types.every(definition => !!definition.bsonType && Object.keys(definition).length === 1);
64+
}
65+
6766
async function parseTypes(types: SchemaType[], signal?: AbortSignal): Promise<MongoDBJSONSchema> {
6867
await allowAbort(signal);
6968
const definedTypes = types.filter(type => type.bsonType.toLowerCase() !== 'undefined');
@@ -72,13 +71,13 @@ async function parseTypes(types: SchemaType[], signal?: AbortSignal): Promise<Mo
7271
return parseType(definedTypes[0], signal);
7372
}
7473
const parsedTypes = await Promise.all(definedTypes.map(type => parseType(type, signal)));
75-
if (definedTypes.some(type => ['Document', 'Array'].includes(type.bsonType))) {
74+
if (isPlainTypesOnly(parsedTypes)) {
7675
return {
77-
anyOf: parsedTypes
76+
bsonType: parsedTypes.map(({ bsonType }) => bsonType)
7877
};
7978
}
8079
return {
81-
bsonType: definedTypes.map((type) => convertInternalType(type.bsonType))
80+
anyOf: parsedTypes
8281
};
8382
}
8483

0 commit comments

Comments
 (0)