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
|
@@ -53,7 +53,7 @@ class SQLiteMigrationProvider {
|
|
|
53
53
|
migrationDirectory: './migrations',
|
|
54
54
|
fileExtensions: ['.sql', '.ts', '.js'],
|
|
55
55
|
encoding: 'utf8',
|
|
56
|
-
...config
|
|
56
|
+
...config,
|
|
57
57
|
};
|
|
58
58
|
}
|
|
59
59
|
static getInstance(config, logger) {
|
|
@@ -105,11 +105,11 @@ class SQLiteMigrationProvider {
|
|
|
105
105
|
name: fileName,
|
|
106
106
|
content,
|
|
107
107
|
checksum: this.calculateChecksum(content),
|
|
108
|
-
timestamp
|
|
108
|
+
timestamp,
|
|
109
109
|
});
|
|
110
110
|
}
|
|
111
111
|
// Cache the migrations
|
|
112
|
-
migrations.forEach(migration => {
|
|
112
|
+
migrations.forEach((migration) => {
|
|
113
113
|
this.migrationCache.set(migration.name, migration);
|
|
114
114
|
});
|
|
115
115
|
this.logger.info(`✅ Discovered ${migrations.length} migration files`);
|
|
@@ -129,7 +129,7 @@ class SQLiteMigrationProvider {
|
|
|
129
129
|
return this.migrationCache.get(name);
|
|
130
130
|
}
|
|
131
131
|
const migrations = await this.discoverMigrations();
|
|
132
|
-
return migrations.find(m => m.name === name) || null;
|
|
132
|
+
return migrations.find((m) => m.name === name) || null;
|
|
133
133
|
}
|
|
134
134
|
/**
|
|
135
135
|
* Validate migration file
|
|
@@ -155,16 +155,16 @@ class SQLiteMigrationProvider {
|
|
|
155
155
|
const dangerousPatterns = [
|
|
156
156
|
/DROP\s+TABLE\s+(?!IF\s+EXISTS)/i,
|
|
157
157
|
/DROP\s+INDEX\s+(?!IF\s+EXISTS)/i,
|
|
158
|
-
/DELETE\s+FROM\s+\w+\s+(?!WHERE)/i
|
|
158
|
+
/DELETE\s+FROM\s+\w+\s+(?!WHERE)/i,
|
|
159
159
|
];
|
|
160
|
-
dangerousPatterns.forEach(pattern => {
|
|
160
|
+
dangerousPatterns.forEach((pattern) => {
|
|
161
161
|
if (pattern.test(migration.content)) {
|
|
162
162
|
errors.push('Dangerous operation detected - consider using IF EXISTS or WHERE clauses');
|
|
163
163
|
}
|
|
164
164
|
});
|
|
165
165
|
return {
|
|
166
166
|
valid: errors.length === 0,
|
|
167
|
-
errors
|
|
167
|
+
errors,
|
|
168
168
|
};
|
|
169
169
|
}
|
|
170
170
|
/**
|
|
@@ -192,7 +192,8 @@ class SQLiteMigrationProvider {
|
|
|
192
192
|
let sql = `-- Create table ${tableName} with SQLite optimizations\n`;
|
|
193
193
|
sql += `CREATE TABLE IF NOT EXISTS ${tableName} (\n`;
|
|
194
194
|
// Add columns with SQLite-specific types
|
|
195
|
-
const columnDefs = columns
|
|
195
|
+
const columnDefs = columns
|
|
196
|
+
.map((col) => {
|
|
196
197
|
let def = ` ${col.name} ${this.mapToSQLiteType(col.type)}`;
|
|
197
198
|
if (col.primaryKey) {
|
|
198
199
|
def += ' PRIMARY KEY';
|
|
@@ -210,11 +211,14 @@ class SQLiteMigrationProvider {
|
|
|
210
211
|
def += ' UNIQUE';
|
|
211
212
|
}
|
|
212
213
|
return def;
|
|
213
|
-
})
|
|
214
|
+
})
|
|
215
|
+
.join(',\n');
|
|
214
216
|
sql += columnDefs;
|
|
215
217
|
// Add constraints
|
|
216
218
|
if (constraints.length > 0) {
|
|
217
|
-
sql +=
|
|
219
|
+
sql +=
|
|
220
|
+
',\n' +
|
|
221
|
+
constraints.map((constraint) => ` ${constraint}`).join(',\n');
|
|
218
222
|
}
|
|
219
223
|
sql += '\n);\n\n';
|
|
220
224
|
// Add indexes with SQLite optimizations
|
|
@@ -284,29 +288,29 @@ class SQLiteMigrationProvider {
|
|
|
284
288
|
*/
|
|
285
289
|
mapToSQLiteType(type) {
|
|
286
290
|
const typeMap = {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
291
|
+
varchar: 'TEXT',
|
|
292
|
+
char: 'TEXT',
|
|
293
|
+
text: 'TEXT',
|
|
294
|
+
string: 'TEXT',
|
|
295
|
+
int: 'INTEGER',
|
|
296
|
+
integer: 'INTEGER',
|
|
297
|
+
bigint: 'INTEGER',
|
|
298
|
+
smallint: 'INTEGER',
|
|
299
|
+
tinyint: 'INTEGER',
|
|
300
|
+
float: 'REAL',
|
|
301
|
+
double: 'REAL',
|
|
302
|
+
decimal: 'REAL',
|
|
303
|
+
numeric: 'REAL',
|
|
304
|
+
boolean: 'INTEGER',
|
|
305
|
+
bool: 'INTEGER',
|
|
306
|
+
date: 'TEXT',
|
|
307
|
+
datetime: 'TEXT',
|
|
308
|
+
timestamp: 'TEXT',
|
|
309
|
+
time: 'TEXT',
|
|
310
|
+
json: 'TEXT',
|
|
311
|
+
jsonb: 'TEXT',
|
|
312
|
+
uuid: 'TEXT',
|
|
313
|
+
blob: 'BLOB',
|
|
310
314
|
};
|
|
311
315
|
return typeMap[type.toLowerCase()] || 'TEXT';
|
|
312
316
|
}
|
|
@@ -335,7 +339,7 @@ class SQLiteMigrationProvider {
|
|
|
335
339
|
let hash = 0;
|
|
336
340
|
for (let i = 0; i < content.length; i++) {
|
|
337
341
|
const char = content.charCodeAt(i);
|
|
338
|
-
hash = (
|
|
342
|
+
hash = (hash << 5) - hash + char;
|
|
339
343
|
hash = hash & hash; // Convert to 32-bit integer
|
|
340
344
|
}
|
|
341
345
|
return hash.toString(16);
|
|
@@ -9,7 +9,7 @@ const noormme_js_1 = require("../noormme.js");
|
|
|
9
9
|
* Create an in-memory SQLite database for testing
|
|
10
10
|
*/
|
|
11
11
|
async function createTestDatabase(config = {}) {
|
|
12
|
-
const { dialect = 'sqlite', database = ':memory:', cleanup = true, seed = false } = config;
|
|
12
|
+
const { dialect = 'sqlite', database = ':memory:', cleanup = true, seed = false, } = config;
|
|
13
13
|
let dbConfig;
|
|
14
14
|
switch (dialect) {
|
|
15
15
|
case 'sqlite':
|
|
@@ -20,11 +20,11 @@ async function createTestDatabase(config = {}) {
|
|
|
20
20
|
host: '',
|
|
21
21
|
port: 0,
|
|
22
22
|
username: '',
|
|
23
|
-
password: ''
|
|
23
|
+
password: '',
|
|
24
24
|
},
|
|
25
25
|
logging: {
|
|
26
|
-
enabled: process.env.TEST_DEBUG === 'true' // Enable with TEST_DEBUG=true
|
|
27
|
-
}
|
|
26
|
+
enabled: process.env.TEST_DEBUG === 'true', // Enable with TEST_DEBUG=true
|
|
27
|
+
},
|
|
28
28
|
};
|
|
29
29
|
break;
|
|
30
30
|
default:
|
|
@@ -45,35 +45,35 @@ async function setupTestSchema(db) {
|
|
|
45
45
|
await kysely.schema
|
|
46
46
|
.createTable('users')
|
|
47
47
|
.ifNotExists()
|
|
48
|
-
.addColumn('id', 'integer', col => col.primaryKey().autoIncrement())
|
|
49
|
-
.addColumn('name', 'varchar(255)', col => col.notNull())
|
|
50
|
-
.addColumn('email', 'varchar(255)', col => col.notNull().unique())
|
|
48
|
+
.addColumn('id', 'integer', (col) => col.primaryKey().autoIncrement())
|
|
49
|
+
.addColumn('name', 'varchar(255)', (col) => col.notNull())
|
|
50
|
+
.addColumn('email', 'varchar(255)', (col) => col.notNull().unique())
|
|
51
51
|
.addColumn('age', 'integer')
|
|
52
|
-
.addColumn('active', 'boolean', col => col.defaultTo(true))
|
|
53
|
-
.addColumn('created_at', 'timestamp', col => col.defaultTo('now()').notNull())
|
|
54
|
-
.addColumn('updated_at', 'timestamp', col => col.defaultTo('now()').notNull())
|
|
52
|
+
.addColumn('active', 'boolean', (col) => col.defaultTo(true))
|
|
53
|
+
.addColumn('created_at', 'timestamp', (col) => col.defaultTo('now()').notNull())
|
|
54
|
+
.addColumn('updated_at', 'timestamp', (col) => col.defaultTo('now()').notNull())
|
|
55
55
|
.execute();
|
|
56
56
|
// Create posts table
|
|
57
57
|
await kysely.schema
|
|
58
58
|
.createTable('posts')
|
|
59
59
|
.ifNotExists()
|
|
60
|
-
.addColumn('id', 'integer', col => col.primaryKey().autoIncrement())
|
|
61
|
-
.addColumn('title', 'varchar(255)', col => col.notNull())
|
|
60
|
+
.addColumn('id', 'integer', (col) => col.primaryKey().autoIncrement())
|
|
61
|
+
.addColumn('title', 'varchar(255)', (col) => col.notNull())
|
|
62
62
|
.addColumn('content', 'text')
|
|
63
|
-
.addColumn('user_id', 'integer', col => col.references('users.id').onDelete('cascade'))
|
|
64
|
-
.addColumn('published', 'boolean', col => col.defaultTo(false))
|
|
65
|
-
.addColumn('created_at', 'timestamp', col => col.defaultTo('now()').notNull())
|
|
66
|
-
.addColumn('updated_at', 'timestamp', col => col.defaultTo('now()').notNull())
|
|
63
|
+
.addColumn('user_id', 'integer', (col) => col.references('users.id').onDelete('cascade'))
|
|
64
|
+
.addColumn('published', 'boolean', (col) => col.defaultTo(false))
|
|
65
|
+
.addColumn('created_at', 'timestamp', (col) => col.defaultTo('now()').notNull())
|
|
66
|
+
.addColumn('updated_at', 'timestamp', (col) => col.defaultTo('now()').notNull())
|
|
67
67
|
.execute();
|
|
68
68
|
// Create comments table
|
|
69
69
|
await kysely.schema
|
|
70
70
|
.createTable('comments')
|
|
71
71
|
.ifNotExists()
|
|
72
|
-
.addColumn('id', 'integer', col => col.primaryKey().autoIncrement())
|
|
73
|
-
.addColumn('content', 'text', col => col.notNull())
|
|
74
|
-
.addColumn('post_id', 'integer', col => col.references('posts.id').onDelete('cascade'))
|
|
75
|
-
.addColumn('user_id', 'integer', col => col.references('users.id').onDelete('cascade'))
|
|
76
|
-
.addColumn('created_at', 'timestamp', col => col.defaultTo('now()').notNull())
|
|
72
|
+
.addColumn('id', 'integer', (col) => col.primaryKey().autoIncrement())
|
|
73
|
+
.addColumn('content', 'text', (col) => col.notNull())
|
|
74
|
+
.addColumn('post_id', 'integer', (col) => col.references('posts.id').onDelete('cascade'))
|
|
75
|
+
.addColumn('user_id', 'integer', (col) => col.references('users.id').onDelete('cascade'))
|
|
76
|
+
.addColumn('created_at', 'timestamp', (col) => col.defaultTo('now()').notNull())
|
|
77
77
|
.execute();
|
|
78
78
|
// Create indexes for better performance
|
|
79
79
|
await kysely.schema
|
|
@@ -121,7 +121,8 @@ async function setupTestSchema(db) {
|
|
|
121
121
|
// Try to manually check if tables exist
|
|
122
122
|
let actualTables = [];
|
|
123
123
|
try {
|
|
124
|
-
actualTables = await kysely
|
|
124
|
+
actualTables = await kysely
|
|
125
|
+
.selectFrom('sqlite_master')
|
|
125
126
|
.select(['name', 'type'])
|
|
126
127
|
.where('type', '=', 'table')
|
|
127
128
|
.where('name', 'not like', 'sqlite_%')
|
|
@@ -134,9 +135,9 @@ async function setupTestSchema(db) {
|
|
|
134
135
|
`Discovery error: ${discoveryError ? discoveryError.join(' ') : 'Unknown'}`);
|
|
135
136
|
}
|
|
136
137
|
// Verify expected tables exist
|
|
137
|
-
const tableNames = schemaInfo.tables.map(t => t.name);
|
|
138
|
+
const tableNames = schemaInfo.tables.map((t) => t.name);
|
|
138
139
|
const expectedTables = ['users', 'posts', 'comments'];
|
|
139
|
-
const missingTables = expectedTables.filter(t => !tableNames.includes(t));
|
|
140
|
+
const missingTables = expectedTables.filter((t) => !tableNames.includes(t));
|
|
140
141
|
if (missingTables.length > 0) {
|
|
141
142
|
throw new Error(`Test setup failed: Missing tables: ${missingTables.join(', ')}. ` +
|
|
142
143
|
`Found tables: ${tableNames.join(', ')}. ` +
|
|
@@ -192,7 +193,7 @@ class TestDataFactory {
|
|
|
192
193
|
email: this.generateUniqueEmail(),
|
|
193
194
|
age: 25,
|
|
194
195
|
active: true,
|
|
195
|
-
...overrides
|
|
196
|
+
...overrides,
|
|
196
197
|
};
|
|
197
198
|
return await userRepo.create(userData);
|
|
198
199
|
}
|
|
@@ -204,7 +205,7 @@ class TestDataFactory {
|
|
|
204
205
|
for (let i = 0; i < count; i++) {
|
|
205
206
|
const user = await this.createUser({
|
|
206
207
|
name: `Test User ${i + 1}`,
|
|
207
|
-
...overrides
|
|
208
|
+
...overrides,
|
|
208
209
|
});
|
|
209
210
|
users.push(user);
|
|
210
211
|
}
|
|
@@ -220,7 +221,7 @@ class TestDataFactory {
|
|
|
220
221
|
content: 'This is a test post content',
|
|
221
222
|
user_id: userId,
|
|
222
223
|
published: false,
|
|
223
|
-
...overrides
|
|
224
|
+
...overrides,
|
|
224
225
|
};
|
|
225
226
|
return await postRepo.create(postData);
|
|
226
227
|
}
|
|
@@ -232,7 +233,7 @@ class TestDataFactory {
|
|
|
232
233
|
for (let i = 0; i < count; i++) {
|
|
233
234
|
const post = await this.createPost(userId, {
|
|
234
235
|
title: `Test Post ${i + 1}`,
|
|
235
|
-
...overrides
|
|
236
|
+
...overrides,
|
|
236
237
|
});
|
|
237
238
|
posts.push(post);
|
|
238
239
|
}
|
|
@@ -247,7 +248,7 @@ class TestDataFactory {
|
|
|
247
248
|
content: 'This is a test comment',
|
|
248
249
|
post_id: postId,
|
|
249
250
|
user_id: userId,
|
|
250
|
-
...overrides
|
|
251
|
+
...overrides,
|
|
251
252
|
};
|
|
252
253
|
return await commentRepo.create(commentData);
|
|
253
254
|
}
|
|
@@ -259,7 +260,7 @@ class TestDataFactory {
|
|
|
259
260
|
for (let i = 0; i < count; i++) {
|
|
260
261
|
const comment = await this.createComment(postId, userId, {
|
|
261
262
|
content: `Test comment ${i + 1}`,
|
|
262
|
-
...overrides
|
|
263
|
+
...overrides,
|
|
263
264
|
});
|
|
264
265
|
comments.push(comment);
|
|
265
266
|
}
|
|
@@ -313,7 +314,8 @@ class TestUtils {
|
|
|
313
314
|
throw new Error('Expected promise to reject, but it resolved');
|
|
314
315
|
}
|
|
315
316
|
catch (error) {
|
|
316
|
-
if (expectedErrorMessage &&
|
|
317
|
+
if (expectedErrorMessage &&
|
|
318
|
+
!String(error).includes(expectedErrorMessage)) {
|
|
317
319
|
throw new Error(`Expected error message to contain "${expectedErrorMessage}", but got: ${error}`);
|
|
318
320
|
}
|
|
319
321
|
return error;
|
|
@@ -337,10 +339,10 @@ class TestUtils {
|
|
|
337
339
|
calls.push(args);
|
|
338
340
|
});
|
|
339
341
|
Object.defineProperty(spy, 'calls', {
|
|
340
|
-
get: () => calls
|
|
342
|
+
get: () => calls,
|
|
341
343
|
});
|
|
342
344
|
Object.defineProperty(spy, 'callCount', {
|
|
343
|
-
get: () => calls.length
|
|
345
|
+
get: () => calls.length,
|
|
344
346
|
});
|
|
345
347
|
return spy;
|
|
346
348
|
}
|
|
@@ -348,7 +350,7 @@ class TestUtils {
|
|
|
348
350
|
* Delay execution for testing timing-sensitive operations
|
|
349
351
|
*/
|
|
350
352
|
static delay(ms) {
|
|
351
|
-
return new Promise(resolve => setTimeout(resolve, ms));
|
|
353
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
352
354
|
}
|
|
353
355
|
}
|
|
354
356
|
exports.TestUtils = TestUtils;
|
|
@@ -197,11 +197,14 @@ export interface EntityType {
|
|
|
197
197
|
}
|
|
198
198
|
export interface DjangoManager<T> {
|
|
199
199
|
all(): Promise<T[]>;
|
|
200
|
-
get(
|
|
201
|
-
get(filter: Partial<T>): Promise<T | null>;
|
|
200
|
+
get(idOrFilter: string | number | Partial<T>): Promise<T | null>;
|
|
202
201
|
filter(filter: Partial<T>): DjangoManager<T>;
|
|
202
|
+
filter(column: string, operator: string, value: any): DjangoManager<T>;
|
|
203
203
|
exclude(filter: Partial<T>): DjangoManager<T>;
|
|
204
|
+
exclude(column: string, operator: string, value: any): DjangoManager<T>;
|
|
204
205
|
order_by(...columns: (keyof T | string)[]): DjangoManager<T>;
|
|
206
|
+
limit(count: number): DjangoManager<T>;
|
|
207
|
+
offset(count: number): DjangoManager<T>;
|
|
205
208
|
count(): Promise<number>;
|
|
206
209
|
exists(): Promise<boolean>;
|
|
207
210
|
first(): Promise<T | null>;
|
package/dist/cjs/types/index.js
CHANGED
|
@@ -14,15 +14,18 @@ function validateNOORMConfig(config) {
|
|
|
14
14
|
}
|
|
15
15
|
// Validate dialect-specific requirements
|
|
16
16
|
if (config.dialect === 'sqlite') {
|
|
17
|
-
if (!config.connection.database.endsWith('.db') &&
|
|
17
|
+
if (!config.connection.database.endsWith('.db') &&
|
|
18
|
+
!config.connection.database.endsWith('.sqlite')) {
|
|
18
19
|
console.warn('SQLite database path should typically end with .db or .sqlite');
|
|
19
20
|
}
|
|
20
21
|
}
|
|
21
22
|
// Validate performance settings
|
|
22
|
-
if (config.performance?.maxBatchSize &&
|
|
23
|
+
if (config.performance?.maxBatchSize &&
|
|
24
|
+
config.performance.maxBatchSize <= 0) {
|
|
23
25
|
throw new Error('maxBatchSize must be greater than 0');
|
|
24
26
|
}
|
|
25
|
-
if (config.performance?.maxCacheSize &&
|
|
27
|
+
if (config.performance?.maxCacheSize &&
|
|
28
|
+
config.performance.maxCacheSize <= 0) {
|
|
26
29
|
throw new Error('maxCacheSize must be greater than 0');
|
|
27
30
|
}
|
|
28
31
|
}
|
|
@@ -30,7 +30,7 @@ class TypeGenerator {
|
|
|
30
30
|
return {
|
|
31
31
|
entities,
|
|
32
32
|
interfaces,
|
|
33
|
-
types
|
|
33
|
+
types,
|
|
34
34
|
};
|
|
35
35
|
}
|
|
36
36
|
/**
|
|
@@ -53,7 +53,7 @@ class TypeGenerator {
|
|
|
53
53
|
interface: interfaceCode,
|
|
54
54
|
insertType,
|
|
55
55
|
updateType,
|
|
56
|
-
selectType
|
|
56
|
+
selectType,
|
|
57
57
|
};
|
|
58
58
|
}
|
|
59
59
|
/**
|
|
@@ -175,54 +175,58 @@ class TypeGenerator {
|
|
|
175
175
|
// Handle PostgreSQL array types
|
|
176
176
|
if (column.type.endsWith('[]')) {
|
|
177
177
|
const baseType = column.type.slice(0, -2);
|
|
178
|
-
const elementType = this.mapColumnToTypeScript({
|
|
178
|
+
const elementType = this.mapColumnToTypeScript({
|
|
179
|
+
...column,
|
|
180
|
+
type: baseType,
|
|
181
|
+
nullable: false,
|
|
182
|
+
});
|
|
179
183
|
const arrayType = `Array<${elementType}>`;
|
|
180
184
|
return column.nullable ? `${arrayType} | null` : arrayType;
|
|
181
185
|
}
|
|
182
186
|
const typeMapping = {
|
|
183
187
|
// PostgreSQL types
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
188
|
+
varchar: 'string',
|
|
189
|
+
text: 'string',
|
|
190
|
+
char: 'string',
|
|
191
|
+
integer: 'number',
|
|
192
|
+
bigint: 'number',
|
|
193
|
+
smallint: 'number',
|
|
194
|
+
decimal: 'number',
|
|
195
|
+
numeric: 'number',
|
|
196
|
+
real: 'number',
|
|
193
197
|
'double precision': 'number',
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
198
|
+
boolean: 'boolean',
|
|
199
|
+
date: 'Date',
|
|
200
|
+
timestamp: 'Date',
|
|
201
|
+
timestamptz: 'Date',
|
|
202
|
+
time: 'Date',
|
|
203
|
+
json: 'Record<string, unknown>',
|
|
204
|
+
jsonb: 'Record<string, unknown>',
|
|
205
|
+
uuid: 'string',
|
|
206
|
+
tsvector: 'string',
|
|
207
|
+
tsquery: 'string',
|
|
204
208
|
// MySQL specific types
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
209
|
+
longtext: 'string',
|
|
210
|
+
mediumtext: 'string',
|
|
211
|
+
tinytext: 'string',
|
|
212
|
+
int: 'number',
|
|
213
|
+
tinyint: 'number',
|
|
214
|
+
float: 'number',
|
|
215
|
+
double: 'number',
|
|
216
|
+
bool: 'boolean',
|
|
217
|
+
datetime: 'Date',
|
|
214
218
|
// SQLite specific types (enhanced)
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
+
blob: 'Buffer',
|
|
220
|
+
int2: 'number',
|
|
221
|
+
int8: 'number',
|
|
222
|
+
clob: 'string',
|
|
219
223
|
// MSSQL specific types
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
224
|
+
nvarchar: 'string',
|
|
225
|
+
nchar: 'string',
|
|
226
|
+
ntext: 'string',
|
|
227
|
+
bit: 'boolean',
|
|
228
|
+
datetime2: 'Date',
|
|
229
|
+
smalldatetime: 'Date',
|
|
226
230
|
};
|
|
227
231
|
// Try exact match first
|
|
228
232
|
if (typeMapping[column.type.toLowerCase()]) {
|
|
@@ -250,7 +254,7 @@ class TypeGenerator {
|
|
|
250
254
|
* Get relationships for a specific table
|
|
251
255
|
*/
|
|
252
256
|
getRelationshipsForTable(tableName, relationships) {
|
|
253
|
-
return relationships.filter(rel => rel.fromTable === tableName);
|
|
257
|
+
return relationships.filter((rel) => rel.fromTable === tableName);
|
|
254
258
|
}
|
|
255
259
|
/**
|
|
256
260
|
* Convert string to camelCase
|
|
@@ -55,7 +55,7 @@ function safeOffset(offset) {
|
|
|
55
55
|
*/
|
|
56
56
|
function safeKeyword(keyword, allowedKeywords) {
|
|
57
57
|
const normalized = keyword.toUpperCase().trim();
|
|
58
|
-
const allowedNormalized = allowedKeywords.map(k => k.toUpperCase().trim());
|
|
58
|
+
const allowedNormalized = allowedKeywords.map((k) => k.toUpperCase().trim());
|
|
59
59
|
if (!allowedNormalized.includes(normalized)) {
|
|
60
60
|
throw new Error(`Invalid keyword: "${keyword}". Allowed keywords: ${allowedKeywords.join(', ')}`);
|
|
61
61
|
}
|
|
@@ -62,7 +62,12 @@ function validateIdentifier(identifier, context = 'identifier') {
|
|
|
62
62
|
}
|
|
63
63
|
// Additional check: prevent reserved SQLite keywords that could be dangerous
|
|
64
64
|
const reservedKeywords = [
|
|
65
|
-
'PRAGMA',
|
|
65
|
+
'PRAGMA',
|
|
66
|
+
'ATTACH',
|
|
67
|
+
'DETACH',
|
|
68
|
+
'VACUUM',
|
|
69
|
+
'ANALYZE',
|
|
70
|
+
'REINDEX',
|
|
66
71
|
];
|
|
67
72
|
for (const keyword of reservedKeywords) {
|
|
68
73
|
if (identifier.toUpperCase() === keyword) {
|
|
@@ -83,7 +88,11 @@ function validateTableReference(tableRef) {
|
|
|
83
88
|
}
|
|
84
89
|
// Validate each part
|
|
85
90
|
parts.forEach((part, index) => {
|
|
86
|
-
const context = index === 0
|
|
91
|
+
const context = index === 0
|
|
92
|
+
? parts.length === 2
|
|
93
|
+
? 'schema name'
|
|
94
|
+
: 'table name'
|
|
95
|
+
: 'table name';
|
|
87
96
|
validateIdentifier(part, context);
|
|
88
97
|
});
|
|
89
98
|
}
|
|
@@ -108,7 +117,8 @@ function validateColumnReference(columnRef) {
|
|
|
108
117
|
context = index === 0 ? 'table name' : 'column name';
|
|
109
118
|
}
|
|
110
119
|
else {
|
|
111
|
-
context =
|
|
120
|
+
context =
|
|
121
|
+
index === 0 ? 'schema name' : index === 1 ? 'table name' : 'column name';
|
|
112
122
|
}
|
|
113
123
|
validateIdentifier(part, context);
|
|
114
124
|
});
|
|
@@ -140,7 +150,7 @@ function validateFilePath(filePath, allowedExtensions) {
|
|
|
140
150
|
}
|
|
141
151
|
// Validate file extension if specified
|
|
142
152
|
if (allowedExtensions && allowedExtensions.length > 0) {
|
|
143
|
-
const hasValidExtension = allowedExtensions.some(ext => filePath.toLowerCase().endsWith(ext.toLowerCase()));
|
|
153
|
+
const hasValidExtension = allowedExtensions.some((ext) => filePath.toLowerCase().endsWith(ext.toLowerCase()));
|
|
144
154
|
if (!hasValidExtension) {
|
|
145
155
|
throw new Error(`Invalid file extension for "${filePath}". ` +
|
|
146
156
|
`Allowed extensions: ${allowedExtensions.join(', ')}`);
|
|
@@ -164,7 +174,9 @@ function validateFilePath(filePath, allowedExtensions) {
|
|
|
164
174
|
function sanitizeDatabasePath(dbPath) {
|
|
165
175
|
validateFilePath(dbPath, ['.db', '.sqlite', '.sqlite3', '.db3']);
|
|
166
176
|
// Ensure the path doesn't escape current directory
|
|
167
|
-
if (dbPath.includes('..') ||
|
|
177
|
+
if (dbPath.includes('..') ||
|
|
178
|
+
dbPath.startsWith('/') ||
|
|
179
|
+
/^[a-zA-Z]:/.test(dbPath)) {
|
|
168
180
|
throw new Error(`Database path "${dbPath}" must be a relative path within the current directory`);
|
|
169
181
|
}
|
|
170
182
|
return dbPath;
|
|
@@ -221,8 +233,7 @@ class RateLimiter {
|
|
|
221
233
|
maxAttempts;
|
|
222
234
|
windowMs;
|
|
223
235
|
attempts = new Map();
|
|
224
|
-
constructor(maxAttempts = 10, windowMs = 60000
|
|
225
|
-
) {
|
|
236
|
+
constructor(maxAttempts = 10, windowMs = 60000) {
|
|
226
237
|
this.maxAttempts = maxAttempts;
|
|
227
238
|
this.windowMs = windowMs;
|
|
228
239
|
}
|
|
@@ -230,7 +241,7 @@ class RateLimiter {
|
|
|
230
241
|
const now = Date.now();
|
|
231
242
|
const attempts = this.attempts.get(key) || [];
|
|
232
243
|
// Remove old attempts outside the window
|
|
233
|
-
const recentAttempts = attempts.filter(time => now - time < this.windowMs);
|
|
244
|
+
const recentAttempts = attempts.filter((time) => now - time < this.windowMs);
|
|
234
245
|
if (recentAttempts.length >= this.maxAttempts) {
|
|
235
246
|
throw new Error(`Rate limit exceeded for ${key}. Please wait before trying again.`);
|
|
236
247
|
}
|
|
@@ -243,7 +254,7 @@ class RateLimiter {
|
|
|
243
254
|
}
|
|
244
255
|
cleanup(now) {
|
|
245
256
|
for (const [key, attempts] of this.attempts.entries()) {
|
|
246
|
-
const recentAttempts = attempts.filter(time => now - time < this.windowMs);
|
|
257
|
+
const recentAttempts = attempts.filter((time) => now - time < this.windowMs);
|
|
247
258
|
if (recentAttempts.length === 0) {
|
|
248
259
|
this.attempts.delete(key);
|
|
249
260
|
}
|
|
@@ -26,11 +26,15 @@ function wrapKyselyError(error, context) {
|
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
// Handle connection errors
|
|
29
|
-
if (message.includes('connect') ||
|
|
29
|
+
if (message.includes('connect') ||
|
|
30
|
+
message.includes('ECONNREFUSED') ||
|
|
31
|
+
message.includes('ENOTFOUND')) {
|
|
30
32
|
return new NoormError_js_1.ConnectionError(message, error);
|
|
31
33
|
}
|
|
32
34
|
// Handle authentication errors
|
|
33
|
-
if (message.includes('authentication') ||
|
|
35
|
+
if (message.includes('authentication') ||
|
|
36
|
+
message.includes('password') ||
|
|
37
|
+
message.includes('SASL')) {
|
|
34
38
|
return new NoormError_js_1.ConnectionError('Authentication failed. Check your username and password.', error);
|
|
35
39
|
}
|
|
36
40
|
// Handle syntax errors
|
|
@@ -38,17 +42,19 @@ function wrapKyselyError(error, context) {
|
|
|
38
42
|
return new NoormError_js_1.NoormError(`SQL syntax error: ${message}`, {
|
|
39
43
|
table: context.table,
|
|
40
44
|
operation: context.operation,
|
|
41
|
-
suggestion:
|
|
42
|
-
originalError: error
|
|
45
|
+
suggestion: "Check your query syntax or report this as a bug if you're using NOORMME methods",
|
|
46
|
+
originalError: error,
|
|
43
47
|
});
|
|
44
48
|
}
|
|
45
49
|
// Handle constraint violations
|
|
46
|
-
if (message.includes('constraint') ||
|
|
50
|
+
if (message.includes('constraint') ||
|
|
51
|
+
message.includes('duplicate') ||
|
|
52
|
+
message.includes('unique')) {
|
|
47
53
|
return new NoormError_js_1.NoormError(`Database constraint violation: ${extractConstraintMessage(message)}`, {
|
|
48
54
|
table: context.table,
|
|
49
55
|
operation: context.operation,
|
|
50
56
|
suggestion: 'Check for duplicate values or foreign key violations',
|
|
51
|
-
originalError: error
|
|
57
|
+
originalError: error,
|
|
52
58
|
});
|
|
53
59
|
}
|
|
54
60
|
// Generic wrapper for other errors
|
|
@@ -56,7 +62,7 @@ function wrapKyselyError(error, context) {
|
|
|
56
62
|
table: context.table,
|
|
57
63
|
operation: context.operation,
|
|
58
64
|
suggestion: 'Check the database connection and query parameters',
|
|
59
|
-
originalError: error
|
|
65
|
+
originalError: error,
|
|
60
66
|
});
|
|
61
67
|
}
|
|
62
68
|
/**
|
|
@@ -121,14 +127,15 @@ function suggestCorrections(input, available, maxSuggestions = 3) {
|
|
|
121
127
|
const suggestions = [];
|
|
122
128
|
for (const option of available) {
|
|
123
129
|
const score = calculateSimilarity(input.toLowerCase(), option.toLowerCase());
|
|
124
|
-
if (score > 0.3) {
|
|
130
|
+
if (score > 0.3) {
|
|
131
|
+
// Only suggest if similarity > 30%
|
|
125
132
|
suggestions.push({ name: option, score });
|
|
126
133
|
}
|
|
127
134
|
}
|
|
128
135
|
return suggestions
|
|
129
136
|
.sort((a, b) => b.score - a.score)
|
|
130
137
|
.slice(0, maxSuggestions)
|
|
131
|
-
.map(s => s.name);
|
|
138
|
+
.map((s) => s.name);
|
|
132
139
|
}
|
|
133
140
|
/**
|
|
134
141
|
* Calculate string similarity using Jaro-Winkler algorithm (simplified)
|
|
@@ -173,7 +180,10 @@ function calculateSimilarity(str1, str2) {
|
|
|
173
180
|
transpositions++;
|
|
174
181
|
k++;
|
|
175
182
|
}
|
|
176
|
-
const jaro = (matches / len1 +
|
|
183
|
+
const jaro = (matches / len1 +
|
|
184
|
+
matches / len2 +
|
|
185
|
+
(matches - transpositions / 2) / matches) /
|
|
186
|
+
3;
|
|
177
187
|
// Jaro-Winkler bonus for common prefix
|
|
178
188
|
let prefix = 0;
|
|
179
189
|
for (let i = 0; i < Math.min(len1, len2, 4); i++) {
|