@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.
Files changed (279) hide show
  1. package/CHANGELOG.md +67 -0
  2. package/README.md +214 -0
  3. package/dist/runtime/analytics/index.d.ts +6 -0
  4. package/dist/runtime/analytics/index.js +49 -0
  5. package/dist/runtime/analytics/index.js.map +1 -0
  6. package/dist/runtime/analytics/metrics.d.ts +75 -0
  7. package/dist/runtime/analytics/metrics.js +1 -0
  8. package/dist/runtime/analytics/metrics.js.map +1 -0
  9. package/dist/runtime/analytics/packs/crm-entity-measures.d.ts +21 -0
  10. package/dist/runtime/analytics/packs/crm-entity-measures.js +1 -0
  11. package/dist/runtime/analytics/packs/crm-entity-measures.js.map +1 -0
  12. package/dist/runtime/analytics/packs/index.d.ts +3 -0
  13. package/dist/runtime/analytics/packs/index.js +1 -0
  14. package/dist/runtime/analytics/packs/index.js.map +1 -0
  15. package/dist/runtime/analytics/packs/monetary-measures.d.ts +21 -0
  16. package/dist/runtime/analytics/packs/monetary-measures.js +1 -0
  17. package/dist/runtime/analytics/packs/monetary-measures.js.map +1 -0
  18. package/dist/runtime/analytics/specs.d.ts +49 -0
  19. package/dist/runtime/analytics/specs.js +1 -0
  20. package/dist/runtime/analytics/specs.js.map +1 -0
  21. package/dist/runtime/analytics/types.d.ts +85 -0
  22. package/dist/runtime/analytics/types.js +49 -0
  23. package/dist/runtime/analytics/types.js.map +1 -0
  24. package/dist/runtime/base-classes/activity-entity-repository.d.ts +26 -0
  25. package/dist/runtime/base-classes/activity-entity-repository.js +195 -0
  26. package/dist/runtime/base-classes/activity-entity-repository.js.map +1 -0
  27. package/dist/runtime/base-classes/activity-entity-service.d.ts +39 -0
  28. package/dist/runtime/base-classes/activity-entity-service.js +214 -0
  29. package/dist/runtime/base-classes/activity-entity-service.js.map +1 -0
  30. package/dist/runtime/base-classes/base-read-use-cases.d.ts +68 -0
  31. package/dist/runtime/base-classes/base-read-use-cases.js +32 -0
  32. package/dist/runtime/base-classes/base-read-use-cases.js.map +1 -0
  33. package/dist/runtime/base-classes/base-repository.d.ts +99 -0
  34. package/dist/runtime/base-classes/base-repository.js +160 -0
  35. package/dist/runtime/base-classes/base-repository.js.map +1 -0
  36. package/dist/runtime/base-classes/base-service.d.ts +98 -0
  37. package/dist/runtime/base-classes/base-service.js +186 -0
  38. package/dist/runtime/base-classes/base-service.js.map +1 -0
  39. package/dist/runtime/base-classes/index.d.ts +18 -0
  40. package/dist/runtime/base-classes/index.js +617 -0
  41. package/dist/runtime/base-classes/index.js.map +1 -0
  42. package/dist/runtime/base-classes/knowledge-entity-repository.d.ts +17 -0
  43. package/dist/runtime/base-classes/knowledge-entity-repository.js +166 -0
  44. package/dist/runtime/base-classes/knowledge-entity-repository.js.map +1 -0
  45. package/dist/runtime/base-classes/knowledge-entity-service.d.ts +15 -0
  46. package/dist/runtime/base-classes/knowledge-entity-service.js +192 -0
  47. package/dist/runtime/base-classes/knowledge-entity-service.js.map +1 -0
  48. package/dist/runtime/base-classes/lifecycle-events.d.ts +49 -0
  49. package/dist/runtime/base-classes/lifecycle-events.js +76 -0
  50. package/dist/runtime/base-classes/lifecycle-events.js.map +1 -0
  51. package/dist/runtime/base-classes/metadata-entity-repository.d.ts +27 -0
  52. package/dist/runtime/base-classes/metadata-entity-repository.js +212 -0
  53. package/dist/runtime/base-classes/metadata-entity-repository.js.map +1 -0
  54. package/dist/runtime/base-classes/metadata-entity-service.d.ts +39 -0
  55. package/dist/runtime/base-classes/metadata-entity-service.js +214 -0
  56. package/dist/runtime/base-classes/metadata-entity-service.js.map +1 -0
  57. package/dist/runtime/base-classes/synced-entity-repository.d.ts +32 -0
  58. package/dist/runtime/base-classes/synced-entity-repository.js +203 -0
  59. package/dist/runtime/base-classes/synced-entity-repository.js.map +1 -0
  60. package/dist/runtime/base-classes/synced-entity-service.d.ts +41 -0
  61. package/dist/runtime/base-classes/synced-entity-service.js +215 -0
  62. package/dist/runtime/base-classes/synced-entity-service.js.map +1 -0
  63. package/dist/runtime/base-classes/with-analytics.d.ts +18 -0
  64. package/dist/runtime/base-classes/with-analytics.js +11 -0
  65. package/dist/runtime/base-classes/with-analytics.js.map +1 -0
  66. package/dist/runtime/constants/tokens.d.ts +29 -0
  67. package/dist/runtime/constants/tokens.js +8 -0
  68. package/dist/runtime/constants/tokens.js.map +1 -0
  69. package/dist/runtime/subsystems/analytics/analytics-query.protocol.d.ts +30 -0
  70. package/dist/runtime/subsystems/analytics/analytics-query.protocol.js +1 -0
  71. package/dist/runtime/subsystems/analytics/analytics-query.protocol.js.map +1 -0
  72. package/dist/runtime/subsystems/analytics/analytics.module.d.ts +34 -0
  73. package/dist/runtime/subsystems/analytics/analytics.module.js +117 -0
  74. package/dist/runtime/subsystems/analytics/analytics.module.js.map +1 -0
  75. package/dist/runtime/subsystems/analytics/analytics.tokens.d.ts +24 -0
  76. package/dist/runtime/subsystems/analytics/analytics.tokens.js +10 -0
  77. package/dist/runtime/subsystems/analytics/analytics.tokens.js.map +1 -0
  78. package/dist/runtime/subsystems/analytics/cube-backend.d.ts +28 -0
  79. package/dist/runtime/subsystems/analytics/cube-backend.js +71 -0
  80. package/dist/runtime/subsystems/analytics/cube-backend.js.map +1 -0
  81. package/dist/runtime/subsystems/analytics/index.d.ts +6 -0
  82. package/dist/runtime/subsystems/analytics/index.js +122 -0
  83. package/dist/runtime/subsystems/analytics/index.js.map +1 -0
  84. package/dist/runtime/subsystems/analytics/noop-backend.d.ts +7 -0
  85. package/dist/runtime/subsystems/analytics/noop-backend.js +25 -0
  86. package/dist/runtime/subsystems/analytics/noop-backend.js.map +1 -0
  87. package/dist/runtime/subsystems/cache/cache.drizzle-backend.d.ts +43 -0
  88. package/dist/runtime/subsystems/cache/cache.drizzle-backend.js +133 -0
  89. package/dist/runtime/subsystems/cache/cache.drizzle-backend.js.map +1 -0
  90. package/dist/runtime/subsystems/cache/cache.memory-backend.d.ts +21 -0
  91. package/dist/runtime/subsystems/cache/cache.memory-backend.js +100 -0
  92. package/dist/runtime/subsystems/cache/cache.memory-backend.js.map +1 -0
  93. package/dist/runtime/subsystems/cache/cache.module.d.ts +37 -0
  94. package/dist/runtime/subsystems/cache/cache.module.js +272 -0
  95. package/dist/runtime/subsystems/cache/cache.module.js.map +1 -0
  96. package/dist/runtime/subsystems/cache/cache.protocol.d.ts +42 -0
  97. package/dist/runtime/subsystems/cache/cache.protocol.js +1 -0
  98. package/dist/runtime/subsystems/cache/cache.protocol.js.map +1 -0
  99. package/dist/runtime/subsystems/cache/cache.schema.d.ts +64 -0
  100. package/dist/runtime/subsystems/cache/cache.schema.js +18 -0
  101. package/dist/runtime/subsystems/cache/cache.schema.js.map +1 -0
  102. package/dist/runtime/subsystems/cache/cache.tokens.d.ts +18 -0
  103. package/dist/runtime/subsystems/cache/cache.tokens.js +8 -0
  104. package/dist/runtime/subsystems/cache/cache.tokens.js.map +1 -0
  105. package/dist/runtime/subsystems/cache/index.d.ts +11 -0
  106. package/dist/runtime/subsystems/cache/index.js +277 -0
  107. package/dist/runtime/subsystems/cache/index.js.map +1 -0
  108. package/dist/runtime/subsystems/events/domain-events.schema.d.ts +187 -0
  109. package/dist/runtime/subsystems/events/domain-events.schema.js +32 -0
  110. package/dist/runtime/subsystems/events/domain-events.schema.js.map +1 -0
  111. package/dist/runtime/subsystems/events/event-bus.drizzle-backend.d.ts +38 -0
  112. package/dist/runtime/subsystems/events/event-bus.drizzle-backend.js +199 -0
  113. package/dist/runtime/subsystems/events/event-bus.drizzle-backend.js.map +1 -0
  114. package/dist/runtime/subsystems/events/event-bus.memory-backend.d.ts +18 -0
  115. package/dist/runtime/subsystems/events/event-bus.memory-backend.js +71 -0
  116. package/dist/runtime/subsystems/events/event-bus.memory-backend.js.map +1 -0
  117. package/dist/runtime/subsystems/events/event-bus.protocol.d.ts +52 -0
  118. package/dist/runtime/subsystems/events/event-bus.protocol.js +1 -0
  119. package/dist/runtime/subsystems/events/event-bus.protocol.js.map +1 -0
  120. package/dist/runtime/subsystems/events/event-bus.redis-backend.d.ts +95 -0
  121. package/dist/runtime/subsystems/events/event-bus.redis-backend.js +229 -0
  122. package/dist/runtime/subsystems/events/event-bus.redis-backend.js.map +1 -0
  123. package/dist/runtime/subsystems/events/events.module.d.ts +46 -0
  124. package/dist/runtime/subsystems/events/events.module.js +531 -0
  125. package/dist/runtime/subsystems/events/events.module.js.map +1 -0
  126. package/dist/runtime/subsystems/events/events.tokens.d.ts +19 -0
  127. package/dist/runtime/subsystems/events/events.tokens.js +8 -0
  128. package/dist/runtime/subsystems/events/events.tokens.js.map +1 -0
  129. package/dist/runtime/subsystems/events/index.d.ts +12 -0
  130. package/dist/runtime/subsystems/events/index.js +536 -0
  131. package/dist/runtime/subsystems/events/index.js.map +1 -0
  132. package/dist/runtime/subsystems/index.d.ts +24 -0
  133. package/dist/runtime/subsystems/index.js +1643 -0
  134. package/dist/runtime/subsystems/index.js.map +1 -0
  135. package/dist/runtime/subsystems/jobs/index.d.ts +14 -0
  136. package/dist/runtime/subsystems/jobs/index.js +680 -0
  137. package/dist/runtime/subsystems/jobs/index.js.map +1 -0
  138. package/dist/runtime/subsystems/jobs/job-queue.bullmq-backend.d.ts +54 -0
  139. package/dist/runtime/subsystems/jobs/job-queue.bullmq-backend.js +186 -0
  140. package/dist/runtime/subsystems/jobs/job-queue.bullmq-backend.js.map +1 -0
  141. package/dist/runtime/subsystems/jobs/job-queue.drizzle-backend.d.ts +38 -0
  142. package/dist/runtime/subsystems/jobs/job-queue.drizzle-backend.js +228 -0
  143. package/dist/runtime/subsystems/jobs/job-queue.drizzle-backend.js.map +1 -0
  144. package/dist/runtime/subsystems/jobs/job-queue.memory-backend.d.ts +12 -0
  145. package/dist/runtime/subsystems/jobs/job-queue.memory-backend.js +44 -0
  146. package/dist/runtime/subsystems/jobs/job-queue.memory-backend.js.map +1 -0
  147. package/dist/runtime/subsystems/jobs/job-queue.protocol.d.ts +48 -0
  148. package/dist/runtime/subsystems/jobs/job-queue.protocol.js +1 -0
  149. package/dist/runtime/subsystems/jobs/job-queue.protocol.js.map +1 -0
  150. package/dist/runtime/subsystems/jobs/job-queue.redis-backend.d.ts +46 -0
  151. package/dist/runtime/subsystems/jobs/job-queue.redis-backend.js +187 -0
  152. package/dist/runtime/subsystems/jobs/job-queue.redis-backend.js.map +1 -0
  153. package/dist/runtime/subsystems/jobs/job-queue.schema.d.ts +237 -0
  154. package/dist/runtime/subsystems/jobs/job-queue.schema.js +44 -0
  155. package/dist/runtime/subsystems/jobs/job-queue.schema.js.map +1 -0
  156. package/dist/runtime/subsystems/jobs/jobs.module.d.ts +18 -0
  157. package/dist/runtime/subsystems/jobs/jobs.module.js +676 -0
  158. package/dist/runtime/subsystems/jobs/jobs.module.js.map +1 -0
  159. package/dist/runtime/subsystems/jobs/jobs.tokens.d.ts +13 -0
  160. package/dist/runtime/subsystems/jobs/jobs.tokens.js +8 -0
  161. package/dist/runtime/subsystems/jobs/jobs.tokens.js.map +1 -0
  162. package/dist/runtime/subsystems/storage/index.d.ts +6 -0
  163. package/dist/runtime/subsystems/storage/index.js +204 -0
  164. package/dist/runtime/subsystems/storage/index.js.map +1 -0
  165. package/dist/runtime/subsystems/storage/storage.local-backend.d.ts +18 -0
  166. package/dist/runtime/subsystems/storage/storage.local-backend.js +108 -0
  167. package/dist/runtime/subsystems/storage/storage.local-backend.js.map +1 -0
  168. package/dist/runtime/subsystems/storage/storage.memory-backend.d.ts +28 -0
  169. package/dist/runtime/subsystems/storage/storage.memory-backend.js +72 -0
  170. package/dist/runtime/subsystems/storage/storage.memory-backend.js.map +1 -0
  171. package/dist/runtime/subsystems/storage/storage.module.d.ts +40 -0
  172. package/dist/runtime/subsystems/storage/storage.module.js +201 -0
  173. package/dist/runtime/subsystems/storage/storage.module.js.map +1 -0
  174. package/dist/runtime/subsystems/storage/storage.protocol.d.ts +69 -0
  175. package/dist/runtime/subsystems/storage/storage.protocol.js +1 -0
  176. package/dist/runtime/subsystems/storage/storage.protocol.js.map +1 -0
  177. package/dist/runtime/subsystems/storage/storage.tokens.d.ts +11 -0
  178. package/dist/runtime/subsystems/storage/storage.tokens.js +6 -0
  179. package/dist/runtime/subsystems/storage/storage.tokens.js.map +1 -0
  180. package/dist/runtime/subsystems/storage/storage.utils.d.ts +9 -0
  181. package/dist/runtime/subsystems/storage/storage.utils.js +18 -0
  182. package/dist/runtime/subsystems/storage/storage.utils.js.map +1 -0
  183. package/dist/runtime/types/drizzle.d.ts +17 -0
  184. package/dist/runtime/types/drizzle.js +1 -0
  185. package/dist/runtime/types/drizzle.js.map +1 -0
  186. package/dist/src/cli/index.d.ts +1 -0
  187. package/dist/src/cli/index.js +7365 -0
  188. package/dist/src/cli/index.js.map +1 -0
  189. package/dist/src/index.d.ts +2384 -0
  190. package/dist/src/index.js +2198 -0
  191. package/dist/src/index.js.map +1 -0
  192. package/package.json +114 -0
  193. package/templates/broadcast/new/backend-interface.ejs.t +47 -0
  194. package/templates/broadcast/new/bridge-listener.ejs.t +67 -0
  195. package/templates/broadcast/new/channel.ejs.t +77 -0
  196. package/templates/broadcast/new/index.ejs.t +21 -0
  197. package/templates/broadcast/new/memory-backend.ejs.t +87 -0
  198. package/templates/broadcast/new/module.ejs.t +57 -0
  199. package/templates/broadcast/new/prompt.js +268 -0
  200. package/templates/broadcast/new/websocket-backend.ejs.t +259 -0
  201. package/templates/entity/new/backend/application/commands/create.ejs.t +55 -0
  202. package/templates/entity/new/backend/application/commands/delete.ejs.t +45 -0
  203. package/templates/entity/new/backend/application/commands/grouped-index.ejs.t +149 -0
  204. package/templates/entity/new/backend/application/commands/index.ejs.t +15 -0
  205. package/templates/entity/new/backend/application/commands/update.ejs.t +58 -0
  206. package/templates/entity/new/backend/application/queries/declarative-queries.ejs.t +36 -0
  207. package/templates/entity/new/backend/application/queries/get-by-id.ejs.t +42 -0
  208. package/templates/entity/new/backend/application/queries/grouped-index.ejs.t +81 -0
  209. package/templates/entity/new/backend/application/queries/index.ejs.t +14 -0
  210. package/templates/entity/new/backend/application/queries/list.ejs.t +36 -0
  211. package/templates/entity/new/backend/application/schemas/_inject-index.ejs.t +7 -0
  212. package/templates/entity/new/backend/application/schemas/dto.ejs.t +45 -0
  213. package/templates/entity/new/backend/database/_inject-index.ejs.t +7 -0
  214. package/templates/entity/new/backend/database/electric-migration.ejs.t +21 -0
  215. package/templates/entity/new/backend/database/repository.ejs.t +450 -0
  216. package/templates/entity/new/backend/database/schema.ejs.t +248 -0
  217. package/templates/entity/new/backend/domain/_inject-index.ejs.t +12 -0
  218. package/templates/entity/new/backend/domain/entity.ejs.t +108 -0
  219. package/templates/entity/new/backend/domain/grouped-index.ejs.t +163 -0
  220. package/templates/entity/new/backend/domain/index.ejs.t +15 -0
  221. package/templates/entity/new/backend/domain/repository-interface.ejs.t +71 -0
  222. package/templates/entity/new/backend/modules/core/_ensure-anchor-tokens.ejs.t +10 -0
  223. package/templates/entity/new/backend/modules/core/_inject-token.ejs.t +7 -0
  224. package/templates/entity/new/backend/modules/core/module.ejs.t +67 -0
  225. package/templates/entity/new/backend/modules/trpc/module.ejs.t +67 -0
  226. package/templates/entity/new/backend/presentation/controller.ejs.t +201 -0
  227. package/templates/entity/new/clean-lite-ps/controller.ejs.t +37 -0
  228. package/templates/entity/new/clean-lite-ps/dto/create.ejs.t +17 -0
  229. package/templates/entity/new/clean-lite-ps/dto/output.ejs.t +25 -0
  230. package/templates/entity/new/clean-lite-ps/dto/update.ejs.t +11 -0
  231. package/templates/entity/new/clean-lite-ps/entity.ejs.t +52 -0
  232. package/templates/entity/new/clean-lite-ps/index.ejs.t +20 -0
  233. package/templates/entity/new/clean-lite-ps/module.ejs.t +43 -0
  234. package/templates/entity/new/clean-lite-ps/prompt-extension.js +617 -0
  235. package/templates/entity/new/clean-lite-ps/repository.ejs.t +62 -0
  236. package/templates/entity/new/clean-lite-ps/service.ejs.t +34 -0
  237. package/templates/entity/new/clean-lite-ps/use-cases/declarative-queries.ejs.t +34 -0
  238. package/templates/entity/new/clean-lite-ps/use-cases/find-by-id.ejs.t +16 -0
  239. package/templates/entity/new/clean-lite-ps/use-cases/list.ejs.t +16 -0
  240. package/templates/entity/new/frontend/_inject-entities-entry.ejs.t +7 -0
  241. package/templates/entity/new/frontend/_inject-entities-import.ejs.t +7 -0
  242. package/templates/entity/new/frontend/collections/_ensure-anchor-collections.ejs.t +10 -0
  243. package/templates/entity/new/frontend/collections/_inject-index.ejs.t +9 -0
  244. package/templates/entity/new/frontend/collections/_inject-schema-import.ejs.t +9 -0
  245. package/templates/entity/new/frontend/collections/collection.ejs.t +61 -0
  246. package/templates/entity/new/frontend/collections/collections-base.ejs.t +24 -0
  247. package/templates/entity/new/frontend/entity/collection.ejs.t +172 -0
  248. package/templates/entity/new/frontend/entity/combined.ejs.t +474 -0
  249. package/templates/entity/new/frontend/entity/fields.ejs.t +104 -0
  250. package/templates/entity/new/frontend/entity/hooks.ejs.t +73 -0
  251. package/templates/entity/new/frontend/entity/index.ejs.t +21 -0
  252. package/templates/entity/new/frontend/entity/mutation-hooks.ejs.t +84 -0
  253. package/templates/entity/new/frontend/entity/mutations.ejs.t +38 -0
  254. package/templates/entity/new/frontend/entity/types.ejs.t +59 -0
  255. package/templates/entity/new/frontend/generated/_inject-index-export.ejs.t +7 -0
  256. package/templates/entity/new/frontend/generated/_inject-index-import.ejs.t +7 -0
  257. package/templates/entity/new/frontend/generated/_inject-index-registry.ejs.t +7 -0
  258. package/templates/entity/new/frontend/store/_inject-collection-import.ejs.t +9 -0
  259. package/templates/entity/new/frontend/store/_inject-collections.ejs.t +9 -0
  260. package/templates/entity/new/frontend/store/_inject-entity.ejs.t +9 -0
  261. package/templates/entity/new/frontend/store/_inject-import.ejs.t +9 -0
  262. package/templates/entity/new/frontend/store/_inject-lookups.ejs.t +9 -0
  263. package/templates/entity/new/frontend/store/_inject-resolve.ejs.t +10 -0
  264. package/templates/entity/new/frontend/store/hooks.ejs.t +72 -0
  265. package/templates/entity/new/frontend/unified-entity.ejs.t +28 -0
  266. package/templates/entity/new/prompt.js +1421 -0
  267. package/templates/relationship/new/controller.ejs.t +36 -0
  268. package/templates/relationship/new/dto/create.ejs.t +41 -0
  269. package/templates/relationship/new/dto/output.ejs.t +44 -0
  270. package/templates/relationship/new/dto/update.ejs.t +10 -0
  271. package/templates/relationship/new/entity.ejs.t +98 -0
  272. package/templates/relationship/new/index.ejs.t +19 -0
  273. package/templates/relationship/new/module.ejs.t +35 -0
  274. package/templates/relationship/new/prompt.js +682 -0
  275. package/templates/relationship/new/repository.ejs.t +54 -0
  276. package/templates/relationship/new/service.ejs.t +31 -0
  277. package/templates/relationship/new/use-cases/declarative-queries.ejs.t +34 -0
  278. package/templates/relationship/new/use-cases/find-by-id.ejs.t +16 -0
  279. package/templates/relationship/new/use-cases/list.ejs.t +16 -0
@@ -0,0 +1,81 @@
1
+ ---
2
+ to: "<%= generate.queries ? outputPaths.queriesGroupedIndex : '' %>"
3
+ skip_if: <%= !isCleanArchitecture %>
4
+ force: true
5
+ ---
6
+ <% if (outputPaths.queriesGroupedIndex) { -%>
7
+ /**
8
+ * <%= className %> Queries Module
9
+ * Generated by entity codegen - do not edit directly
10
+ *
11
+ * This file contains all query handlers for <%= className %>
12
+ * using grouped file layout (file_grouping: "grouped")
13
+ */
14
+
15
+ import { Inject, Injectable, NotFoundException } from '@nestjs/common';
16
+ import { <%= repositoryToken %> } from '<%= imports.constants %>';
17
+ import type { I<%= className %>Repository<%= hasRelationships ? `, ${className}With` : '' %> } from '<%= imports.domain %>';
18
+ import { <%= className %> } from '<%= imports.domain %>';
19
+
20
+ // ============================================================================
21
+ // Get <%= className %> By ID Query
22
+ // ============================================================================
23
+
24
+ /**
25
+ * Get <%= className %> By ID Query
26
+ * Generated by entity codegen - do not edit directly
27
+ *
28
+ * EXTENSION POINTS (add query logic here):
29
+ * - Authorization: Check if user can access this specific record
30
+ * - Enrichment: Add computed fields or related data
31
+ * - Caching: Add cache layer for frequently accessed records
32
+ */
33
+ @Injectable()
34
+ export class <%= getByIdQueryClass %> {
35
+ constructor(
36
+ @Inject(<%= repositoryToken %>)
37
+ private readonly <%= camelName %>Repository: I<%= className %>Repository,
38
+ ) {}
39
+
40
+ async execute(id: string<%= hasRelationships ? `, include?: ${className}With` : '' %>): Promise<<%= className %>> {
41
+ // TODO: Add authorization check if needed (row-level security)
42
+
43
+ const entity = await this.<%= camelName %>Repository.findById(id<%= hasRelationships ? ', include' : '' %>);
44
+ if (!entity) {
45
+ throw new NotFoundException(`<%= className %> with id ${id} not found`);
46
+ }
47
+
48
+ // TODO: Add enrichment or computed fields if needed
49
+
50
+ return entity;
51
+ }
52
+ }
53
+
54
+ // ============================================================================
55
+ // List <%= classNamePlural %> Query
56
+ // ============================================================================
57
+
58
+ /**
59
+ * List <%= classNamePlural %> Query
60
+ * Generated by entity codegen - do not edit directly
61
+ *
62
+ * EXTENSION POINTS (add query logic here):
63
+ * - Filtering: Add where clauses based on query parameters
64
+ * - Authorization: Filter results based on user permissions (row-level security)
65
+ * - Pagination: Add limit/offset or cursor-based pagination
66
+ * - Sorting: Add order by clauses
67
+ * - Caching: Add cache layer for frequently accessed lists
68
+ */
69
+ @Injectable()
70
+ export class <%= listQueryClass %> {
71
+ constructor(
72
+ @Inject(<%= repositoryToken %>)
73
+ private readonly <%= camelName %>Repository: I<%= className %>Repository,
74
+ ) {}
75
+
76
+ async execute(<%= hasRelationships ? `include?: ${className}With` : '' %>): Promise<<%= className %>[]> {
77
+ // TODO: Add filtering, pagination, sorting as needed
78
+ return this.<%= camelName %>Repository.findAll(<%= hasRelationships ? 'include' : '' %>);
79
+ }
80
+ }
81
+ <% } -%>
@@ -0,0 +1,14 @@
1
+ ---
2
+ to: "<%= generate.queries ? outputPaths.queriesIndex : '' %>"
3
+ skip_if: <%= !isCleanArchitecture %>
4
+ force: true
5
+ ---
6
+ <% if (outputPaths.queriesIndex) { -%>
7
+ /**
8
+ * <%= className %> Queries Barrel Export
9
+ * Generated by entity codegen - do not edit directly
10
+ */
11
+
12
+ export * from './<%= fileNames.getByIdQuery.replace('.ts', '') %>';
13
+ export * from './<%= fileNames.listQuery.replace('.ts', '') %>';
14
+ <% } -%>
@@ -0,0 +1,36 @@
1
+ ---
2
+ to: "<%= generate.queries ? outputPaths.listQuery : '' %>"
3
+ skip_if: <%= !isCleanArchitecture %>
4
+ force: true
5
+ ---
6
+ <% if (outputPaths.listQuery) { -%>
7
+ /**
8
+ * List <%= classNamePlural %> Query
9
+ * Generated by entity codegen - do not edit directly
10
+ *
11
+ * EXTENSION POINTS (add query logic here):
12
+ * - Filtering: Add where clauses based on query parameters
13
+ * - Authorization: Filter results based on user permissions (row-level security)
14
+ * - Pagination: Add limit/offset or cursor-based pagination
15
+ * - Sorting: Add order by clauses
16
+ * - Caching: Add cache layer for frequently accessed lists
17
+ */
18
+
19
+ import { Inject, Injectable } from '@nestjs/common';
20
+ import { <%= repositoryToken %> } from '<%= imports.constants %>';
21
+ import type { I<%= className %>Repository<%= hasRelationships ? `, ${className}With` : '' %> } from '<%= imports.domain %>';
22
+ import { <%= className %> } from '<%= imports.domain %>';
23
+
24
+ @Injectable()
25
+ export class <%= listQueryClass %> {
26
+ constructor(
27
+ @Inject(<%= repositoryToken %>)
28
+ private readonly <%= camelName %>Repository: I<%= className %>Repository,
29
+ ) {}
30
+
31
+ async execute(<%= hasRelationships ? `include?: ${className}With` : '' %>): Promise<<%= className %>[]> {
32
+ // TODO: Add filtering, pagination, sorting as needed
33
+ return this.<%= camelName %>Repository.findAll(<%= hasRelationships ? 'include' : '' %>);
34
+ }
35
+ }
36
+ <% } -%>
@@ -0,0 +1,7 @@
1
+ ---
2
+ to: "<%= isCleanArchitecture ? (generate.dtos ? `${basePaths.backendSrc}/${backendLayers.schemas}/index.ts` : '') : '' %>"
3
+ inject: true
4
+ append: true
5
+ skip_if: <%= name %>.dto
6
+ ---
7
+ export * from './<%= name %>.dto';
@@ -0,0 +1,45 @@
1
+ ---
2
+ to: "<%= generate.dtos ? outputPaths.dto : '' %>"
3
+ skip_if: <%= !isCleanArchitecture %>
4
+ force: true
5
+ ---
6
+ /**
7
+ * <%= className %> DTOs
8
+ * Generated by entity codegen - do not edit directly
9
+ */
10
+
11
+ import { z } from 'zod';
12
+ <% if (hasEntityRefFields) { -%>
13
+ import { entityTypeSchema } from '<%= locations.dbContextEngine.import %>';
14
+ <% } -%>
15
+
16
+ export const create<%= className %>Schema = z.object({
17
+ <% fields.forEach((field) => { -%>
18
+ <% let zodChain = field.zodType; -%>
19
+ <% if (field.type === 'string' && field.maxLength) { zodChain += `.max(${field.maxLength})`; } -%>
20
+ <% if (field.type === 'string' && field.minLength) { zodChain += `.min(${field.minLength})`; } -%>
21
+ <% if (['integer', 'decimal'].includes(field.type) && field.min !== undefined) { zodChain += `.min(${field.min})`; } -%>
22
+ <% if (['integer', 'decimal'].includes(field.type) && field.max !== undefined) { zodChain += `.max(${field.max})`; } -%>
23
+ <% if (field.choices) { zodChain = `z.enum([${field.choices.map(c => `'${c}'`).join(', ')}])`; } -%>
24
+ <% if (field.nullable) { zodChain += '.nullable()'; } -%>
25
+ <% if (!field.required) { zodChain += '.optional()'; } -%>
26
+ <%- field.camelName %>: <%- zodChain %>,
27
+ <% }) -%>
28
+ });
29
+
30
+ export type Create<%= className %>Dto = z.infer<typeof create<%= className %>Schema>;
31
+
32
+ export const update<%= className %>Schema = z.object({
33
+ <% fields.forEach((field) => { -%>
34
+ <% let zodChain = field.zodType; -%>
35
+ <% if (field.type === 'string' && field.maxLength) { zodChain += `.max(${field.maxLength})`; } -%>
36
+ <% if (field.type === 'string' && field.minLength) { zodChain += `.min(${field.minLength})`; } -%>
37
+ <% if (['integer', 'decimal'].includes(field.type) && field.min !== undefined) { zodChain += `.min(${field.min})`; } -%>
38
+ <% if (['integer', 'decimal'].includes(field.type) && field.max !== undefined) { zodChain += `.max(${field.max})`; } -%>
39
+ <% if (field.choices) { zodChain = `z.enum([${field.choices.map(c => `'${c}'`).join(', ')}])`; } -%>
40
+ <% if (field.nullable) { zodChain += '.nullable()'; } -%>
41
+ <%- field.camelName %>: <%- zodChain %>.optional(),
42
+ <% }) -%>
43
+ });
44
+
45
+ export type Update<%= className %>Dto = z.infer<typeof update<%= className %>Schema>;
@@ -0,0 +1,7 @@
1
+ ---
2
+ to: "<%= isCleanArchitecture ? (generate.drizzleSchema ? `${basePaths.backendSrc}/${backendLayers.drizzle}/index.ts` : '') : '' %>"
3
+ inject: true
4
+ append: true
5
+ skip_if: <%= plural %>.schema
6
+ ---
7
+ export * from './<%= plural %>.schema';
@@ -0,0 +1,21 @@
1
+ ---
2
+ to: "<%= exposeElectric && databaseDialect === 'postgres' ? `${locations.dbMigrations.path}/${new Date().toISOString().replace(/[-:T]/g, '').slice(0, 14)}_Add${classNamePlural}ToElectric.sql` : '' %>"
3
+ skip_if: <%= !isCleanArchitecture %>
4
+ force: true
5
+ ---
6
+ -- Electric SQL setup for <%= table %>
7
+ -- Generated by entity codegen
8
+
9
+ -- Enable full row logging for Electric replication
10
+ ALTER TABLE "<%= table %>" REPLICA IDENTITY FULL;
11
+
12
+ -- Add table to Electric publication if not already a member
13
+ DO $$
14
+ BEGIN
15
+ IF NOT EXISTS (
16
+ SELECT 1 FROM pg_publication_tables
17
+ WHERE pubname = 'electric_publication_default' AND tablename = '<%= table %>'
18
+ ) THEN
19
+ ALTER PUBLICATION electric_publication_default ADD TABLE "<%= table %>";
20
+ END IF;
21
+ END $$;
@@ -0,0 +1,450 @@
1
+ ---
2
+ to: <%= basePaths.backendSrc %>/<%= paths.repositories %>/<%= name %>.repository.ts
3
+ skip_if: <%= !isCleanArchitecture %>
4
+ force: true
5
+ ---
6
+ /**
7
+ * <%= className %> Repository Implementation
8
+ * Generated by entity codegen - do not edit directly
9
+ */
10
+ <% if (behaviorStrategy === 'base_class') { -%>
11
+
12
+ import { Injectable } from '@nestjs/common';
13
+ import { eq<%= (hasEntityRefFields || hasMultiFieldQuery) ? ', and' : '' %><%= hasOrderedQuery ? ', desc, asc' : '' %> } from 'drizzle-orm';
14
+ import { BaseRepository, type BehaviorConfig } from '../base.repository';
15
+ <% if (hasEntityRefFields) { -%>
16
+ import type { EntityType } from '<%= locations.dbSchemaServer.import %>';
17
+ <% } -%>
18
+ import type {
19
+ Create<%= className %>Input,
20
+ I<%= className %>Repository,
21
+ Update<%= className %>Input,
22
+ <% if (hasRelationships) { -%>
23
+ <%= className %>With,
24
+ <% } -%>
25
+ } from '../../../domain';
26
+ <%
27
+ // Collect unique entity imports - only include relationships with existing target entities
28
+ const entityImports = new Set([className]);
29
+ if (hasExistingRelationships) {
30
+ [...existingBelongsTo, ...existingHasMany, ...existingHasOne].forEach((rel) => {
31
+ entityImports.add(rel.targetClass);
32
+ });
33
+ }
34
+ -%>
35
+ import { <%- [...entityImports].join(', ') %> } from '../../../domain';
36
+ import { <%= plural %> } from '<%= locations.dbSchemaServer.import %>';
37
+
38
+ @Injectable()
39
+ export class <%= className %>Repository
40
+ extends BaseRepository<
41
+ typeof <%= plural %>,
42
+ <%= className %>,
43
+ Create<%= className %>Input,
44
+ Update<%= className %>Input
45
+ >
46
+ implements I<%= className %>Repository
47
+ {
48
+ protected readonly table = <%= plural %>;
49
+
50
+ // Behaviors declared in YAML -> generated as config object
51
+ protected readonly behaviors: BehaviorConfig = {
52
+ timestamps: <%= repositoryBehaviorConfig.timestamps %>,
53
+ softDelete: <%= repositoryBehaviorConfig.softDelete %>,
54
+ userTracking: <%= repositoryBehaviorConfig.userTracking %>,
55
+ };
56
+
57
+ protected toEntity(record: typeof <%= plural %>.$inferSelect): <%= className %> {
58
+ return <%= className %>.fromRecord(record);
59
+ }
60
+ <% belongsToRelations.forEach((rel) => { -%>
61
+
62
+ async findBy<%= rel.foreignKeyPascal %>(id: string): Promise<<%= className %>[]> {
63
+ const records = await this.baseQuery()
64
+ .where(eq(this.table.<%= rel.foreignKeyCamel %>, id));
65
+ return records.map((r) => this.toEntity(r));
66
+ }
67
+ <% }) -%>
68
+ <% entityRefFields.forEach((ref) => { -%>
69
+
70
+ async findBy<%= ref.pascalName %>(entityType: EntityType, entityId: string): Promise<<%= className %>[]> {
71
+ const records = await this.baseQuery()
72
+ .where(
73
+ and(
74
+ eq(this.table.<%= ref.camelName %>EntityType, entityType),
75
+ eq(this.table.<%= ref.camelName %>EntityId, entityId)
76
+ )
77
+ );
78
+ return records.map((r) => this.toEntity(r));
79
+ }
80
+ <% }) -%>
81
+ <% if (hasDeclarativeQueries) { -%>
82
+
83
+ // ═══════════════════════════════════════════════════════════════════════
84
+ // Declarative queries (from queries: block in entity YAML)
85
+ // ═══════════════════════════════════════════════════════════════════════
86
+ <% processedQueries.forEach((q) => { -%>
87
+
88
+ async <%= q.methodName %>(<%- q.params.map(p => `${p.camelName}: ${p.tsType}`).join(', ') %>): Promise<<%- q.returnType %>> {
89
+ <% if (q.hasVia) { -%>
90
+ // Junction query through <%= q.viaTable %>
91
+ const junctionRecords = await this.baseQuery()
92
+ .innerJoin(<%= q.viaTableCamel %>, eq(<%= q.viaTableCamel %>.<%= name %>Id, this.table.id))
93
+ .where(<%= q.params.map(p => `eq(${q.viaTableCamel}.${p.camelName}, ${p.camelName})`).join(', ') %>);
94
+ <% if (q.hasSelect) { -%>
95
+ return junctionRecords.map(r => r.<%= q.selectFields[0] %>);
96
+ <% } else { -%>
97
+ return junctionRecords.map(r => this.toEntity(r));
98
+ <% } -%>
99
+ <% } else if (q.isUnique) { -%>
100
+ const records = await this.baseQuery()
101
+ .where(<%= q.hasMultipleParams ? 'and(' : '' %><%= q.params.map(p => `eq(this.table.${p.camelName}, ${p.camelName})`).join(', ') %><%= q.hasMultipleParams ? ')' : '' %>)
102
+ .limit(1);
103
+ return records[0] ? this.toEntity(records[0]) : null;
104
+ <% } else { -%>
105
+ const records = await this.baseQuery()
106
+ .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}))` : '' %>;
107
+ return records.map(r => this.toEntity(r));
108
+ <% } -%>
109
+ }
110
+ <% }) -%>
111
+ <% } -%>
112
+ <% if (hasRelationships) { -%>
113
+
114
+ // ═══════════════════════════════════════════════════════════════════════
115
+ // Relationship loading (extends base class)
116
+ // ═══════════════════════════════════════════════════════════════════════
117
+
118
+ async findByIdWithRelations(
119
+ id: string,
120
+ include?: <%= className %>With,
121
+ ): Promise<<%= className %> | null> {
122
+ const record = await this.db.query.<%= plural %>.findFirst({
123
+ where: eq(<%= plural %>.id, id),
124
+ with: this.buildWithClause(include),
125
+ });
126
+ return record ? this.mapToEntityWithRelations(record) : null;
127
+ }
128
+
129
+ async findAllWithRelations(include?: <%= className %>With): Promise<<%= className %>[]> {
130
+ const records = await this.db.query.<%= plural %>.findMany({
131
+ with: this.buildWithClause(include),
132
+ });
133
+ return records.map((r) => this.mapToEntityWithRelations(r));
134
+ }
135
+
136
+ private buildWithClause(include?: <%= className %>With) {
137
+ if (!include) return undefined;
138
+ const result: Record<string, true> = {};
139
+ <% relationships.forEach((rel) => { -%>
140
+ if (include.<%= rel.name %>) result.<%= rel.name %> = true;
141
+ <% }) -%>
142
+ return Object.keys(result).length > 0 ? result : undefined;
143
+ }
144
+
145
+ // biome-ignore lint/suspicious/noExplicitAny: Drizzle relational query returns dynamic shape
146
+ private mapToEntityWithRelations(record: any): <%= className %> {
147
+ <% if (hasExistingRelationships) { -%>
148
+ return <%= className %>.fromRecord(record, (name, data) => {
149
+ switch (name) {
150
+ <% existingBelongsTo.forEach((rel) => { -%>
151
+ case '<%= rel.name %>':
152
+ // biome-ignore lint/suspicious/noExplicitAny: Cast for Drizzle record
153
+ return <%= rel.targetClass %>.fromRecord(data as any);
154
+ <% }) -%>
155
+ <% existingHasMany.forEach((rel) => { -%>
156
+ case '<%= rel.name %>':
157
+ // biome-ignore lint/suspicious/noExplicitAny: Cast for Drizzle records
158
+ return (data as any[]).map((r) => <%= rel.targetClass %>.fromRecord(r));
159
+ <% }) -%>
160
+ <% existingHasOne.forEach((rel) => { -%>
161
+ case '<%= rel.name %>':
162
+ // biome-ignore lint/suspicious/noExplicitAny: Cast for Drizzle record
163
+ return <%= rel.targetClass %>.fromRecord(data as any);
164
+ <% }) -%>
165
+ default:
166
+ return data;
167
+ }
168
+ });
169
+ <% } else { -%>
170
+ // Related entities not yet generated - return entity without relationship mapping
171
+ return <%= className %>.fromRecord(record);
172
+ <% } -%>
173
+ }
174
+ <% } -%>
175
+ }
176
+ <% } else { -%>
177
+ <%# ================================================================== -%>
178
+ <%# INLINE STRATEGY - Full CRUD code generated directly -%>
179
+ <%# ================================================================== -%>
180
+
181
+ import { Inject, Injectable } from '@nestjs/common';
182
+ import { eq<%= hasSoftDelete ? ', isNull, isNotNull' : '' %><%= (hasEntityRefFields || hasMultiFieldQuery) ? ', and' : '' %><%= hasOrderedQuery ? ', desc, asc' : '' %> } from 'drizzle-orm';
183
+ import { DRIZZLE } from '<%= imports.repositoryToConstants %>';
184
+ <% if (hasEntityRefFields) { -%>
185
+ import type { EntityType } from '<%= locations.dbSchemaServer.import %>';
186
+ <% } -%>
187
+ import type {
188
+ Create<%= className %>Input,
189
+ I<%= className %>Repository,
190
+ Update<%= className %>Input,
191
+ <% if (hasRelationships) { -%>
192
+ <%= className %>With,
193
+ <% } -%>
194
+ } from '../../../domain';
195
+ <%
196
+ // Collect unique entity imports - only include relationships with existing target entities
197
+ const entityImports = new Set([className]);
198
+ if (hasExistingRelationships) {
199
+ [...existingBelongsTo, ...existingHasMany, ...existingHasOne].forEach((rel) => {
200
+ entityImports.add(rel.targetClass);
201
+ });
202
+ }
203
+ -%>
204
+ import { <%- [...entityImports].join(', ') %> } from '../../../domain';
205
+ import type { DrizzleDB } from '../database.module';
206
+ import { <%= plural %> } from '<%= locations.dbSchemaServer.import %>';
207
+
208
+ @Injectable()
209
+ export class <%= className %>Repository implements I<%= className %>Repository {
210
+ constructor(@Inject(DRIZZLE) private readonly db: DrizzleDB) {}
211
+
212
+ async create(input: Create<%= className %>Input): Promise<<%= className %>> {
213
+ <% if (hasTimestamps) { -%>
214
+ const now = new Date();
215
+ <% } -%>
216
+ const result = await this.db
217
+ .insert(<%= plural %>)
218
+ .values({
219
+ <% fields.forEach((field) => { -%>
220
+ <%= field.camelName %>: input.<%= field.camelName %>,
221
+ <% }) -%>
222
+ <% if (hasTimestamps) { -%>
223
+ createdAt: now,
224
+ updatedAt: now,
225
+ <% } -%>
226
+ })
227
+ .returning();
228
+
229
+ const record = result[0] as typeof <%= plural %>.$inferSelect;
230
+ return <%= className %>.fromRecord(record);
231
+ }
232
+
233
+ async findById(id: string<%= hasRelationships ? `, include?: ${className}With` : '' %>): Promise<<%= className %> | null> {
234
+ <% if (hasRelationships) { -%>
235
+ const record = await this.db.query.<%= plural %>.findFirst({
236
+ where: eq(<%= plural %>.id, id),
237
+ with: this.buildWithClause(include),
238
+ });
239
+
240
+ return record ? this.mapToEntity(record) : null;
241
+ <% } else { -%>
242
+ const result = await this.baseQuery()
243
+ .where(eq(<%= plural %>.id, id))
244
+ .limit(1);
245
+
246
+ const record = result[0];
247
+ return record ? <%= className %>.fromRecord(record) : null;
248
+ <% } -%>
249
+ }
250
+
251
+ async findAll(<%= hasRelationships ? `include?: ${className}With` : '' %>): Promise<<%= className %>[]> {
252
+ <% if (hasRelationships) { -%>
253
+ const records = await this.db.query.<%= plural %>.findMany({
254
+ with: this.buildWithClause(include),
255
+ });
256
+
257
+ return records.map((r) => this.mapToEntity(r));
258
+ <% } else { -%>
259
+ const records = await this.baseQuery();
260
+ return records.map(<%= className %>.fromRecord);
261
+ <% } -%>
262
+ }
263
+
264
+ async update(id: string, input: Update<%= className %>Input): Promise<<%= className %> | null> {
265
+ const result = await this.db
266
+ .update(<%= plural %>)
267
+ .set({
268
+ ...input,
269
+ <% if (hasTimestamps) { -%>
270
+ updatedAt: new Date(),
271
+ <% } -%>
272
+ })
273
+ .where(eq(<%= plural %>.id, id))
274
+ .returning();
275
+
276
+ const record = result[0];
277
+ return record ? <%= className %>.fromRecord(record) : null;
278
+ }
279
+
280
+ async delete(id: string): Promise<<%= className %> | null> {
281
+ <% if (hasSoftDelete) { -%>
282
+ // Soft delete - set deletedAt timestamp
283
+ const result = await this.db
284
+ .update(<%= plural %>)
285
+ .set({ deletedAt: new Date() })
286
+ .where(eq(<%= plural %>.id, id))
287
+ .returning();
288
+ <% } else { -%>
289
+ const result = await this.db
290
+ .delete(<%= plural %>)
291
+ .where(eq(<%= plural %>.id, id))
292
+ .returning();
293
+ <% } -%>
294
+
295
+ const record = result[0];
296
+ return record ? <%= className %>.fromRecord(record) : null;
297
+ }
298
+ <% if (hasSoftDelete) { -%>
299
+
300
+ async restore(id: string): Promise<<%= className %> | null> {
301
+ const result = await this.db
302
+ .update(<%= plural %>)
303
+ .set({ deletedAt: null })
304
+ .where(eq(<%= plural %>.id, id))
305
+ .returning();
306
+
307
+ const record = result[0];
308
+ return record ? <%= className %>.fromRecord(record) : null;
309
+ }
310
+
311
+ async findWithDeleted(): Promise<<%= className %>[]> {
312
+ const records = await this.db.select().from(<%= plural %>);
313
+ return records.map(<%= className %>.fromRecord);
314
+ }
315
+
316
+ async findOnlyDeleted(): Promise<<%= className %>[]> {
317
+ const records = await this.db
318
+ .select()
319
+ .from(<%= plural %>)
320
+ .where(isNotNull(<%= plural %>.deletedAt));
321
+ return records.map(<%= className %>.fromRecord);
322
+ }
323
+ <% } -%>
324
+
325
+ private baseQuery() {
326
+ <% if (hasSoftDelete) { -%>
327
+ return this.db.select().from(<%= plural %>).where(isNull(<%= plural %>.deletedAt));
328
+ <% } else { -%>
329
+ return this.db.select().from(<%= plural %>);
330
+ <% } -%>
331
+ }
332
+ <% belongsToRelations.forEach((rel) => { -%>
333
+
334
+ async findBy<%= rel.foreignKeyPascal %>(id: string<%= hasRelationships ? `, include?: ${className}With` : '' %>): Promise<<%= className %>[]> {
335
+ <% if (hasRelationships) { -%>
336
+ const records = await this.db.query.<%= plural %>.findMany({
337
+ where: eq(<%= plural %>.<%= rel.foreignKeyCamel %>, id),
338
+ with: this.buildWithClause(include),
339
+ });
340
+
341
+ return records.map((r) => this.mapToEntity(r));
342
+ <% } else { -%>
343
+ const records = await this.baseQuery()
344
+ .where(eq(<%= plural %>.<%= rel.foreignKeyCamel %>, id));
345
+
346
+ return records.map(<%= className %>.fromRecord);
347
+ <% } -%>
348
+ }
349
+ <% }) -%>
350
+ <% entityRefFields.forEach((ref) => { -%>
351
+
352
+ async findBy<%= ref.pascalName %>(entityType: EntityType, entityId: string<%= hasRelationships ? `, include?: ${className}With` : '' %>): Promise<<%= className %>[]> {
353
+ <% if (hasRelationships) { -%>
354
+ const records = await this.db.query.<%= plural %>.findMany({
355
+ where: and(
356
+ eq(<%= plural %>.<%= ref.camelName %>EntityType, entityType),
357
+ eq(<%= plural %>.<%= ref.camelName %>EntityId, entityId)
358
+ ),
359
+ with: this.buildWithClause(include),
360
+ });
361
+
362
+ return records.map((r) => this.mapToEntity(r));
363
+ <% } else { -%>
364
+ const records = await this.baseQuery()
365
+ .where(
366
+ and(
367
+ eq(<%= plural %>.<%= ref.camelName %>EntityType, entityType),
368
+ eq(<%= plural %>.<%= ref.camelName %>EntityId, entityId)
369
+ )
370
+ );
371
+
372
+ return records.map(<%= className %>.fromRecord);
373
+ <% } -%>
374
+ }
375
+ <% }) -%>
376
+ <% if (hasDeclarativeQueries) { -%>
377
+
378
+ // ═══════════════════════════════════════════════════════════════════════
379
+ // Declarative queries (from queries: block in entity YAML)
380
+ // ═══════════════════════════════════════════════════════════════════════
381
+ <% processedQueries.forEach((q) => { -%>
382
+
383
+ async <%= q.methodName %>(<%- q.params.map(p => `${p.camelName}: ${p.tsType}`).join(', ') %>): Promise<<%- q.returnType %>> {
384
+ <% if (q.hasVia) { -%>
385
+ // Junction query through <%= q.viaTable %>
386
+ const junctionRecords = await this.baseQuery()
387
+ .innerJoin(<%= q.viaTableCamel %>, eq(<%= q.viaTableCamel %>.<%= name %>Id, <%= plural %>.id))
388
+ .where(<%= q.params.map(p => `eq(${q.viaTableCamel}.${p.camelName}, ${p.camelName})`).join(', ') %>);
389
+ <% if (q.hasSelect) { -%>
390
+ return junctionRecords.map(r => r.<%= q.selectFields[0] %>);
391
+ <% } else { -%>
392
+ return junctionRecords.map(r => <%= className %>.fromRecord(r));
393
+ <% } -%>
394
+ <% } else if (q.isUnique) { -%>
395
+ const records = await this.baseQuery()
396
+ .where(<%= q.hasMultipleParams ? 'and(' : '' %><%= q.params.map(p => `eq(${plural}.${p.camelName}, ${p.camelName})`).join(', ') %><%= q.hasMultipleParams ? ')' : '' %>)
397
+ .limit(1);
398
+ return records[0] ? <%= className %>.fromRecord(records[0]) : null;
399
+ <% } else { -%>
400
+ const records = await this.baseQuery()
401
+ .where(<%= q.hasMultipleParams ? 'and(' : '' %><%= q.params.map(p => `eq(${plural}.${p.camelName}, ${p.camelName})`).join(', ') %><%= q.hasMultipleParams ? ')' : '' %>)<%= q.hasOrder ? `.orderBy(${q.orderDirection}(${plural}.${q.orderBy}))` : '' %>;
402
+ return records.map(<%= className %>.fromRecord);
403
+ <% } -%>
404
+ }
405
+ <% }) -%>
406
+ <% } -%>
407
+ <% if (hasRelationships) { -%>
408
+
409
+ private buildWithClause(include?: <%= className %>With) {
410
+ if (!include) return undefined;
411
+ // Drizzle expects `true` or object, not `false`. Only include truthy values.
412
+ const result: Record<string, true> = {};
413
+ <% relationships.forEach((rel) => { -%>
414
+ if (include.<%= rel.name %>) result.<%= rel.name %> = true;
415
+ <% }) -%>
416
+ return Object.keys(result).length > 0 ? result : undefined;
417
+ }
418
+
419
+ // biome-ignore lint/suspicious/noExplicitAny: Drizzle relational query returns dynamic shape
420
+ private mapToEntity(record: any): <%= className %> {
421
+ <% if (hasExistingRelationships) { -%>
422
+ return <%= className %>.fromRecord(record, (name, data) => {
423
+ switch (name) {
424
+ <% existingBelongsTo.forEach((rel) => { -%>
425
+ case '<%= rel.name %>':
426
+ // biome-ignore lint/suspicious/noExplicitAny: Cast for Drizzle record
427
+ return <%= rel.targetClass %>.fromRecord(data as any);
428
+ <% }) -%>
429
+ <% existingHasMany.forEach((rel) => { -%>
430
+ case '<%= rel.name %>':
431
+ // biome-ignore lint/suspicious/noExplicitAny: Cast for Drizzle records
432
+ return (data as any[]).map((r) => <%= rel.targetClass %>.fromRecord(r));
433
+ <% }) -%>
434
+ <% existingHasOne.forEach((rel) => { -%>
435
+ case '<%= rel.name %>':
436
+ // biome-ignore lint/suspicious/noExplicitAny: Cast for Drizzle record
437
+ return <%= rel.targetClass %>.fromRecord(data as any);
438
+ <% }) -%>
439
+ default:
440
+ return data;
441
+ }
442
+ });
443
+ <% } else { -%>
444
+ // Related entities not yet generated - return entity without relationship mapping
445
+ return <%= className %>.fromRecord(record);
446
+ <% } -%>
447
+ }
448
+ <% } -%>
449
+ }
450
+ <% } -%>