Skip to content
Merged

Dev #20

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
723 changes: 721 additions & 2 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,14 @@
"devDependencies": {
"@types/better-sqlite3": "^7.6.13",
"@types/commander": "^2.12.0",
"@types/ioredis": "^4.28.10",
"@types/pg": "^8.16.0",
"@types/seedrandom": "^3.0.8",
"@types/tedious": "^4.0.14",
"@vitest/coverage-v8": "^4.1.0",
"@vitest/ui": "^4.1.0",
"ioredis": "^5.10.1",
"tedious": "^19.2.1",
"typescript": "5.9.3",
"vitest": "^4.0.17"
},
Expand All @@ -69,4 +73,4 @@
"publishConfig": {
"access": "public"
}
}
}
2 changes: 1 addition & 1 deletion src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ program
.description("Generate and populate test data")
.requiredOption("-s, --schema <path>", "Path to schema JSON file")
.requiredOption("-c, --config <path>", "Path to configuration JSON file")
.option("-d, --db <type>", "Database type (mongodb, postgresql, firestore, in-memory)", "in-memory")
.option("-d, --db <type>", "Database type (mongodb, postgresql, firestore, in-memory, dynamodb, sqlserver, redis)", "in-memory")
.option("-u, --url <url>", "Database connection URL (or credentials for Firestore)")
.action(async (options) => {
try {
Expand Down
62 changes: 18 additions & 44 deletions src/generator/adapters/BaseAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import seedrandom from "seedrandom";
import crypto from "crypto";
import { Faker, en } from "@faker-js/faker";
import { fieldInferenceEngine } from "../core/FieldInferenceEngine";
import { ConstraintEngine, ColumnDependencyGraph } from "../core/ConstraintEngine";

export interface CollectionDetails {
primaryKey?: string;
Expand Down Expand Up @@ -1424,60 +1425,33 @@ export abstract class BaseAdapter {

/**
* Sort fields topologically based on cross-column constraints.
* Uses ColumnDependencyGraph from ConstraintEngine for cycle-safe sorting.
* If B depends on A (e.g. B > A), A comes first.
*/
protected sortFieldsByDependency(fields: SchemaField[]): SchemaField[] {
const dependencyMap = new Map<string, Set<string>>();
const graph = new ColumnDependencyGraph(fields);
const orderedNames = graph.getTopologicalSort();

const nameToField = new Map<string, SchemaField>();

for (const field of fields) {
nameToField.set(field.name, field);
if (!dependencyMap.has(field.name)) {
dependencyMap.set(field.name, new Set());
}

const c = field.constraints;
if (c) {
const deps = [c.minColumn, c.maxColumn, c.gtColumn, c.ltColumn];
for (const dep of deps) {
if (dep) {
dependencyMap.get(field.name)!.add(dep);
}
}
}
}

const visited = new Set<string>();
const tempVisited = new Set<string>();
const sorted: SchemaField[] = [];

const visit = (fieldName: string) => {
if (tempVisited.has(fieldName)) return; // Cyclic dependency detected, ignore
if (visited.has(fieldName)) return;

tempVisited.add(fieldName);

const deps = dependencyMap.get(fieldName);
if (deps) {
for (const depName of deps) {
if (nameToField.has(depName)) {
visit(depName);
}
}

const orderedFields: SchemaField[] = [];
for (const name of orderedNames) {
const field = nameToField.get(name);
if (field) {
orderedFields.push(field);
}

tempVisited.delete(fieldName);
visited.add(fieldName);

const f = nameToField.get(fieldName);
if (f) sorted.push(f);
};

}

for (const field of fields) {
visit(field.name);
if (!orderedFields.includes(field)) {
orderedFields.push(field);
}
}

return sorted;
return orderedFields;
}

protected buildRelationshipMap(relationships: SchemaRelationship[]): void {
Expand Down
Loading
Loading