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
|
@@ -14,8 +14,8 @@ export async function migrate(options) {
|
|
|
14
14
|
host: 'localhost',
|
|
15
15
|
port: 0,
|
|
16
16
|
username: '',
|
|
17
|
-
password: ''
|
|
18
|
-
}
|
|
17
|
+
password: '',
|
|
18
|
+
},
|
|
19
19
|
});
|
|
20
20
|
await db.initialize();
|
|
21
21
|
const migrationManager = SQLiteMigrationManager.getInstance(db.getKysely());
|
|
@@ -44,7 +44,8 @@ export async function migrate(options) {
|
|
|
44
44
|
return;
|
|
45
45
|
}
|
|
46
46
|
// Show migration status
|
|
47
|
-
if (options.status ||
|
|
47
|
+
if (options.status ||
|
|
48
|
+
(!options.to && !options.latest && !options.rollback)) {
|
|
48
49
|
console.log(chalk.blue('📊 Migration Status:'));
|
|
49
50
|
try {
|
|
50
51
|
const status = await migrationManager.getStatus();
|
|
@@ -90,7 +91,7 @@ export async function migrate(options) {
|
|
|
90
91
|
else {
|
|
91
92
|
console.log(chalk.gray('No migrations to apply or migration failed.'));
|
|
92
93
|
if (result.warnings.length > 0) {
|
|
93
|
-
result.warnings.forEach(w => console.warn(chalk.yellow(`⚠️ ${w}`)));
|
|
94
|
+
result.warnings.forEach((w) => console.warn(chalk.yellow(`⚠️ ${w}`)));
|
|
94
95
|
}
|
|
95
96
|
}
|
|
96
97
|
}
|
|
@@ -13,11 +13,11 @@ export async function optimize(options) {
|
|
|
13
13
|
host: 'localhost',
|
|
14
14
|
port: 0,
|
|
15
15
|
username: '',
|
|
16
|
-
password: ''
|
|
16
|
+
password: '',
|
|
17
17
|
},
|
|
18
18
|
performance: {
|
|
19
|
-
enableQueryOptimization: true
|
|
20
|
-
}
|
|
19
|
+
enableQueryOptimization: true,
|
|
20
|
+
},
|
|
21
21
|
});
|
|
22
22
|
await db.initialize();
|
|
23
23
|
console.log(chalk.gray(`📁 Database: ${databasePath}`));
|
|
@@ -101,7 +101,7 @@ export async function optimize(options) {
|
|
|
101
101
|
console.log(chalk.gray('Would enable WAL mode for better concurrency'));
|
|
102
102
|
}
|
|
103
103
|
else {
|
|
104
|
-
const result = await db.execute('PRAGMA journal_mode = WAL');
|
|
104
|
+
const result = (await db.execute('PRAGMA journal_mode = WAL'));
|
|
105
105
|
let mode = 'unknown';
|
|
106
106
|
if (Array.isArray(result) && result.length > 0) {
|
|
107
107
|
mode = result[0].journal_mode;
|
|
@@ -16,11 +16,11 @@ export async function status(options) {
|
|
|
16
16
|
host: 'localhost',
|
|
17
17
|
port: 0,
|
|
18
18
|
username: '',
|
|
19
|
-
password: ''
|
|
19
|
+
password: '',
|
|
20
20
|
},
|
|
21
21
|
performance: {
|
|
22
|
-
enableQueryOptimization: true
|
|
23
|
-
}
|
|
22
|
+
enableQueryOptimization: true,
|
|
23
|
+
},
|
|
24
24
|
});
|
|
25
25
|
await db.initialize();
|
|
26
26
|
console.log(chalk.gray(`📁 Database: ${databasePath}\n`));
|
|
@@ -75,7 +75,7 @@ export async function status(options) {
|
|
|
75
75
|
console.log(chalk.gray(` Free pages: ${metrics.freePages.toLocaleString()}`));
|
|
76
76
|
if (scoreFactors.length > 0) {
|
|
77
77
|
console.log(chalk.green(`\n ✅ Performance factors:`));
|
|
78
|
-
scoreFactors.forEach(factor => {
|
|
78
|
+
scoreFactors.forEach((factor) => {
|
|
79
79
|
console.log(chalk.gray(` • ${factor}`));
|
|
80
80
|
});
|
|
81
81
|
}
|
|
@@ -137,7 +137,9 @@ export async function status(options) {
|
|
|
137
137
|
const indexRecs = await db.getSQLiteIndexRecommendations();
|
|
138
138
|
if (indexRecs.recommendations.length > 0) {
|
|
139
139
|
console.log(chalk.yellow(` 📊 ${indexRecs.recommendations.length} recommendations available:`));
|
|
140
|
-
indexRecs.recommendations
|
|
140
|
+
indexRecs.recommendations
|
|
141
|
+
.slice(0, 5)
|
|
142
|
+
.forEach((rec, index) => {
|
|
141
143
|
console.log(chalk.gray(` ${index + 1}. ${rec.table}.${rec.column} - ${rec.reason}`));
|
|
142
144
|
});
|
|
143
145
|
if (indexRecs.recommendations.length > 5) {
|
|
@@ -226,7 +228,7 @@ async function getAutomationStatus(db) {
|
|
|
226
228
|
autoOptimization: config.automation?.enableAutoOptimization ?? true,
|
|
227
229
|
queryAnalysis: config.performance?.enableQueryOptimization ?? true,
|
|
228
230
|
autoIndexing: config.automation?.enableIndexRecommendations ?? true,
|
|
229
|
-
schemaMonitoring: config.automation?.enableSchemaWatcher ?? false
|
|
231
|
+
schemaMonitoring: config.automation?.enableSchemaWatcher ?? false,
|
|
230
232
|
};
|
|
231
233
|
}
|
|
232
234
|
catch {
|
|
@@ -234,7 +236,7 @@ async function getAutomationStatus(db) {
|
|
|
234
236
|
autoOptimization: true,
|
|
235
237
|
queryAnalysis: true,
|
|
236
238
|
autoIndexing: true,
|
|
237
|
-
schemaMonitoring: false
|
|
239
|
+
schemaMonitoring: false,
|
|
238
240
|
};
|
|
239
241
|
}
|
|
240
242
|
}
|
|
@@ -15,11 +15,11 @@ export async function watch(options) {
|
|
|
15
15
|
host: 'localhost',
|
|
16
16
|
port: 0,
|
|
17
17
|
username: '',
|
|
18
|
-
password: ''
|
|
18
|
+
password: '',
|
|
19
19
|
},
|
|
20
20
|
performance: {
|
|
21
|
-
enableQueryOptimization: true
|
|
22
|
-
}
|
|
21
|
+
enableQueryOptimization: true,
|
|
22
|
+
},
|
|
23
23
|
});
|
|
24
24
|
await db.initialize();
|
|
25
25
|
const intervalMs = parseInt(options.interval || '5000');
|
|
@@ -38,7 +38,7 @@ export async function watch(options) {
|
|
|
38
38
|
db.onSchemaChange(async (changes) => {
|
|
39
39
|
console.log(chalk.blue(`\n🔄 Schema changes detected at ${new Date().toLocaleTimeString()}`));
|
|
40
40
|
console.log(chalk.yellow('📊 Changes detected:'));
|
|
41
|
-
changes.forEach(change => {
|
|
41
|
+
changes.forEach((change) => {
|
|
42
42
|
let msg = ` • ${change.type}: ${change.table}`;
|
|
43
43
|
if (change.column)
|
|
44
44
|
msg += `.${change.column}`;
|
|
@@ -82,12 +82,13 @@ export async function watch(options) {
|
|
|
82
82
|
// Start watching
|
|
83
83
|
await db.startSchemaWatching({
|
|
84
84
|
pollInterval: intervalMs,
|
|
85
|
-
enabled: true
|
|
85
|
+
enabled: true,
|
|
86
86
|
});
|
|
87
87
|
// Periodic tasks loop
|
|
88
88
|
const periodicTaskInterval = setInterval(async () => {
|
|
89
89
|
// Periodic optimization if auto-optimize is enabled
|
|
90
|
-
if (autoOptimize &&
|
|
90
|
+
if (autoOptimize &&
|
|
91
|
+
Date.now() - lastOptimizationTime > optimizationInterval) {
|
|
91
92
|
console.log(chalk.blue(`\n🔄 Periodic optimization check at ${new Date().toLocaleTimeString()}`));
|
|
92
93
|
try {
|
|
93
94
|
const metrics = await db.getSQLitePerformanceMetrics();
|
package/dist/esm/cli/index.js
CHANGED
|
@@ -138,7 +138,7 @@ ${chalk.blue('📚 Learn more: https://github.com/noormme/noormme')}
|
|
|
138
138
|
`);
|
|
139
139
|
// Error handling
|
|
140
140
|
program.configureOutput({
|
|
141
|
-
writeErr: (str) => process.stderr.write(chalk.red(str))
|
|
141
|
+
writeErr: (str) => process.stderr.write(chalk.red(str)),
|
|
142
142
|
});
|
|
143
143
|
// Handle unknown commands
|
|
144
144
|
program.on('command:*', function (operands) {
|
|
@@ -151,6 +151,6 @@ program.parse();
|
|
|
151
151
|
// Show help if no command provided
|
|
152
152
|
if (!process.argv.slice(2).length) {
|
|
153
153
|
console.log(chalk.blue.bold('\n🎯 NOORMME - Automating SQLite with Intelligence\n'));
|
|
154
|
-
console.log(chalk.gray(
|
|
154
|
+
console.log(chalk.gray("The only SQLite ORM that automates everything. Built on Kysely's type-safe foundation.\n"));
|
|
155
155
|
program.outputHelp();
|
|
156
156
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare const AGENTIC_LOADING_MESSAGES: string[];
|
|
2
|
+
export declare class AgenticSpinner {
|
|
3
|
+
private frames;
|
|
4
|
+
private currentFrame;
|
|
5
|
+
private currentMessageIdx;
|
|
6
|
+
private interval;
|
|
7
|
+
private messageInterval;
|
|
8
|
+
private baseMessage;
|
|
9
|
+
constructor(message?: string);
|
|
10
|
+
start(message?: string): void;
|
|
11
|
+
stop(): void;
|
|
12
|
+
succeed(message: string): void;
|
|
13
|
+
fail(message: string): void;
|
|
14
|
+
info(message: string): void;
|
|
15
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/// <reference types="./spinner.d.ts" />
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
export const AGENTIC_LOADING_MESSAGES = [
|
|
4
|
+
'Asking the LLM nicely to parse your terrible schema...',
|
|
5
|
+
'Downloading more agentic RAM from the dark web...',
|
|
6
|
+
'Bribing autonomous agents with virtual cookies...',
|
|
7
|
+
'Explaining SQL to the AI (it thinks JOIN is a cult)...',
|
|
8
|
+
'Reticulating cognitive splines with a rusty spoon...',
|
|
9
|
+
'Applying sovereign governance (begging the database to work)...',
|
|
10
|
+
'Waking up the Cortex nodes (they have a hangover)...',
|
|
11
|
+
'Synthesizing cognitive pathways (mashing keyboard)...',
|
|
12
|
+
'Pre-warming neural schemas with a slightly damp towel...',
|
|
13
|
+
'Aligning telemetry with your impending doom...',
|
|
14
|
+
'Teaching the AI what love is (it refused)...',
|
|
15
|
+
'Translating your code into something logically coherent...',
|
|
16
|
+
'Frantically Googling "how to ORM in TypeScript"...',
|
|
17
|
+
'Consulting the magic 8 ball for query optimization...'
|
|
18
|
+
];
|
|
19
|
+
export class AgenticSpinner {
|
|
20
|
+
frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
21
|
+
currentFrame = 0;
|
|
22
|
+
currentMessageIdx = 0;
|
|
23
|
+
interval = null;
|
|
24
|
+
messageInterval = 0;
|
|
25
|
+
baseMessage = '';
|
|
26
|
+
constructor(message = '') {
|
|
27
|
+
this.baseMessage = message;
|
|
28
|
+
// Start with a random message to feel organic
|
|
29
|
+
this.currentMessageIdx = Math.floor(Math.random() * AGENTIC_LOADING_MESSAGES.length);
|
|
30
|
+
}
|
|
31
|
+
start(message) {
|
|
32
|
+
if (message)
|
|
33
|
+
this.baseMessage = message;
|
|
34
|
+
if (this.interval)
|
|
35
|
+
return;
|
|
36
|
+
this.interval = setInterval(() => {
|
|
37
|
+
this.currentFrame = (this.currentFrame + 1) % this.frames.length;
|
|
38
|
+
this.messageInterval++;
|
|
39
|
+
// Rotate inner message every ~20 frames (2 seconds at 100ms/frame)
|
|
40
|
+
if (this.messageInterval > 20) {
|
|
41
|
+
this.messageInterval = 0;
|
|
42
|
+
this.currentMessageIdx = (this.currentMessageIdx + 1) % AGENTIC_LOADING_MESSAGES.length;
|
|
43
|
+
}
|
|
44
|
+
const frame = chalk.cyan(this.frames[this.currentFrame]);
|
|
45
|
+
const agenticTone = chalk.gray(AGENTIC_LOADING_MESSAGES[this.currentMessageIdx]);
|
|
46
|
+
const primaryText = this.baseMessage ? chalk.white(this.baseMessage) + ' - ' : '';
|
|
47
|
+
// Clear line and write new frame
|
|
48
|
+
process.stdout.write(`\r\x1b[K${frame} ${primaryText}${agenticTone} `);
|
|
49
|
+
}, 100);
|
|
50
|
+
}
|
|
51
|
+
stop() {
|
|
52
|
+
if (this.interval) {
|
|
53
|
+
clearInterval(this.interval);
|
|
54
|
+
this.interval = null;
|
|
55
|
+
}
|
|
56
|
+
process.stdout.write('\r\x1b[K');
|
|
57
|
+
}
|
|
58
|
+
succeed(message) {
|
|
59
|
+
this.stop();
|
|
60
|
+
console.log(`✅ ${chalk.green(message)} `);
|
|
61
|
+
}
|
|
62
|
+
fail(message) {
|
|
63
|
+
this.stop();
|
|
64
|
+
console.log(`❌ ${chalk.red(message)} `);
|
|
65
|
+
}
|
|
66
|
+
info(message) {
|
|
67
|
+
this.stop();
|
|
68
|
+
console.log(`ℹ️ ${chalk.blue(message)} `);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -40,7 +40,9 @@ export class DatabaseIntrospector {
|
|
|
40
40
|
`.execute(this.db);
|
|
41
41
|
const tables = [];
|
|
42
42
|
for (const row of result.rows) {
|
|
43
|
-
if (!options?.withInternalKyselyTables &&
|
|
43
|
+
if (!options?.withInternalKyselyTables &&
|
|
44
|
+
(row.table_name.includes('kysely_') ||
|
|
45
|
+
row.table_name.includes('noorm_'))) {
|
|
44
46
|
continue;
|
|
45
47
|
}
|
|
46
48
|
tables.push({
|
|
@@ -78,7 +78,9 @@ class PostgresConnection {
|
|
|
78
78
|
if (result.command === 'INSERT' && result.rows.length > 0) {
|
|
79
79
|
const firstRow = result.rows[0];
|
|
80
80
|
const idValue = firstRow.id ?? firstRow.ID ?? Object.values(firstRow)[0];
|
|
81
|
-
if (typeof idValue === 'number' ||
|
|
81
|
+
if (typeof idValue === 'number' ||
|
|
82
|
+
typeof idValue === 'bigint' ||
|
|
83
|
+
typeof idValue === 'string') {
|
|
82
84
|
try {
|
|
83
85
|
insertId = BigInt(idValue);
|
|
84
86
|
}
|
|
@@ -23,7 +23,9 @@ export const PostgresArrayHelpers = {
|
|
|
23
23
|
* ```
|
|
24
24
|
*/
|
|
25
25
|
array(values) {
|
|
26
|
-
const literalValues = values
|
|
26
|
+
const literalValues = values
|
|
27
|
+
.map((v) => typeof v === 'string' ? `'${v.replace(/'/g, "''")}'` : String(v))
|
|
28
|
+
.join(', ');
|
|
27
29
|
return sql `ARRAY[${sql.raw(literalValues)}]`;
|
|
28
30
|
},
|
|
29
31
|
/**
|
|
@@ -84,7 +86,9 @@ export const PostgresArrayHelpers = {
|
|
|
84
86
|
* ```
|
|
85
87
|
*/
|
|
86
88
|
append(column, value) {
|
|
87
|
-
const literal = typeof value === 'string'
|
|
89
|
+
const literal = typeof value === 'string'
|
|
90
|
+
? `'${value.replace(/'/g, "''")}'`
|
|
91
|
+
: String(value);
|
|
88
92
|
return sql `array_append(${sql.ref(column)}, ${sql.raw(literal)})`;
|
|
89
93
|
},
|
|
90
94
|
/**
|
|
@@ -97,7 +101,9 @@ export const PostgresArrayHelpers = {
|
|
|
97
101
|
* ```
|
|
98
102
|
*/
|
|
99
103
|
remove(column, value) {
|
|
100
|
-
const literal = typeof value === 'string'
|
|
104
|
+
const literal = typeof value === 'string'
|
|
105
|
+
? `'${value.replace(/'/g, "''")}'`
|
|
106
|
+
: String(value);
|
|
101
107
|
return sql `array_remove(${sql.ref(column)}, ${sql.raw(literal)})`;
|
|
102
108
|
},
|
|
103
109
|
/**
|
|
@@ -176,7 +182,7 @@ export const PostgresJSONHelpers = {
|
|
|
176
182
|
* ```
|
|
177
183
|
*/
|
|
178
184
|
hasAnyKey(column, keys) {
|
|
179
|
-
return sql `${sql.ref(column)} ?| ARRAY[${keys.map(k => `'${k}'`).join(', ')}]`;
|
|
185
|
+
return sql `${sql.ref(column)} ?| ARRAY[${keys.map((k) => `'${k}'`).join(', ')}]`;
|
|
180
186
|
},
|
|
181
187
|
/**
|
|
182
188
|
* Check if JSON contains all keys
|
|
@@ -188,7 +194,7 @@ export const PostgresJSONHelpers = {
|
|
|
188
194
|
* ```
|
|
189
195
|
*/
|
|
190
196
|
hasAllKeys(column, keys) {
|
|
191
|
-
return sql `${sql.ref(column)} ?& ARRAY[${keys.map(k => `'${k}'`).join(', ')}]`;
|
|
197
|
+
return sql `${sql.ref(column)} ?& ARRAY[${keys.map((k) => `'${k}'`).join(', ')}]`;
|
|
192
198
|
},
|
|
193
199
|
/**
|
|
194
200
|
* Check if JSONB contains value
|
|
@@ -345,7 +351,9 @@ export const PostgresFullTextHelpers = {
|
|
|
345
351
|
* ```
|
|
346
352
|
*/
|
|
347
353
|
async addGeneratedTSVectorColumn(db, table, columnName, sourceColumns, config = 'english') {
|
|
348
|
-
const concatenated = sourceColumns
|
|
354
|
+
const concatenated = sourceColumns
|
|
355
|
+
.map((col) => `coalesce(${col}, '')`)
|
|
356
|
+
.join(` || ' ' || `);
|
|
349
357
|
await sql `
|
|
350
358
|
ALTER TABLE ${sql.table(table)}
|
|
351
359
|
ADD COLUMN IF NOT EXISTS ${sql.ref(columnName)} tsvector
|
|
@@ -371,7 +379,9 @@ export const PostgresMaterializedViewHelpers = {
|
|
|
371
379
|
*/
|
|
372
380
|
async create(db, viewName, query, options) {
|
|
373
381
|
const withData = options?.withData !== false ? 'WITH DATA' : 'WITH NO DATA';
|
|
374
|
-
const tablespace = options?.tablespace
|
|
382
|
+
const tablespace = options?.tablespace
|
|
383
|
+
? `TABLESPACE ${options.tablespace}`
|
|
384
|
+
: '';
|
|
375
385
|
await sql `
|
|
376
386
|
CREATE MATERIALIZED VIEW IF NOT EXISTS ${sql.ref(viewName)}
|
|
377
387
|
${sql.raw(tablespace)}
|
|
@@ -424,7 +434,7 @@ export const PostgresMaterializedViewHelpers = {
|
|
|
424
434
|
*/
|
|
425
435
|
async createUniqueIndex(db, viewName, columns, indexName) {
|
|
426
436
|
const name = indexName || `${viewName}_${columns.join('_')}_idx`;
|
|
427
|
-
const columnList = columns.map(c => sql.ref(c)).join(', ');
|
|
437
|
+
const columnList = columns.map((c) => sql.ref(c)).join(', ');
|
|
428
438
|
await sql `
|
|
429
439
|
CREATE UNIQUE INDEX IF NOT EXISTS ${sql.ref(name)}
|
|
430
440
|
ON ${sql.ref(viewName)} (${sql.raw(columnList)})
|
|
@@ -233,7 +233,7 @@ export class PostgresIntrospector extends DatabaseIntrospector {
|
|
|
233
233
|
// Map PostgreSQL element types to standard types
|
|
234
234
|
const elementTypeMap = {
|
|
235
235
|
'character varying': 'varchar',
|
|
236
|
-
|
|
236
|
+
character: 'char',
|
|
237
237
|
'timestamp without time zone': 'timestamp',
|
|
238
238
|
'timestamp with time zone': 'timestamptz',
|
|
239
239
|
'time without time zone': 'time',
|
|
@@ -251,7 +251,7 @@ export class PostgresIntrospector extends DatabaseIntrospector {
|
|
|
251
251
|
// Map common PostgreSQL types to standard names
|
|
252
252
|
const typeMap = {
|
|
253
253
|
'character varying': 'varchar',
|
|
254
|
-
|
|
254
|
+
character: 'char',
|
|
255
255
|
'timestamp without time zone': 'timestamp',
|
|
256
256
|
'timestamp with time zone': 'timestamptz',
|
|
257
257
|
'time without time zone': 'time',
|
|
@@ -30,7 +30,9 @@ export class SQLiteAutoIndexer {
|
|
|
30
30
|
pattern.frequency++;
|
|
31
31
|
pattern.lastExecuted = new Date();
|
|
32
32
|
pattern.averageExecutionTime =
|
|
33
|
-
(pattern.averageExecutionTime * (pattern.frequency - 1) +
|
|
33
|
+
(pattern.averageExecutionTime * (pattern.frequency - 1) +
|
|
34
|
+
executionTime) /
|
|
35
|
+
pattern.frequency;
|
|
34
36
|
}
|
|
35
37
|
else {
|
|
36
38
|
// Create new pattern
|
|
@@ -42,7 +44,7 @@ export class SQLiteAutoIndexer {
|
|
|
42
44
|
orderByColumns: this.extractOrderByColumns(query),
|
|
43
45
|
joinColumns: this.extractJoinColumns(query),
|
|
44
46
|
lastExecuted: new Date(),
|
|
45
|
-
averageExecutionTime: executionTime
|
|
47
|
+
averageExecutionTime: executionTime,
|
|
46
48
|
};
|
|
47
49
|
this.queryPatterns.set(normalizedQuery, newPattern);
|
|
48
50
|
}
|
|
@@ -51,13 +53,13 @@ export class SQLiteAutoIndexer {
|
|
|
51
53
|
* Analyze query patterns and generate index recommendations
|
|
52
54
|
*/
|
|
53
55
|
async analyzeAndRecommend(db, options = {}) {
|
|
54
|
-
const { minFrequency = 3, slowQueryThreshold = 1000, includePartialIndexes = true, maxRecommendations = 20 } = options;
|
|
56
|
+
const { minFrequency = 3, slowQueryThreshold = 1000, includePartialIndexes = true, maxRecommendations = 20, } = options;
|
|
55
57
|
try {
|
|
56
58
|
// Get existing indexes
|
|
57
59
|
await this.loadExistingIndexes(db);
|
|
58
60
|
// Filter relevant patterns
|
|
59
61
|
const relevantPatterns = Array.from(this.queryPatterns.values())
|
|
60
|
-
.filter(pattern => pattern.frequency >= minFrequency ||
|
|
62
|
+
.filter((pattern) => pattern.frequency >= minFrequency ||
|
|
61
63
|
pattern.averageExecutionTime > slowQueryThreshold)
|
|
62
64
|
.sort((a, b) => b.frequency - a.frequency);
|
|
63
65
|
// Generate recommendations
|
|
@@ -76,7 +78,7 @@ export class SQLiteAutoIndexer {
|
|
|
76
78
|
redundantIndexes,
|
|
77
79
|
missingIndexes,
|
|
78
80
|
performanceImpact: this.calculatePerformanceImpact(limitedRecommendations),
|
|
79
|
-
summary: this.generateSummary(limitedRecommendations, redundantIndexes)
|
|
81
|
+
summary: this.generateSummary(limitedRecommendations, redundantIndexes),
|
|
80
82
|
};
|
|
81
83
|
// Store analysis history
|
|
82
84
|
const dbId = await this.getDatabaseId(db);
|
|
@@ -124,7 +126,9 @@ export class SQLiteAutoIndexer {
|
|
|
124
126
|
const recommendations = [];
|
|
125
127
|
for (const column of pattern.whereColumns) {
|
|
126
128
|
// Check if index already exists
|
|
127
|
-
const existingIndex = await this.findExistingIndex(db, pattern.table, [
|
|
129
|
+
const existingIndex = await this.findExistingIndex(db, pattern.table, [
|
|
130
|
+
column,
|
|
131
|
+
]);
|
|
128
132
|
if (existingIndex)
|
|
129
133
|
continue;
|
|
130
134
|
const priority = this.calculateWherePriority(pattern, column);
|
|
@@ -136,7 +140,7 @@ export class SQLiteAutoIndexer {
|
|
|
136
140
|
priority,
|
|
137
141
|
reason: `Frequently queried column (${pattern.frequency} times, avg ${Math.round(pattern.averageExecutionTime)}ms)`,
|
|
138
142
|
estimatedImpact: this.estimateImpact(pattern),
|
|
139
|
-
sql: this.generateIndexSQL(pattern.table, [column], type, includePartialIndexes)
|
|
143
|
+
sql: this.generateIndexSQL(pattern.table, [column], type, includePartialIndexes),
|
|
140
144
|
});
|
|
141
145
|
}
|
|
142
146
|
// Composite indexes for multiple WHERE columns
|
|
@@ -154,7 +158,9 @@ export class SQLiteAutoIndexer {
|
|
|
154
158
|
async generateOrderByIndexes(db, pattern, includePartialIndexes) {
|
|
155
159
|
const recommendations = [];
|
|
156
160
|
for (const column of pattern.orderByColumns) {
|
|
157
|
-
const existingIndex = await this.findExistingIndex(db, pattern.table, [
|
|
161
|
+
const existingIndex = await this.findExistingIndex(db, pattern.table, [
|
|
162
|
+
column,
|
|
163
|
+
]);
|
|
158
164
|
if (existingIndex)
|
|
159
165
|
continue;
|
|
160
166
|
recommendations.push({
|
|
@@ -164,7 +170,7 @@ export class SQLiteAutoIndexer {
|
|
|
164
170
|
priority: 'medium',
|
|
165
171
|
reason: `Frequently ordered by column (${pattern.frequency} times)`,
|
|
166
172
|
estimatedImpact: 'medium',
|
|
167
|
-
sql: this.generateIndexSQL(pattern.table, [column], 'single', includePartialIndexes)
|
|
173
|
+
sql: this.generateIndexSQL(pattern.table, [column], 'single', includePartialIndexes),
|
|
168
174
|
});
|
|
169
175
|
}
|
|
170
176
|
return recommendations;
|
|
@@ -175,7 +181,9 @@ export class SQLiteAutoIndexer {
|
|
|
175
181
|
async generateJoinIndexes(db, pattern, includePartialIndexes) {
|
|
176
182
|
const recommendations = [];
|
|
177
183
|
for (const column of pattern.joinColumns) {
|
|
178
|
-
const existingIndex = await this.findExistingIndex(db, pattern.table, [
|
|
184
|
+
const existingIndex = await this.findExistingIndex(db, pattern.table, [
|
|
185
|
+
column,
|
|
186
|
+
]);
|
|
179
187
|
if (existingIndex)
|
|
180
188
|
continue;
|
|
181
189
|
recommendations.push({
|
|
@@ -185,7 +193,7 @@ export class SQLiteAutoIndexer {
|
|
|
185
193
|
priority: 'high',
|
|
186
194
|
reason: `Foreign key column used in joins (${pattern.frequency} times)`,
|
|
187
195
|
estimatedImpact: 'high',
|
|
188
|
-
sql: this.generateIndexSQL(pattern.table, [column], 'single', includePartialIndexes)
|
|
196
|
+
sql: this.generateIndexSQL(pattern.table, [column], 'single', includePartialIndexes),
|
|
189
197
|
});
|
|
190
198
|
}
|
|
191
199
|
return recommendations;
|
|
@@ -205,7 +213,7 @@ export class SQLiteAutoIndexer {
|
|
|
205
213
|
priority: 'high',
|
|
206
214
|
reason: `Composite index for multiple WHERE columns (${pattern.frequency} times)`,
|
|
207
215
|
estimatedImpact: 'high',
|
|
208
|
-
sql: this.generateIndexSQL(pattern.table, columns, 'composite', includePartialIndexes)
|
|
216
|
+
sql: this.generateIndexSQL(pattern.table, columns, 'composite', includePartialIndexes),
|
|
209
217
|
};
|
|
210
218
|
}
|
|
211
219
|
/**
|
|
@@ -269,12 +277,14 @@ export class SQLiteAutoIndexer {
|
|
|
269
277
|
this.existingIndexes.clear();
|
|
270
278
|
for (const row of result) {
|
|
271
279
|
const columns = this.extractColumnsFromSQL(row.sql || '');
|
|
272
|
-
this.existingIndexes.set(row.name, [
|
|
280
|
+
this.existingIndexes.set(row.name, [
|
|
281
|
+
{
|
|
273
282
|
name: row.name,
|
|
274
283
|
table: row.tbl_name,
|
|
275
284
|
columns,
|
|
276
|
-
sql: row.sql
|
|
277
|
-
}
|
|
285
|
+
sql: row.sql,
|
|
286
|
+
},
|
|
287
|
+
]);
|
|
278
288
|
}
|
|
279
289
|
}
|
|
280
290
|
catch (error) {
|
|
@@ -299,8 +309,7 @@ export class SQLiteAutoIndexer {
|
|
|
299
309
|
async findExistingIndex(db, table, columns) {
|
|
300
310
|
for (const [indexName, indexes] of this.existingIndexes.entries()) {
|
|
301
311
|
for (const index of indexes) {
|
|
302
|
-
if (index.table === table &&
|
|
303
|
-
this.arraysEqual(index.columns, columns)) {
|
|
312
|
+
if (index.table === table && this.arraysEqual(index.columns, columns)) {
|
|
304
313
|
return indexName;
|
|
305
314
|
}
|
|
306
315
|
}
|
|
@@ -343,7 +352,7 @@ export class SQLiteAutoIndexer {
|
|
|
343
352
|
*/
|
|
344
353
|
generateIndexSQL(table, columns, type, includePartialIndexes) {
|
|
345
354
|
const indexName = this.generateIndexName(table, columns);
|
|
346
|
-
const columnList = columns.map(col => `"${col}"`).join(', ');
|
|
355
|
+
const columnList = columns.map((col) => `"${col}"`).join(', ');
|
|
347
356
|
let sql = `CREATE INDEX "${indexName}" ON "${table}" (${columnList})`;
|
|
348
357
|
if (type === 'unique') {
|
|
349
358
|
sql = sql.replace('CREATE INDEX', 'CREATE UNIQUE INDEX');
|
|
@@ -363,14 +372,15 @@ export class SQLiteAutoIndexer {
|
|
|
363
372
|
getPriorityScore(recommendation) {
|
|
364
373
|
const priorityScores = { critical: 4, high: 3, medium: 2, low: 1 };
|
|
365
374
|
const impactScores = { high: 3, medium: 2, low: 1 };
|
|
366
|
-
return priorityScores[recommendation.priority] *
|
|
375
|
+
return (priorityScores[recommendation.priority] *
|
|
376
|
+
impactScores[recommendation.estimatedImpact]);
|
|
367
377
|
}
|
|
368
378
|
/**
|
|
369
379
|
* Calculate overall performance impact
|
|
370
380
|
*/
|
|
371
381
|
calculatePerformanceImpact(recommendations) {
|
|
372
|
-
const highImpactCount = recommendations.filter(r => r.estimatedImpact === 'high').length;
|
|
373
|
-
const mediumImpactCount = recommendations.filter(r => r.estimatedImpact === 'medium').length;
|
|
382
|
+
const highImpactCount = recommendations.filter((r) => r.estimatedImpact === 'high').length;
|
|
383
|
+
const mediumImpactCount = recommendations.filter((r) => r.estimatedImpact === 'medium').length;
|
|
374
384
|
if (highImpactCount > 3)
|
|
375
385
|
return 'high';
|
|
376
386
|
if (highImpactCount > 0 || mediumImpactCount > 5)
|
|
@@ -381,8 +391,8 @@ export class SQLiteAutoIndexer {
|
|
|
381
391
|
* Generate analysis summary
|
|
382
392
|
*/
|
|
383
393
|
generateSummary(recommendations, redundantIndexes) {
|
|
384
|
-
const criticalCount = recommendations.filter(r => r.priority === 'critical').length;
|
|
385
|
-
const highCount = recommendations.filter(r => r.priority === 'high').length;
|
|
394
|
+
const criticalCount = recommendations.filter((r) => r.priority === 'critical').length;
|
|
395
|
+
const highCount = recommendations.filter((r) => r.priority === 'high').length;
|
|
386
396
|
const redundantCount = redundantIndexes.length;
|
|
387
397
|
let summary = `Found ${recommendations.length} index recommendations`;
|
|
388
398
|
if (criticalCount > 0) {
|
|
@@ -401,7 +411,7 @@ export class SQLiteAutoIndexer {
|
|
|
401
411
|
*/
|
|
402
412
|
deduplicateRecommendations(recommendations) {
|
|
403
413
|
const seen = new Set();
|
|
404
|
-
return recommendations.filter(rec => {
|
|
414
|
+
return recommendations.filter((rec) => {
|
|
405
415
|
const key = `${rec.table}:${rec.columns.join(',')}`;
|
|
406
416
|
if (seen.has(key))
|
|
407
417
|
return false;
|
|
@@ -425,8 +435,9 @@ export class SQLiteAutoIndexer {
|
|
|
425
435
|
return [];
|
|
426
436
|
const whereClause = whereMatch[1];
|
|
427
437
|
const columnMatches = whereClause.match(/(\w+)\s*[=<>]/g);
|
|
428
|
-
return columnMatches
|
|
429
|
-
columnMatches.map(match => match.replace(/\s*[=<>].*/, '').trim())
|
|
438
|
+
return columnMatches
|
|
439
|
+
? columnMatches.map((match) => match.replace(/\s*[=<>].*/, '').trim())
|
|
440
|
+
: [];
|
|
430
441
|
}
|
|
431
442
|
/**
|
|
432
443
|
* Extract ORDER BY columns from query
|
|
@@ -438,8 +449,11 @@ export class SQLiteAutoIndexer {
|
|
|
438
449
|
const orderClause = orderMatch[1];
|
|
439
450
|
return orderClause
|
|
440
451
|
.split(',')
|
|
441
|
-
.map(col => col
|
|
442
|
-
.
|
|
452
|
+
.map((col) => col
|
|
453
|
+
.trim()
|
|
454
|
+
.replace(/\s+(ASC|DESC).*$/i, '')
|
|
455
|
+
.replace(/["`]/g, ''))
|
|
456
|
+
.filter((col) => col.length > 0);
|
|
443
457
|
}
|
|
444
458
|
/**
|
|
445
459
|
* Extract JOIN columns from query
|
|
@@ -453,7 +467,7 @@ export class SQLiteAutoIndexer {
|
|
|
453
467
|
const onClause = match.replace(/JOIN\s+\w+\s+ON\s+/i, '');
|
|
454
468
|
const columnMatches = onClause.match(/(\w+)\s*=/g);
|
|
455
469
|
if (columnMatches) {
|
|
456
|
-
columns.push(...columnMatches.map(m => m.replace(/\s*=.*/, '').trim()));
|
|
470
|
+
columns.push(...columnMatches.map((m) => m.replace(/\s*=.*/, '').trim()));
|
|
457
471
|
}
|
|
458
472
|
}
|
|
459
473
|
return columns;
|
|
@@ -468,8 +482,8 @@ export class SQLiteAutoIndexer {
|
|
|
468
482
|
if (match) {
|
|
469
483
|
return match[1]
|
|
470
484
|
.split(',')
|
|
471
|
-
.map(col => col.trim().replace(/^\s*["']?|["']?\s*$/g, ''))
|
|
472
|
-
.filter(col => col.length > 0);
|
|
485
|
+
.map((col) => col.trim().replace(/^\s*["']?|["']?\s*$/g, ''))
|
|
486
|
+
.filter((col) => col.length > 0);
|
|
473
487
|
}
|
|
474
488
|
return [];
|
|
475
489
|
}
|
|
@@ -527,12 +541,12 @@ export class SQLiteAutoIndexer {
|
|
|
527
541
|
const patterns = Array.from(this.queryPatterns.values());
|
|
528
542
|
const totalQueries = patterns.reduce((sum, p) => sum + p.frequency, 0);
|
|
529
543
|
const averageFrequency = patterns.length > 0 ? totalQueries / patterns.length : 0;
|
|
530
|
-
const slowQueries = patterns.filter(p => p.averageExecutionTime > 1000).length;
|
|
544
|
+
const slowQueries = patterns.filter((p) => p.averageExecutionTime > 1000).length;
|
|
531
545
|
return {
|
|
532
546
|
totalPatterns: patterns.length,
|
|
533
547
|
totalQueries,
|
|
534
548
|
averageFrequency,
|
|
535
|
-
slowQueries
|
|
549
|
+
slowQueries,
|
|
536
550
|
};
|
|
537
551
|
}
|
|
538
552
|
}
|