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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="./repository-factory.d.ts" />
|
|
2
|
-
import { RelationshipNotFoundError, ColumnNotFoundError } from '../errors/NoormError.js';
|
|
2
|
+
import { RelationshipNotFoundError, ColumnNotFoundError, } from '../errors/NoormError.js';
|
|
3
3
|
import { RelationshipEngine } from '../relationships/relationship-engine.js';
|
|
4
4
|
import { CognitiveRepository } from '../agentic/CognitiveRepository.js';
|
|
5
5
|
/**
|
|
@@ -16,7 +16,9 @@ class DjangoManagerImpl {
|
|
|
16
16
|
this.table = table;
|
|
17
17
|
this.primaryKey = primaryKey;
|
|
18
18
|
this.transformer = transformer;
|
|
19
|
-
this.query =
|
|
19
|
+
this.query =
|
|
20
|
+
initialQuery ||
|
|
21
|
+
this.db.selectFrom(this.table.name).selectAll();
|
|
20
22
|
}
|
|
21
23
|
async all() {
|
|
22
24
|
return this.execute();
|
|
@@ -34,33 +36,53 @@ class DjangoManagerImpl {
|
|
|
34
36
|
const result = await q.executeTakeFirst();
|
|
35
37
|
return result ? this.transformer(result) : null;
|
|
36
38
|
}
|
|
37
|
-
filter(
|
|
39
|
+
filter(filterOrColumn, operator, value) {
|
|
38
40
|
let q = this.query;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
if (typeof filterOrColumn === 'object') {
|
|
42
|
+
for (const [key, val] of Object.entries(filterOrColumn)) {
|
|
43
|
+
if (val !== undefined) {
|
|
44
|
+
q = q.where(key, '=', val);
|
|
45
|
+
}
|
|
42
46
|
}
|
|
43
47
|
}
|
|
48
|
+
else if (operator && value !== undefined) {
|
|
49
|
+
q = q.where(filterOrColumn, operator, value);
|
|
50
|
+
}
|
|
44
51
|
return new DjangoManagerImpl(this.db, this.table, this.primaryKey, this.transformer, q);
|
|
45
52
|
}
|
|
46
|
-
exclude(
|
|
53
|
+
exclude(filterOrColumn, operator, value) {
|
|
47
54
|
let q = this.query;
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
55
|
+
if (typeof filterOrColumn === 'object') {
|
|
56
|
+
for (const [key, val] of Object.entries(filterOrColumn)) {
|
|
57
|
+
if (val !== undefined) {
|
|
58
|
+
q = q.where(key, '!=', val);
|
|
59
|
+
}
|
|
51
60
|
}
|
|
52
61
|
}
|
|
62
|
+
else if (operator && value !== undefined) {
|
|
63
|
+
// For simple exclude with operator, we invert the operator if possible or use !=
|
|
64
|
+
const negOperator = operator === '=' ? '!=' : operator === '!=' ? '=' : '!=';
|
|
65
|
+
q = q.where(filterOrColumn, negOperator, value);
|
|
66
|
+
}
|
|
53
67
|
return new DjangoManagerImpl(this.db, this.table, this.primaryKey, this.transformer, q);
|
|
54
68
|
}
|
|
55
69
|
order_by(...columns) {
|
|
56
70
|
let q = this.query;
|
|
57
71
|
for (const col of columns) {
|
|
58
72
|
const direction = String(col).startsWith('-') ? 'desc' : 'asc';
|
|
59
|
-
const actualCol = String(col).startsWith('-')
|
|
73
|
+
const actualCol = String(col).startsWith('-')
|
|
74
|
+
? String(col).substring(1)
|
|
75
|
+
: String(col);
|
|
60
76
|
q = q.orderBy(actualCol, direction);
|
|
61
77
|
}
|
|
62
78
|
return new DjangoManagerImpl(this.db, this.table, this.primaryKey, this.transformer, q);
|
|
63
79
|
}
|
|
80
|
+
limit(count) {
|
|
81
|
+
return new DjangoManagerImpl(this.db, this.table, this.primaryKey, this.transformer, this.query.limit(count));
|
|
82
|
+
}
|
|
83
|
+
offset(count) {
|
|
84
|
+
return new DjangoManagerImpl(this.db, this.table, this.primaryKey, this.transformer, this.query.offset(count));
|
|
85
|
+
}
|
|
64
86
|
async count() {
|
|
65
87
|
const result = await this.query
|
|
66
88
|
.clearSelect()
|
|
@@ -69,7 +91,9 @@ class DjangoManagerImpl {
|
|
|
69
91
|
return Number(result?.count || 0);
|
|
70
92
|
}
|
|
71
93
|
async exists() {
|
|
72
|
-
const result = await this.query
|
|
94
|
+
const result = await this.query
|
|
95
|
+
.select(this.primaryKey)
|
|
96
|
+
.executeTakeFirst();
|
|
73
97
|
return result !== undefined;
|
|
74
98
|
}
|
|
75
99
|
async first() {
|
|
@@ -77,7 +101,10 @@ class DjangoManagerImpl {
|
|
|
77
101
|
return result ? this.transformer(result) : null;
|
|
78
102
|
}
|
|
79
103
|
async last() {
|
|
80
|
-
const result = await this.query
|
|
104
|
+
const result = await this.query
|
|
105
|
+
.orderBy(this.primaryKey, 'desc')
|
|
106
|
+
.limit(1)
|
|
107
|
+
.executeTakeFirst();
|
|
81
108
|
return result ? this.transformer(result) : null;
|
|
82
109
|
}
|
|
83
110
|
async create(data) {
|
|
@@ -136,14 +163,17 @@ export class RepositoryFactory {
|
|
|
136
163
|
*/
|
|
137
164
|
transformData(data, table) {
|
|
138
165
|
const booleanColumns = table.columns
|
|
139
|
-
.filter(col => col.type.toLowerCase() === 'boolean' ||
|
|
140
|
-
.
|
|
166
|
+
.filter((col) => col.type.toLowerCase() === 'boolean' ||
|
|
167
|
+
col.type.toLowerCase() === 'bool')
|
|
168
|
+
.map((col) => col.name);
|
|
141
169
|
const dateColumns = table.columns
|
|
142
|
-
.filter(col => {
|
|
170
|
+
.filter((col) => {
|
|
143
171
|
const type = col.type.toLowerCase();
|
|
144
|
-
return type.includes('date') ||
|
|
172
|
+
return (type.includes('date') ||
|
|
173
|
+
type.includes('timestamp') ||
|
|
174
|
+
type.includes('time'));
|
|
145
175
|
})
|
|
146
|
-
.map(col => col.name);
|
|
176
|
+
.map((col) => col.name);
|
|
147
177
|
if (booleanColumns.length === 0 && dateColumns.length === 0)
|
|
148
178
|
return data;
|
|
149
179
|
const transformRecord = (record) => {
|
|
@@ -164,7 +194,8 @@ export class RepositoryFactory {
|
|
|
164
194
|
// Transform dates
|
|
165
195
|
for (const col of dateColumns) {
|
|
166
196
|
if (col in transformed && transformed[col]) {
|
|
167
|
-
if (typeof transformed[col] === 'string' ||
|
|
197
|
+
if (typeof transformed[col] === 'string' ||
|
|
198
|
+
typeof transformed[col] === 'number') {
|
|
168
199
|
const date = new Date(transformed[col]);
|
|
169
200
|
if (!isNaN(date.getTime()))
|
|
170
201
|
transformed[col] = date;
|
|
@@ -173,14 +204,16 @@ export class RepositoryFactory {
|
|
|
173
204
|
}
|
|
174
205
|
return transformed;
|
|
175
206
|
};
|
|
176
|
-
return Array.isArray(data)
|
|
207
|
+
return Array.isArray(data)
|
|
208
|
+
? data.map(transformRecord)
|
|
209
|
+
: transformRecord(data);
|
|
177
210
|
}
|
|
178
211
|
/**
|
|
179
212
|
* Create a repository for the specified table
|
|
180
213
|
*/
|
|
181
214
|
createRepository(table, relationships) {
|
|
182
215
|
this.setRelationships(relationships);
|
|
183
|
-
const primaryKey = table.columns.find(c => c.isPrimaryKey)?.name || 'id';
|
|
216
|
+
const primaryKey = table.columns.find((c) => c.isPrimaryKey)?.name || 'id';
|
|
184
217
|
const transformer = (data) => this.transformData(data, table);
|
|
185
218
|
const baseRepository = {
|
|
186
219
|
objects: new DjangoManagerImpl(this.db, table, primaryKey, transformer),
|
|
@@ -193,7 +226,10 @@ export class RepositoryFactory {
|
|
|
193
226
|
return result ? transformer(result) : null;
|
|
194
227
|
},
|
|
195
228
|
findAll: async () => {
|
|
196
|
-
const results = await this.db
|
|
229
|
+
const results = await this.db
|
|
230
|
+
.selectFrom(table.name)
|
|
231
|
+
.selectAll()
|
|
232
|
+
.execute();
|
|
197
233
|
return transformer(results);
|
|
198
234
|
},
|
|
199
235
|
create: async (data) => {
|
|
@@ -217,20 +253,32 @@ export class RepositoryFactory {
|
|
|
217
253
|
return transformer(result);
|
|
218
254
|
},
|
|
219
255
|
delete: async (id) => {
|
|
220
|
-
const result = await this.db
|
|
256
|
+
const result = await this.db
|
|
257
|
+
.deleteFrom(table.name)
|
|
258
|
+
.where(primaryKey, '=', id)
|
|
259
|
+
.executeTakeFirst();
|
|
221
260
|
return Number(result.numDeletedRows || 0) > 0;
|
|
222
261
|
},
|
|
223
262
|
count: async () => {
|
|
224
|
-
const result = await this.db
|
|
263
|
+
const result = await this.db
|
|
264
|
+
.selectFrom(table.name)
|
|
265
|
+
.select((eb) => eb.fn.countAll().as('count'))
|
|
266
|
+
.executeTakeFirst();
|
|
225
267
|
return Number(result?.count || 0);
|
|
226
268
|
},
|
|
227
269
|
exists: async (id) => {
|
|
228
|
-
const result = await this.db
|
|
270
|
+
const result = await this.db
|
|
271
|
+
.selectFrom(table.name)
|
|
272
|
+
.select(primaryKey)
|
|
273
|
+
.where(primaryKey, '=', id)
|
|
274
|
+
.executeTakeFirst();
|
|
229
275
|
return result !== undefined;
|
|
230
276
|
},
|
|
231
277
|
paginate: async (options) => {
|
|
232
278
|
let query = this.db.selectFrom(table.name).selectAll();
|
|
233
|
-
let countQuery = this.db
|
|
279
|
+
let countQuery = this.db
|
|
280
|
+
.selectFrom(table.name)
|
|
281
|
+
.select((eb) => eb.fn.countAll().as('count'));
|
|
234
282
|
if (options.where) {
|
|
235
283
|
for (const [key, value] of Object.entries(options.where)) {
|
|
236
284
|
if (value !== undefined) {
|
|
@@ -254,8 +302,8 @@ export class RepositoryFactory {
|
|
|
254
302
|
total,
|
|
255
303
|
totalPages,
|
|
256
304
|
hasNext: options.page < totalPages,
|
|
257
|
-
hasPrev: options.page > 1
|
|
258
|
-
}
|
|
305
|
+
hasPrev: options.page > 1,
|
|
306
|
+
},
|
|
259
307
|
};
|
|
260
308
|
},
|
|
261
309
|
findWithRelations: async (id, relations) => {
|
|
@@ -271,23 +319,27 @@ export class RepositoryFactory {
|
|
|
271
319
|
await this.relationshipEngine.loadRelationships(entities, relations);
|
|
272
320
|
},
|
|
273
321
|
withCount: async (id, relationshipNames) => {
|
|
274
|
-
const entity = await baseRepository.findById(id);
|
|
322
|
+
const entity = (await baseRepository.findById(id));
|
|
275
323
|
if (!entity)
|
|
276
324
|
throw new Error(`Entity ${id} not found`);
|
|
277
|
-
const tableRelationships = relationships.filter(r => r.fromTable === table.name);
|
|
325
|
+
const tableRelationships = relationships.filter((r) => r.fromTable === table.name);
|
|
278
326
|
const counts = {};
|
|
279
327
|
for (const name of relationshipNames) {
|
|
280
|
-
const rel = tableRelationships.find(r => r.name === name);
|
|
328
|
+
const rel = tableRelationships.find((r) => r.name === name);
|
|
281
329
|
if (!rel)
|
|
282
|
-
throw new RelationshipNotFoundError(name, table.name, tableRelationships.map(r => r.name));
|
|
330
|
+
throw new RelationshipNotFoundError(name, table.name, tableRelationships.map((r) => r.name));
|
|
283
331
|
const val = entity[rel.fromColumn];
|
|
284
332
|
if (val !== undefined) {
|
|
285
|
-
const res = await this.db
|
|
333
|
+
const res = await this.db
|
|
334
|
+
.selectFrom(rel.toTable)
|
|
335
|
+
.select((eb) => eb.fn.countAll().as('count'))
|
|
336
|
+
.where(rel.toColumn, '=', val)
|
|
337
|
+
.executeTakeFirst();
|
|
286
338
|
counts[`${name}Count`] = Number(res?.count || 0);
|
|
287
339
|
}
|
|
288
340
|
}
|
|
289
341
|
return { ...entity, ...counts };
|
|
290
|
-
}
|
|
342
|
+
},
|
|
291
343
|
};
|
|
292
344
|
let repository = this.wrapWithDynamicMethods(baseRepository, table);
|
|
293
345
|
if (this.cortex)
|
|
@@ -295,7 +347,7 @@ export class RepositoryFactory {
|
|
|
295
347
|
return repository;
|
|
296
348
|
}
|
|
297
349
|
wrapWithDynamicMethods(repository, table) {
|
|
298
|
-
const availableColumns = table.columns.map(c => c.name);
|
|
350
|
+
const availableColumns = table.columns.map((c) => c.name);
|
|
299
351
|
const db = this.db;
|
|
300
352
|
const transformer = (data) => this.transformData(data, table);
|
|
301
353
|
return new Proxy(repository, {
|
|
@@ -304,16 +356,23 @@ export class RepositoryFactory {
|
|
|
304
356
|
return Reflect.get(target, prop, receiver);
|
|
305
357
|
if (typeof prop === 'string' && prop.startsWith('findBy')) {
|
|
306
358
|
return async (value) => {
|
|
307
|
-
const columnName = prop
|
|
308
|
-
|
|
359
|
+
const columnName = prop
|
|
360
|
+
.substring(6)
|
|
361
|
+
.replace(/([a-z])([A-Z])/g, '$1_$2')
|
|
362
|
+
.toLowerCase();
|
|
363
|
+
const actualColumn = availableColumns.find((col) => col.toLowerCase() === columnName.toLowerCase());
|
|
309
364
|
if (!actualColumn)
|
|
310
365
|
throw new ColumnNotFoundError(columnName, table.name, availableColumns);
|
|
311
|
-
const result = await db
|
|
366
|
+
const result = await db
|
|
367
|
+
.selectFrom(table.name)
|
|
368
|
+
.selectAll()
|
|
369
|
+
.where(actualColumn, '=', value)
|
|
370
|
+
.executeTakeFirst();
|
|
312
371
|
return transformer(result || null);
|
|
313
372
|
};
|
|
314
373
|
}
|
|
315
374
|
return undefined;
|
|
316
|
-
}
|
|
375
|
+
},
|
|
317
376
|
});
|
|
318
377
|
}
|
|
319
378
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/// <reference types="./alter-table-add-index-builder.d.ts" />
|
|
2
2
|
import { AddIndexNode } from '../../operation-node/add-index-node.js';
|
|
3
3
|
import { AlterTableNode } from '../../operation-node/alter-table-node.js';
|
|
4
|
-
import { IndexTypeNode } from '../../operation-node/index-type-node.js';
|
|
4
|
+
import { IndexTypeNode, } from '../../operation-node/index-type-node.js';
|
|
5
5
|
import { parseOrderedColumnName, } from '../../parser/reference-parser.js';
|
|
6
6
|
import { freeze } from '../../util/object-utils.js';
|
|
7
7
|
export class AlterTableAddIndexBuilder {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference types="./create-index-builder.d.ts" />
|
|
2
|
-
import { CreateIndexNode
|
|
3
|
-
import { IndexTypeNode } from '../../operation-node/index-type-node.js';
|
|
2
|
+
import { CreateIndexNode } from '../../operation-node/create-index-node.js';
|
|
3
|
+
import { IndexTypeNode, } from '../../operation-node/index-type-node.js';
|
|
4
4
|
import { parseOrderedColumnName, } from '../../parser/reference-parser.js';
|
|
5
5
|
import { parseTable } from '../../parser/table-parser.js';
|
|
6
6
|
import { freeze } from '../../util/object-utils.js';
|
|
@@ -22,9 +22,7 @@ export class SchemaDiscoveryCoordinator {
|
|
|
22
22
|
*/
|
|
23
23
|
async discoverSchema(db, config = {}, dialect) {
|
|
24
24
|
// Determine the dialect - handle both string and dialect objects
|
|
25
|
-
const dialectName = typeof dialect === 'string'
|
|
26
|
-
? dialect
|
|
27
|
-
: dialect?.name || 'sqlite';
|
|
25
|
+
const dialectName = typeof dialect === 'string' ? dialect : dialect?.name || 'sqlite';
|
|
28
26
|
this.currentDialect = dialectName;
|
|
29
27
|
// Check if dialect is supported
|
|
30
28
|
if (!this.factory.isDialectSupported(dialectName)) {
|
|
@@ -20,7 +20,7 @@ export class RelationshipDiscovery {
|
|
|
20
20
|
for (const table of tables) {
|
|
21
21
|
for (const fk of table.foreignKeys) {
|
|
22
22
|
// Find the referenced table
|
|
23
|
-
const referencedTable = tables.find(t => t.name === fk.referencedTable);
|
|
23
|
+
const referencedTable = tables.find((t) => t.name === fk.referencedTable);
|
|
24
24
|
if (!referencedTable)
|
|
25
25
|
continue;
|
|
26
26
|
// Create relationship name based on column name
|
|
@@ -34,7 +34,7 @@ export class RelationshipDiscovery {
|
|
|
34
34
|
fromTable: table.name,
|
|
35
35
|
fromColumn: fk.column,
|
|
36
36
|
toTable: fk.referencedTable,
|
|
37
|
-
toColumn: fk.referencedColumn
|
|
37
|
+
toColumn: fk.referencedColumn,
|
|
38
38
|
});
|
|
39
39
|
// Add reverse relationship
|
|
40
40
|
const reverseName = NameGenerator.generateReverseRelationshipName(table.name, fk.column);
|
|
@@ -44,7 +44,7 @@ export class RelationshipDiscovery {
|
|
|
44
44
|
fromTable: fk.referencedTable,
|
|
45
45
|
fromColumn: fk.referencedColumn,
|
|
46
46
|
toTable: table.name,
|
|
47
|
-
toColumn: fk.column
|
|
47
|
+
toColumn: fk.column,
|
|
48
48
|
});
|
|
49
49
|
}
|
|
50
50
|
}
|
|
@@ -64,7 +64,7 @@ export class RelationshipDiscovery {
|
|
|
64
64
|
toColumn: fk2.referencedColumn,
|
|
65
65
|
throughTable: table.name,
|
|
66
66
|
throughFromColumn: fk1.column,
|
|
67
|
-
throughToColumn: fk2.column
|
|
67
|
+
throughToColumn: fk2.column,
|
|
68
68
|
});
|
|
69
69
|
// B -> A via Table
|
|
70
70
|
relationships.push({
|
|
@@ -76,7 +76,7 @@ export class RelationshipDiscovery {
|
|
|
76
76
|
toColumn: fk1.referencedColumn,
|
|
77
77
|
throughTable: table.name,
|
|
78
78
|
throughFromColumn: fk2.column,
|
|
79
|
-
throughToColumn: fk1.column
|
|
79
|
+
throughToColumn: fk1.column,
|
|
80
80
|
});
|
|
81
81
|
}
|
|
82
82
|
}
|
|
@@ -91,7 +91,7 @@ export class RelationshipDiscovery {
|
|
|
91
91
|
oneToMany: 0,
|
|
92
92
|
manyToMany: 0,
|
|
93
93
|
selfReferencing: 0,
|
|
94
|
-
circularReferences: []
|
|
94
|
+
circularReferences: [],
|
|
95
95
|
};
|
|
96
96
|
for (const table of tables) {
|
|
97
97
|
for (const fk of table.foreignKeys) {
|
|
@@ -100,7 +100,7 @@ export class RelationshipDiscovery {
|
|
|
100
100
|
patterns.selfReferencing++;
|
|
101
101
|
}
|
|
102
102
|
// Check for many-to-many (junction tables)
|
|
103
|
-
const referencedTable = tables.find(t => t.name === fk.referencedTable);
|
|
103
|
+
const referencedTable = tables.find((t) => t.name === fk.referencedTable);
|
|
104
104
|
if (referencedTable && this.isJunctionTable(table)) {
|
|
105
105
|
patterns.manyToMany++;
|
|
106
106
|
}
|
|
@@ -122,10 +122,10 @@ export class RelationshipDiscovery {
|
|
|
122
122
|
if (table.foreignKeys.length !== 2)
|
|
123
123
|
return false;
|
|
124
124
|
// 2. Mostly columns that are either PK or part of FKs
|
|
125
|
-
const fkColumns = new Set(table.foreignKeys.map(fk => fk.column));
|
|
125
|
+
const fkColumns = new Set(table.foreignKeys.map((fk) => fk.column));
|
|
126
126
|
const pkColumns = new Set(table.primaryKey || []);
|
|
127
|
-
const otherColumns = table.columns.filter(col => !fkColumns.has(col.name) && !pkColumns.has(col.name));
|
|
128
|
-
// If it has too many "data" columns, it might not be a pure junction table,
|
|
127
|
+
const otherColumns = table.columns.filter((col) => !fkColumns.has(col.name) && !pkColumns.has(col.name));
|
|
128
|
+
// If it has too many "data" columns, it might not be a pure junction table,
|
|
129
129
|
// but we can still treat it as one for M2M navigation if it has 2 FKs.
|
|
130
130
|
// Pure junction tables usually have 0-1 extra columns (like 'created_at').
|
|
131
131
|
return otherColumns.length <= 2;
|
|
@@ -148,7 +148,7 @@ export class RelationshipDiscovery {
|
|
|
148
148
|
return;
|
|
149
149
|
visited.add(tableName);
|
|
150
150
|
recursionStack.add(tableName);
|
|
151
|
-
const table = tables.find(t => t.name === tableName);
|
|
151
|
+
const table = tables.find((t) => t.name === tableName);
|
|
152
152
|
if (table) {
|
|
153
153
|
for (const fk of table.foreignKeys) {
|
|
154
154
|
dfs(fk.referencedTable, [...path, tableName]);
|
|
@@ -168,7 +168,7 @@ export class RelationshipDiscovery {
|
|
|
168
168
|
*/
|
|
169
169
|
validateRelationships(tables) {
|
|
170
170
|
const issues = [];
|
|
171
|
-
const tableNames = new Set(tables.map(t => t.name));
|
|
171
|
+
const tableNames = new Set(tables.map((t) => t.name));
|
|
172
172
|
for (const table of tables) {
|
|
173
173
|
for (const fk of table.foreignKeys) {
|
|
174
174
|
// Check if referenced table exists
|
|
@@ -176,15 +176,15 @@ export class RelationshipDiscovery {
|
|
|
176
176
|
issues.push(`Foreign key '${fk.name}' in table '${table.name}' references non-existent table '${fk.referencedTable}'`);
|
|
177
177
|
}
|
|
178
178
|
// Check if referenced column exists in referenced table
|
|
179
|
-
const referencedTable = tables.find(t => t.name === fk.referencedTable);
|
|
179
|
+
const referencedTable = tables.find((t) => t.name === fk.referencedTable);
|
|
180
180
|
if (referencedTable) {
|
|
181
|
-
const referencedColumnExists = referencedTable.columns.some(col => col.name === fk.referencedColumn);
|
|
181
|
+
const referencedColumnExists = referencedTable.columns.some((col) => col.name === fk.referencedColumn);
|
|
182
182
|
if (!referencedColumnExists) {
|
|
183
183
|
issues.push(`Foreign key '${fk.name}' in table '${table.name}' references non-existent column '${fk.referencedColumn}' in table '${fk.referencedTable}'`);
|
|
184
184
|
}
|
|
185
185
|
}
|
|
186
186
|
// Check if foreign key column exists
|
|
187
|
-
const fkColumnExists = table.columns.some(col => col.name === fk.column);
|
|
187
|
+
const fkColumnExists = table.columns.some((col) => col.name === fk.column);
|
|
188
188
|
if (!fkColumnExists) {
|
|
189
189
|
issues.push(`Foreign key '${fk.name}' in table '${table.name}' references non-existent column '${fk.column}'`);
|
|
190
190
|
}
|
|
@@ -192,7 +192,7 @@ export class RelationshipDiscovery {
|
|
|
192
192
|
}
|
|
193
193
|
return {
|
|
194
194
|
isValid: issues.length === 0,
|
|
195
|
-
issues
|
|
195
|
+
issues,
|
|
196
196
|
};
|
|
197
197
|
}
|
|
198
198
|
}
|
|
@@ -38,7 +38,7 @@ export class TableMetadataDiscovery {
|
|
|
38
38
|
const [columns, indexes, foreignKeys] = await Promise.all([
|
|
39
39
|
introspector.getColumns(table.name).catch(() => []),
|
|
40
40
|
introspector.getIndexes(table.name).catch(() => []),
|
|
41
|
-
introspector.getForeignKeys(table.name).catch(() => [])
|
|
41
|
+
introspector.getForeignKeys(table.name).catch(() => []),
|
|
42
42
|
]);
|
|
43
43
|
// Find primary key columns
|
|
44
44
|
const primaryKeyColumns = columns
|
|
@@ -52,7 +52,7 @@ export class TableMetadataDiscovery {
|
|
|
52
52
|
indexes: indexes.map((idx) => ({
|
|
53
53
|
name: idx.name,
|
|
54
54
|
columns: idx.columns,
|
|
55
|
-
unique: idx.unique
|
|
55
|
+
unique: idx.unique,
|
|
56
56
|
})),
|
|
57
57
|
foreignKeys: foreignKeys.map((fk) => ({
|
|
58
58
|
name: fk.name,
|
|
@@ -60,8 +60,8 @@ export class TableMetadataDiscovery {
|
|
|
60
60
|
referencedTable: fk.referencedTable,
|
|
61
61
|
referencedColumn: fk.referencedColumn,
|
|
62
62
|
onDelete: fk.onDelete,
|
|
63
|
-
onUpdate: fk.onUpdate
|
|
64
|
-
}))
|
|
63
|
+
onUpdate: fk.onUpdate,
|
|
64
|
+
})),
|
|
65
65
|
};
|
|
66
66
|
}
|
|
67
67
|
catch (error) {
|
|
@@ -84,8 +84,8 @@ export class TableMetadataDiscovery {
|
|
|
84
84
|
indexCount: indexes.length,
|
|
85
85
|
foreignKeyCount: foreignKeys.length,
|
|
86
86
|
lastModified: new Date(), // Fallback
|
|
87
|
-
indexes: indexes.map(idx => idx.name),
|
|
88
|
-
constraints: foreignKeys.map(fk => fk.name)
|
|
87
|
+
indexes: indexes.map((idx) => idx.name),
|
|
88
|
+
constraints: foreignKeys.map((fk) => fk.name),
|
|
89
89
|
};
|
|
90
90
|
}
|
|
91
91
|
catch (error) {
|
|
@@ -106,7 +106,7 @@ export class TableMetadataDiscovery {
|
|
|
106
106
|
issues.push('Table must have at least one column');
|
|
107
107
|
}
|
|
108
108
|
// Check for duplicate column names
|
|
109
|
-
const columnNames = table.columns.map(col => col.name);
|
|
109
|
+
const columnNames = table.columns.map((col) => col.name);
|
|
110
110
|
const duplicates = columnNames.filter((name, index) => columnNames.indexOf(name) !== index);
|
|
111
111
|
if (duplicates.length > 0) {
|
|
112
112
|
issues.push(`Duplicate column names found: ${duplicates.join(', ')}`);
|
|
@@ -114,14 +114,14 @@ export class TableMetadataDiscovery {
|
|
|
114
114
|
// Check for valid primary key
|
|
115
115
|
if (table.primaryKey && table.primaryKey.length > 0) {
|
|
116
116
|
const primaryKeyColumns = table.primaryKey;
|
|
117
|
-
const invalidPkColumns = primaryKeyColumns.filter(pkCol => !table.columns.some(col => col.name === pkCol));
|
|
117
|
+
const invalidPkColumns = primaryKeyColumns.filter((pkCol) => !table.columns.some((col) => col.name === pkCol));
|
|
118
118
|
if (invalidPkColumns.length > 0) {
|
|
119
119
|
issues.push(`Primary key references non-existent columns: ${invalidPkColumns.join(', ')}`);
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
122
|
return {
|
|
123
123
|
isValid: issues.length === 0,
|
|
124
|
-
issues
|
|
124
|
+
issues,
|
|
125
125
|
};
|
|
126
126
|
}
|
|
127
127
|
}
|
|
@@ -25,8 +25,9 @@ export class ViewDiscovery {
|
|
|
25
25
|
views.push({
|
|
26
26
|
name: table.name,
|
|
27
27
|
schema: table.schema,
|
|
28
|
-
definition: (await this.getViewDefinition(introspector, table.name)) ??
|
|
29
|
-
|
|
28
|
+
definition: (await this.getViewDefinition(introspector, table.name)) ??
|
|
29
|
+
undefined,
|
|
30
|
+
columns: [], // Views don't have explicit columns in this context
|
|
30
31
|
});
|
|
31
32
|
}
|
|
32
33
|
}
|
|
@@ -81,7 +82,7 @@ export class ViewDiscovery {
|
|
|
81
82
|
/UPDATE\s+SET/i,
|
|
82
83
|
/INSERT\s+INTO/i,
|
|
83
84
|
/TRUNCATE/i,
|
|
84
|
-
/ALTER\s+TABLE/i
|
|
85
|
+
/ALTER\s+TABLE/i,
|
|
85
86
|
];
|
|
86
87
|
if (view.definition) {
|
|
87
88
|
for (const pattern of dangerousPatterns) {
|
|
@@ -92,7 +93,7 @@ export class ViewDiscovery {
|
|
|
92
93
|
}
|
|
93
94
|
return {
|
|
94
95
|
isValid: issues.length === 0,
|
|
95
|
-
issues
|
|
96
|
+
issues,
|
|
96
97
|
};
|
|
97
98
|
}
|
|
98
99
|
/**
|
|
@@ -88,7 +88,7 @@ export class DiscoveryFactory {
|
|
|
88
88
|
relationshipDiscovery: this.createRelationshipDiscovery(),
|
|
89
89
|
viewDiscovery: this.createViewDiscovery(),
|
|
90
90
|
indexDiscovery: this.createIndexDiscovery(dialect),
|
|
91
|
-
constraintDiscovery: this.createConstraintDiscovery(dialect)
|
|
91
|
+
constraintDiscovery: this.createConstraintDiscovery(dialect),
|
|
92
92
|
};
|
|
93
93
|
}
|
|
94
94
|
/**
|
|
@@ -115,7 +115,7 @@ export class DiscoveryFactory {
|
|
|
115
115
|
supportsConstraints: true,
|
|
116
116
|
supportsForeignKeys: true,
|
|
117
117
|
supportsCheckConstraints: true,
|
|
118
|
-
supportsDeferredConstraints: false
|
|
118
|
+
supportsDeferredConstraints: false,
|
|
119
119
|
};
|
|
120
120
|
case 'postgres':
|
|
121
121
|
case 'postgresql':
|
|
@@ -125,7 +125,7 @@ export class DiscoveryFactory {
|
|
|
125
125
|
supportsConstraints: true,
|
|
126
126
|
supportsForeignKeys: true,
|
|
127
127
|
supportsCheckConstraints: true,
|
|
128
|
-
supportsDeferredConstraints: true
|
|
128
|
+
supportsDeferredConstraints: true,
|
|
129
129
|
};
|
|
130
130
|
default:
|
|
131
131
|
return {
|
|
@@ -134,7 +134,7 @@ export class DiscoveryFactory {
|
|
|
134
134
|
supportsConstraints: false,
|
|
135
135
|
supportsForeignKeys: false,
|
|
136
136
|
supportsCheckConstraints: false,
|
|
137
|
-
supportsDeferredConstraints: false
|
|
137
|
+
supportsDeferredConstraints: false,
|
|
138
138
|
};
|
|
139
139
|
}
|
|
140
140
|
}
|
|
@@ -56,9 +56,13 @@ export class NameGenerator {
|
|
|
56
56
|
}
|
|
57
57
|
// Handle words that are already plural
|
|
58
58
|
// Common plural endings that shouldn't be pluralized further
|
|
59
|
-
if (str.endsWith('ses') ||
|
|
60
|
-
str.endsWith('
|
|
61
|
-
str.endsWith('
|
|
59
|
+
if (str.endsWith('ses') ||
|
|
60
|
+
str.endsWith('xes') ||
|
|
61
|
+
str.endsWith('zes') ||
|
|
62
|
+
str.endsWith('ches') ||
|
|
63
|
+
str.endsWith('shes') ||
|
|
64
|
+
str.endsWith('ies') ||
|
|
65
|
+
str.endsWith('ves')) {
|
|
62
66
|
return str;
|
|
63
67
|
}
|
|
64
68
|
// Handle words ending in 's' - likely already plural
|
|
@@ -71,11 +75,16 @@ export class NameGenerator {
|
|
|
71
75
|
return str;
|
|
72
76
|
}
|
|
73
77
|
// Handle words ending in 'y' preceded by a consonant
|
|
74
|
-
if (str.endsWith('y') &&
|
|
78
|
+
if (str.endsWith('y') &&
|
|
79
|
+
str.length > 1 &&
|
|
80
|
+
!'aeiou'.includes(str[str.length - 2])) {
|
|
75
81
|
return str.slice(0, -1) + 'ies';
|
|
76
82
|
}
|
|
77
83
|
// Handle words ending in sh, ch, x, z
|
|
78
|
-
if (str.endsWith('sh') ||
|
|
84
|
+
if (str.endsWith('sh') ||
|
|
85
|
+
str.endsWith('ch') ||
|
|
86
|
+
str.endsWith('x') ||
|
|
87
|
+
str.endsWith('z')) {
|
|
79
88
|
return str + 'es';
|
|
80
89
|
}
|
|
81
90
|
// Default: add 's'
|