Skip to content

Commit dfacd16

Browse files
committed
Array lengths
1 parent a6cc38d commit dfacd16

File tree

2 files changed

+160
-11
lines changed

2 files changed

+160
-11
lines changed

packages/compass-collection/src/components/mock-data-generator-modal/script-generation-utils.spec.ts

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,4 +232,118 @@ describe('Script Generation', () => {
232232
}
233233
});
234234
});
235+
236+
describe('Configurable Array Lengths', () => {
237+
it('should use default array length when no map provided', () => {
238+
const schema = {
239+
'tags[]': createFieldMapping('lorem.word'),
240+
};
241+
242+
const result = generateScript(schema, {
243+
databaseName: 'testdb',
244+
collectionName: 'posts',
245+
documentCount: 1,
246+
});
247+
248+
expect(result.success).to.equal(true);
249+
if (result.success) {
250+
expect(result.script).to.contain('Array.from({length: 3}');
251+
}
252+
});
253+
254+
it('should use custom array length from map', () => {
255+
const schema = {
256+
'tags[]': createFieldMapping('lorem.word'),
257+
};
258+
259+
const result = generateScript(schema, {
260+
databaseName: 'testdb',
261+
collectionName: 'posts',
262+
documentCount: 1,
263+
arrayLengthMap: {
264+
tags: 5,
265+
},
266+
});
267+
268+
expect(result.success).to.equal(true);
269+
if (result.success) {
270+
expect(result.script).to.contain('Array.from({length: 5}');
271+
}
272+
});
273+
274+
it('should handle nested array length configuration', () => {
275+
const schema = {
276+
'users[].tags[]': createFieldMapping('lorem.word'),
277+
};
278+
279+
const result = generateScript(schema, {
280+
databaseName: 'testdb',
281+
collectionName: 'groups',
282+
documentCount: 1,
283+
arrayLengthMap: {
284+
users: {
285+
tags: 4,
286+
},
287+
},
288+
});
289+
290+
expect(result.success).to.equal(true);
291+
if (result.success) {
292+
// Should have tags array with length 4
293+
expect(result.script).to.contain('Array.from({length: 4}');
294+
}
295+
});
296+
297+
it('should handle hierarchical array length map', () => {
298+
const schema = {
299+
'departments[].employees[].skills[]': createFieldMapping('lorem.word'),
300+
};
301+
302+
const result = generateScript(schema, {
303+
databaseName: 'testdb',
304+
collectionName: 'company',
305+
documentCount: 1,
306+
arrayLengthMap: {
307+
departments: {
308+
employees: {
309+
skills: 3,
310+
},
311+
},
312+
},
313+
});
314+
315+
expect(result.success).to.equal(true);
316+
if (result.success) {
317+
expect(result.script).to.contain('Array.from({length: 3}');
318+
}
319+
});
320+
321+
it('should handle zero-length arrays', () => {
322+
const schema = {
323+
'tags[]': createFieldMapping('lorem.word'),
324+
'categories[]': createFieldMapping('lorem.word'),
325+
};
326+
327+
const result = generateScript(schema, {
328+
databaseName: 'testdb',
329+
collectionName: 'posts',
330+
documentCount: 1,
331+
arrayLengthMap: {
332+
tags: 0,
333+
categories: 2,
334+
},
335+
});
336+
337+
expect(result.success).to.equal(true);
338+
if (result.success) {
339+
// Should have tags array with length 0 (empty array)
340+
expect(result.script).to.contain('Array.from({length: 0}');
341+
// Should have categories array with length 2
342+
expect(result.script).to.contain('Array.from({length: 2}');
343+
// Verify both arrays are present
344+
expect(result.script).to.contain('tags:');
345+
expect(result.script).to.contain('categories:');
346+
}
347+
});
348+
});
235349
});

packages/compass-collection/src/components/mock-data-generator-modal/script-generation-utils.ts

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,16 @@ export interface FieldMapping {
44
fakerArgs: any[]; // TODO: type this properly later
55
}
66

7+
// Hierarchical array length map that mirrors document structure
8+
export type ArrayLengthMap = {
9+
[fieldName: string]: number | ArrayLengthMap;
10+
};
11+
712
export interface ScriptOptions {
813
documentCount: number;
914
databaseName: string;
1015
collectionName: string;
11-
// TODO: array lengths - for now use fixed length
16+
arrayLengthMap?: ArrayLengthMap;
1217
}
1318

1419
export interface ScriptResult {
@@ -220,7 +225,11 @@ export function generateScript(
220225
try {
221226
const structure = buildDocumentStructure(schema);
222227

223-
const documentCode = generateDocumentCode(structure);
228+
const documentCode = generateDocumentCode(
229+
structure,
230+
2,
231+
options.arrayLengthMap || {}
232+
);
224233

225234
// Escape ' and ` in database/collection names for template literals
226235
const escapedDbName = options.databaseName
@@ -233,7 +242,7 @@ export function generateScript(
233242
// Validate document count
234243
const documentCount = Math.max(
235244
1,
236-
Math.min(10000, Math.floor(options.documentCount))
245+
Math.min(10000, Math.floor(options.documentCount)) // TODO
237246
);
238247

239248
const script = `// Mock Data Generator Script
@@ -279,7 +288,8 @@ console.log(\`Successfully inserted \${documents.length} documents into ${escape
279288
*/
280289
function generateDocumentCode(
281290
structure: DocumentStructure,
282-
indent: number = 2
291+
indent: number = 2,
292+
arrayLengthMap: ArrayLengthMap = {}
283293
): string {
284294
// For each field in structure:
285295
// - If FieldMapping: generate faker call
@@ -297,13 +307,28 @@ function generateDocumentCode(
297307
rootLevelFields.push(`${fieldIndent}${fieldName}: ${fakerCall}`);
298308
} else if ('type' in value && value.type === 'array') {
299309
// It's an array
300-
const arrayCode = generateArrayCode(value as ArrayStructure, indent + 2);
310+
const nestedArrayLengthMap =
311+
typeof arrayLengthMap[fieldName] === 'object'
312+
? arrayLengthMap[fieldName]
313+
: {};
314+
const arrayCode = generateArrayCode(
315+
value as ArrayStructure,
316+
indent + 2,
317+
fieldName,
318+
arrayLengthMap,
319+
nestedArrayLengthMap
320+
);
301321
rootLevelFields.push(`${fieldIndent}${fieldName}: ${arrayCode}`);
302322
} else {
303323
// It's a nested object: recursive call
324+
const nestedArrayLengthMap =
325+
typeof arrayLengthMap[fieldName] === 'object'
326+
? arrayLengthMap[fieldName]
327+
: arrayLengthMap;
304328
const nestedCode = generateDocumentCode(
305329
value as DocumentStructure,
306-
indent + 2
330+
indent + 2,
331+
nestedArrayLengthMap
307332
);
308333
rootLevelFields.push(`${fieldIndent}${fieldName}: ${nestedCode}`);
309334
}
@@ -322,12 +347,18 @@ function generateDocumentCode(
322347
*/
323348
function generateArrayCode(
324349
arrayStructure: ArrayStructure,
325-
indent: number = 2
350+
indent: number = 2,
351+
fieldName: string = '',
352+
parentArrayLengthMap: ArrayLengthMap = {},
353+
nestedArrayLengthMap: ArrayLengthMap = {}
326354
): string {
327355
const elementType = arrayStructure.elementType;
328356

329-
// Fixed length for now - TODO: make configurable
330-
const arrayLength = 3;
357+
// Get array length from map or use default
358+
const arrayLength =
359+
typeof parentArrayLengthMap[fieldName] === 'number'
360+
? parentArrayLengthMap[fieldName]
361+
: 3;
331362

332363
if ('mongoType' in elementType) {
333364
// Array of primitives
@@ -337,14 +368,18 @@ function generateArrayCode(
337368
// Nested array (e.g., matrix[][])
338369
const nestedArrayCode = generateArrayCode(
339370
elementType as ArrayStructure,
340-
indent
371+
indent,
372+
'', // No specific field name for nested arrays
373+
nestedArrayLengthMap,
374+
{}
341375
);
342376
return `Array.from({length: ${arrayLength}}, () => ${nestedArrayCode})`;
343377
} else {
344378
// Array of objects
345379
const objectCode = generateDocumentCode(
346380
elementType as DocumentStructure,
347-
indent
381+
indent,
382+
nestedArrayLengthMap
348383
);
349384
return `Array.from({length: ${arrayLength}}, () => ${objectCode})`;
350385
}

0 commit comments

Comments
 (0)