Skip to content

Commit 81f92f2

Browse files
committed
address comments
1 parent e8f2d11 commit 81f92f2

File tree

7 files changed

+329
-85
lines changed

7 files changed

+329
-85
lines changed

package-lock.json

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

packages/compass-collection/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@
5353
"@mongodb-js/compass-components": "^1.47.0",
5454
"@mongodb-js/compass-connections": "^1.69.0",
5555
"@mongodb-js/compass-logging": "^1.7.10",
56-
"@mongodb-js/compass-schema": "^6.70.0",
5756
"@mongodb-js/compass-telemetry": "^1.12.0",
5857
"@mongodb-js/compass-workspaces": "^0.50.0",
5958
"@mongodb-js/connection-info": "^0.17.0",
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
import { expect } from 'chai';
2+
import { calculateSchemaDepth } from './calculate-schema-depth';
3+
import type {
4+
Schema,
5+
SchemaField,
6+
DocumentSchemaType,
7+
ArraySchemaType,
8+
} from 'mongodb-schema';
9+
10+
describe('calculateSchemaDepth', function () {
11+
it('returns 1 for flat schema', async function () {
12+
const schema: Schema = {
13+
fields: [
14+
{ name: 'a', types: [{ bsonType: 'String' }] } as SchemaField,
15+
{ name: 'b', types: [{ bsonType: 'Number' }] } as SchemaField,
16+
],
17+
count: 2,
18+
};
19+
const depth = await calculateSchemaDepth(schema);
20+
expect(depth).to.equal(1);
21+
});
22+
23+
it('returns correct depth for nested document', async function () {
24+
const schema: Schema = {
25+
fields: [
26+
{
27+
name: 'a',
28+
types: [
29+
{
30+
bsonType: 'Document',
31+
fields: [
32+
{
33+
name: 'b',
34+
types: [
35+
{
36+
bsonType: 'Document',
37+
fields: [
38+
{
39+
name: 'c',
40+
types: [{ bsonType: 'String' }],
41+
} as SchemaField,
42+
],
43+
} as DocumentSchemaType,
44+
],
45+
} as SchemaField,
46+
],
47+
} as DocumentSchemaType,
48+
],
49+
} as SchemaField,
50+
],
51+
count: 1,
52+
};
53+
const depth = await calculateSchemaDepth(schema);
54+
expect(depth).to.equal(3);
55+
});
56+
57+
it('returns correct depth for nested arrays', async function () {
58+
const schema: Schema = {
59+
fields: [
60+
{
61+
name: 'arr',
62+
types: [
63+
{
64+
bsonType: 'Array',
65+
types: [
66+
{
67+
bsonType: 'Array',
68+
types: [
69+
{
70+
bsonType: 'Document',
71+
fields: [
72+
{
73+
name: 'x',
74+
types: [{ bsonType: 'String' }],
75+
} as SchemaField,
76+
],
77+
} as DocumentSchemaType,
78+
],
79+
} as ArraySchemaType,
80+
],
81+
} as ArraySchemaType,
82+
],
83+
} as SchemaField,
84+
],
85+
count: 1,
86+
};
87+
const depth = await calculateSchemaDepth(schema);
88+
expect(depth).to.equal(4);
89+
});
90+
91+
it('returns 0 for empty schema', async function () {
92+
const schema: Schema = { fields: [], count: 0 };
93+
const depth = await calculateSchemaDepth(schema);
94+
expect(depth).to.equal(0);
95+
});
96+
97+
it('handles mixed types at root', async function () {
98+
const schema: Schema = {
99+
fields: [
100+
{
101+
name: 'a',
102+
types: [
103+
{ bsonType: 'String' },
104+
{
105+
bsonType: 'Document',
106+
fields: [
107+
{
108+
name: 'b',
109+
types: [{ bsonType: 'Number' }],
110+
} as SchemaField,
111+
],
112+
} as DocumentSchemaType,
113+
],
114+
} as SchemaField,
115+
],
116+
count: 1,
117+
};
118+
const depth = await calculateSchemaDepth(schema);
119+
expect(depth).to.equal(2);
120+
});
121+
122+
it('handles deeply nested mixed arrays and documents', async function () {
123+
const schema: Schema = {
124+
fields: [
125+
{
126+
name: 'root',
127+
types: [
128+
{
129+
bsonType: 'Array',
130+
types: [
131+
{
132+
bsonType: 'Document',
133+
fields: [
134+
{
135+
name: 'nestedArr',
136+
types: [
137+
{
138+
bsonType: 'Array',
139+
types: [
140+
{
141+
bsonType: 'Document',
142+
fields: [
143+
{
144+
name: 'leaf',
145+
types: [{ bsonType: 'String' }],
146+
} as SchemaField,
147+
],
148+
} as DocumentSchemaType,
149+
],
150+
} as ArraySchemaType,
151+
],
152+
} as SchemaField,
153+
],
154+
} as DocumentSchemaType,
155+
],
156+
} as ArraySchemaType,
157+
],
158+
} as SchemaField,
159+
],
160+
count: 1,
161+
};
162+
const depth = await calculateSchemaDepth(schema);
163+
expect(depth).to.equal(5);
164+
});
165+
});
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import type {
2+
ArraySchemaType,
3+
DocumentSchemaType,
4+
Schema,
5+
SchemaField,
6+
SchemaType,
7+
} from 'mongodb-schema';
8+
9+
// Every 1000 iterations, unblock the thread.
10+
const UNBLOCK_INTERVAL_COUNT = 1000;
11+
const unblockThread = async () =>
12+
new Promise<void>((resolve) => setTimeout(resolve));
13+
14+
export async function calculateSchemaDepth(schema: Schema): Promise<number> {
15+
let unblockThreadCounter = 0;
16+
let deepestPath = 0;
17+
18+
async function traverseSchemaTree(
19+
fieldsOrTypes: SchemaField[] | SchemaType[],
20+
depth: number
21+
): Promise<void> {
22+
unblockThreadCounter++;
23+
if (unblockThreadCounter === UNBLOCK_INTERVAL_COUNT) {
24+
unblockThreadCounter = 0;
25+
await unblockThread();
26+
}
27+
28+
if (!fieldsOrTypes || fieldsOrTypes.length === 0) {
29+
return;
30+
}
31+
32+
deepestPath = Math.max(depth, deepestPath);
33+
34+
for (const fieldOrType of fieldsOrTypes) {
35+
if ((fieldOrType as DocumentSchemaType).bsonType === 'Document') {
36+
await traverseSchemaTree(
37+
(fieldOrType as DocumentSchemaType).fields,
38+
depth + 1 // Increment by one when we go a level deeper.
39+
);
40+
} else if (
41+
(fieldOrType as ArraySchemaType).bsonType === 'Array' ||
42+
(fieldOrType as SchemaField).types
43+
) {
44+
const increment =
45+
(fieldOrType as ArraySchemaType).bsonType === 'Array' ? 1 : 0;
46+
await traverseSchemaTree(
47+
(fieldOrType as ArraySchemaType | SchemaField).types,
48+
depth + increment // Increment by one when we go a level deeper.
49+
);
50+
}
51+
}
52+
}
53+
54+
await traverseSchemaTree(schema.fields, 1);
55+
56+
return deepestPath;
57+
}

0 commit comments

Comments
 (0)