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
|
@@ -16,7 +16,7 @@ export class ConnectionFactory {
|
|
|
16
16
|
activeConnections: 0,
|
|
17
17
|
failedCreations: 0,
|
|
18
18
|
averageCreationTime: 0,
|
|
19
|
-
averageValidationTime: 0
|
|
19
|
+
averageValidationTime: 0,
|
|
20
20
|
};
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
@@ -36,7 +36,7 @@ export class ConnectionFactory {
|
|
|
36
36
|
lastUsed: new Date(),
|
|
37
37
|
isActive: true,
|
|
38
38
|
inUse: false,
|
|
39
|
-
config
|
|
39
|
+
config,
|
|
40
40
|
};
|
|
41
41
|
this.connections.set(id, connection);
|
|
42
42
|
this.updateStats('created', performance.now() - startTime);
|
|
@@ -60,7 +60,7 @@ export class ConnectionFactory {
|
|
|
60
60
|
this.updateStats('validated', responseTime);
|
|
61
61
|
return {
|
|
62
62
|
isValid: true,
|
|
63
|
-
responseTime
|
|
63
|
+
responseTime,
|
|
64
64
|
};
|
|
65
65
|
}
|
|
66
66
|
catch (error) {
|
|
@@ -70,7 +70,7 @@ export class ConnectionFactory {
|
|
|
70
70
|
return {
|
|
71
71
|
isValid: false,
|
|
72
72
|
error: errorMessage,
|
|
73
|
-
responseTime
|
|
73
|
+
responseTime,
|
|
74
74
|
};
|
|
75
75
|
}
|
|
76
76
|
}
|
|
@@ -90,13 +90,13 @@ export class ConnectionFactory {
|
|
|
90
90
|
* Get active connections
|
|
91
91
|
*/
|
|
92
92
|
getActiveConnections() {
|
|
93
|
-
return Array.from(this.connections.values()).filter(conn => conn.isActive);
|
|
93
|
+
return Array.from(this.connections.values()).filter((conn) => conn.isActive);
|
|
94
94
|
}
|
|
95
95
|
/**
|
|
96
96
|
* Get idle connections
|
|
97
97
|
*/
|
|
98
98
|
getIdleConnections() {
|
|
99
|
-
return Array.from(this.connections.values()).filter(conn => conn.isActive && !conn.inUse);
|
|
99
|
+
return Array.from(this.connections.values()).filter((conn) => conn.isActive && !conn.inUse);
|
|
100
100
|
}
|
|
101
101
|
/**
|
|
102
102
|
* Mark connection as in use
|
|
@@ -137,7 +137,7 @@ export class ConnectionFactory {
|
|
|
137
137
|
* Destroy all connections
|
|
138
138
|
*/
|
|
139
139
|
async destroyAllConnections() {
|
|
140
|
-
const destroyPromises = Array.from(this.connections.keys()).map(id => this.destroyConnection(id));
|
|
140
|
+
const destroyPromises = Array.from(this.connections.keys()).map((id) => this.destroyConnection(id));
|
|
141
141
|
await Promise.all(destroyPromises);
|
|
142
142
|
this.logger.info('Destroyed all connections');
|
|
143
143
|
}
|
|
@@ -148,8 +148,7 @@ export class ConnectionFactory {
|
|
|
148
148
|
const now = Date.now();
|
|
149
149
|
let cleaned = 0;
|
|
150
150
|
for (const [id, connection] of this.connections.entries()) {
|
|
151
|
-
if (!connection.inUse &&
|
|
152
|
-
now - connection.lastUsed.getTime() > maxAge) {
|
|
151
|
+
if (!connection.inUse && now - connection.lastUsed.getTime() > maxAge) {
|
|
153
152
|
if (await this.destroyConnection(id)) {
|
|
154
153
|
cleaned++;
|
|
155
154
|
}
|
|
@@ -170,7 +169,7 @@ export class ConnectionFactory {
|
|
|
170
169
|
id: connection.id,
|
|
171
170
|
isValid: result.isValid,
|
|
172
171
|
error: result.error,
|
|
173
|
-
responseTime: result.responseTime
|
|
172
|
+
responseTime: result.responseTime,
|
|
174
173
|
};
|
|
175
174
|
});
|
|
176
175
|
return Promise.all(validationPromises);
|
|
@@ -188,7 +187,7 @@ export class ConnectionFactory {
|
|
|
188
187
|
const connections = this.getAllConnections();
|
|
189
188
|
const activeConnections = this.getActiveConnections();
|
|
190
189
|
const idleConnections = this.getIdleConnections();
|
|
191
|
-
const inUseConnections = connections.filter(c => c.inUse);
|
|
190
|
+
const inUseConnections = connections.filter((c) => c.inUse);
|
|
192
191
|
const issues = [];
|
|
193
192
|
// Check for failed creations
|
|
194
193
|
if (this.stats.failedCreations > 0) {
|
|
@@ -204,7 +203,9 @@ export class ConnectionFactory {
|
|
|
204
203
|
}
|
|
205
204
|
let status = 'healthy';
|
|
206
205
|
if (issues.length > 0) {
|
|
207
|
-
status = issues.some(issue => issue.includes('failures'))
|
|
206
|
+
status = issues.some((issue) => issue.includes('failures'))
|
|
207
|
+
? 'critical'
|
|
208
|
+
: 'warning';
|
|
208
209
|
}
|
|
209
210
|
return {
|
|
210
211
|
status,
|
|
@@ -213,8 +214,8 @@ export class ConnectionFactory {
|
|
|
213
214
|
total: connections.length,
|
|
214
215
|
active: activeConnections.length,
|
|
215
216
|
idle: idleConnections.length,
|
|
216
|
-
inUse: inUseConnections.length
|
|
217
|
-
}
|
|
217
|
+
inUse: inUseConnections.length,
|
|
218
|
+
},
|
|
218
219
|
};
|
|
219
220
|
}
|
|
220
221
|
/**
|
|
@@ -282,7 +283,7 @@ export class ConnectionPoolManager {
|
|
|
282
283
|
acquireTimeout: 30000,
|
|
283
284
|
idleTimeout: 300000,
|
|
284
285
|
validationInterval: 60000,
|
|
285
|
-
...poolConfig
|
|
286
|
+
...poolConfig,
|
|
286
287
|
};
|
|
287
288
|
this.startValidationTimer();
|
|
288
289
|
}
|
|
@@ -293,7 +294,7 @@ export class ConnectionPoolManager {
|
|
|
293
294
|
this.logger.info(`Initializing connection pool with ${this.poolConfig.minConnections} minimum connections`);
|
|
294
295
|
const initPromises = Array.from({ length: this.poolConfig.minConnections }, (_, i) => this.factory.createConnection({
|
|
295
296
|
...this.config,
|
|
296
|
-
id: `pool_conn_${i}
|
|
297
|
+
id: `pool_conn_${i}`,
|
|
297
298
|
}));
|
|
298
299
|
try {
|
|
299
300
|
await Promise.all(initPromises);
|
|
@@ -325,7 +326,7 @@ export class ConnectionPoolManager {
|
|
|
325
326
|
if (currentConnections.length < this.poolConfig.maxConnections) {
|
|
326
327
|
const newConnection = await this.factory.createConnection({
|
|
327
328
|
...this.config,
|
|
328
|
-
id: `pool_conn_${Date.now()}
|
|
329
|
+
id: `pool_conn_${Date.now()}`,
|
|
329
330
|
});
|
|
330
331
|
this.factory.markInUse(newConnection);
|
|
331
332
|
this.logger.debug(`Created and acquired new connection ${newConnection.id}`);
|
|
@@ -381,8 +382,8 @@ export class ConnectionPoolManager {
|
|
|
381
382
|
...factoryStats,
|
|
382
383
|
poolSize: connections.length,
|
|
383
384
|
idleConnections: this.factory.getIdleConnections().length,
|
|
384
|
-
inUseConnections: connections.filter(c => c.inUse).length,
|
|
385
|
-
waitingQueue: this.waitingQueue.length
|
|
385
|
+
inUseConnections: connections.filter((c) => c.inUse).length,
|
|
386
|
+
waitingQueue: this.waitingQueue.length,
|
|
386
387
|
};
|
|
387
388
|
}
|
|
388
389
|
/**
|
|
@@ -417,7 +418,7 @@ export class ConnectionPoolManager {
|
|
|
417
418
|
async waitForConnection(startTime) {
|
|
418
419
|
return new Promise((resolve, reject) => {
|
|
419
420
|
const timeout = setTimeout(() => {
|
|
420
|
-
const index = this.waitingQueue.findIndex(item => item.reject === reject);
|
|
421
|
+
const index = this.waitingQueue.findIndex((item) => item.reject === reject);
|
|
421
422
|
if (index !== -1) {
|
|
422
423
|
this.waitingQueue.splice(index, 1);
|
|
423
424
|
}
|
|
@@ -432,7 +433,7 @@ export class ConnectionPoolManager {
|
|
|
432
433
|
clearTimeout(timeout);
|
|
433
434
|
reject(error);
|
|
434
435
|
},
|
|
435
|
-
timestamp: Date.now()
|
|
436
|
+
timestamp: Date.now(),
|
|
436
437
|
});
|
|
437
438
|
});
|
|
438
439
|
}
|
|
@@ -462,7 +463,9 @@ export class ConnectionPoolManager {
|
|
|
462
463
|
* Validate all connections in the pool
|
|
463
464
|
*/
|
|
464
465
|
async validateConnections() {
|
|
465
|
-
const validationPromises = this.factory
|
|
466
|
+
const validationPromises = this.factory
|
|
467
|
+
.getIdleConnections()
|
|
468
|
+
.map(async (connection) => {
|
|
466
469
|
const validation = await this.factory.validateConnection(connection);
|
|
467
470
|
if (!validation.isValid) {
|
|
468
471
|
await this.factory.destroyConnection(connection.id);
|
|
@@ -476,7 +479,9 @@ export class ConnectionPoolManager {
|
|
|
476
479
|
async cleanupIdleConnections() {
|
|
477
480
|
const now = Date.now();
|
|
478
481
|
const idleConnections = this.factory.getIdleConnections();
|
|
479
|
-
const excessConnections = idleConnections
|
|
482
|
+
const excessConnections = idleConnections
|
|
483
|
+
.filter((conn) => now - conn.lastUsed.getTime() > this.poolConfig.idleTimeout)
|
|
484
|
+
.slice(this.poolConfig.minConnections);
|
|
480
485
|
for (const connection of excessConnections) {
|
|
481
486
|
await this.factory.destroyConnection(connection.id);
|
|
482
487
|
}
|
|
@@ -23,11 +23,11 @@ export class MetricsCollector {
|
|
|
23
23
|
maxHistorySize: 10000,
|
|
24
24
|
warningRetentionDays: 7,
|
|
25
25
|
persistPath: config.persistPath,
|
|
26
|
-
...config
|
|
26
|
+
...config,
|
|
27
27
|
};
|
|
28
28
|
this.startCleanupTimer();
|
|
29
29
|
// Attempt to load metrics on startup (fire and forget)
|
|
30
|
-
this.load().catch(err => this.logger.warn('Failed to load metrics:', err));
|
|
30
|
+
this.load().catch((err) => this.logger.warn('Failed to load metrics:', err));
|
|
31
31
|
}
|
|
32
32
|
/**
|
|
33
33
|
* Load metrics from disk
|
|
@@ -65,7 +65,7 @@ export class MetricsCollector {
|
|
|
65
65
|
const data = JSON.stringify({
|
|
66
66
|
queryHistory: this.queryHistory,
|
|
67
67
|
warnings: this.warnings,
|
|
68
|
-
savedAt: Date.now()
|
|
68
|
+
savedAt: Date.now(),
|
|
69
69
|
}, null, 2);
|
|
70
70
|
await fs.writeFile(this.config.persistPath, data, 'utf-8');
|
|
71
71
|
this.logger.debug(`Saved metrics to ${this.config.persistPath}`);
|
|
@@ -87,7 +87,7 @@ export class MetricsCollector {
|
|
|
87
87
|
table: options.table,
|
|
88
88
|
operation: options.operation,
|
|
89
89
|
resultCount: options.resultCount,
|
|
90
|
-
error: options.error
|
|
90
|
+
error: options.error,
|
|
91
91
|
};
|
|
92
92
|
this.queryHistory.push(metrics);
|
|
93
93
|
// Keep history size under control
|
|
@@ -104,12 +104,13 @@ export class MetricsCollector {
|
|
|
104
104
|
*/
|
|
105
105
|
getPerformanceStats() {
|
|
106
106
|
const totalQueries = this.queryHistory.length;
|
|
107
|
-
const slowQueries = this.queryHistory.filter(q => q.executionTime > this.config.slowQueryThreshold).length;
|
|
107
|
+
const slowQueries = this.queryHistory.filter((q) => q.executionTime > this.config.slowQueryThreshold).length;
|
|
108
108
|
const averageExecutionTime = totalQueries > 0
|
|
109
|
-
? this.queryHistory.reduce((sum, q) => sum + q.executionTime, 0) /
|
|
109
|
+
? this.queryHistory.reduce((sum, q) => sum + q.executionTime, 0) /
|
|
110
|
+
totalQueries
|
|
110
111
|
: 0;
|
|
111
112
|
const errorRate = totalQueries > 0
|
|
112
|
-
? this.queryHistory.filter(q => q.error).length / totalQueries
|
|
113
|
+
? this.queryHistory.filter((q) => q.error).length / totalQueries
|
|
113
114
|
: 0;
|
|
114
115
|
const warningCount = {};
|
|
115
116
|
for (const warning of this.warnings) {
|
|
@@ -124,7 +125,7 @@ export class MetricsCollector {
|
|
|
124
125
|
errorRate,
|
|
125
126
|
warningCount,
|
|
126
127
|
topSlowQueries,
|
|
127
|
-
queryPatterns
|
|
128
|
+
queryPatterns,
|
|
128
129
|
};
|
|
129
130
|
}
|
|
130
131
|
/**
|
|
@@ -139,14 +140,13 @@ export class MetricsCollector {
|
|
|
139
140
|
* Get warnings by type
|
|
140
141
|
*/
|
|
141
142
|
getWarningsByType(type) {
|
|
142
|
-
return this.warnings.filter(w => w.type === type);
|
|
143
|
+
return this.warnings.filter((w) => w.type === type);
|
|
143
144
|
}
|
|
144
145
|
/**
|
|
145
146
|
* Get query history
|
|
146
147
|
*/
|
|
147
148
|
getQueryHistory(limit) {
|
|
148
|
-
const history = this.queryHistory
|
|
149
|
-
.sort((a, b) => b.timestamp - a.timestamp);
|
|
149
|
+
const history = this.queryHistory.sort((a, b) => b.timestamp - a.timestamp);
|
|
150
150
|
return limit ? history.slice(0, limit) : history;
|
|
151
151
|
}
|
|
152
152
|
/**
|
|
@@ -155,7 +155,7 @@ export class MetricsCollector {
|
|
|
155
155
|
getSlowQueries(threshold) {
|
|
156
156
|
const actualThreshold = threshold || this.config.slowQueryThreshold;
|
|
157
157
|
return this.queryHistory
|
|
158
|
-
.filter(q => q.executionTime > actualThreshold)
|
|
158
|
+
.filter((q) => q.executionTime > actualThreshold)
|
|
159
159
|
.sort((a, b) => b.executionTime - a.executionTime);
|
|
160
160
|
}
|
|
161
161
|
/**
|
|
@@ -180,7 +180,7 @@ export class MetricsCollector {
|
|
|
180
180
|
let maxCountInWindow = 0;
|
|
181
181
|
for (const query of queries) {
|
|
182
182
|
const windowStart = query.timestamp - windowMs;
|
|
183
|
-
const countInWindow = queries.filter(q => q.timestamp >= windowStart && q.timestamp <= query.timestamp).length;
|
|
183
|
+
const countInWindow = queries.filter((q) => q.timestamp >= windowStart && q.timestamp <= query.timestamp).length;
|
|
184
184
|
maxCountInWindow = Math.max(maxCountInWindow, countInWindow);
|
|
185
185
|
}
|
|
186
186
|
if (maxCountInWindow >= 5) {
|
|
@@ -193,7 +193,7 @@ export class MetricsCollector {
|
|
|
193
193
|
pattern,
|
|
194
194
|
count: maxCountInWindow,
|
|
195
195
|
timeWindow: windowMs,
|
|
196
|
-
severity
|
|
196
|
+
severity,
|
|
197
197
|
});
|
|
198
198
|
break;
|
|
199
199
|
}
|
|
@@ -219,7 +219,7 @@ export class MetricsCollector {
|
|
|
219
219
|
config: this.config,
|
|
220
220
|
stats: this.getPerformanceStats(),
|
|
221
221
|
warnings: this.warnings,
|
|
222
|
-
queries: this.queryHistory
|
|
222
|
+
queries: this.queryHistory,
|
|
223
223
|
};
|
|
224
224
|
}
|
|
225
225
|
/**
|
|
@@ -244,7 +244,7 @@ export class MetricsCollector {
|
|
|
244
244
|
// Clean up old recent queries (keep last 10 seconds)
|
|
245
245
|
const cutoff = Date.now() - 10000;
|
|
246
246
|
for (const [query, queries] of this.recentQueries.entries()) {
|
|
247
|
-
const recent = queries.filter(q => q.timestamp >= cutoff);
|
|
247
|
+
const recent = queries.filter((q) => q.timestamp >= cutoff);
|
|
248
248
|
if (recent.length === 0) {
|
|
249
249
|
this.recentQueries.delete(query);
|
|
250
250
|
}
|
|
@@ -266,8 +266,10 @@ export class MetricsCollector {
|
|
|
266
266
|
suggestion: 'Consider adding indexes or optimizing the query',
|
|
267
267
|
query: metrics.query,
|
|
268
268
|
table: metrics.table,
|
|
269
|
-
severity: metrics.executionTime > this.config.slowQueryThreshold * 3
|
|
270
|
-
|
|
269
|
+
severity: metrics.executionTime > this.config.slowQueryThreshold * 3
|
|
270
|
+
? 'high'
|
|
271
|
+
: 'medium',
|
|
272
|
+
timestamp: Date.now(),
|
|
271
273
|
});
|
|
272
274
|
}
|
|
273
275
|
// Check for N+1 queries
|
|
@@ -278,15 +280,18 @@ export class MetricsCollector {
|
|
|
278
280
|
}
|
|
279
281
|
}
|
|
280
282
|
// Check for large result sets
|
|
281
|
-
if (metrics.resultCount &&
|
|
283
|
+
if (metrics.resultCount &&
|
|
284
|
+
metrics.resultCount > this.config.largeResultSetThreshold) {
|
|
282
285
|
warnings.push({
|
|
283
286
|
type: 'large_result_set',
|
|
284
287
|
message: `Large result set: ${metrics.resultCount} rows returned`,
|
|
285
288
|
suggestion: 'Consider using pagination or filtering to reduce result size',
|
|
286
289
|
query: metrics.query,
|
|
287
290
|
table: metrics.table,
|
|
288
|
-
severity: metrics.resultCount > this.config.largeResultSetThreshold * 5
|
|
289
|
-
|
|
291
|
+
severity: metrics.resultCount > this.config.largeResultSetThreshold * 5
|
|
292
|
+
? 'high'
|
|
293
|
+
: 'medium',
|
|
294
|
+
timestamp: Date.now(),
|
|
290
295
|
});
|
|
291
296
|
}
|
|
292
297
|
// Log warnings
|
|
@@ -302,7 +307,7 @@ export class MetricsCollector {
|
|
|
302
307
|
// Look for the same query executed multiple times in quick succession
|
|
303
308
|
if (recentQueries.length >= 5) {
|
|
304
309
|
const timeWindow = 5000; // 5 seconds
|
|
305
|
-
const recentInWindow = recentQueries.filter(q => Date.now() - q.timestamp < timeWindow);
|
|
310
|
+
const recentInWindow = recentQueries.filter((q) => Date.now() - q.timestamp < timeWindow);
|
|
306
311
|
if (recentInWindow.length >= 5) {
|
|
307
312
|
return {
|
|
308
313
|
type: 'n_plus_one',
|
|
@@ -311,7 +316,7 @@ export class MetricsCollector {
|
|
|
311
316
|
query: metrics.query,
|
|
312
317
|
table: metrics.table,
|
|
313
318
|
severity: 'high',
|
|
314
|
-
timestamp: Date.now()
|
|
319
|
+
timestamp: Date.now(),
|
|
315
320
|
};
|
|
316
321
|
}
|
|
317
322
|
}
|
|
@@ -351,11 +356,11 @@ export class MetricsCollector {
|
|
|
351
356
|
*/
|
|
352
357
|
getWarningEmoji(type) {
|
|
353
358
|
const emojis = {
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
+
n_plus_one: '🔄',
|
|
360
|
+
missing_index: '📇',
|
|
361
|
+
slow_query: '🐌',
|
|
362
|
+
full_table_scan: '🔍',
|
|
363
|
+
large_result_set: '📊',
|
|
359
364
|
};
|
|
360
365
|
return emojis[type] || '⚠️';
|
|
361
366
|
}
|
|
@@ -389,7 +394,7 @@ export class MetricsCollector {
|
|
|
389
394
|
.map(([query, { totalTime, count }]) => ({
|
|
390
395
|
query,
|
|
391
396
|
averageTime: totalTime / count,
|
|
392
|
-
count
|
|
397
|
+
count,
|
|
393
398
|
}))
|
|
394
399
|
.sort((a, b) => b.averageTime - a.averageTime)
|
|
395
400
|
.slice(0, 10);
|
|
@@ -411,7 +416,7 @@ export class MetricsCollector {
|
|
|
411
416
|
.map(([pattern, { totalTime, count }]) => ({
|
|
412
417
|
pattern,
|
|
413
418
|
frequency: count,
|
|
414
|
-
averageTime: totalTime / count
|
|
419
|
+
averageTime: totalTime / count,
|
|
415
420
|
}))
|
|
416
421
|
.sort((a, b) => b.frequency - a.frequency)
|
|
417
422
|
.slice(0, 20);
|
|
@@ -422,22 +427,22 @@ export class MetricsCollector {
|
|
|
422
427
|
startCleanupTimer() {
|
|
423
428
|
this.cleanupTimer = setInterval(() => {
|
|
424
429
|
this.cleanup();
|
|
425
|
-
this.save().catch(err => this.logger.warn('Failed to auto-save metrics:', err));
|
|
430
|
+
this.save().catch((err) => this.logger.warn('Failed to auto-save metrics:', err));
|
|
426
431
|
}, 60000); // Cleanup and save every minute
|
|
427
432
|
}
|
|
428
433
|
/**
|
|
429
434
|
* Cleanup old data
|
|
430
435
|
*/
|
|
431
436
|
cleanup() {
|
|
432
|
-
const cutoffTime = Date.now() -
|
|
437
|
+
const cutoffTime = Date.now() - this.config.warningRetentionDays * 24 * 60 * 60 * 1000;
|
|
433
438
|
// Remove old warnings
|
|
434
|
-
this.warnings = this.warnings.filter(w => w.timestamp > cutoffTime);
|
|
439
|
+
this.warnings = this.warnings.filter((w) => w.timestamp > cutoffTime);
|
|
435
440
|
// Remove old queries (keep last 24 hours)
|
|
436
|
-
const queryCutoff = Date.now() -
|
|
437
|
-
this.queryHistory = this.queryHistory.filter(q => q.timestamp > queryCutoff);
|
|
441
|
+
const queryCutoff = Date.now() - 24 * 60 * 60 * 1000;
|
|
442
|
+
this.queryHistory = this.queryHistory.filter((q) => q.timestamp > queryCutoff);
|
|
438
443
|
// Clean up recent queries
|
|
439
444
|
for (const [query, queries] of this.recentQueries.entries()) {
|
|
440
|
-
const recent = queries.filter(q => q.timestamp > queryCutoff);
|
|
445
|
+
const recent = queries.filter((q) => q.timestamp > queryCutoff);
|
|
441
446
|
if (recent.length === 0) {
|
|
442
447
|
this.recentQueries.delete(query);
|
|
443
448
|
}
|
|
@@ -21,7 +21,7 @@ export class QueryParser {
|
|
|
21
21
|
groupByColumns: this.extractGroupByColumns(normalized),
|
|
22
22
|
hasLimit: lowerQuery.includes('limit'),
|
|
23
23
|
hasAggregates: this.hasAggregates(normalized),
|
|
24
|
-
isComplex: this.isComplexQuery(normalized)
|
|
24
|
+
isComplex: this.isComplexQuery(normalized),
|
|
25
25
|
};
|
|
26
26
|
}
|
|
27
27
|
/**
|
|
@@ -58,7 +58,7 @@ export class QueryParser {
|
|
|
58
58
|
// FROM clause
|
|
59
59
|
const fromMatches = query.match(/from\s+(\w+)/gi);
|
|
60
60
|
if (fromMatches) {
|
|
61
|
-
fromMatches.forEach(match => {
|
|
61
|
+
fromMatches.forEach((match) => {
|
|
62
62
|
const table = match.split(/\s+/)[1];
|
|
63
63
|
if (table)
|
|
64
64
|
tables.add(table);
|
|
@@ -67,7 +67,7 @@ export class QueryParser {
|
|
|
67
67
|
// JOIN clauses
|
|
68
68
|
const joinMatches = query.match(/join\s+(\w+)/gi);
|
|
69
69
|
if (joinMatches) {
|
|
70
|
-
joinMatches.forEach(match => {
|
|
70
|
+
joinMatches.forEach((match) => {
|
|
71
71
|
const table = match.split(/\s+/)[1];
|
|
72
72
|
if (table)
|
|
73
73
|
tables.add(table);
|
|
@@ -85,7 +85,7 @@ export class QueryParser {
|
|
|
85
85
|
const whereClause = whereMatch[1];
|
|
86
86
|
const columnMatches = whereClause.match(/(\w+)\s*[=<>!]/g);
|
|
87
87
|
return columnMatches
|
|
88
|
-
? columnMatches.map(match => match.split(/\s+/)[0]).filter(Boolean)
|
|
88
|
+
? columnMatches.map((match) => match.split(/\s+/)[0]).filter(Boolean)
|
|
89
89
|
: [];
|
|
90
90
|
}
|
|
91
91
|
/**
|
|
@@ -114,7 +114,7 @@ export class QueryParser {
|
|
|
114
114
|
return [];
|
|
115
115
|
return orderByMatch[1]
|
|
116
116
|
.split(',')
|
|
117
|
-
.map(col => col.trim().split(/\s+/)[0])
|
|
117
|
+
.map((col) => col.trim().split(/\s+/)[0])
|
|
118
118
|
.filter(Boolean);
|
|
119
119
|
}
|
|
120
120
|
/**
|
|
@@ -126,7 +126,7 @@ export class QueryParser {
|
|
|
126
126
|
return [];
|
|
127
127
|
return groupByMatch[1]
|
|
128
128
|
.split(',')
|
|
129
|
-
.map(col => col.trim())
|
|
129
|
+
.map((col) => col.trim())
|
|
130
130
|
.filter(Boolean);
|
|
131
131
|
}
|
|
132
132
|
/**
|
|
@@ -134,25 +134,25 @@ export class QueryParser {
|
|
|
134
134
|
*/
|
|
135
135
|
static hasAggregates(query) {
|
|
136
136
|
const lowerQuery = query.toLowerCase();
|
|
137
|
-
return lowerQuery.includes('group by') ||
|
|
137
|
+
return (lowerQuery.includes('group by') ||
|
|
138
138
|
lowerQuery.includes('having') ||
|
|
139
139
|
lowerQuery.includes('count(') ||
|
|
140
140
|
lowerQuery.includes('sum(') ||
|
|
141
141
|
lowerQuery.includes('avg(') ||
|
|
142
142
|
lowerQuery.includes('max(') ||
|
|
143
|
-
lowerQuery.includes('min(');
|
|
143
|
+
lowerQuery.includes('min('));
|
|
144
144
|
}
|
|
145
145
|
/**
|
|
146
146
|
* Check if query is complex (joins, subqueries, etc.)
|
|
147
147
|
*/
|
|
148
148
|
static isComplexQuery(query) {
|
|
149
149
|
const lowerQuery = query.toLowerCase();
|
|
150
|
-
return lowerQuery.includes('join') ||
|
|
150
|
+
return (lowerQuery.includes('join') ||
|
|
151
151
|
lowerQuery.includes('subquery') ||
|
|
152
152
|
lowerQuery.includes('union') ||
|
|
153
153
|
lowerQuery.includes('except') ||
|
|
154
154
|
lowerQuery.includes('intersect') ||
|
|
155
|
-
(lowerQuery.includes('select') && lowerQuery.includes('('));
|
|
155
|
+
(lowerQuery.includes('select') && lowerQuery.includes('(')));
|
|
156
156
|
}
|
|
157
157
|
/**
|
|
158
158
|
* Check if query could return many rows
|
|
@@ -191,7 +191,7 @@ export class QueryParser {
|
|
|
191
191
|
*/
|
|
192
192
|
static generateCacheKey(query, params = []) {
|
|
193
193
|
const normalized = this.normalizeQuery(query);
|
|
194
|
-
const paramsKey = params.map(p => String(p)).join('|');
|
|
194
|
+
const paramsKey = params.map((p) => String(p)).join('|');
|
|
195
195
|
return `${normalized}:${paramsKey}`;
|
|
196
196
|
}
|
|
197
197
|
/**
|
|
@@ -237,12 +237,11 @@ export class QueryParser {
|
|
|
237
237
|
original: query,
|
|
238
238
|
frequency: 1,
|
|
239
239
|
averageTime: executionTime,
|
|
240
|
-
tables: parsed.tables
|
|
240
|
+
tables: parsed.tables,
|
|
241
241
|
});
|
|
242
242
|
}
|
|
243
243
|
}
|
|
244
|
-
return Array.from(patternMap.values())
|
|
245
|
-
.sort((a, b) => b.frequency - a.frequency);
|
|
244
|
+
return Array.from(patternMap.values()).sort((a, b) => b.frequency - a.frequency);
|
|
246
245
|
}
|
|
247
246
|
/**
|
|
248
247
|
* Detect potential N+1 query patterns
|
|
@@ -268,7 +267,7 @@ export class QueryParser {
|
|
|
268
267
|
let maxCountInWindow = 0;
|
|
269
268
|
for (const query of queries) {
|
|
270
269
|
const windowStart = query.timestamp - windowMs;
|
|
271
|
-
const countInWindow = queries.filter(q => q.timestamp >= windowStart && q.timestamp <= query.timestamp).length;
|
|
270
|
+
const countInWindow = queries.filter((q) => q.timestamp >= windowStart && q.timestamp <= query.timestamp).length;
|
|
272
271
|
maxCountInWindow = Math.max(maxCountInWindow, countInWindow);
|
|
273
272
|
}
|
|
274
273
|
if (maxCountInWindow >= 5) {
|
|
@@ -281,7 +280,7 @@ export class QueryParser {
|
|
|
281
280
|
pattern,
|
|
282
281
|
count: maxCountInWindow,
|
|
283
282
|
timeWindow: windowMs,
|
|
284
|
-
severity
|
|
283
|
+
severity,
|
|
285
284
|
});
|
|
286
285
|
break; // Only report the most severe pattern
|
|
287
286
|
}
|
|
@@ -8,7 +8,7 @@ import { parseTable } from '../parser/table-parser.js';
|
|
|
8
8
|
import { parseValueExpression } from '../parser/value-parser.js';
|
|
9
9
|
import { createQueryId } from '../util/query-id.js';
|
|
10
10
|
import { createRawBuilder } from './raw-builder.js';
|
|
11
|
-
import { validateColumnReference, validateTableReference, validateIdentifier } from '../util/security-validator.js';
|
|
11
|
+
import { validateColumnReference, validateTableReference, validateIdentifier, } from '../util/security-validator.js';
|
|
12
12
|
export const sql = Object.assign((sqlFragments, ...parameters) => {
|
|
13
13
|
return createRawBuilder({
|
|
14
14
|
queryId: createQueryId(),
|
|
@@ -39,7 +39,7 @@ export class RelationshipEngine {
|
|
|
39
39
|
*/
|
|
40
40
|
async loadEntityRelationships(entity, relations) {
|
|
41
41
|
for (const relationName of relations) {
|
|
42
|
-
const relationship = this.relationships.find(r => r.name === relationName);
|
|
42
|
+
const relationship = this.relationships.find((r) => r.name === relationName);
|
|
43
43
|
if (!relationship)
|
|
44
44
|
continue;
|
|
45
45
|
await this.loadSingleRelationship(entity, relationship);
|
|
@@ -50,7 +50,7 @@ export class RelationshipEngine {
|
|
|
50
50
|
*/
|
|
51
51
|
async batchLoadRelationships(entities, relations) {
|
|
52
52
|
for (const relationName of relations) {
|
|
53
|
-
const relationship = this.relationships.find(r => r.name === relationName);
|
|
53
|
+
const relationship = this.relationships.find((r) => r.name === relationName);
|
|
54
54
|
if (!relationship)
|
|
55
55
|
continue;
|
|
56
56
|
await this.batchLoadSingleRelationship(entities, relationship);
|
|
@@ -83,6 +83,7 @@ export class RelationshipEngine {
|
|
|
83
83
|
relatedData = await this.loadManyToManyRelationship(entity, relationship);
|
|
84
84
|
break;
|
|
85
85
|
}
|
|
86
|
+
;
|
|
86
87
|
entity[relationship.name] = relatedData;
|
|
87
88
|
}
|
|
88
89
|
/**
|
|
@@ -90,8 +91,8 @@ export class RelationshipEngine {
|
|
|
90
91
|
*/
|
|
91
92
|
async batchLoadSingleRelationship(entities, relationship) {
|
|
92
93
|
const entityValues = entities
|
|
93
|
-
.map(e => e[relationship.fromColumn])
|
|
94
|
-
.filter(v => v !== undefined && v !== null);
|
|
94
|
+
.map((e) => e[relationship.fromColumn])
|
|
95
|
+
.filter((v) => v !== undefined && v !== null);
|
|
95
96
|
if (entityValues.length === 0)
|
|
96
97
|
return;
|
|
97
98
|
let relatedData;
|
|
@@ -136,6 +137,7 @@ export class RelationshipEngine {
|
|
|
136
137
|
else {
|
|
137
138
|
entityRelatedData = groupedData.get(entityValue) || [];
|
|
138
139
|
}
|
|
140
|
+
;
|
|
139
141
|
entity[relationship.name] = entityRelatedData;
|
|
140
142
|
}
|
|
141
143
|
}
|
|
@@ -165,8 +167,8 @@ export class RelationshipEngine {
|
|
|
165
167
|
throw new Error('Many-to-many relationship requires throughTable');
|
|
166
168
|
}
|
|
167
169
|
const entityValues = entities
|
|
168
|
-
.map(e => e[relationship.fromColumn])
|
|
169
|
-
.filter(v => v !== undefined && v !== null);
|
|
170
|
+
.map((e) => e[relationship.fromColumn])
|
|
171
|
+
.filter((v) => v !== undefined && v !== null);
|
|
170
172
|
if (entityValues.length === 0)
|
|
171
173
|
return [];
|
|
172
174
|
return await this.db
|
|
@@ -180,7 +182,7 @@ export class RelationshipEngine {
|
|
|
180
182
|
* Get relationships for a specific table
|
|
181
183
|
*/
|
|
182
184
|
getRelationshipsForTable(tableName) {
|
|
183
|
-
return this.relationships.filter(r => r.fromTable === tableName);
|
|
185
|
+
return this.relationships.filter((r) => r.fromTable === tableName);
|
|
184
186
|
}
|
|
185
187
|
/**
|
|
186
188
|
* Get all relationships
|
|
@@ -198,6 +200,6 @@ export class RelationshipEngine {
|
|
|
198
200
|
* Remove a relationship
|
|
199
201
|
*/
|
|
200
202
|
removeRelationship(relationshipName) {
|
|
201
|
-
this.relationships = this.relationships.filter(r => r.name !== relationshipName);
|
|
203
|
+
this.relationships = this.relationships.filter((r) => r.name !== relationshipName);
|
|
202
204
|
}
|
|
203
205
|
}
|