noormme 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +84 -65
- package/dist/cjs/agentic/ActionJournal.js +13 -9
- package/dist/cjs/agentic/CapabilityManager.js +35 -21
- package/dist/cjs/agentic/CognitiveRepository.js +19 -9
- package/dist/cjs/agentic/ContextBuffer.js +24 -12
- package/dist/cjs/agentic/Cortex.js +11 -4
- package/dist/cjs/agentic/EpisodicMemory.js +7 -5
- package/dist/cjs/agentic/PersonaManager.js +16 -8
- package/dist/cjs/agentic/PolicyEnforcer.js +31 -12
- package/dist/cjs/agentic/ResourceMonitor.js +4 -4
- package/dist/cjs/agentic/SessionCompressor.js +22 -14
- package/dist/cjs/agentic/SessionManager.js +36 -18
- package/dist/cjs/agentic/VectorIndexer.js +22 -18
- package/dist/cjs/agentic/improvement/AblationEngine.js +22 -15
- package/dist/cjs/agentic/improvement/ActionRefiner.js +12 -10
- package/dist/cjs/agentic/improvement/ConflictResolver.js +5 -5
- package/dist/cjs/agentic/improvement/CortexJanitor.js +30 -9
- package/dist/cjs/agentic/improvement/CuriosityEngine.js +27 -23
- package/dist/cjs/agentic/improvement/EvolutionRitual.js +4 -4
- package/dist/cjs/agentic/improvement/EvolutionaryPilot.js +16 -6
- package/dist/cjs/agentic/improvement/GoalArchitect.d.ts +2 -2
- package/dist/cjs/agentic/improvement/GoalArchitect.js +20 -18
- package/dist/cjs/agentic/improvement/GovernanceManager.js +19 -11
- package/dist/cjs/agentic/improvement/HiveLink.js +22 -15
- package/dist/cjs/agentic/improvement/KnowledgeDistiller.js +48 -32
- package/dist/cjs/agentic/improvement/RecursiveReasoner.js +40 -17
- package/dist/cjs/agentic/improvement/ReflectionEngine.js +10 -8
- package/dist/cjs/agentic/improvement/RitualOrchestrator.js +28 -22
- package/dist/cjs/agentic/improvement/RuleEngine.js +22 -17
- package/dist/cjs/agentic/improvement/SelfEvolution.js +24 -18
- package/dist/cjs/agentic/improvement/SelfTestRegistry.js +18 -15
- package/dist/cjs/agentic/improvement/SkillSynthesizer.js +42 -27
- package/dist/cjs/agentic/improvement/SovereignMetrics.js +19 -17
- package/dist/cjs/agentic/improvement/StrategicPlanner.js +120 -55
- package/dist/cjs/agentic/telemetry/CognitiveSynthesizer.js +26 -12
- package/dist/cjs/agentic/telemetry/EventHarvester.js +3 -2
- package/dist/cjs/agentic/telemetry/ResearchAlchemist.js +5 -2
- package/dist/cjs/cache/cache-manager.js +7 -4
- package/dist/cjs/cli/commands/analyze.js +5 -4
- package/dist/cjs/cli/commands/generate.js +81 -44
- package/dist/cjs/cli/commands/init.js +7 -3
- package/dist/cjs/cli/commands/inspect.js +139 -36
- package/dist/cjs/cli/commands/migrate.js +5 -4
- package/dist/cjs/cli/commands/optimize.js +4 -4
- package/dist/cjs/cli/commands/status.js +9 -7
- package/dist/cjs/cli/commands/watch.js +7 -6
- package/dist/cjs/cli/index.js +2 -2
- package/dist/cjs/cli/ui/spinner.d.ts +15 -0
- package/dist/cjs/cli/ui/spinner.js +76 -0
- package/dist/cjs/dialect/database-introspector.js +3 -1
- package/dist/cjs/dialect/postgresql/postgresql-driver.js +3 -1
- package/dist/cjs/dialect/postgresql/postgresql-features.js +18 -8
- package/dist/cjs/dialect/postgresql/postgresql-introspector.js +2 -2
- package/dist/cjs/dialect/sqlite/sqlite-auto-indexer.js +47 -33
- package/dist/cjs/dialect/sqlite/sqlite-auto-optimizer.js +8 -7
- package/dist/cjs/dialect/sqlite/sqlite-driver.js +2 -2
- package/dist/cjs/dialect/sqlite/sqlite-introspector.js +15 -12
- package/dist/cjs/edge-runtime/edge-config.js +21 -19
- package/dist/cjs/errors/NoormError.js +22 -20
- package/dist/cjs/helpers/agent-schema.js +2 -0
- package/dist/cjs/helpers/postgresql.js +7 -4
- package/dist/cjs/helpers/schema-evolution.js +31 -6
- package/dist/cjs/index.d.ts +3 -3
- package/dist/cjs/logging/logger.js +8 -4
- package/dist/cjs/migration/data_migrator.js +12 -11
- package/dist/cjs/migration/database_migration_manager.js +17 -13
- package/dist/cjs/migration/schema_differ.js +22 -14
- package/dist/cjs/migration/schema_introspector.js +8 -8
- package/dist/cjs/migration/type_mapper.js +68 -67
- package/dist/cjs/noormme.js +52 -37
- package/dist/cjs/performance/index.js +5 -5
- package/dist/cjs/performance/query-optimizer.js +26 -21
- package/dist/cjs/performance/services/cache-service.js +26 -16
- package/dist/cjs/performance/services/connection-factory.js +28 -23
- package/dist/cjs/performance/services/metrics-collector.js +41 -36
- package/dist/cjs/performance/utils/query-parser.js +15 -16
- package/dist/cjs/relationships/relationship-engine.js +10 -8
- package/dist/cjs/repository/repository-factory.js +97 -38
- package/dist/cjs/schema/core/coordinators/schema-discovery.coordinator.js +1 -3
- package/dist/cjs/schema/core/discovery/relationship-discovery.js +16 -16
- package/dist/cjs/schema/core/discovery/table-metadata-discovery.js +9 -9
- package/dist/cjs/schema/core/discovery/view-discovery.js +5 -4
- package/dist/cjs/schema/core/factories/discovery-factory.js +4 -4
- package/dist/cjs/schema/core/utils/name-generator.js +14 -5
- package/dist/cjs/schema/core/utils/type-mapper.js +24 -24
- package/dist/cjs/schema/dialects/postgresql/postgresql-discovery.coordinator.js +8 -7
- package/dist/cjs/schema/dialects/sqlite/discovery/sqlite-constraint-discovery.js +17 -15
- package/dist/cjs/schema/dialects/sqlite/discovery/sqlite-index-discovery.js +8 -8
- package/dist/cjs/schema/dialects/sqlite/introspection/sqlite-schema-introspector.js +6 -11
- package/dist/cjs/schema/dialects/sqlite/sqlite-discovery.coordinator.js +14 -13
- package/dist/cjs/schema/test/basic-schema-test.js +11 -9
- package/dist/cjs/schema/test/dialect-capabilities.test.js +6 -6
- package/dist/cjs/schema/test/discovery-factory.test.js +2 -2
- package/dist/cjs/schema/test/error-handling.test.js +8 -6
- package/dist/cjs/schema/test/integration.test.js +24 -18
- package/dist/cjs/schema/test/schema-discovery-coordinator.test.js +9 -9
- package/dist/cjs/schema/test/simple-schema-test.js +9 -9
- package/dist/cjs/schema/test/sqlite-discovery-coordinator.test.js +64 -48
- package/dist/cjs/schema/test/test-runner.js +3 -3
- package/dist/cjs/sqlite-migration/index.d.ts +2 -2
- package/dist/cjs/sqlite-migration/sqlite-migration-manager.js +21 -17
- package/dist/cjs/sqlite-migration/sqlite-migration-provider.js +38 -34
- package/dist/cjs/testing/test-utils.js +36 -34
- package/dist/cjs/types/index.d.ts +5 -2
- package/dist/cjs/types/index.js +6 -3
- package/dist/cjs/types/type-generator.js +46 -42
- package/dist/cjs/util/safe-sql-helpers.js +1 -1
- package/dist/cjs/util/security-validator.js +20 -9
- package/dist/cjs/utils/errorHelpers.js +20 -10
- package/dist/cjs/watch/schema-watcher.js +22 -23
- package/dist/esm/agentic/ActionJournal.js +13 -9
- package/dist/esm/agentic/CapabilityManager.js +35 -21
- package/dist/esm/agentic/CognitiveRepository.js +19 -9
- package/dist/esm/agentic/ContextBuffer.js +24 -12
- package/dist/esm/agentic/Cortex.js +11 -4
- package/dist/esm/agentic/EpisodicMemory.js +7 -5
- package/dist/esm/agentic/PersonaManager.js +16 -8
- package/dist/esm/agentic/PolicyEnforcer.js +31 -12
- package/dist/esm/agentic/ResourceMonitor.js +4 -4
- package/dist/esm/agentic/SessionCompressor.js +22 -14
- package/dist/esm/agentic/SessionManager.js +36 -18
- package/dist/esm/agentic/VectorIndexer.js +22 -18
- package/dist/esm/agentic/improvement/AblationEngine.js +22 -15
- package/dist/esm/agentic/improvement/ActionRefiner.js +12 -10
- package/dist/esm/agentic/improvement/ConflictResolver.js +5 -5
- package/dist/esm/agentic/improvement/CortexJanitor.js +30 -9
- package/dist/esm/agentic/improvement/CuriosityEngine.js +27 -23
- package/dist/esm/agentic/improvement/EvolutionRitual.js +4 -4
- package/dist/esm/agentic/improvement/EvolutionaryPilot.js +16 -6
- package/dist/esm/agentic/improvement/GoalArchitect.d.ts +2 -2
- package/dist/esm/agentic/improvement/GoalArchitect.js +20 -18
- package/dist/esm/agentic/improvement/GovernanceManager.js +19 -11
- package/dist/esm/agentic/improvement/HiveLink.js +22 -15
- package/dist/esm/agentic/improvement/KnowledgeDistiller.js +48 -32
- package/dist/esm/agentic/improvement/RecursiveReasoner.js +40 -17
- package/dist/esm/agentic/improvement/ReflectionEngine.js +10 -8
- package/dist/esm/agentic/improvement/RitualOrchestrator.js +28 -22
- package/dist/esm/agentic/improvement/RuleEngine.js +22 -17
- package/dist/esm/agentic/improvement/SelfEvolution.js +24 -18
- package/dist/esm/agentic/improvement/SelfTestRegistry.js +18 -15
- package/dist/esm/agentic/improvement/SkillSynthesizer.js +42 -27
- package/dist/esm/agentic/improvement/SovereignMetrics.js +19 -17
- package/dist/esm/agentic/improvement/StrategicPlanner.js +120 -55
- package/dist/esm/agentic/telemetry/CognitiveSynthesizer.js +26 -12
- package/dist/esm/agentic/telemetry/EventHarvester.js +3 -2
- package/dist/esm/agentic/telemetry/ResearchAlchemist.js +5 -2
- package/dist/esm/cache/cache-manager.js +7 -4
- package/dist/esm/cli/commands/analyze.js +5 -4
- package/dist/esm/cli/commands/generate.js +82 -45
- package/dist/esm/cli/commands/init.js +8 -4
- package/dist/esm/cli/commands/inspect.js +140 -37
- package/dist/esm/cli/commands/migrate.js +5 -4
- package/dist/esm/cli/commands/optimize.js +4 -4
- package/dist/esm/cli/commands/status.js +9 -7
- package/dist/esm/cli/commands/watch.js +7 -6
- package/dist/esm/cli/index.js +2 -2
- package/dist/esm/cli/ui/spinner.d.ts +15 -0
- package/dist/esm/cli/ui/spinner.js +70 -0
- package/dist/esm/dialect/database-introspector.js +3 -1
- package/dist/esm/dialect/postgresql/postgresql-driver.js +3 -1
- package/dist/esm/dialect/postgresql/postgresql-features.js +18 -8
- package/dist/esm/dialect/postgresql/postgresql-introspector.js +2 -2
- package/dist/esm/dialect/sqlite/sqlite-auto-indexer.js +47 -33
- package/dist/esm/dialect/sqlite/sqlite-auto-optimizer.js +8 -7
- package/dist/esm/dialect/sqlite/sqlite-driver.js +2 -2
- package/dist/esm/dialect/sqlite/sqlite-introspector.js +15 -12
- package/dist/esm/dynamic/dynamic.js +1 -1
- package/dist/esm/edge-runtime/edge-config.js +21 -19
- package/dist/esm/errors/NoormError.js +22 -20
- package/dist/esm/helpers/agent-schema.js +2 -0
- package/dist/esm/helpers/postgresql.js +7 -4
- package/dist/esm/helpers/schema-evolution.js +31 -6
- package/dist/esm/index.d.ts +3 -3
- package/dist/esm/index.js +2 -2
- package/dist/esm/logging/logger.js +8 -4
- package/dist/esm/migration/data_migrator.js +12 -11
- package/dist/esm/migration/database_migration_manager.js +18 -14
- package/dist/esm/migration/schema_differ.js +22 -14
- package/dist/esm/migration/schema_introspector.js +8 -8
- package/dist/esm/migration/type_mapper.js +68 -67
- package/dist/esm/noormme.js +52 -37
- package/dist/esm/performance/index.js +5 -5
- package/dist/esm/performance/query-optimizer.js +26 -21
- package/dist/esm/performance/services/cache-service.js +26 -16
- package/dist/esm/performance/services/connection-factory.js +28 -23
- package/dist/esm/performance/services/metrics-collector.js +41 -36
- package/dist/esm/performance/utils/query-parser.js +15 -16
- package/dist/esm/raw-builder/sql.js +1 -1
- package/dist/esm/relationships/relationship-engine.js +10 -8
- package/dist/esm/repository/repository-factory.js +98 -39
- package/dist/esm/schema/builders/alter-table-add-index-builder.js +1 -1
- package/dist/esm/schema/builders/create-index-builder.js +2 -2
- package/dist/esm/schema/core/coordinators/schema-discovery.coordinator.js +1 -3
- package/dist/esm/schema/core/discovery/relationship-discovery.js +16 -16
- package/dist/esm/schema/core/discovery/table-metadata-discovery.js +9 -9
- package/dist/esm/schema/core/discovery/view-discovery.js +5 -4
- package/dist/esm/schema/core/factories/discovery-factory.js +4 -4
- package/dist/esm/schema/core/utils/name-generator.js +14 -5
- package/dist/esm/schema/core/utils/type-mapper.js +24 -24
- package/dist/esm/schema/dialects/postgresql/postgresql-discovery.coordinator.js +8 -7
- package/dist/esm/schema/dialects/sqlite/discovery/sqlite-constraint-discovery.js +17 -15
- package/dist/esm/schema/dialects/sqlite/discovery/sqlite-index-discovery.js +8 -8
- package/dist/esm/schema/dialects/sqlite/introspection/sqlite-schema-introspector.js +6 -11
- package/dist/esm/schema/dialects/sqlite/sqlite-discovery.coordinator.js +14 -13
- package/dist/esm/schema/test/basic-schema-test.js +11 -9
- package/dist/esm/schema/test/dialect-capabilities.test.js +6 -6
- package/dist/esm/schema/test/discovery-factory.test.js +2 -2
- package/dist/esm/schema/test/error-handling.test.js +8 -6
- package/dist/esm/schema/test/integration.test.js +24 -18
- package/dist/esm/schema/test/schema-discovery-coordinator.test.js +9 -9
- package/dist/esm/schema/test/simple-schema-test.js +9 -9
- package/dist/esm/schema/test/sqlite-discovery-coordinator.test.js +64 -48
- package/dist/esm/schema/test/test-runner.js +3 -3
- package/dist/esm/sqlite-migration/index.d.ts +2 -2
- package/dist/esm/sqlite-migration/sqlite-migration-manager.js +21 -17
- package/dist/esm/sqlite-migration/sqlite-migration-provider.js +38 -34
- package/dist/esm/testing/test-utils.js +36 -34
- package/dist/esm/types/index.d.ts +5 -2
- package/dist/esm/types/index.js +6 -3
- package/dist/esm/types/type-generator.js +46 -42
- package/dist/esm/util/safe-sql-helpers.js +1 -1
- package/dist/esm/util/security-validator.js +20 -9
- package/dist/esm/utils/errorHelpers.js +21 -11
- package/dist/esm/watch/schema-watcher.js +22 -23
- package/package.json +40 -44
|
@@ -2,14 +2,17 @@
|
|
|
2
2
|
import { promises as fs } from 'fs';
|
|
3
3
|
import * as path from 'path';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
|
+
import { AgenticSpinner } from '../ui/spinner.js';
|
|
5
6
|
import { NOORMME } from '../../noormme.js';
|
|
6
|
-
import { sanitizeDatabasePath, validateOutputDirectory } from '../../util/security-validator.js';
|
|
7
|
+
import { sanitizeDatabasePath, validateOutputDirectory, } from '../../util/security-validator.js';
|
|
7
8
|
export async function generate(options = {}) {
|
|
8
9
|
console.log(chalk.blue.bold('\n🔧 NOORMME Code Generation - Automating TypeScript & Repositories\n'));
|
|
9
10
|
try {
|
|
10
11
|
// SECURITY: Validate and sanitize database path to prevent path traversal attacks
|
|
11
12
|
const databasePathInput = options.database || process.env.DATABASE_PATH || './database.sqlite';
|
|
12
13
|
const databasePath = sanitizeDatabasePath(databasePathInput);
|
|
14
|
+
const spinner = new AgenticSpinner();
|
|
15
|
+
spinner.start('Awakening connection to the Data Engine...');
|
|
13
16
|
const db = new NOORMME({
|
|
14
17
|
dialect: 'sqlite',
|
|
15
18
|
connection: {
|
|
@@ -17,17 +20,19 @@ export async function generate(options = {}) {
|
|
|
17
20
|
host: 'localhost',
|
|
18
21
|
port: 0,
|
|
19
22
|
username: '',
|
|
20
|
-
password: ''
|
|
21
|
-
}
|
|
23
|
+
password: '',
|
|
24
|
+
},
|
|
22
25
|
});
|
|
23
26
|
await db.initialize();
|
|
27
|
+
spinner.start('Discovering cognitive schemas...');
|
|
24
28
|
const schemaInfo = await db.getSchemaInfo();
|
|
25
29
|
// SECURITY: Validate output directory to prevent path traversal attacks
|
|
26
30
|
const outputDir = options.output || './generated';
|
|
27
31
|
validateOutputDirectory(outputDir);
|
|
28
32
|
const format = options.format || 'dts';
|
|
33
|
+
spinner.stop();
|
|
29
34
|
console.log(chalk.gray(`📁 Output directory: ${outputDir}`));
|
|
30
|
-
console.log(chalk.gray(`📊 Discovered ${schemaInfo.tables.length}
|
|
35
|
+
console.log(chalk.gray(`📊 Discovered ${schemaInfo.tables.length} tabular memories\n`));
|
|
31
36
|
// Ensure output directory exists
|
|
32
37
|
await fs.mkdir(outputDir, { recursive: true });
|
|
33
38
|
let generatedFiles = [];
|
|
@@ -55,11 +60,12 @@ export async function generate(options = {}) {
|
|
|
55
60
|
generatedFiles.push(configPath);
|
|
56
61
|
console.log(chalk.green(`✅ Generated automation config: automation.config.ts`));
|
|
57
62
|
// Generate usage examples
|
|
63
|
+
spinner.start('Pre-warming usage patterns...');
|
|
58
64
|
const examplesContent = generateUsageExamples(schemaInfo.tables);
|
|
59
65
|
const examplesPath = path.join(outputDir, 'usage-examples.ts');
|
|
60
66
|
await fs.writeFile(examplesPath, examplesContent);
|
|
61
67
|
generatedFiles.push(examplesPath);
|
|
62
|
-
|
|
68
|
+
spinner.succeed(`Generated usage examples: usage-examples.ts`);
|
|
63
69
|
console.log(chalk.green.bold(`\n🎉 Generated ${generatedFiles.length} files successfully!`));
|
|
64
70
|
console.log(chalk.blue('\nNext steps:'));
|
|
65
71
|
console.log(chalk.gray('1. Import and use the generated types in your project'));
|
|
@@ -74,9 +80,11 @@ export async function generate(options = {}) {
|
|
|
74
80
|
}
|
|
75
81
|
}
|
|
76
82
|
function generateTypeScriptTypes(tables) {
|
|
77
|
-
const interfaces = tables
|
|
83
|
+
const interfaces = tables
|
|
84
|
+
.map((table) => generateTableInterface(table))
|
|
85
|
+
.join('\n\n');
|
|
78
86
|
const databaseInterface = `export interface Database {
|
|
79
|
-
${tables.map(t => ` ${t.name}: ${pascalCase(t.name)}Table;`).join('\n')}
|
|
87
|
+
${tables.map((t) => ` ${t.name}: ${pascalCase(t.name)}Table;`).join('\n')}
|
|
80
88
|
}`;
|
|
81
89
|
return `// Auto-generated by NOORMME CLI
|
|
82
90
|
// Do not edit manually - regenerate with: npx noormme generate
|
|
@@ -86,14 +94,14 @@ ${interfaces}
|
|
|
86
94
|
${databaseInterface}
|
|
87
95
|
|
|
88
96
|
// Repository types for each table
|
|
89
|
-
${tables.map(table => generateRepositoryType(table)).join('\n\n')}
|
|
97
|
+
${tables.map((table) => generateRepositoryType(table)).join('\n\n')}
|
|
90
98
|
|
|
91
99
|
// Export all table types
|
|
92
100
|
export type {
|
|
93
|
-
${tables.map(t => ` ${pascalCase(t.name)}Table,`).join('\n')}
|
|
94
|
-
${tables.map(t => ` ${pascalCase(t.name)}Insert,`).join('\n')}
|
|
95
|
-
${tables.map(t => ` ${pascalCase(t.name)}Update,`).join('\n')}
|
|
96
|
-
${tables.map(t => ` ${pascalCase(t.name)}Repository,`).join('\n')}
|
|
101
|
+
${tables.map((t) => ` ${pascalCase(t.name)}Table,`).join('\n')}
|
|
102
|
+
${tables.map((t) => ` ${pascalCase(t.name)}Insert,`).join('\n')}
|
|
103
|
+
${tables.map((t) => ` ${pascalCase(t.name)}Update,`).join('\n')}
|
|
104
|
+
${tables.map((t) => ` ${pascalCase(t.name)}Repository,`).join('\n')}
|
|
97
105
|
}
|
|
98
106
|
`;
|
|
99
107
|
}
|
|
@@ -101,23 +109,21 @@ function generateTableInterface(table) {
|
|
|
101
109
|
const tableName = pascalCase(table.name);
|
|
102
110
|
// Base table interface
|
|
103
111
|
const baseInterface = `export interface ${tableName}Table {
|
|
104
|
-
${table.columns.map(col => generateColumnType(col)).join('\n')}
|
|
112
|
+
${table.columns.map((col) => generateColumnType(col)).join('\n')}
|
|
105
113
|
}`;
|
|
106
114
|
// Insert type (optional fields that have defaults or are auto-increment)
|
|
107
|
-
const requiredFields = table.columns.filter(col => !col.nullable &&
|
|
115
|
+
const requiredFields = table.columns.filter((col) => !col.nullable &&
|
|
108
116
|
!col.isAutoIncrement &&
|
|
109
117
|
col.defaultValue === undefined &&
|
|
110
118
|
!col.isPrimaryKey);
|
|
111
|
-
const optionalFields = table.columns.filter(col => col.nullable ||
|
|
112
|
-
col.isAutoIncrement ||
|
|
113
|
-
col.defaultValue !== undefined);
|
|
119
|
+
const optionalFields = table.columns.filter((col) => col.nullable || col.isAutoIncrement || col.defaultValue !== undefined);
|
|
114
120
|
const insertInterface = `export interface ${tableName}Insert {
|
|
115
|
-
${requiredFields.map(col => generateColumnType(col)).join('\n')}
|
|
116
|
-
${optionalFields.map(col => generateColumnType(col, true)).join('\n')}
|
|
121
|
+
${requiredFields.map((col) => generateColumnType(col)).join('\n')}
|
|
122
|
+
${optionalFields.map((col) => generateColumnType(col, true)).join('\n')}
|
|
117
123
|
}`;
|
|
118
124
|
// Update type (all fields optional except primary key)
|
|
119
125
|
const updateInterface = `export interface ${tableName}Update {
|
|
120
|
-
${table.columns.map(col => generateColumnType(col, !col.isPrimaryKey)).join('\n')}
|
|
126
|
+
${table.columns.map((col) => generateColumnType(col, !col.isPrimaryKey)).join('\n')}
|
|
121
127
|
}`;
|
|
122
128
|
return `${baseInterface}
|
|
123
129
|
|
|
@@ -157,8 +163,8 @@ function generateRepositoryType(table) {
|
|
|
157
163
|
}>;
|
|
158
164
|
withCount(id: ${primaryKeyType}, relationships: string[]): Promise<${tableName}Table & Record<string, number>>;
|
|
159
165
|
// Dynamic finders
|
|
160
|
-
${table.columns.map(col => ` findBy${pascalCase(col.name)}(value: ${mapColumnToTsType(col)}): Promise<${tableName}Table | null>;`).join('\n')}
|
|
161
|
-
${table.columns.map(col => ` findManyBy${pascalCase(col.name)}(value: ${mapColumnToTsType(col)}): Promise<${tableName}Table[]>;`).join('\n')}
|
|
166
|
+
${table.columns.map((col) => ` findBy${pascalCase(col.name)}(value: ${mapColumnToTsType(col)}): Promise<${tableName}Table | null>;`).join('\n')}
|
|
167
|
+
${table.columns.map((col) => ` findManyBy${pascalCase(col.name)}(value: ${mapColumnToTsType(col)}): Promise<${tableName}Table[]>;`).join('\n')}
|
|
162
168
|
}`;
|
|
163
169
|
}
|
|
164
170
|
function generateColumnType(column, optional = false) {
|
|
@@ -171,11 +177,16 @@ function generateColumnType(column, optional = false) {
|
|
|
171
177
|
function mapColumnToTsType(column) {
|
|
172
178
|
const type = column.type.toLowerCase();
|
|
173
179
|
// Integer types
|
|
174
|
-
if (type.includes('int') ||
|
|
180
|
+
if (type.includes('int') ||
|
|
181
|
+
type.includes('serial') ||
|
|
182
|
+
type.includes('bigint')) {
|
|
175
183
|
return 'number';
|
|
176
184
|
}
|
|
177
185
|
// Float types
|
|
178
|
-
if (type.includes('float') ||
|
|
186
|
+
if (type.includes('float') ||
|
|
187
|
+
type.includes('double') ||
|
|
188
|
+
type.includes('decimal') ||
|
|
189
|
+
type.includes('numeric')) {
|
|
179
190
|
return 'number';
|
|
180
191
|
}
|
|
181
192
|
// Boolean types
|
|
@@ -183,7 +194,9 @@ function mapColumnToTsType(column) {
|
|
|
183
194
|
return 'boolean';
|
|
184
195
|
}
|
|
185
196
|
// Date/time types
|
|
186
|
-
if (type.includes('date') ||
|
|
197
|
+
if (type.includes('date') ||
|
|
198
|
+
type.includes('time') ||
|
|
199
|
+
type.includes('timestamp')) {
|
|
187
200
|
return 'Date';
|
|
188
201
|
}
|
|
189
202
|
// JSON types
|
|
@@ -206,12 +219,12 @@ function getPrimaryKeyType(table) {
|
|
|
206
219
|
return 'unknown';
|
|
207
220
|
}
|
|
208
221
|
if (table.primaryKey.length === 1) {
|
|
209
|
-
const pkColumn = table.columns.find(col => col.name === table.primaryKey[0]);
|
|
222
|
+
const pkColumn = table.columns.find((col) => col.name === table.primaryKey[0]);
|
|
210
223
|
return pkColumn ? mapColumnToTsType(pkColumn) : 'unknown';
|
|
211
224
|
}
|
|
212
225
|
// Composite primary key
|
|
213
|
-
const types = table.primaryKey.map(pkCol => {
|
|
214
|
-
const column = table.columns.find(col => col.name === pkCol);
|
|
226
|
+
const types = table.primaryKey.map((pkCol) => {
|
|
227
|
+
const column = table.columns.find((col) => col.name === pkCol);
|
|
215
228
|
return column ? mapColumnToTsType(column) : 'any';
|
|
216
229
|
});
|
|
217
230
|
return `[${types.join(', ')}]`;
|
|
@@ -219,11 +232,12 @@ function getPrimaryKeyType(table) {
|
|
|
219
232
|
function generateRepositoryClasses(tables) {
|
|
220
233
|
const imports = `import { NOORMME } from 'noormme'
|
|
221
234
|
import type {
|
|
222
|
-
${tables.map(t => ` ${pascalCase(t.name)}Table,`).join('\n')}
|
|
223
|
-
${tables.map(t => ` ${pascalCase(t.name)}Insert,`).join('\n')}
|
|
224
|
-
${tables.map(t => ` ${pascalCase(t.name)}Update,`).join('\n')}
|
|
235
|
+
${tables.map((t) => ` ${pascalCase(t.name)}Table,`).join('\n')}
|
|
236
|
+
${tables.map((t) => ` ${pascalCase(t.name)}Insert,`).join('\n')}
|
|
237
|
+
${tables.map((t) => ` ${pascalCase(t.name)}Update,`).join('\n')}
|
|
225
238
|
} from './database'`;
|
|
226
|
-
const repositoryClasses = tables
|
|
239
|
+
const repositoryClasses = tables
|
|
240
|
+
.map((table) => {
|
|
227
241
|
const tableName = table.name;
|
|
228
242
|
const className = pascalCase(table.name) + 'Repository';
|
|
229
243
|
const primaryKeyType = getPrimaryKeyType(table);
|
|
@@ -266,23 +280,30 @@ ${tables.map(t => ` ${pascalCase(t.name)}Update,`).join('\n')}
|
|
|
266
280
|
}
|
|
267
281
|
|
|
268
282
|
// Dynamic finders
|
|
269
|
-
${table.columns
|
|
283
|
+
${table.columns
|
|
284
|
+
.map((col) => ` async findBy${pascalCase(col.name)}(value: ${mapColumnToTsType(col)}): Promise<${pascalCase(tableName)}Table | null> {
|
|
270
285
|
const repo = this.db.getRepository('${tableName}')
|
|
271
286
|
return await repo.findBy${pascalCase(col.name)}(value)
|
|
272
|
-
}`)
|
|
287
|
+
}`)
|
|
288
|
+
.join('\n')}
|
|
273
289
|
|
|
274
|
-
${table.columns
|
|
290
|
+
${table.columns
|
|
291
|
+
.map((col) => ` async findManyBy${pascalCase(col.name)}(value: ${mapColumnToTsType(col)}): Promise<${pascalCase(tableName)}Table[]> {
|
|
275
292
|
const repo = this.db.getRepository('${tableName}')
|
|
276
293
|
return await repo.findManyBy${pascalCase(col.name)}(value)
|
|
277
|
-
}`)
|
|
294
|
+
}`)
|
|
295
|
+
.join('\n')}
|
|
278
296
|
}`;
|
|
279
|
-
})
|
|
297
|
+
})
|
|
298
|
+
.join('\n\n');
|
|
280
299
|
const factoryClass = `export class RepositoryFactory {
|
|
281
300
|
constructor(private db: NOORMME) {}
|
|
282
301
|
|
|
283
|
-
${tables
|
|
302
|
+
${tables
|
|
303
|
+
.map((table) => ` get ${table.name}(): ${pascalCase(table.name)}Repository {
|
|
284
304
|
return new ${pascalCase(table.name)}Repository(this.db)
|
|
285
|
-
}`)
|
|
305
|
+
}`)
|
|
306
|
+
.join('\n')}
|
|
286
307
|
}`;
|
|
287
308
|
return `${imports}
|
|
288
309
|
|
|
@@ -351,14 +372,21 @@ export const automationConfig: Partial<NOORMConfig> = {
|
|
|
351
372
|
|
|
352
373
|
// Table-specific automation settings
|
|
353
374
|
export const tableAutomationSettings = {
|
|
354
|
-
${tables
|
|
375
|
+
${tables
|
|
376
|
+
.map((table) => ` ${table.name}: {
|
|
355
377
|
// Auto-generated settings for ${table.name} table
|
|
356
378
|
enableAutoIndexing: true,
|
|
357
379
|
enablePerformanceMonitoring: true,
|
|
358
380
|
recommendedIndexes: [
|
|
359
|
-
${table.columns
|
|
381
|
+
${table.columns
|
|
382
|
+
.filter((col) => col.name.includes('email') ||
|
|
383
|
+
col.name.includes('status') ||
|
|
384
|
+
col.name.includes('created'))
|
|
385
|
+
.map((col) => `'${col.name}'`)
|
|
386
|
+
.join(',\n ') || '// No recommended indexes'}
|
|
360
387
|
]
|
|
361
|
-
},`)
|
|
388
|
+
},`)
|
|
389
|
+
.join('\n')}
|
|
362
390
|
}
|
|
363
391
|
|
|
364
392
|
// Usage example:
|
|
@@ -393,7 +421,11 @@ async function basicCrudExample() {
|
|
|
393
421
|
|
|
394
422
|
// Create a new record
|
|
395
423
|
const new${pascalCase(tableName)} = await ${tableName}Repo.create({
|
|
396
|
-
${firstTable?.columns
|
|
424
|
+
${firstTable?.columns
|
|
425
|
+
.filter((col) => !col.isAutoIncrement && !col.isPrimaryKey)
|
|
426
|
+
.slice(0, 3)
|
|
427
|
+
.map((col) => `${col.name}: 'example_value'`)
|
|
428
|
+
.join(',\n ') || '// Add your data here'}
|
|
397
429
|
})
|
|
398
430
|
|
|
399
431
|
// Find by ID
|
|
@@ -412,12 +444,17 @@ async function basicCrudExample() {
|
|
|
412
444
|
async function dynamicFinderExample() {
|
|
413
445
|
const ${tableName}Repo = repositories.${tableName}
|
|
414
446
|
|
|
415
|
-
${firstTable?.columns
|
|
447
|
+
${firstTable?.columns
|
|
448
|
+
.filter((col) => !col.isPrimaryKey)
|
|
449
|
+
.slice(0, 2)
|
|
450
|
+
.map((col) => `
|
|
416
451
|
// Find by ${col.name}
|
|
417
452
|
const ${tableName}By${pascalCase(col.name)} = await ${tableName}Repo.findBy${pascalCase(col.name)}('value')
|
|
418
453
|
|
|
419
454
|
// Find many by ${col.name}
|
|
420
|
-
const ${tableName}sBy${pascalCase(col.name)} = await ${tableName}Repo.findManyBy${pascalCase(col.name)}('value')`)
|
|
455
|
+
const ${tableName}sBy${pascalCase(col.name)} = await ${tableName}Repo.findManyBy${pascalCase(col.name)}('value')`)
|
|
456
|
+
.join('') ||
|
|
457
|
+
'// Dynamic finders will be available based on your table columns'}
|
|
421
458
|
}
|
|
422
459
|
|
|
423
460
|
// Example 3: Direct repository access
|
|
@@ -3,7 +3,8 @@ import inquirer from 'inquirer';
|
|
|
3
3
|
import { promises as fs } from 'fs';
|
|
4
4
|
import * as path from 'path';
|
|
5
5
|
import chalk from 'chalk';
|
|
6
|
-
import {
|
|
6
|
+
import { AgenticSpinner } from '../ui/spinner.js';
|
|
7
|
+
import { sanitizeDatabasePath, validateOutputDirectory, } from '../../util/security-validator.js';
|
|
7
8
|
export async function init(options) {
|
|
8
9
|
console.log(chalk.blue.bold('\n🎯 NOORMME Zero-Configuration Setup\n'));
|
|
9
10
|
console.log(chalk.gray('Setting up NOORMME with complete SQLite automation...\n'));
|
|
@@ -14,11 +15,12 @@ export async function init(options) {
|
|
|
14
15
|
// SECURITY: Validate output directory to prevent path traversal attacks
|
|
15
16
|
const outputDir = options.output || 'lib';
|
|
16
17
|
validateOutputDirectory(outputDir);
|
|
17
|
-
|
|
18
|
+
const spinner = new AgenticSpinner();
|
|
19
|
+
spinner.start('Detecting existing Data Engine matrix...');
|
|
18
20
|
// Check if database exists
|
|
19
21
|
const dbExists = await checkDatabaseExists(databasePath);
|
|
20
22
|
if (dbExists) {
|
|
21
|
-
|
|
23
|
+
spinner.succeed(`Found existing data layer: ${databasePath}`);
|
|
22
24
|
console.log(chalk.gray('NOORMME will automatically discover your schema and optimize performance\n'));
|
|
23
25
|
}
|
|
24
26
|
else {
|
|
@@ -60,11 +62,13 @@ export async function init(options) {
|
|
|
60
62
|
return;
|
|
61
63
|
}
|
|
62
64
|
// Generate files with automation focus
|
|
65
|
+
spinner.start('Bootstrapping sovereign infrastructure...');
|
|
63
66
|
await generateDbFile(databasePath, outputDir, options.force, autoOptimize, autoIndex);
|
|
64
67
|
await generateEnvExample(databasePath);
|
|
65
68
|
await generateAutomationConfig(databasePath, autoOptimize, autoIndex);
|
|
66
69
|
await generateReadme();
|
|
67
70
|
await generatePackageScripts();
|
|
71
|
+
spinner.succeed('Infrastructure sequence complete');
|
|
68
72
|
console.log(chalk.green.bold('\n✅ NOORMME initialized with complete automation!\n'));
|
|
69
73
|
console.log(chalk.blue('🚀 What NOORMME will do automatically:'));
|
|
70
74
|
console.log(chalk.gray('✅ Discover your existing database schema'));
|
|
@@ -452,7 +456,7 @@ async function generatePackageScripts() {
|
|
|
452
456
|
'db:analyze': 'noormme analyze --report',
|
|
453
457
|
'db:migrate': 'noormme migrate --latest',
|
|
454
458
|
'db:watch': 'noormme watch --auto-optimize',
|
|
455
|
-
'db:status': 'noormme status'
|
|
459
|
+
'db:status': 'noormme status',
|
|
456
460
|
};
|
|
457
461
|
let hasChanges = false;
|
|
458
462
|
for (const [key, value] of Object.entries(noormmeScripts)) {
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
/// <reference types="./inspect.d.ts" />
|
|
2
2
|
import chalk from 'chalk';
|
|
3
|
+
import { AgenticSpinner } from '../ui/spinner.js';
|
|
3
4
|
import { NOORMME } from '../../noormme.js';
|
|
4
|
-
import { sanitizeDatabasePath, validateIdentifier } from '../../util/security-validator.js';
|
|
5
|
+
import { sanitizeDatabasePath, validateIdentifier, } from '../../util/security-validator.js';
|
|
5
6
|
export async function inspect(tableName, options = {}) {
|
|
6
7
|
console.log(chalk.blue.bold('\n🔍 NOORMME Schema Inspection - Intelligent Database Discovery\n'));
|
|
7
8
|
try {
|
|
8
9
|
// SECURITY: Validate and sanitize database path to prevent path traversal attacks
|
|
9
10
|
const databasePathInput = options.database || process.env.DATABASE_PATH || './database.sqlite';
|
|
10
11
|
const databasePath = sanitizeDatabasePath(databasePathInput);
|
|
12
|
+
const spinner = new AgenticSpinner();
|
|
13
|
+
spinner.start('Connecting to Data Engine layer...');
|
|
11
14
|
const db = new NOORMME({
|
|
12
15
|
dialect: 'sqlite',
|
|
13
16
|
connection: {
|
|
@@ -15,21 +18,23 @@ export async function inspect(tableName, options = {}) {
|
|
|
15
18
|
host: 'localhost',
|
|
16
19
|
port: 0,
|
|
17
20
|
username: '',
|
|
18
|
-
password: ''
|
|
19
|
-
}
|
|
21
|
+
password: '',
|
|
22
|
+
},
|
|
20
23
|
});
|
|
21
24
|
await db.initialize();
|
|
22
25
|
console.log(chalk.gray(`📁 Database: ${databasePath}\n`));
|
|
26
|
+
spinner.start('Introspecting cognitive matrix...');
|
|
23
27
|
const schemaInfo = await db.getSchemaInfo();
|
|
28
|
+
spinner.stop();
|
|
24
29
|
if (tableName) {
|
|
25
30
|
// SECURITY: Validate table name to prevent SQL injection
|
|
26
31
|
validateIdentifier(tableName, 'table name');
|
|
27
32
|
// Show specific table with automation insights
|
|
28
|
-
const table = schemaInfo.tables.find(t => t.name === tableName);
|
|
33
|
+
const table = schemaInfo.tables.find((t) => t.name === tableName);
|
|
29
34
|
if (!table) {
|
|
30
35
|
console.error(chalk.red(`❌ Table '${tableName}' not found`));
|
|
31
36
|
console.log(chalk.gray('Available tables:'));
|
|
32
|
-
schemaInfo.tables.forEach(t => console.log(chalk.gray(` - ${t.name}`)));
|
|
37
|
+
schemaInfo.tables.forEach((t) => console.log(chalk.gray(` - ${t.name}`)));
|
|
33
38
|
process.exit(1);
|
|
34
39
|
}
|
|
35
40
|
const rowCount = await getTableRowCount(db, tableName);
|
|
@@ -82,7 +87,9 @@ export async function inspect(tableName, options = {}) {
|
|
|
82
87
|
}
|
|
83
88
|
async function getTableRowCount(db, tableName) {
|
|
84
89
|
try {
|
|
85
|
-
const introspector = db.getKysely()
|
|
90
|
+
const introspector = db.getKysely()
|
|
91
|
+
.getExecutor()
|
|
92
|
+
.adapter.createIntrospector(db.getKysely());
|
|
86
93
|
return await introspector.getRowCount(tableName);
|
|
87
94
|
}
|
|
88
95
|
catch {
|
|
@@ -90,28 +97,82 @@ async function getTableRowCount(db, tableName) {
|
|
|
90
97
|
}
|
|
91
98
|
}
|
|
92
99
|
function showTablesList(tables, rowCounts) {
|
|
93
|
-
const tableData = tables.map(table => ({
|
|
100
|
+
const tableData = tables.map((table) => ({
|
|
94
101
|
name: table.name,
|
|
95
102
|
rows: rowCounts.get(table.name) ?? 0,
|
|
96
103
|
columns: table.columns.length,
|
|
97
104
|
primaryKey: table.primaryKey?.join(', ') || 'None',
|
|
98
105
|
foreignKeys: table.foreignKeys.length,
|
|
99
|
-
indexes: table.indexes.length
|
|
106
|
+
indexes: table.indexes.length,
|
|
100
107
|
}));
|
|
101
108
|
// Simple table formatting
|
|
102
|
-
console.log(chalk.gray('┌─' +
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
109
|
+
console.log(chalk.gray('┌─' +
|
|
110
|
+
'─'.repeat(20) +
|
|
111
|
+
'┬─' +
|
|
112
|
+
'─'.repeat(10) +
|
|
113
|
+
'┬─' +
|
|
114
|
+
'─'.repeat(8) +
|
|
115
|
+
'┬─' +
|
|
116
|
+
'─'.repeat(15) +
|
|
117
|
+
'┬─' +
|
|
118
|
+
'─'.repeat(5) +
|
|
119
|
+
'┬─' +
|
|
120
|
+
'─'.repeat(8) +
|
|
121
|
+
'┐'));
|
|
122
|
+
console.log(chalk.gray('│ ') +
|
|
123
|
+
chalk.bold('Table Name'.padEnd(19)) +
|
|
124
|
+
chalk.gray('│ ') +
|
|
125
|
+
chalk.bold('Rows'.padEnd(9)) +
|
|
126
|
+
chalk.gray('│ ') +
|
|
127
|
+
chalk.bold('Cols'.padEnd(7)) +
|
|
128
|
+
chalk.gray('│ ') +
|
|
129
|
+
chalk.bold('Primary Key'.padEnd(14)) +
|
|
130
|
+
chalk.gray('│ ') +
|
|
131
|
+
chalk.bold('FKs'.padEnd(4)) +
|
|
132
|
+
chalk.gray('│ ') +
|
|
133
|
+
chalk.bold('Indexes'.padEnd(7)) +
|
|
134
|
+
chalk.gray('│'));
|
|
135
|
+
console.log(chalk.gray('├─' +
|
|
136
|
+
'─'.repeat(20) +
|
|
137
|
+
'┼─' +
|
|
138
|
+
'─'.repeat(10) +
|
|
139
|
+
'┼─' +
|
|
140
|
+
'─'.repeat(8) +
|
|
141
|
+
'┼─' +
|
|
142
|
+
'─'.repeat(15) +
|
|
143
|
+
'┼─' +
|
|
144
|
+
'─'.repeat(5) +
|
|
145
|
+
'┼─' +
|
|
146
|
+
'─'.repeat(8) +
|
|
147
|
+
'┤'));
|
|
148
|
+
tableData.forEach((table) => {
|
|
149
|
+
console.log(chalk.gray('│ ') +
|
|
150
|
+
chalk.cyan(table.name.padEnd(19)) +
|
|
151
|
+
chalk.gray('│ ') +
|
|
152
|
+
String(table.rows.toLocaleString()).padEnd(9) +
|
|
153
|
+
chalk.gray('│ ') +
|
|
154
|
+
String(table.columns).padEnd(7) +
|
|
155
|
+
chalk.gray('│ ') +
|
|
156
|
+
table.primaryKey.padEnd(14) +
|
|
157
|
+
chalk.gray('│ ') +
|
|
158
|
+
String(table.foreignKeys).padEnd(4) +
|
|
159
|
+
chalk.gray('│ ') +
|
|
160
|
+
String(table.indexes).padEnd(7) +
|
|
112
161
|
chalk.gray('│'));
|
|
113
162
|
});
|
|
114
|
-
console.log(chalk.gray('└─' +
|
|
163
|
+
console.log(chalk.gray('└─' +
|
|
164
|
+
'─'.repeat(20) +
|
|
165
|
+
'┴─' +
|
|
166
|
+
'─'.repeat(10) +
|
|
167
|
+
'┴─' +
|
|
168
|
+
'─'.repeat(8) +
|
|
169
|
+
'┴─' +
|
|
170
|
+
'─'.repeat(15) +
|
|
171
|
+
'┴─' +
|
|
172
|
+
'─'.repeat(5) +
|
|
173
|
+
'┴─' +
|
|
174
|
+
'─'.repeat(8) +
|
|
175
|
+
'┘'));
|
|
115
176
|
}
|
|
116
177
|
async function showTableOptimizations(table, db) {
|
|
117
178
|
try {
|
|
@@ -129,7 +190,8 @@ async function showTableOptimizations(table, db) {
|
|
|
129
190
|
console.log(chalk.green('✅ No optimization recommendations for this table'));
|
|
130
191
|
}
|
|
131
192
|
// Check for foreign key constraints
|
|
132
|
-
if (table.foreignKeys.length === 0 &&
|
|
193
|
+
if (table.foreignKeys.length === 0 &&
|
|
194
|
+
table.columns.some((col) => col.name.includes('_id'))) {
|
|
133
195
|
console.log(chalk.yellow('💡 Consider adding foreign key constraints for data integrity'));
|
|
134
196
|
}
|
|
135
197
|
}
|
|
@@ -217,7 +279,9 @@ async function showIndexAnalysis(db) {
|
|
|
217
279
|
const indexRecs = await db.getSQLiteIndexRecommendations();
|
|
218
280
|
if (indexRecs.recommendations.length > 0) {
|
|
219
281
|
console.log(chalk.yellow(`💡 ${indexRecs.recommendations.length} index recommendations available:`));
|
|
220
|
-
indexRecs.recommendations
|
|
282
|
+
indexRecs.recommendations
|
|
283
|
+
.slice(0, 10)
|
|
284
|
+
.forEach((rec, index) => {
|
|
221
285
|
console.log(chalk.gray(` ${index + 1}. ${rec.table}.${rec.column} - ${rec.reason}`));
|
|
222
286
|
});
|
|
223
287
|
if (indexRecs.recommendations.length > 10) {
|
|
@@ -255,7 +319,8 @@ async function showAutomationRecommendations(schemaInfo, db) {
|
|
|
255
319
|
recommendations.push(`Consider adding indexes to tables: ${tablesWithoutIndexes.map((t) => t.name).join(', ')}`);
|
|
256
320
|
}
|
|
257
321
|
// Check for missing foreign keys
|
|
258
|
-
const tablesWithIdColumns = schemaInfo.tables.filter((table) => table.columns.some((col) => col.name.includes('_id')) &&
|
|
322
|
+
const tablesWithIdColumns = schemaInfo.tables.filter((table) => table.columns.some((col) => col.name.includes('_id')) &&
|
|
323
|
+
table.foreignKeys.length === 0);
|
|
259
324
|
if (tablesWithIdColumns.length > 0) {
|
|
260
325
|
recommendations.push(`Add foreign key constraints to tables: ${tablesWithIdColumns.map((t) => t.name).join(', ')}`);
|
|
261
326
|
}
|
|
@@ -301,20 +366,56 @@ function showTableDetails(table, relationships, db, rowCount = 0) {
|
|
|
301
366
|
console.log();
|
|
302
367
|
// Columns
|
|
303
368
|
console.log(chalk.blue.bold('Columns:'));
|
|
304
|
-
console.log(chalk.gray('┌─' +
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
369
|
+
console.log(chalk.gray('┌─' +
|
|
370
|
+
'─'.repeat(25) +
|
|
371
|
+
'┬─' +
|
|
372
|
+
'─'.repeat(15) +
|
|
373
|
+
'┬─' +
|
|
374
|
+
'─'.repeat(8) +
|
|
375
|
+
'┬─' +
|
|
376
|
+
'─'.repeat(10) +
|
|
377
|
+
'┐'));
|
|
378
|
+
console.log(chalk.gray('│ ') +
|
|
379
|
+
chalk.bold('Name'.padEnd(24)) +
|
|
380
|
+
chalk.gray('│ ') +
|
|
381
|
+
chalk.bold('Type'.padEnd(14)) +
|
|
382
|
+
chalk.gray('│ ') +
|
|
383
|
+
chalk.bold('Nullable'.padEnd(7)) +
|
|
384
|
+
chalk.gray('│ ') +
|
|
385
|
+
chalk.bold('Default'.padEnd(9)) +
|
|
386
|
+
chalk.gray('│'));
|
|
387
|
+
console.log(chalk.gray('├─' +
|
|
388
|
+
'─'.repeat(25) +
|
|
389
|
+
'┼─' +
|
|
390
|
+
'─'.repeat(15) +
|
|
391
|
+
'┼─' +
|
|
392
|
+
'─'.repeat(8) +
|
|
393
|
+
'┼─' +
|
|
394
|
+
'─'.repeat(10) +
|
|
395
|
+
'┤'));
|
|
396
|
+
table.columns.forEach((col) => {
|
|
308
397
|
const name = col.isPrimaryKey ? chalk.yellow(`${col.name} (PK)`) : col.name;
|
|
309
398
|
const nullable = col.nullable ? chalk.green('YES') : chalk.red('NO');
|
|
310
399
|
const defaultValue = col.defaultValue ? String(col.defaultValue) : '';
|
|
311
|
-
console.log(chalk.gray('│ ') +
|
|
312
|
-
|
|
313
|
-
chalk.gray('│ ') +
|
|
314
|
-
|
|
400
|
+
console.log(chalk.gray('│ ') +
|
|
401
|
+
name.padEnd(24) +
|
|
402
|
+
chalk.gray('│ ') +
|
|
403
|
+
col.type.padEnd(14) +
|
|
404
|
+
chalk.gray('│ ') +
|
|
405
|
+
nullable.padEnd(7) +
|
|
406
|
+
chalk.gray('│ ') +
|
|
407
|
+
defaultValue.padEnd(9) +
|
|
315
408
|
chalk.gray('│'));
|
|
316
409
|
});
|
|
317
|
-
console.log(chalk.gray('└─' +
|
|
410
|
+
console.log(chalk.gray('└─' +
|
|
411
|
+
'─'.repeat(25) +
|
|
412
|
+
'┴─' +
|
|
413
|
+
'─'.repeat(15) +
|
|
414
|
+
'┴─' +
|
|
415
|
+
'─'.repeat(8) +
|
|
416
|
+
'┴─' +
|
|
417
|
+
'─'.repeat(10) +
|
|
418
|
+
'┘'));
|
|
318
419
|
// Primary Key
|
|
319
420
|
if (table.primaryKey && table.primaryKey.length > 0) {
|
|
320
421
|
console.log();
|
|
@@ -325,7 +426,7 @@ function showTableDetails(table, relationships, db, rowCount = 0) {
|
|
|
325
426
|
if (table.foreignKeys.length > 0) {
|
|
326
427
|
console.log();
|
|
327
428
|
console.log(chalk.blue.bold('Foreign Keys:'));
|
|
328
|
-
table.foreignKeys.forEach(fk => {
|
|
429
|
+
table.foreignKeys.forEach((fk) => {
|
|
329
430
|
console.log(chalk.gray(` ${fk.column} → ${fk.referencedTable}.${fk.referencedColumn}`));
|
|
330
431
|
if (fk.onDelete)
|
|
331
432
|
console.log(chalk.gray(` ON DELETE ${fk.onDelete}`));
|
|
@@ -337,17 +438,17 @@ function showTableDetails(table, relationships, db, rowCount = 0) {
|
|
|
337
438
|
if (table.indexes.length > 0) {
|
|
338
439
|
console.log();
|
|
339
440
|
console.log(chalk.blue.bold('Indexes:'));
|
|
340
|
-
table.indexes.forEach(idx => {
|
|
441
|
+
table.indexes.forEach((idx) => {
|
|
341
442
|
const type = idx.unique ? chalk.yellow('UNIQUE') : 'INDEX';
|
|
342
443
|
console.log(chalk.gray(` ${idx.name} (${type}): ${idx.columns.join(', ')}`));
|
|
343
444
|
});
|
|
344
445
|
}
|
|
345
446
|
// Relationships for this table
|
|
346
|
-
const tableRelationships = relationships.filter(r => r.fromTable === table.name || r.toTable === table.name);
|
|
447
|
+
const tableRelationships = relationships.filter((r) => r.fromTable === table.name || r.toTable === table.name);
|
|
347
448
|
if (tableRelationships.length > 0) {
|
|
348
449
|
console.log();
|
|
349
450
|
console.log(chalk.blue.bold('Relationships:'));
|
|
350
|
-
tableRelationships.forEach(rel => {
|
|
451
|
+
tableRelationships.forEach((rel) => {
|
|
351
452
|
const direction = rel.fromTable === table.name ? '→' : '←';
|
|
352
453
|
const otherTable = rel.fromTable === table.name ? rel.toTable : rel.fromTable;
|
|
353
454
|
const type = rel.type.toUpperCase().replace('-', ' ');
|
|
@@ -362,7 +463,9 @@ function showTableDetails(table, relationships, db, rowCount = 0) {
|
|
|
362
463
|
console.log(chalk.gray(`const records = await ${table.name}Repo.findAll()`));
|
|
363
464
|
console.log(chalk.gray(`const record = await ${table.name}Repo.findById(1)`));
|
|
364
465
|
if (tableRelationships.length > 0) {
|
|
365
|
-
const relationshipNames = tableRelationships
|
|
466
|
+
const relationshipNames = tableRelationships
|
|
467
|
+
.map((r) => `'${r.name}'`)
|
|
468
|
+
.join(', ');
|
|
366
469
|
console.log(chalk.gray(`const withRelations = await ${table.name}Repo.findWithRelations(1, [${relationshipNames}])`));
|
|
367
470
|
}
|
|
368
471
|
console.log(chalk.gray('```'));
|
|
@@ -372,7 +475,7 @@ function showRelationships(relationships) {
|
|
|
372
475
|
console.log(chalk.gray('No relationships found.'));
|
|
373
476
|
return;
|
|
374
477
|
}
|
|
375
|
-
relationships.forEach(rel => {
|
|
478
|
+
relationships.forEach((rel) => {
|
|
376
479
|
const type = rel.type.toUpperCase().replace('-', ' ');
|
|
377
480
|
console.log(chalk.cyan(`${rel.name} (${type})`));
|
|
378
481
|
console.log(chalk.gray(` ${rel.fromTable}.${rel.fromColumn} → ${rel.toTable}.${rel.toColumn}`));
|