Skip to content

Commit 2050d5a

Browse files
committed
abort with timeout
1 parent 01e65bd commit 2050d5a

File tree

5 files changed

+159
-36
lines changed

5 files changed

+159
-36
lines changed

src/schema-accessor.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Schema as InternalSchema } from './schema-analyzer';
2-
import convertors from './schema-convertors';
2+
import { convertors } from './schema-convertors';
33
import { ExpandedJSONSchema, MongoDBJSONSchema, StandardJSONSchema } from './types';
44

55
export interface SchemaAccessor {

src/schema-convertors/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import internalSchemaToExpanded from './internalToExpanded';
22
import internalSchemaToMongoDB from './internalToMongoDB';
33
import internalSchemaToStandard from './internalToStandard';
44

5-
export default {
5+
export const convertors = {
66
internalSchemaToStandard,
77
internalSchemaToMongoDB,
88
internalSchemaToExpanded

src/schema-convertors/internalToMongoDB.test.ts

Lines changed: 132 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import assert from 'assert';
2-
import internalSchemaToStandard from './internalToMongoDB';
2+
import internalSchemaToMongoDB from './internalToMongoDB';
33

4-
describe('internalSchemaToStandard', function() {
5-
describe('Converts: ', function() {
6-
it('get me analyzed thing', async function() {
4+
describe('internalSchemaToMongoDB', async function() {
5+
describe('Converts: ', async function() {
6+
it('all the types', async function() {
77
const internal = {
88
count: 1,
99
fields: [
@@ -892,7 +892,7 @@ describe('internalSchemaToStandard', function() {
892892
}
893893
]
894894
};
895-
const standard = internalSchemaToStandard(internal);
895+
const standard = await internalSchemaToMongoDB(internal);
896896
assert.deepStrictEqual(standard, {
897897
bsonType: 'object',
898898
required: [],
@@ -1006,7 +1006,7 @@ describe('internalSchemaToStandard', function() {
10061006
});
10071007
});
10081008

1009-
it('nested document/object', function() {
1009+
it('nested document/object', async function() {
10101010
const internal = {
10111011
count: 2,
10121012
fields: [
@@ -1105,7 +1105,7 @@ describe('internalSchemaToStandard', function() {
11051105
}
11061106
]
11071107
};
1108-
const standard = internalSchemaToStandard(internal);
1108+
const standard = await internalSchemaToMongoDB(internal);
11091109
assert.deepStrictEqual(standard, {
11101110
bsonType: 'object',
11111111
required: ['author'],
@@ -1126,8 +1126,8 @@ describe('internalSchemaToStandard', function() {
11261126
});
11271127
});
11281128

1129-
describe('arrays', function() {
1130-
it('array - single type', function() {
1129+
describe('arrays', async function() {
1130+
it('array - single type', async function() {
11311131
const internal = {
11321132
count: 2,
11331133
fields: [
@@ -1190,7 +1190,7 @@ describe('internalSchemaToStandard', function() {
11901190
}
11911191
]
11921192
};
1193-
const standard = internalSchemaToStandard(internal);
1193+
const standard = await internalSchemaToMongoDB(internal);
11941194
assert.deepStrictEqual(standard, {
11951195
bsonType: 'object',
11961196
required: [],
@@ -1205,7 +1205,7 @@ describe('internalSchemaToStandard', function() {
12051205
});
12061206
});
12071207

1208-
it('array - complex mixed type', function() {
1208+
it('array - complex mixed type', async function() {
12091209
const internal = {
12101210
count: 2,
12111211
fields: [
@@ -1335,7 +1335,7 @@ describe('internalSchemaToStandard', function() {
13351335
}
13361336
]
13371337
};
1338-
const standard = internalSchemaToStandard(internal);
1338+
const standard = await internalSchemaToMongoDB(internal);
13391339
assert.deepStrictEqual(standard, {
13401340
bsonType: 'object',
13411341
required: [],
@@ -1366,7 +1366,7 @@ describe('internalSchemaToStandard', function() {
13661366
});
13671367
});
13681368

1369-
it('array - simple mixed type', function() {
1369+
it('array - simple mixed type', async function() {
13701370
const internal = {
13711371
count: 2,
13721372
fields: [
@@ -1429,7 +1429,7 @@ describe('internalSchemaToStandard', function() {
14291429
}
14301430
]
14311431
};
1432-
const standard = internalSchemaToStandard(internal);
1432+
const standard = await internalSchemaToMongoDB(internal);
14331433
assert.deepStrictEqual(standard, {
14341434
bsonType: 'object',
14351435
required: ['arrayMixedType'],
@@ -1445,8 +1445,8 @@ describe('internalSchemaToStandard', function() {
14451445
});
14461446
});
14471447

1448-
describe('mixed types', function() {
1449-
it('simple mixed type', function() {
1448+
describe('mixed types', async function() {
1449+
it('simple mixed type', async function() {
14501450
const internal = {
14511451
count: 2,
14521452
fields: [
@@ -1507,7 +1507,7 @@ describe('internalSchemaToStandard', function() {
15071507
}
15081508
]
15091509
};
1510-
const standard = internalSchemaToStandard(internal);
1510+
const standard = await internalSchemaToMongoDB(internal);
15111511
assert.deepStrictEqual(standard, {
15121512
bsonType: 'object',
15131513
required: [],
@@ -1519,7 +1519,7 @@ describe('internalSchemaToStandard', function() {
15191519
});
15201520
});
15211521

1522-
it('complex mixed type', function() {
1522+
it('complex mixed type', async function() {
15231523
const internal = {
15241524
count: 2,
15251525
fields: [
@@ -1623,7 +1623,7 @@ describe('internalSchemaToStandard', function() {
16231623
}
16241624
]
16251625
};
1626-
const standard = internalSchemaToStandard(internal);
1626+
const standard = await internalSchemaToMongoDB(internal);
16271627
assert.deepStrictEqual(standard, {
16281628
bsonType: 'object',
16291629
required: [],
@@ -1651,5 +1651,118 @@ describe('internalSchemaToStandard', function() {
16511651
});
16521652
});
16531653
});
1654+
1655+
it('can be aborted', async function() {
1656+
const internal = {
1657+
count: 2,
1658+
fields: [
1659+
{
1660+
name: 'mixedComplexType',
1661+
path: [
1662+
'mixedComplexType'
1663+
],
1664+
count: 2,
1665+
type: [
1666+
'Array',
1667+
'Document',
1668+
'Undefined'
1669+
],
1670+
probability: 0.6666666666666666,
1671+
hasDuplicates: false,
1672+
types: [
1673+
{
1674+
name: 'Array',
1675+
path: [
1676+
'mixedComplexType'
1677+
],
1678+
count: 1,
1679+
probability: 0.3333333333333333,
1680+
bsonType: 'Array',
1681+
types: [
1682+
{
1683+
name: 'Int32',
1684+
path: [
1685+
'mixedComplexType'
1686+
],
1687+
count: 3,
1688+
probability: 1,
1689+
unique: 3,
1690+
hasDuplicates: false,
1691+
values: [
1692+
1,
1693+
2,
1694+
3
1695+
],
1696+
bsonType: 'Int32'
1697+
}
1698+
],
1699+
totalCount: 3,
1700+
lengths: [
1701+
3
1702+
],
1703+
averageLength: 3
1704+
},
1705+
{
1706+
name: 'Document',
1707+
path: [
1708+
'mixedComplexType'
1709+
],
1710+
count: 1,
1711+
probability: 0.3333333333333333,
1712+
bsonType: 'Document',
1713+
fields: [
1714+
{
1715+
name: 'a',
1716+
path: [
1717+
'mixedComplexType',
1718+
'a'
1719+
],
1720+
count: 1,
1721+
type: 'String',
1722+
probability: 1,
1723+
hasDuplicates: false,
1724+
types: [
1725+
{
1726+
name: 'String',
1727+
path: [
1728+
'mixedComplexType',
1729+
'a'
1730+
],
1731+
count: 1,
1732+
probability: 1,
1733+
unique: 1,
1734+
hasDuplicates: false,
1735+
values: [
1736+
'bc'
1737+
],
1738+
bsonType: 'String'
1739+
}
1740+
]
1741+
}
1742+
]
1743+
},
1744+
{
1745+
name: 'Undefined',
1746+
bsonType: 'Undefined',
1747+
unique: 1,
1748+
hasDuplicates: false,
1749+
path: [
1750+
'mixedComplexType'
1751+
],
1752+
count: 1,
1753+
probability: 0.3333333333333333
1754+
}
1755+
]
1756+
}
1757+
]
1758+
};
1759+
const abortController = new AbortController();
1760+
const promise = internalSchemaToMongoDB(internal, { signal: abortController.signal });
1761+
abortController.abort(new Error('Too long, didn\'t wait.'));
1762+
await assert.rejects(promise, {
1763+
name: 'Error',
1764+
message: 'Too long, didn\'t wait.'
1765+
});
1766+
});
16541767
});
16551768
});

src/schema-convertors/internalToMongoDB.ts

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,33 +36,42 @@ const convertInternalType = (type: string) => {
3636
return bsonType;
3737
};
3838

39-
function parseType(type: SchemaType, signal?: AbortSignal): MongoDBJSONSchema {
40-
if (signal?.aborted) throw new Error('Operation aborted');
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+
48+
async function parseType(type: SchemaType, signal?: AbortSignal): Promise<MongoDBJSONSchema> {
49+
await allowAbort(signal);
4150
const schema: MongoDBJSONSchema = {
4251
bsonType: convertInternalType(type.bsonType)
4352
};
4453
switch (type.bsonType) {
4554
case 'Array':
46-
schema.items = parseTypes((type as ArraySchemaType).types);
55+
schema.items = await parseTypes((type as ArraySchemaType).types);
4756
break;
4857
case 'Document':
4958
Object.assign(schema,
50-
parseFields((type as DocumentSchemaType).fields, signal)
59+
await parseFields((type as DocumentSchemaType).fields, signal)
5160
);
5261
break;
5362
}
5463

5564
return schema;
5665
}
5766

58-
function parseTypes(types: SchemaType[], signal?: AbortSignal): MongoDBJSONSchema {
59-
if (signal?.aborted) throw signal.reason ?? new Error('Operation aborted');
67+
async function parseTypes(types: SchemaType[], signal?: AbortSignal): Promise<MongoDBJSONSchema> {
68+
await allowAbort(signal);
6069
const definedTypes = types.filter(type => type.bsonType.toLowerCase() !== 'undefined');
6170
const isSingleType = definedTypes.length === 1;
6271
if (isSingleType) {
6372
return parseType(definedTypes[0], signal);
6473
}
65-
const parsedTypes = definedTypes.map(type => parseType(type, signal));
74+
const parsedTypes = await Promise.all(definedTypes.map(type => parseType(type, signal)));
6675
if (definedTypes.some(type => ['Document', 'Array'].includes(type.bsonType))) {
6776
return {
6877
anyOf: parsedTypes
@@ -73,29 +82,30 @@ function parseTypes(types: SchemaType[], signal?: AbortSignal): MongoDBJSONSchem
7382
};
7483
}
7584

76-
function parseFields(fields: DocumentSchemaType['fields'], signal?: AbortSignal): {
85+
async function parseFields(fields: DocumentSchemaType['fields'], signal?: AbortSignal): Promise<{
7786
required: MongoDBJSONSchema['required'],
7887
properties: MongoDBJSONSchema['properties'],
79-
} {
88+
}> {
8089
const required = [];
8190
const properties: MongoDBJSONSchema['properties'] = {};
8291
for (const field of fields) {
83-
if (signal?.aborted) throw new Error('Operation aborted');
8492
if (field.probability === 1) required.push(field.name);
85-
properties[field.name] = parseTypes(field.types, signal);
93+
properties[field.name] = await parseTypes(field.types, signal);
8694
}
8795

8896
return { required, properties };
8997
}
9098

91-
export default function internalSchemaToMongodb(
99+
export default async function internalSchemaToMongodb(
92100
internalSchema: InternalSchema,
93101
options: {
94102
signal?: AbortSignal
95-
} = {}): MongoDBJSONSchema {
103+
} = {}): Promise<MongoDBJSONSchema> {
104+
const { required, properties } = await parseFields(internalSchema.fields, options.signal);
96105
const schema: MongoDBJSONSchema = {
97106
bsonType: 'object',
98-
...parseFields(internalSchema.fields, options.signal)
107+
required,
108+
properties
99109
};
100110
return schema;
101111
}

test/analyze-documents.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { analyzeDocuments } from '../src';
2-
import convertors from '../src/schema-convertors';
2+
import { convertors } from '../src/schema-convertors';
33
import sinon from 'sinon';
44
import assert from 'assert';
55

0 commit comments

Comments
 (0)