@pattern-stack/codegen 0.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/CHANGELOG.md +67 -0
- package/README.md +214 -0
- package/dist/runtime/analytics/index.d.ts +6 -0
- package/dist/runtime/analytics/index.js +49 -0
- package/dist/runtime/analytics/index.js.map +1 -0
- package/dist/runtime/analytics/metrics.d.ts +75 -0
- package/dist/runtime/analytics/metrics.js +1 -0
- package/dist/runtime/analytics/metrics.js.map +1 -0
- package/dist/runtime/analytics/packs/crm-entity-measures.d.ts +21 -0
- package/dist/runtime/analytics/packs/crm-entity-measures.js +1 -0
- package/dist/runtime/analytics/packs/crm-entity-measures.js.map +1 -0
- package/dist/runtime/analytics/packs/index.d.ts +3 -0
- package/dist/runtime/analytics/packs/index.js +1 -0
- package/dist/runtime/analytics/packs/index.js.map +1 -0
- package/dist/runtime/analytics/packs/monetary-measures.d.ts +21 -0
- package/dist/runtime/analytics/packs/monetary-measures.js +1 -0
- package/dist/runtime/analytics/packs/monetary-measures.js.map +1 -0
- package/dist/runtime/analytics/specs.d.ts +49 -0
- package/dist/runtime/analytics/specs.js +1 -0
- package/dist/runtime/analytics/specs.js.map +1 -0
- package/dist/runtime/analytics/types.d.ts +85 -0
- package/dist/runtime/analytics/types.js +49 -0
- package/dist/runtime/analytics/types.js.map +1 -0
- package/dist/runtime/base-classes/activity-entity-repository.d.ts +26 -0
- package/dist/runtime/base-classes/activity-entity-repository.js +195 -0
- package/dist/runtime/base-classes/activity-entity-repository.js.map +1 -0
- package/dist/runtime/base-classes/activity-entity-service.d.ts +39 -0
- package/dist/runtime/base-classes/activity-entity-service.js +214 -0
- package/dist/runtime/base-classes/activity-entity-service.js.map +1 -0
- package/dist/runtime/base-classes/base-read-use-cases.d.ts +68 -0
- package/dist/runtime/base-classes/base-read-use-cases.js +32 -0
- package/dist/runtime/base-classes/base-read-use-cases.js.map +1 -0
- package/dist/runtime/base-classes/base-repository.d.ts +99 -0
- package/dist/runtime/base-classes/base-repository.js +160 -0
- package/dist/runtime/base-classes/base-repository.js.map +1 -0
- package/dist/runtime/base-classes/base-service.d.ts +98 -0
- package/dist/runtime/base-classes/base-service.js +186 -0
- package/dist/runtime/base-classes/base-service.js.map +1 -0
- package/dist/runtime/base-classes/index.d.ts +18 -0
- package/dist/runtime/base-classes/index.js +617 -0
- package/dist/runtime/base-classes/index.js.map +1 -0
- package/dist/runtime/base-classes/knowledge-entity-repository.d.ts +17 -0
- package/dist/runtime/base-classes/knowledge-entity-repository.js +166 -0
- package/dist/runtime/base-classes/knowledge-entity-repository.js.map +1 -0
- package/dist/runtime/base-classes/knowledge-entity-service.d.ts +15 -0
- package/dist/runtime/base-classes/knowledge-entity-service.js +192 -0
- package/dist/runtime/base-classes/knowledge-entity-service.js.map +1 -0
- package/dist/runtime/base-classes/lifecycle-events.d.ts +49 -0
- package/dist/runtime/base-classes/lifecycle-events.js +76 -0
- package/dist/runtime/base-classes/lifecycle-events.js.map +1 -0
- package/dist/runtime/base-classes/metadata-entity-repository.d.ts +27 -0
- package/dist/runtime/base-classes/metadata-entity-repository.js +212 -0
- package/dist/runtime/base-classes/metadata-entity-repository.js.map +1 -0
- package/dist/runtime/base-classes/metadata-entity-service.d.ts +39 -0
- package/dist/runtime/base-classes/metadata-entity-service.js +214 -0
- package/dist/runtime/base-classes/metadata-entity-service.js.map +1 -0
- package/dist/runtime/base-classes/synced-entity-repository.d.ts +32 -0
- package/dist/runtime/base-classes/synced-entity-repository.js +203 -0
- package/dist/runtime/base-classes/synced-entity-repository.js.map +1 -0
- package/dist/runtime/base-classes/synced-entity-service.d.ts +41 -0
- package/dist/runtime/base-classes/synced-entity-service.js +215 -0
- package/dist/runtime/base-classes/synced-entity-service.js.map +1 -0
- package/dist/runtime/base-classes/with-analytics.d.ts +18 -0
- package/dist/runtime/base-classes/with-analytics.js +11 -0
- package/dist/runtime/base-classes/with-analytics.js.map +1 -0
- package/dist/runtime/constants/tokens.d.ts +29 -0
- package/dist/runtime/constants/tokens.js +8 -0
- package/dist/runtime/constants/tokens.js.map +1 -0
- package/dist/runtime/subsystems/analytics/analytics-query.protocol.d.ts +30 -0
- package/dist/runtime/subsystems/analytics/analytics-query.protocol.js +1 -0
- package/dist/runtime/subsystems/analytics/analytics-query.protocol.js.map +1 -0
- package/dist/runtime/subsystems/analytics/analytics.module.d.ts +34 -0
- package/dist/runtime/subsystems/analytics/analytics.module.js +117 -0
- package/dist/runtime/subsystems/analytics/analytics.module.js.map +1 -0
- package/dist/runtime/subsystems/analytics/analytics.tokens.d.ts +24 -0
- package/dist/runtime/subsystems/analytics/analytics.tokens.js +10 -0
- package/dist/runtime/subsystems/analytics/analytics.tokens.js.map +1 -0
- package/dist/runtime/subsystems/analytics/cube-backend.d.ts +28 -0
- package/dist/runtime/subsystems/analytics/cube-backend.js +71 -0
- package/dist/runtime/subsystems/analytics/cube-backend.js.map +1 -0
- package/dist/runtime/subsystems/analytics/index.d.ts +6 -0
- package/dist/runtime/subsystems/analytics/index.js +122 -0
- package/dist/runtime/subsystems/analytics/index.js.map +1 -0
- package/dist/runtime/subsystems/analytics/noop-backend.d.ts +7 -0
- package/dist/runtime/subsystems/analytics/noop-backend.js +25 -0
- package/dist/runtime/subsystems/analytics/noop-backend.js.map +1 -0
- package/dist/runtime/subsystems/cache/cache.drizzle-backend.d.ts +43 -0
- package/dist/runtime/subsystems/cache/cache.drizzle-backend.js +133 -0
- package/dist/runtime/subsystems/cache/cache.drizzle-backend.js.map +1 -0
- package/dist/runtime/subsystems/cache/cache.memory-backend.d.ts +21 -0
- package/dist/runtime/subsystems/cache/cache.memory-backend.js +100 -0
- package/dist/runtime/subsystems/cache/cache.memory-backend.js.map +1 -0
- package/dist/runtime/subsystems/cache/cache.module.d.ts +37 -0
- package/dist/runtime/subsystems/cache/cache.module.js +272 -0
- package/dist/runtime/subsystems/cache/cache.module.js.map +1 -0
- package/dist/runtime/subsystems/cache/cache.protocol.d.ts +42 -0
- package/dist/runtime/subsystems/cache/cache.protocol.js +1 -0
- package/dist/runtime/subsystems/cache/cache.protocol.js.map +1 -0
- package/dist/runtime/subsystems/cache/cache.schema.d.ts +64 -0
- package/dist/runtime/subsystems/cache/cache.schema.js +18 -0
- package/dist/runtime/subsystems/cache/cache.schema.js.map +1 -0
- package/dist/runtime/subsystems/cache/cache.tokens.d.ts +18 -0
- package/dist/runtime/subsystems/cache/cache.tokens.js +8 -0
- package/dist/runtime/subsystems/cache/cache.tokens.js.map +1 -0
- package/dist/runtime/subsystems/cache/index.d.ts +11 -0
- package/dist/runtime/subsystems/cache/index.js +277 -0
- package/dist/runtime/subsystems/cache/index.js.map +1 -0
- package/dist/runtime/subsystems/events/domain-events.schema.d.ts +187 -0
- package/dist/runtime/subsystems/events/domain-events.schema.js +32 -0
- package/dist/runtime/subsystems/events/domain-events.schema.js.map +1 -0
- package/dist/runtime/subsystems/events/event-bus.drizzle-backend.d.ts +38 -0
- package/dist/runtime/subsystems/events/event-bus.drizzle-backend.js +199 -0
- package/dist/runtime/subsystems/events/event-bus.drizzle-backend.js.map +1 -0
- package/dist/runtime/subsystems/events/event-bus.memory-backend.d.ts +18 -0
- package/dist/runtime/subsystems/events/event-bus.memory-backend.js +71 -0
- package/dist/runtime/subsystems/events/event-bus.memory-backend.js.map +1 -0
- package/dist/runtime/subsystems/events/event-bus.protocol.d.ts +52 -0
- package/dist/runtime/subsystems/events/event-bus.protocol.js +1 -0
- package/dist/runtime/subsystems/events/event-bus.protocol.js.map +1 -0
- package/dist/runtime/subsystems/events/event-bus.redis-backend.d.ts +95 -0
- package/dist/runtime/subsystems/events/event-bus.redis-backend.js +229 -0
- package/dist/runtime/subsystems/events/event-bus.redis-backend.js.map +1 -0
- package/dist/runtime/subsystems/events/events.module.d.ts +46 -0
- package/dist/runtime/subsystems/events/events.module.js +531 -0
- package/dist/runtime/subsystems/events/events.module.js.map +1 -0
- package/dist/runtime/subsystems/events/events.tokens.d.ts +19 -0
- package/dist/runtime/subsystems/events/events.tokens.js +8 -0
- package/dist/runtime/subsystems/events/events.tokens.js.map +1 -0
- package/dist/runtime/subsystems/events/index.d.ts +12 -0
- package/dist/runtime/subsystems/events/index.js +536 -0
- package/dist/runtime/subsystems/events/index.js.map +1 -0
- package/dist/runtime/subsystems/index.d.ts +24 -0
- package/dist/runtime/subsystems/index.js +1643 -0
- package/dist/runtime/subsystems/index.js.map +1 -0
- package/dist/runtime/subsystems/jobs/index.d.ts +14 -0
- package/dist/runtime/subsystems/jobs/index.js +680 -0
- package/dist/runtime/subsystems/jobs/index.js.map +1 -0
- package/dist/runtime/subsystems/jobs/job-queue.bullmq-backend.d.ts +54 -0
- package/dist/runtime/subsystems/jobs/job-queue.bullmq-backend.js +186 -0
- package/dist/runtime/subsystems/jobs/job-queue.bullmq-backend.js.map +1 -0
- package/dist/runtime/subsystems/jobs/job-queue.drizzle-backend.d.ts +38 -0
- package/dist/runtime/subsystems/jobs/job-queue.drizzle-backend.js +228 -0
- package/dist/runtime/subsystems/jobs/job-queue.drizzle-backend.js.map +1 -0
- package/dist/runtime/subsystems/jobs/job-queue.memory-backend.d.ts +12 -0
- package/dist/runtime/subsystems/jobs/job-queue.memory-backend.js +44 -0
- package/dist/runtime/subsystems/jobs/job-queue.memory-backend.js.map +1 -0
- package/dist/runtime/subsystems/jobs/job-queue.protocol.d.ts +48 -0
- package/dist/runtime/subsystems/jobs/job-queue.protocol.js +1 -0
- package/dist/runtime/subsystems/jobs/job-queue.protocol.js.map +1 -0
- package/dist/runtime/subsystems/jobs/job-queue.redis-backend.d.ts +46 -0
- package/dist/runtime/subsystems/jobs/job-queue.redis-backend.js +187 -0
- package/dist/runtime/subsystems/jobs/job-queue.redis-backend.js.map +1 -0
- package/dist/runtime/subsystems/jobs/job-queue.schema.d.ts +237 -0
- package/dist/runtime/subsystems/jobs/job-queue.schema.js +44 -0
- package/dist/runtime/subsystems/jobs/job-queue.schema.js.map +1 -0
- package/dist/runtime/subsystems/jobs/jobs.module.d.ts +18 -0
- package/dist/runtime/subsystems/jobs/jobs.module.js +676 -0
- package/dist/runtime/subsystems/jobs/jobs.module.js.map +1 -0
- package/dist/runtime/subsystems/jobs/jobs.tokens.d.ts +13 -0
- package/dist/runtime/subsystems/jobs/jobs.tokens.js +8 -0
- package/dist/runtime/subsystems/jobs/jobs.tokens.js.map +1 -0
- package/dist/runtime/subsystems/storage/index.d.ts +6 -0
- package/dist/runtime/subsystems/storage/index.js +204 -0
- package/dist/runtime/subsystems/storage/index.js.map +1 -0
- package/dist/runtime/subsystems/storage/storage.local-backend.d.ts +18 -0
- package/dist/runtime/subsystems/storage/storage.local-backend.js +108 -0
- package/dist/runtime/subsystems/storage/storage.local-backend.js.map +1 -0
- package/dist/runtime/subsystems/storage/storage.memory-backend.d.ts +28 -0
- package/dist/runtime/subsystems/storage/storage.memory-backend.js +72 -0
- package/dist/runtime/subsystems/storage/storage.memory-backend.js.map +1 -0
- package/dist/runtime/subsystems/storage/storage.module.d.ts +40 -0
- package/dist/runtime/subsystems/storage/storage.module.js +201 -0
- package/dist/runtime/subsystems/storage/storage.module.js.map +1 -0
- package/dist/runtime/subsystems/storage/storage.protocol.d.ts +69 -0
- package/dist/runtime/subsystems/storage/storage.protocol.js +1 -0
- package/dist/runtime/subsystems/storage/storage.protocol.js.map +1 -0
- package/dist/runtime/subsystems/storage/storage.tokens.d.ts +11 -0
- package/dist/runtime/subsystems/storage/storage.tokens.js +6 -0
- package/dist/runtime/subsystems/storage/storage.tokens.js.map +1 -0
- package/dist/runtime/subsystems/storage/storage.utils.d.ts +9 -0
- package/dist/runtime/subsystems/storage/storage.utils.js +18 -0
- package/dist/runtime/subsystems/storage/storage.utils.js.map +1 -0
- package/dist/runtime/types/drizzle.d.ts +17 -0
- package/dist/runtime/types/drizzle.js +1 -0
- package/dist/runtime/types/drizzle.js.map +1 -0
- package/dist/src/cli/index.d.ts +1 -0
- package/dist/src/cli/index.js +7365 -0
- package/dist/src/cli/index.js.map +1 -0
- package/dist/src/index.d.ts +2384 -0
- package/dist/src/index.js +2198 -0
- package/dist/src/index.js.map +1 -0
- package/package.json +114 -0
- package/templates/broadcast/new/backend-interface.ejs.t +47 -0
- package/templates/broadcast/new/bridge-listener.ejs.t +67 -0
- package/templates/broadcast/new/channel.ejs.t +77 -0
- package/templates/broadcast/new/index.ejs.t +21 -0
- package/templates/broadcast/new/memory-backend.ejs.t +87 -0
- package/templates/broadcast/new/module.ejs.t +57 -0
- package/templates/broadcast/new/prompt.js +268 -0
- package/templates/broadcast/new/websocket-backend.ejs.t +259 -0
- package/templates/entity/new/backend/application/commands/create.ejs.t +55 -0
- package/templates/entity/new/backend/application/commands/delete.ejs.t +45 -0
- package/templates/entity/new/backend/application/commands/grouped-index.ejs.t +149 -0
- package/templates/entity/new/backend/application/commands/index.ejs.t +15 -0
- package/templates/entity/new/backend/application/commands/update.ejs.t +58 -0
- package/templates/entity/new/backend/application/queries/declarative-queries.ejs.t +36 -0
- package/templates/entity/new/backend/application/queries/get-by-id.ejs.t +42 -0
- package/templates/entity/new/backend/application/queries/grouped-index.ejs.t +81 -0
- package/templates/entity/new/backend/application/queries/index.ejs.t +14 -0
- package/templates/entity/new/backend/application/queries/list.ejs.t +36 -0
- package/templates/entity/new/backend/application/schemas/_inject-index.ejs.t +7 -0
- package/templates/entity/new/backend/application/schemas/dto.ejs.t +45 -0
- package/templates/entity/new/backend/database/_inject-index.ejs.t +7 -0
- package/templates/entity/new/backend/database/electric-migration.ejs.t +21 -0
- package/templates/entity/new/backend/database/repository.ejs.t +450 -0
- package/templates/entity/new/backend/database/schema.ejs.t +248 -0
- package/templates/entity/new/backend/domain/_inject-index.ejs.t +12 -0
- package/templates/entity/new/backend/domain/entity.ejs.t +108 -0
- package/templates/entity/new/backend/domain/grouped-index.ejs.t +163 -0
- package/templates/entity/new/backend/domain/index.ejs.t +15 -0
- package/templates/entity/new/backend/domain/repository-interface.ejs.t +71 -0
- package/templates/entity/new/backend/modules/core/_ensure-anchor-tokens.ejs.t +10 -0
- package/templates/entity/new/backend/modules/core/_inject-token.ejs.t +7 -0
- package/templates/entity/new/backend/modules/core/module.ejs.t +67 -0
- package/templates/entity/new/backend/modules/trpc/module.ejs.t +67 -0
- package/templates/entity/new/backend/presentation/controller.ejs.t +201 -0
- package/templates/entity/new/clean-lite-ps/controller.ejs.t +37 -0
- package/templates/entity/new/clean-lite-ps/dto/create.ejs.t +17 -0
- package/templates/entity/new/clean-lite-ps/dto/output.ejs.t +25 -0
- package/templates/entity/new/clean-lite-ps/dto/update.ejs.t +11 -0
- package/templates/entity/new/clean-lite-ps/entity.ejs.t +52 -0
- package/templates/entity/new/clean-lite-ps/index.ejs.t +20 -0
- package/templates/entity/new/clean-lite-ps/module.ejs.t +43 -0
- package/templates/entity/new/clean-lite-ps/prompt-extension.js +617 -0
- package/templates/entity/new/clean-lite-ps/repository.ejs.t +62 -0
- package/templates/entity/new/clean-lite-ps/service.ejs.t +34 -0
- package/templates/entity/new/clean-lite-ps/use-cases/declarative-queries.ejs.t +34 -0
- package/templates/entity/new/clean-lite-ps/use-cases/find-by-id.ejs.t +16 -0
- package/templates/entity/new/clean-lite-ps/use-cases/list.ejs.t +16 -0
- package/templates/entity/new/frontend/_inject-entities-entry.ejs.t +7 -0
- package/templates/entity/new/frontend/_inject-entities-import.ejs.t +7 -0
- package/templates/entity/new/frontend/collections/_ensure-anchor-collections.ejs.t +10 -0
- package/templates/entity/new/frontend/collections/_inject-index.ejs.t +9 -0
- package/templates/entity/new/frontend/collections/_inject-schema-import.ejs.t +9 -0
- package/templates/entity/new/frontend/collections/collection.ejs.t +61 -0
- package/templates/entity/new/frontend/collections/collections-base.ejs.t +24 -0
- package/templates/entity/new/frontend/entity/collection.ejs.t +172 -0
- package/templates/entity/new/frontend/entity/combined.ejs.t +474 -0
- package/templates/entity/new/frontend/entity/fields.ejs.t +104 -0
- package/templates/entity/new/frontend/entity/hooks.ejs.t +73 -0
- package/templates/entity/new/frontend/entity/index.ejs.t +21 -0
- package/templates/entity/new/frontend/entity/mutation-hooks.ejs.t +84 -0
- package/templates/entity/new/frontend/entity/mutations.ejs.t +38 -0
- package/templates/entity/new/frontend/entity/types.ejs.t +59 -0
- package/templates/entity/new/frontend/generated/_inject-index-export.ejs.t +7 -0
- package/templates/entity/new/frontend/generated/_inject-index-import.ejs.t +7 -0
- package/templates/entity/new/frontend/generated/_inject-index-registry.ejs.t +7 -0
- package/templates/entity/new/frontend/store/_inject-collection-import.ejs.t +9 -0
- package/templates/entity/new/frontend/store/_inject-collections.ejs.t +9 -0
- package/templates/entity/new/frontend/store/_inject-entity.ejs.t +9 -0
- package/templates/entity/new/frontend/store/_inject-import.ejs.t +9 -0
- package/templates/entity/new/frontend/store/_inject-lookups.ejs.t +9 -0
- package/templates/entity/new/frontend/store/_inject-resolve.ejs.t +10 -0
- package/templates/entity/new/frontend/store/hooks.ejs.t +72 -0
- package/templates/entity/new/frontend/unified-entity.ejs.t +28 -0
- package/templates/entity/new/prompt.js +1421 -0
- package/templates/relationship/new/controller.ejs.t +36 -0
- package/templates/relationship/new/dto/create.ejs.t +41 -0
- package/templates/relationship/new/dto/output.ejs.t +44 -0
- package/templates/relationship/new/dto/update.ejs.t +10 -0
- package/templates/relationship/new/entity.ejs.t +98 -0
- package/templates/relationship/new/index.ejs.t +19 -0
- package/templates/relationship/new/module.ejs.t +35 -0
- package/templates/relationship/new/prompt.js +682 -0
- package/templates/relationship/new/repository.ejs.t +54 -0
- package/templates/relationship/new/service.ejs.t +31 -0
- package/templates/relationship/new/use-cases/declarative-queries.ejs.t +34 -0
- package/templates/relationship/new/use-cases/find-by-id.ejs.t +16 -0
- package/templates/relationship/new/use-cases/list.ejs.t +16 -0
|
@@ -0,0 +1,617 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clean-Lite-PS template locals extension
|
|
3
|
+
*
|
|
4
|
+
* Exports buildCleanLitePsLocals(definition, baseLocals) which derives
|
|
5
|
+
* all variables required by the clean-lite-ps template set.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// ============================================================================
|
|
9
|
+
// Family → Base Class Mapping
|
|
10
|
+
// ============================================================================
|
|
11
|
+
|
|
12
|
+
const FAMILY_MAP = {
|
|
13
|
+
'synced': {
|
|
14
|
+
repositoryBaseClass: 'SyncedEntityRepository',
|
|
15
|
+
serviceBaseClass: 'SyncedEntityService',
|
|
16
|
+
repositoryBaseImport: '@shared/base-classes/synced-entity-repository',
|
|
17
|
+
serviceBaseImport: '@shared/base-classes/synced-entity-service',
|
|
18
|
+
repositoryInheritedMethods: [
|
|
19
|
+
'findById, findByIds, list, count, exists, create, update, delete, upsertMany',
|
|
20
|
+
'findByExternalId, findAllByUserId, findVisibleByUserId, syncUpsert',
|
|
21
|
+
],
|
|
22
|
+
serviceInheritedMethods: [
|
|
23
|
+
'findById, findByIds, list, count, exists, create, update, delete',
|
|
24
|
+
'findByExternalId, findAllByUserId, findVisibleByUserId',
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
activity: {
|
|
28
|
+
repositoryBaseClass: 'ActivityEntityRepository',
|
|
29
|
+
serviceBaseClass: 'ActivityEntityService',
|
|
30
|
+
repositoryBaseImport: '@shared/base-classes/activity-entity-repository',
|
|
31
|
+
serviceBaseImport: '@shared/base-classes/activity-entity-service',
|
|
32
|
+
repositoryInheritedMethods: [
|
|
33
|
+
'findById, findByIds, list, count, exists, create, update, delete, upsertMany',
|
|
34
|
+
'findByDateRange, findByUserId, findByOpportunityId, findRecentByOpportunityId',
|
|
35
|
+
],
|
|
36
|
+
serviceInheritedMethods: [
|
|
37
|
+
'findById, findByIds, list, count, exists, create, update, delete',
|
|
38
|
+
'findByDateRange, findByUserId, findByOpportunityId, findRecentByOpportunityId',
|
|
39
|
+
],
|
|
40
|
+
},
|
|
41
|
+
knowledge: {
|
|
42
|
+
repositoryBaseClass: 'KnowledgeEntityRepository',
|
|
43
|
+
serviceBaseClass: 'KnowledgeEntityService',
|
|
44
|
+
repositoryBaseImport: '@shared/base-classes/knowledge-entity-repository',
|
|
45
|
+
serviceBaseImport: '@shared/base-classes/knowledge-entity-service',
|
|
46
|
+
repositoryInheritedMethods: [
|
|
47
|
+
'findById, findByIds, list, count, exists, create, update, delete, upsertMany',
|
|
48
|
+
'semanticSearch, findPendingByOpportunityId, updateStatus, updateStatusBatch',
|
|
49
|
+
],
|
|
50
|
+
serviceInheritedMethods: [
|
|
51
|
+
'findById, findByIds, list, count, exists, create, update, delete',
|
|
52
|
+
'semanticSearch, findPendingByOpportunityId, updateStatus, updateStatusBatch',
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
metadata: {
|
|
56
|
+
repositoryBaseClass: 'MetadataEntityRepository',
|
|
57
|
+
serviceBaseClass: 'MetadataEntityService',
|
|
58
|
+
repositoryBaseImport: '@shared/base-classes/metadata-entity-repository',
|
|
59
|
+
serviceBaseImport: '@shared/base-classes/metadata-entity-service',
|
|
60
|
+
repositoryInheritedMethods: [
|
|
61
|
+
'findById, findByIds, list, count, exists, create, update, delete, upsertMany',
|
|
62
|
+
'findByEntityIdAndType, listByEntityId, listHistoryByEntityId',
|
|
63
|
+
],
|
|
64
|
+
serviceInheritedMethods: [
|
|
65
|
+
'findById, findByIds, list, count, exists, create, update, delete',
|
|
66
|
+
'findByEntityIdAndType, listByEntityId, listHistoryByEntityId',
|
|
67
|
+
],
|
|
68
|
+
},
|
|
69
|
+
base: {
|
|
70
|
+
repositoryBaseClass: 'BaseRepository',
|
|
71
|
+
serviceBaseClass: 'BaseService',
|
|
72
|
+
repositoryBaseImport: '@shared/base-classes/base-repository',
|
|
73
|
+
serviceBaseImport: '@shared/base-classes/base-service',
|
|
74
|
+
repositoryInheritedMethods: [
|
|
75
|
+
'findById, findByIds, list, count, exists, create, update, delete, upsertMany',
|
|
76
|
+
],
|
|
77
|
+
serviceInheritedMethods: [
|
|
78
|
+
'findById, findByIds, list, count, exists, create, update, delete',
|
|
79
|
+
],
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
// ============================================================================
|
|
84
|
+
// Helper utilities
|
|
85
|
+
// ============================================================================
|
|
86
|
+
|
|
87
|
+
const capitalize = (s) => s.charAt(0).toUpperCase() + s.slice(1);
|
|
88
|
+
const camelCase = (s) => s.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
|
|
89
|
+
const pascalCase = (s) => capitalize(camelCase(s));
|
|
90
|
+
const pluralize = (s) => {
|
|
91
|
+
if (s.endsWith('y')) return s.slice(0, -1) + 'ies';
|
|
92
|
+
if (s.endsWith('s') || s.endsWith('x') || s.endsWith('ch') || s.endsWith('sh'))
|
|
93
|
+
return s + 'es';
|
|
94
|
+
return s + 's';
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
// ============================================================================
|
|
98
|
+
// Drizzle type mapping
|
|
99
|
+
// ============================================================================
|
|
100
|
+
|
|
101
|
+
const DRIZZLE_TYPE_MAP = {
|
|
102
|
+
string: 'text',
|
|
103
|
+
integer: 'integer',
|
|
104
|
+
decimal: 'numeric',
|
|
105
|
+
boolean: 'boolean',
|
|
106
|
+
uuid: 'uuid',
|
|
107
|
+
date: 'date',
|
|
108
|
+
datetime: 'timestamp',
|
|
109
|
+
json: 'jsonb',
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
// Drizzle import name for each drizzle type
|
|
113
|
+
const DRIZZLE_IMPORT_MAP = {
|
|
114
|
+
text: 'text',
|
|
115
|
+
integer: 'integer',
|
|
116
|
+
numeric: 'numeric',
|
|
117
|
+
boolean: 'boolean',
|
|
118
|
+
uuid: 'uuid',
|
|
119
|
+
date: 'date',
|
|
120
|
+
timestamp: 'timestamp',
|
|
121
|
+
jsonb: 'jsonb',
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
// ============================================================================
|
|
125
|
+
// Zod type mapping
|
|
126
|
+
// ============================================================================
|
|
127
|
+
|
|
128
|
+
const ZOD_TYPE_MAP = {
|
|
129
|
+
string: 'z.string()',
|
|
130
|
+
integer: 'z.number().int()',
|
|
131
|
+
// PG numeric is returned by Drizzle as a string; z.coerce.number() parses
|
|
132
|
+
// strings at the boundary while still accepting numeric JSON input.
|
|
133
|
+
decimal: 'z.coerce.number()',
|
|
134
|
+
boolean: 'z.boolean()',
|
|
135
|
+
uuid: 'z.string().uuid()',
|
|
136
|
+
date: 'z.coerce.date()',
|
|
137
|
+
datetime: 'z.coerce.date()',
|
|
138
|
+
// jsonb has no schema guarantees and routinely holds arrays, objects, or
|
|
139
|
+
// scalars — z.unknown() preserves that. Use z.record(...) shaping in refine
|
|
140
|
+
// code at the consumer if stricter validation is needed.
|
|
141
|
+
json: 'z.unknown()',
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
// TypeScript type mapping
|
|
145
|
+
const TS_TYPE_MAP = {
|
|
146
|
+
string: 'string',
|
|
147
|
+
integer: 'number',
|
|
148
|
+
decimal: 'number',
|
|
149
|
+
boolean: 'boolean',
|
|
150
|
+
uuid: 'string',
|
|
151
|
+
date: 'Date',
|
|
152
|
+
datetime: 'Date',
|
|
153
|
+
json: 'unknown',
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
// Fields managed by behaviors — excluded from create DTO
|
|
157
|
+
const BEHAVIOR_MANAGED_FIELDS = new Set([
|
|
158
|
+
'created_at',
|
|
159
|
+
'updated_at',
|
|
160
|
+
'deleted_at',
|
|
161
|
+
'created_by',
|
|
162
|
+
'updated_by',
|
|
163
|
+
'valid_from',
|
|
164
|
+
'valid_to',
|
|
165
|
+
'is_active',
|
|
166
|
+
]);
|
|
167
|
+
|
|
168
|
+
// ============================================================================
|
|
169
|
+
// Field processors
|
|
170
|
+
// ============================================================================
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Build a Drizzle column chain for a field
|
|
174
|
+
*/
|
|
175
|
+
function buildDrizzleChain(fieldName, field, drizzleType) {
|
|
176
|
+
const nullable = field.nullable ?? false;
|
|
177
|
+
const required = field.required ?? false;
|
|
178
|
+
const hasDefault = field.default !== undefined && field.default !== null;
|
|
179
|
+
|
|
180
|
+
let chain = `${drizzleType}('${fieldName}')`;
|
|
181
|
+
|
|
182
|
+
// Add .notNull() for non-nullable required fields
|
|
183
|
+
if (required && !nullable) {
|
|
184
|
+
chain += '.notNull()';
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Boolean defaults
|
|
188
|
+
if (drizzleType === 'boolean' && hasDefault) {
|
|
189
|
+
chain += `.default(${field.default})`;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Timestamp defaults for datetime fields in behavior context handled separately
|
|
193
|
+
return chain;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Process entity fields into ProcessedField[]
|
|
198
|
+
*/
|
|
199
|
+
function processFields(fields) {
|
|
200
|
+
const processed = [];
|
|
201
|
+
|
|
202
|
+
for (const [fieldName, field] of Object.entries(fields)) {
|
|
203
|
+
if (fieldName === 'id') continue;
|
|
204
|
+
|
|
205
|
+
const type = field.type || 'string';
|
|
206
|
+
const nullable = field.nullable ?? false;
|
|
207
|
+
const required = field.required ?? false;
|
|
208
|
+
const hasDefault = field.default !== undefined && field.default !== null;
|
|
209
|
+
const choices = field.choices;
|
|
210
|
+
const hasChoices = Array.isArray(choices) && choices.length > 0;
|
|
211
|
+
|
|
212
|
+
const drizzleType = DRIZZLE_TYPE_MAP[type] || 'text';
|
|
213
|
+
const tsType = hasChoices
|
|
214
|
+
? choices.map((c) => `'${c}'`).join(' | ')
|
|
215
|
+
: (TS_TYPE_MAP[type] || 'unknown');
|
|
216
|
+
const zodType = hasChoices
|
|
217
|
+
? `z.enum([${choices.map((c) => `'${c}'`).join(', ')}])`
|
|
218
|
+
: (ZOD_TYPE_MAP[type] || 'z.unknown()');
|
|
219
|
+
|
|
220
|
+
const drizzleChain = buildDrizzleChain(fieldName, field, drizzleType);
|
|
221
|
+
|
|
222
|
+
processed.push({
|
|
223
|
+
name: fieldName,
|
|
224
|
+
camelName: camelCase(fieldName),
|
|
225
|
+
type,
|
|
226
|
+
drizzleType,
|
|
227
|
+
zodType,
|
|
228
|
+
tsType,
|
|
229
|
+
nullable,
|
|
230
|
+
required,
|
|
231
|
+
hasDefault,
|
|
232
|
+
isPrimaryKey: false,
|
|
233
|
+
drizzleChain,
|
|
234
|
+
choices,
|
|
235
|
+
hasChoices,
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return processed;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Process belongs_to relationships into BelongsToRelation[]
|
|
244
|
+
*/
|
|
245
|
+
function processBelongsTo(relationships) {
|
|
246
|
+
if (!relationships) return [];
|
|
247
|
+
|
|
248
|
+
const result = [];
|
|
249
|
+
|
|
250
|
+
for (const [relName, rel] of Object.entries(relationships)) {
|
|
251
|
+
if (rel.type !== 'belongs_to') continue;
|
|
252
|
+
|
|
253
|
+
const target = rel.target;
|
|
254
|
+
const field = rel.foreign_key;
|
|
255
|
+
const nullable = rel.nullable ?? true;
|
|
256
|
+
const relatedPlural = pluralize(target);
|
|
257
|
+
|
|
258
|
+
result.push({
|
|
259
|
+
field,
|
|
260
|
+
camelField: camelCase(field),
|
|
261
|
+
relatedEntity: target,
|
|
262
|
+
relatedEntityPascal: pascalCase(target),
|
|
263
|
+
relatedTable: relatedPlural,
|
|
264
|
+
relatedPlural,
|
|
265
|
+
nullable,
|
|
266
|
+
importPath: `../${relatedPlural}/${target}.entity`,
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
return result;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Collect drizzle imports needed for entity fields
|
|
275
|
+
*/
|
|
276
|
+
function collectDrizzleImports(processedFields, belongsTo, hasTimestamps, hasSoftDelete) {
|
|
277
|
+
const imports = new Set(['pgTable', 'uuid']);
|
|
278
|
+
|
|
279
|
+
for (const field of processedFields) {
|
|
280
|
+
const importName = DRIZZLE_IMPORT_MAP[field.drizzleType];
|
|
281
|
+
if (importName) imports.add(importName);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// FK uuid columns from belongs_to
|
|
285
|
+
if (belongsTo.length > 0) {
|
|
286
|
+
imports.add('uuid');
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Behavior imports
|
|
290
|
+
if (hasTimestamps || hasSoftDelete) {
|
|
291
|
+
imports.add('timestamp');
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
if (belongsTo.length > 0) {
|
|
295
|
+
imports.add('relations');
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
return Array.from(imports).sort();
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Derive Zod chain for a field in create DTO context
|
|
303
|
+
*/
|
|
304
|
+
function zodChainForCreate(field) {
|
|
305
|
+
const { type, nullable, required, hasDefault, hasChoices, choices } = field;
|
|
306
|
+
|
|
307
|
+
if (hasChoices) {
|
|
308
|
+
const base = `z.enum([${choices.map((c) => `'${c}'`).join(', ')}])`;
|
|
309
|
+
if (!required && !nullable) return base + '.optional()';
|
|
310
|
+
if (nullable) return base + '.nullable()';
|
|
311
|
+
return base;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
let base = ZOD_TYPE_MAP[type] || 'z.unknown()';
|
|
315
|
+
|
|
316
|
+
if (type === 'boolean' && hasDefault) {
|
|
317
|
+
base += `.default(${field.default ?? false})`;
|
|
318
|
+
return base;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if (nullable) {
|
|
322
|
+
return base + '.nullable()';
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if (!required) {
|
|
326
|
+
return base + '.optional()';
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
return base;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Derive Zod chain for a field in output DTO context
|
|
334
|
+
*/
|
|
335
|
+
function zodChainForOutput(field) {
|
|
336
|
+
const { type, nullable, hasChoices, choices } = field;
|
|
337
|
+
|
|
338
|
+
if (hasChoices) {
|
|
339
|
+
const base = `z.enum([${choices.map((c) => `'${c}'`).join(', ')}])`;
|
|
340
|
+
if (nullable) return base + '.nullable()';
|
|
341
|
+
return base;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
let base = ZOD_TYPE_MAP[type] || 'z.unknown()';
|
|
345
|
+
|
|
346
|
+
if (nullable) {
|
|
347
|
+
return base + '.nullable()';
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
return base;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// ============================================================================
|
|
354
|
+
// Query processing
|
|
355
|
+
// ============================================================================
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Derive repository method name from a declarative query definition.
|
|
359
|
+
* E.g., { by: ['user_id'] } → 'findByUserId'
|
|
360
|
+
* { by: ['email'], unique: true } → 'findByEmail'
|
|
361
|
+
* { by: ['opportunity_id'], select: ['email'] } → 'findEmailsByOpportunityId'
|
|
362
|
+
*/
|
|
363
|
+
function deriveQueryMethodName(query) {
|
|
364
|
+
const byFields = Array.isArray(query.by) ? query.by : [];
|
|
365
|
+
const selectFields = Array.isArray(query.select) ? query.select : [];
|
|
366
|
+
|
|
367
|
+
const byPart = byFields.map((f) => pascalCase(f)).join('And');
|
|
368
|
+
|
|
369
|
+
if (selectFields.length > 0) {
|
|
370
|
+
const selectPart = selectFields.map((f) => pascalCase(f)).join('And') + 's';
|
|
371
|
+
return `find${selectPart}By${byPart}`;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
return `findBy${byPart}`;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Process declarative queries from YAML queries: block.
|
|
379
|
+
* Produces typed query metadata for template generation.
|
|
380
|
+
*/
|
|
381
|
+
function processQueries(queriesBlock, processedFields, entityNamePascal) {
|
|
382
|
+
if (!queriesBlock || !Array.isArray(queriesBlock) || queriesBlock.length === 0) {
|
|
383
|
+
return [];
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// Build field name → TS type lookup
|
|
387
|
+
const fieldTypeMap = {};
|
|
388
|
+
for (const pf of processedFields) {
|
|
389
|
+
fieldTypeMap[pf.name] = pf.tsType;
|
|
390
|
+
fieldTypeMap[pf.camelName] = pf.tsType;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
return queriesBlock.map((q) => {
|
|
394
|
+
const byFields = Array.isArray(q.by) ? q.by : [];
|
|
395
|
+
const selectFields = Array.isArray(q.select) ? q.select : [];
|
|
396
|
+
const isUnique = q.unique ?? false;
|
|
397
|
+
const viaTable = q.via ?? null;
|
|
398
|
+
|
|
399
|
+
const params = byFields.map((f) => ({
|
|
400
|
+
name: f,
|
|
401
|
+
camelName: camelCase(f),
|
|
402
|
+
tsType: fieldTypeMap[f] || fieldTypeMap[camelCase(f)] || 'string',
|
|
403
|
+
}));
|
|
404
|
+
|
|
405
|
+
let orderBy = null;
|
|
406
|
+
let orderDirection = null;
|
|
407
|
+
if (q.order) {
|
|
408
|
+
const parts = q.order.trim().split(/\s+/);
|
|
409
|
+
orderBy = camelCase(parts[0]);
|
|
410
|
+
orderDirection = parts[1] || 'asc';
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
const methodName = deriveQueryMethodName(q);
|
|
414
|
+
|
|
415
|
+
let returnType;
|
|
416
|
+
if (isUnique) {
|
|
417
|
+
returnType = `${entityNamePascal} | null`;
|
|
418
|
+
} else if (selectFields.length > 0) {
|
|
419
|
+
const camelFields = selectFields.map((f) => camelCase(f));
|
|
420
|
+
returnType = selectFields.length === 1
|
|
421
|
+
? `${fieldTypeMap[selectFields[0]] || fieldTypeMap[camelFields[0]] || 'string'}[]`
|
|
422
|
+
: `Pick<${entityNamePascal}, ${camelFields.map((f) => `'${f}'`).join(' | ')}>[]`;
|
|
423
|
+
} else {
|
|
424
|
+
returnType = `${entityNamePascal}[]`;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// Prefix class name with entity to guarantee uniqueness across modules.
|
|
428
|
+
// e.g. methodName 'findByDomain' on Account → 'FindAccountByDomainUseCase'
|
|
429
|
+
// methodName 'findEmailsByOpportunityId' on Contact → 'FindContactEmailsByOpportunityIdUseCase'
|
|
430
|
+
const methodPascal = pascalCase(methodName);
|
|
431
|
+
const useCaseClassName = methodPascal.replace(/^Find/, `Find${entityNamePascal}`) + 'UseCase';
|
|
432
|
+
|
|
433
|
+
return {
|
|
434
|
+
by: byFields,
|
|
435
|
+
unique: isUnique,
|
|
436
|
+
select: selectFields,
|
|
437
|
+
order: q.order ?? null,
|
|
438
|
+
limit: q.limit ?? null,
|
|
439
|
+
via: viaTable,
|
|
440
|
+
methodName,
|
|
441
|
+
returnType,
|
|
442
|
+
params,
|
|
443
|
+
isUnique,
|
|
444
|
+
orderBy,
|
|
445
|
+
orderDirection,
|
|
446
|
+
viaTable,
|
|
447
|
+
viaTableCamel: viaTable ? camelCase(viaTable) : null,
|
|
448
|
+
selectFields: selectFields.map((f) => camelCase(f)),
|
|
449
|
+
useCaseClassName,
|
|
450
|
+
hasVia: viaTable != null,
|
|
451
|
+
hasSelect: selectFields.length > 0,
|
|
452
|
+
hasOrder: q.order != null,
|
|
453
|
+
hasLimit: q.limit != null,
|
|
454
|
+
hasMultipleParams: params.length > 1,
|
|
455
|
+
};
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// ============================================================================
|
|
460
|
+
// Main export
|
|
461
|
+
// ============================================================================
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* Build Clean-Lite-PS template locals from entity definition and base locals
|
|
465
|
+
*
|
|
466
|
+
* @param {object} definition - Parsed entity YAML
|
|
467
|
+
* @param {object} baseLocals - Locals from main prompt.js
|
|
468
|
+
* @returns {object} Merged locals with all clean-lite-ps variables
|
|
469
|
+
*/
|
|
470
|
+
export function buildCleanLitePsLocals(definition, baseLocals) {
|
|
471
|
+
const entity = definition.entity;
|
|
472
|
+
const fields = definition.fields || {};
|
|
473
|
+
const relationships = definition.relationships || {};
|
|
474
|
+
const behaviors = definition.behaviors || [];
|
|
475
|
+
const queriesBlock = definition.queries || null;
|
|
476
|
+
|
|
477
|
+
// Source root — configurable via baseLocals.srcRoot or entity.src_root, defaults to 'src'
|
|
478
|
+
const srcRoot = baseLocals.srcRoot || entity.src_root || 'src';
|
|
479
|
+
|
|
480
|
+
const entityName = entity.name;
|
|
481
|
+
const entityNamePascal = pascalCase(entityName);
|
|
482
|
+
const entityNamePlural = entity.plural || pluralize(entityName);
|
|
483
|
+
const entityNamePluralPascal = pascalCase(entityNamePlural);
|
|
484
|
+
|
|
485
|
+
// Family resolution
|
|
486
|
+
const family = entity.family || 'base';
|
|
487
|
+
const familyConfig = FAMILY_MAP[family] || FAMILY_MAP['base'];
|
|
488
|
+
|
|
489
|
+
// Process entity fields
|
|
490
|
+
const processedFields = processFields(fields);
|
|
491
|
+
|
|
492
|
+
// Behavior flags (re-read from behaviors array for clean-lite-ps use)
|
|
493
|
+
const behaviorNames = behaviors.map((b) => (typeof b === 'string' ? b : b.name));
|
|
494
|
+
const hasTimestamps = behaviorNames.includes('timestamps');
|
|
495
|
+
const hasSoftDelete = behaviorNames.includes('soft_delete');
|
|
496
|
+
|
|
497
|
+
// Process declarative queries
|
|
498
|
+
const processedQueries = processQueries(queriesBlock, processedFields, entityNamePascal);
|
|
499
|
+
const hasDeclarativeQueries = processedQueries.length > 0;
|
|
500
|
+
const declarativeQueryClasses = processedQueries.map((q) => q.useCaseClassName);
|
|
501
|
+
const hasMultiFieldQuery = processedQueries.some((q) => q.hasMultipleParams);
|
|
502
|
+
const hasOrderedQuery = processedQueries.some((q) => q.hasOrder);
|
|
503
|
+
const hasViaQuery = processedQueries.some((q) => q.hasVia);
|
|
504
|
+
|
|
505
|
+
// Process belongs_to relationships
|
|
506
|
+
const belongsTo = processBelongsTo(relationships);
|
|
507
|
+
|
|
508
|
+
// Filter FK fields that are already emitted by the clpBelongsTo loop
|
|
509
|
+
const fkFieldNames = new Set(belongsTo.map((r) => r.field));
|
|
510
|
+
const nonFkFields = processedFields.filter((f) => !fkFieldNames.has(f.name));
|
|
511
|
+
|
|
512
|
+
// Drizzle imports needed
|
|
513
|
+
const drizzleEntityImports = collectDrizzleImports(processedFields, belongsTo, hasTimestamps, hasSoftDelete);
|
|
514
|
+
// Whether relations() import is needed
|
|
515
|
+
const hasRelationsBlock = belongsTo.length > 0;
|
|
516
|
+
|
|
517
|
+
// Output paths
|
|
518
|
+
const outputPaths = {
|
|
519
|
+
entity: `${srcRoot}/modules/${entityNamePlural}/${entityName}.entity.ts`,
|
|
520
|
+
repository: `${srcRoot}/modules/${entityNamePlural}/${entityName}.repository.ts`,
|
|
521
|
+
service: `${srcRoot}/modules/${entityNamePlural}/${entityName}.service.ts`,
|
|
522
|
+
controller: `${srcRoot}/modules/${entityNamePlural}/${entityName}.controller.ts`,
|
|
523
|
+
module: `${srcRoot}/modules/${entityNamePlural}/${entityNamePlural}.module.ts`,
|
|
524
|
+
findByIdUseCase: `${srcRoot}/modules/${entityNamePlural}/use-cases/find-${entityName}-by-id.use-case.ts`,
|
|
525
|
+
listUseCase: `${srcRoot}/modules/${entityNamePlural}/use-cases/list-${entityNamePlural}.use-case.ts`,
|
|
526
|
+
createDto: `${srcRoot}/modules/${entityNamePlural}/dto/create-${entityName}.dto.ts`,
|
|
527
|
+
updateDto: `${srcRoot}/modules/${entityNamePlural}/dto/update-${entityName}.dto.ts`,
|
|
528
|
+
outputDto: `${srcRoot}/modules/${entityNamePlural}/dto/${entityName}-output.dto.ts`,
|
|
529
|
+
declarativeQueries: hasDeclarativeQueries
|
|
530
|
+
? `${srcRoot}/modules/${entityNamePlural}/use-cases/declarative-queries.ts`
|
|
531
|
+
: null,
|
|
532
|
+
};
|
|
533
|
+
|
|
534
|
+
// Class names
|
|
535
|
+
const classNames = {
|
|
536
|
+
entity: entityNamePascal,
|
|
537
|
+
entityTable: entityNamePlural,
|
|
538
|
+
repository: `${entityNamePascal}Repository`,
|
|
539
|
+
service: `${entityNamePascal}Service`,
|
|
540
|
+
controller: `${entityNamePascal}Controller`,
|
|
541
|
+
module: `${entityNamePluralPascal}Module`,
|
|
542
|
+
findByIdUseCase: `Find${entityNamePascal}ByIdUseCase`,
|
|
543
|
+
listUseCase: `List${entityNamePluralPascal}UseCase`,
|
|
544
|
+
createDto: `Create${entityNamePascal}Dto`,
|
|
545
|
+
updateDto: `Update${entityNamePascal}Dto`,
|
|
546
|
+
outputDto: `${entityNamePascal}OutputDto`,
|
|
547
|
+
createSchema: `Create${entityNamePascal}Schema`,
|
|
548
|
+
updateSchema: `Update${entityNamePascal}Schema`,
|
|
549
|
+
outputSchema: `${entityNamePascal}OutputSchema`,
|
|
550
|
+
};
|
|
551
|
+
|
|
552
|
+
// Fields for create DTO: exclude id, behavior-managed fields, and FK fields
|
|
553
|
+
const createDtoFields = nonFkFields.filter(
|
|
554
|
+
(f) => !BEHAVIOR_MANAGED_FIELDS.has(f.name),
|
|
555
|
+
);
|
|
556
|
+
|
|
557
|
+
// FK fields from belongs_to for create/output DTOs
|
|
558
|
+
const belongsToFkFields = belongsTo.map((rel) => ({
|
|
559
|
+
camelName: rel.camelField,
|
|
560
|
+
zodChainCreate: rel.nullable ? 'z.string().uuid().nullable()' : 'z.string().uuid()',
|
|
561
|
+
zodChainOutput: rel.nullable ? 'z.string().uuid().nullable()' : 'z.string().uuid()',
|
|
562
|
+
nullable: rel.nullable,
|
|
563
|
+
}));
|
|
564
|
+
|
|
565
|
+
// Build zodChain for each create DTO field
|
|
566
|
+
const createDtoFieldsWithZod = createDtoFields.map((f) => ({
|
|
567
|
+
...f,
|
|
568
|
+
zodChainCreate: zodChainForCreate(f),
|
|
569
|
+
}));
|
|
570
|
+
|
|
571
|
+
// Build zodChain for each output DTO field (all non-FK fields)
|
|
572
|
+
const outputDtoFields = nonFkFields.map((f) => ({
|
|
573
|
+
...f,
|
|
574
|
+
zodChainOutput: zodChainForOutput(f),
|
|
575
|
+
}));
|
|
576
|
+
|
|
577
|
+
return {
|
|
578
|
+
// Clean-Lite-PS identity
|
|
579
|
+
entityName,
|
|
580
|
+
entityNamePascal,
|
|
581
|
+
entityNamePlural,
|
|
582
|
+
entityNamePluralPascal,
|
|
583
|
+
|
|
584
|
+
// Family
|
|
585
|
+
family,
|
|
586
|
+
...familyConfig,
|
|
587
|
+
|
|
588
|
+
// Behavior flags (also exposed at top level for template use)
|
|
589
|
+
hasTimestamps,
|
|
590
|
+
hasSoftDelete,
|
|
591
|
+
|
|
592
|
+
// Output paths
|
|
593
|
+
clpOutputPaths: outputPaths,
|
|
594
|
+
|
|
595
|
+
// Class names
|
|
596
|
+
classNames,
|
|
597
|
+
|
|
598
|
+
// Field data
|
|
599
|
+
clpProcessedFields: nonFkFields,
|
|
600
|
+
clpCreateDtoFields: createDtoFieldsWithZod,
|
|
601
|
+
clpOutputDtoFields: outputDtoFields,
|
|
602
|
+
clpBelongsTo: belongsTo,
|
|
603
|
+
clpBelongsToFkFields: belongsToFkFields,
|
|
604
|
+
|
|
605
|
+
// Drizzle
|
|
606
|
+
clpDrizzleImports: drizzleEntityImports,
|
|
607
|
+
clpHasRelationsBlock: hasRelationsBlock,
|
|
608
|
+
|
|
609
|
+
// Declarative queries
|
|
610
|
+
processedQueries,
|
|
611
|
+
hasDeclarativeQueries,
|
|
612
|
+
declarativeQueryClasses,
|
|
613
|
+
hasMultiFieldQuery,
|
|
614
|
+
hasOrderedQuery,
|
|
615
|
+
hasViaQuery,
|
|
616
|
+
};
|
|
617
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
---
|
|
2
|
+
to: "<%= typeof clpOutputPaths !== 'undefined' ? clpOutputPaths.repository : null %>"
|
|
3
|
+
skip_if: "<%= typeof clpOutputPaths === 'undefined' %>"
|
|
4
|
+
force: true
|
|
5
|
+
---
|
|
6
|
+
import { Injectable, Inject } from '@nestjs/common';
|
|
7
|
+
<% if (hasDeclarativeQueries) { -%>
|
|
8
|
+
import { eq<%= hasMultiFieldQuery ? ', and' : '' %><%= hasOrderedQuery ? ', desc, asc' : '' %> } from 'drizzle-orm';
|
|
9
|
+
<% } -%>
|
|
10
|
+
import { DRIZZLE } from '@shared/constants/tokens';
|
|
11
|
+
import type { DrizzleClient } from '@shared/types/drizzle';
|
|
12
|
+
import { <%= repositoryBaseClass %> } from '<%= repositoryBaseImport %>';
|
|
13
|
+
<% if (hasTimestamps || hasSoftDelete) { -%>
|
|
14
|
+
import type { BehaviorConfig } from '@shared/base-classes/base-repository';
|
|
15
|
+
<% } -%>
|
|
16
|
+
import { <%= entityNamePlural %>, type <%= classNames.entity %> } from './<%= entityName %>.entity';
|
|
17
|
+
|
|
18
|
+
@Injectable()
|
|
19
|
+
export class <%= classNames.repository %> extends <%= repositoryBaseClass %><<%= classNames.entity %>> {
|
|
20
|
+
readonly table = <%= entityNamePlural %>;
|
|
21
|
+
<% if (hasTimestamps || hasSoftDelete) { -%>
|
|
22
|
+
|
|
23
|
+
// Behaviors declared in YAML -> generated as config object
|
|
24
|
+
protected override readonly behaviors: BehaviorConfig = {
|
|
25
|
+
timestamps: <%= !!hasTimestamps %>,
|
|
26
|
+
softDelete: <%= !!hasSoftDelete %>,
|
|
27
|
+
userTracking: false,
|
|
28
|
+
};
|
|
29
|
+
<% } -%>
|
|
30
|
+
|
|
31
|
+
constructor(@Inject(DRIZZLE) db: DrizzleClient) {
|
|
32
|
+
super(db);
|
|
33
|
+
}
|
|
34
|
+
<% if (hasDeclarativeQueries) { -%>
|
|
35
|
+
|
|
36
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
37
|
+
// Declarative queries (from queries: block in entity YAML)
|
|
38
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
39
|
+
<%_ processedQueries.forEach((q) => { _%>
|
|
40
|
+
|
|
41
|
+
async <%= q.methodName %>(<%- q.params.map(p => `${p.camelName}: ${p.tsType}`).join(', ') %>): Promise<<%- q.returnType %>> {
|
|
42
|
+
<% if (q.isUnique) { -%>
|
|
43
|
+
const rows = await this.baseQuery()
|
|
44
|
+
.where(<%- q.hasMultipleParams ? 'and(' : '' %><%- q.params.map(p => `eq(this.table['${p.camelName}'], ${p.camelName})`).join(', ') %><%- q.hasMultipleParams ? ')' : '' %>)
|
|
45
|
+
.limit(1);
|
|
46
|
+
return (rows[0] as <%= classNames.entity %>) ?? null;
|
|
47
|
+
<% } else { -%>
|
|
48
|
+
const rows = await this.baseQuery()
|
|
49
|
+
.where(<%- q.hasMultipleParams ? 'and(' : '' %><%- q.params.map(p => `eq(this.table['${p.camelName}'], ${p.camelName})`).join(', ') %><%- q.hasMultipleParams ? ')' : '' %>)<%- q.hasOrder ? `.orderBy(${q.orderDirection}(this.table['${q.orderBy}']))` : '' %>;
|
|
50
|
+
return rows as <%= classNames.entity %>[];
|
|
51
|
+
<% } -%>
|
|
52
|
+
}
|
|
53
|
+
<%_ }) _%>
|
|
54
|
+
<% } else { -%>
|
|
55
|
+
|
|
56
|
+
// TODO: Add entity-specific query methods here.
|
|
57
|
+
<% } -%>
|
|
58
|
+
// Inherited from <%= repositoryBaseClass %>:
|
|
59
|
+
<%_ repositoryInheritedMethods.forEach(line => { _%>
|
|
60
|
+
// <%= line %>
|
|
61
|
+
<%_ }) _%>
|
|
62
|
+
}
|