@tstdl/base 0.93.87 → 0.93.90

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 (314) hide show
  1. package/ai/genkit/helpers.d.ts +3 -1
  2. package/ai/genkit/helpers.js +3 -3
  3. package/api/server/gateway.d.ts +3 -0
  4. package/api/server/gateway.js +15 -4
  5. package/api/server/middlewares/catch-error.middleware.js +2 -4
  6. package/api/server/middlewares/cors.middleware.js +2 -3
  7. package/api/server/middlewares/csrf.middleware.d.ts +41 -0
  8. package/api/server/middlewares/csrf.middleware.js +108 -0
  9. package/api/server/middlewares/index.d.ts +1 -0
  10. package/api/server/middlewares/index.js +1 -0
  11. package/api/server/module.d.ts +8 -2
  12. package/api/server/module.js +14 -8
  13. package/api/server/tests/csrf.middleware.test.js +91 -0
  14. package/audit/drizzle/{0000_bored_stick.sql → 0000_lumpy_thunderball.sql} +3 -3
  15. package/audit/drizzle/meta/0000_snapshot.json +4 -4
  16. package/audit/drizzle/meta/_journal.json +2 -9
  17. package/audit/module.d.ts +4 -1
  18. package/audit/module.js +3 -2
  19. package/audit/schemas.d.ts +1 -1
  20. package/audit/types.d.ts +1 -1
  21. package/audit/types.js +1 -1
  22. package/authentication/client/authentication.service.d.ts +14 -1
  23. package/authentication/client/authentication.service.js +82 -23
  24. package/authentication/client/http-client.middleware.d.ts +6 -0
  25. package/authentication/client/http-client.middleware.js +36 -0
  26. package/authentication/client/module.js +8 -2
  27. package/authentication/models/service-account.model.d.ts +2 -2
  28. package/authentication/models/service-account.model.js +10 -5
  29. package/authentication/models/subject.model.d.ts +20 -5
  30. package/authentication/models/subject.model.js +34 -29
  31. package/authentication/models/system-account.model.d.ts +3 -2
  32. package/authentication/models/system-account.model.js +11 -5
  33. package/authentication/models/user.model.d.ts +2 -11
  34. package/authentication/models/user.model.js +5 -16
  35. package/authentication/server/authentication-api-request-token.provider.d.ts +0 -2
  36. package/authentication/server/authentication-api-request-token.provider.js +3 -11
  37. package/authentication/server/authentication.api-controller.d.ts +1 -2
  38. package/authentication/server/authentication.api-controller.js +8 -9
  39. package/authentication/server/authentication.audit.d.ts +3 -2
  40. package/authentication/server/authentication.service.d.ts +27 -1
  41. package/authentication/server/authentication.service.js +67 -18
  42. package/authentication/server/drizzle/{0000_normal_paper_doll.sql → 0000_soft_tag.sql} +25 -32
  43. package/authentication/server/drizzle/meta/0000_snapshot.json +180 -205
  44. package/authentication/server/drizzle/meta/_journal.json +2 -2
  45. package/authentication/server/helper.js +9 -2
  46. package/authentication/server/module.d.ts +4 -1
  47. package/authentication/server/module.js +9 -5
  48. package/authentication/server/schemas.d.ts +2 -1
  49. package/authentication/server/schemas.js +2 -2
  50. package/authentication/server/subject.service.d.ts +17 -11
  51. package/authentication/server/subject.service.js +86 -84
  52. package/authentication/tests/authentication-ancillary.service.test.d.ts +1 -0
  53. package/authentication/tests/authentication-ancillary.service.test.js +13 -0
  54. package/authentication/tests/authentication-secret-requirements.validator.test.d.ts +1 -0
  55. package/authentication/tests/authentication-secret-requirements.validator.test.js +29 -0
  56. package/authentication/tests/authentication.api-controller.test.d.ts +1 -0
  57. package/authentication/tests/authentication.api-controller.test.js +88 -0
  58. package/authentication/tests/authentication.api-request-token.provider.test.d.ts +1 -0
  59. package/authentication/tests/authentication.api-request-token.provider.test.js +48 -0
  60. package/authentication/tests/authentication.client-middleware.test.d.ts +1 -0
  61. package/authentication/tests/authentication.client-middleware.test.js +23 -0
  62. package/authentication/tests/authentication.client-service.test.d.ts +1 -0
  63. package/authentication/tests/authentication.client-service.test.js +70 -0
  64. package/authentication/tests/authentication.service.test.d.ts +1 -0
  65. package/authentication/tests/authentication.service.test.js +186 -0
  66. package/authentication/tests/authentication.test-ancillary-service.d.ts +9 -0
  67. package/authentication/tests/authentication.test-ancillary-service.js +27 -0
  68. package/authentication/tests/helper.test.d.ts +1 -0
  69. package/authentication/tests/helper.test.js +107 -0
  70. package/authentication/tests/secret-requirements.error.test.d.ts +1 -0
  71. package/authentication/tests/secret-requirements.error.test.js +14 -0
  72. package/authentication/tests/subject.service.test.d.ts +1 -0
  73. package/authentication/tests/subject.service.test.js +140 -0
  74. package/circuit-breaker/postgres/drizzle/meta/0000_snapshot.json +1 -1
  75. package/circuit-breaker/postgres/drizzle/meta/_journal.json +2 -2
  76. package/circuit-breaker/postgres/module.d.ts +7 -1
  77. package/circuit-breaker/postgres/module.js +8 -6
  78. package/circuit-breaker/tests/circuit-breaker.test.js +2 -22
  79. package/document-management/api/document-management.api.js +2 -6
  80. package/document-management/server/services/document-validation.service.js +6 -5
  81. package/document-management/server/services/document-workflow.service.js +5 -5
  82. package/document-management/service-models/document-folders.view-model.d.ts +5 -2
  83. package/document-management/service-models/document-folders.view-model.js +42 -9
  84. package/document-management/service-models/enriched/enriched-document-management-data.view.js +1 -1
  85. package/examples/document-management/main.js +4 -4
  86. package/http/client/adapters/undici.adapter.d.ts +7 -5
  87. package/http/client/adapters/undici.adapter.js +13 -10
  88. package/http/client/module.d.ts +3 -1
  89. package/http/client/module.js +8 -9
  90. package/http/server/http-server.d.ts +2 -0
  91. package/http/server/node/module.d.ts +6 -2
  92. package/http/server/node/module.js +6 -4
  93. package/http/server/node/node-http-server.d.ts +2 -0
  94. package/http/server/node/node-http-server.js +7 -0
  95. package/http/types.d.ts +1 -1
  96. package/key-value-store/postgres/module.d.ts +7 -1
  97. package/key-value-store/postgres/module.js +7 -3
  98. package/lock/postgres/lock.js +0 -1
  99. package/lock/postgres/module.d.ts +7 -1
  100. package/lock/postgres/module.js +9 -5
  101. package/logger/formatter.d.ts +2 -0
  102. package/logger/formatters/json.js +2 -2
  103. package/logger/formatters/pretty-print.js +8 -10
  104. package/logger/logger.d.ts +1 -1
  105. package/logger/logger.js +15 -12
  106. package/message-bus/local/module.d.ts +5 -2
  107. package/message-bus/local/module.js +5 -4
  108. package/module/module.d.ts +2 -1
  109. package/module/module.js +3 -0
  110. package/module/modules/web-server.module.d.ts +11 -6
  111. package/module/modules/web-server.module.js +15 -10
  112. package/orm/decorators.d.ts +24 -1
  113. package/orm/decorators.js +40 -4
  114. package/orm/query/base.d.ts +17 -17
  115. package/orm/query/base.js +1 -1
  116. package/orm/repository.types.d.ts +45 -1
  117. package/orm/schemas/tsvector.js +1 -1
  118. package/orm/server/drizzle/schema-converter.d.ts +3 -1
  119. package/orm/server/drizzle/schema-converter.js +120 -14
  120. package/orm/server/index.d.ts +1 -0
  121. package/orm/server/index.js +1 -0
  122. package/orm/server/module.d.ts +4 -2
  123. package/orm/server/module.js +6 -5
  124. package/orm/server/query-converter.d.ts +6 -3
  125. package/orm/server/query-converter.js +32 -20
  126. package/orm/server/repository-config.d.ts +8 -0
  127. package/orm/server/repository-config.js +8 -0
  128. package/orm/server/repository.d.ts +117 -43
  129. package/orm/server/repository.js +757 -253
  130. package/orm/server/transaction.d.ts +4 -2
  131. package/orm/server/transaction.js +14 -5
  132. package/orm/server/transactional.d.ts +6 -2
  133. package/orm/server/transactional.js +39 -9
  134. package/orm/server/types.d.ts +2 -0
  135. package/orm/sqls/case-when.d.ts +3 -3
  136. package/orm/sqls/case-when.js +2 -2
  137. package/orm/sqls/sqls.d.ts +31 -5
  138. package/orm/sqls/sqls.js +69 -6
  139. package/orm/tests/data-types.test.d.ts +1 -0
  140. package/orm/tests/data-types.test.js +39 -0
  141. package/orm/tests/decorators.test.d.ts +1 -0
  142. package/orm/tests/decorators.test.js +77 -0
  143. package/orm/tests/encryption.test.d.ts +1 -0
  144. package/orm/tests/encryption.test.js +34 -0
  145. package/orm/tests/query-complex.test.d.ts +1 -0
  146. package/orm/tests/query-complex.test.js +203 -0
  147. package/orm/tests/query-converter-complex.test.d.ts +1 -0
  148. package/orm/tests/query-converter-complex.test.js +126 -0
  149. package/orm/tests/query-converter.test.d.ts +1 -0
  150. package/orm/tests/query-converter.test.js +123 -0
  151. package/orm/tests/repository-advanced.test.d.ts +1 -0
  152. package/orm/tests/repository-advanced.test.js +232 -0
  153. package/orm/tests/repository-attributes.test.d.ts +1 -0
  154. package/orm/tests/repository-attributes.test.js +99 -0
  155. package/orm/tests/repository-comprehensive.test.d.ts +1 -0
  156. package/orm/tests/repository-comprehensive.test.js +187 -0
  157. package/orm/tests/repository-coverage.test.d.ts +1 -0
  158. package/orm/tests/repository-coverage.test.js +303 -0
  159. package/orm/tests/repository-cti-complex.test.d.ts +1 -0
  160. package/orm/tests/repository-cti-complex.test.js +170 -0
  161. package/orm/tests/repository-cti-embedded.test.d.ts +1 -0
  162. package/orm/tests/repository-cti-embedded.test.js +188 -0
  163. package/orm/tests/repository-cti-extensive.test.d.ts +1 -0
  164. package/orm/tests/repository-cti-extensive.test.js +308 -0
  165. package/orm/tests/repository-cti-mapping.test.d.ts +1 -0
  166. package/orm/tests/repository-cti-mapping.test.js +121 -0
  167. package/orm/tests/repository-cti-search.test.d.ts +1 -0
  168. package/orm/tests/repository-cti-search.test.js +152 -0
  169. package/orm/tests/repository-cti-soft-delete.test.d.ts +1 -0
  170. package/orm/tests/repository-cti-soft-delete.test.js +115 -0
  171. package/orm/tests/repository-cti-transactions.test.d.ts +1 -0
  172. package/orm/tests/repository-cti-transactions.test.js +126 -0
  173. package/orm/tests/repository-cti-upsert-many.test.d.ts +1 -0
  174. package/orm/tests/repository-cti-upsert-many.test.js +127 -0
  175. package/orm/tests/repository-cti.test.d.ts +1 -0
  176. package/orm/tests/repository-cti.test.js +456 -0
  177. package/orm/tests/repository-edge-cases.test.d.ts +1 -0
  178. package/orm/tests/repository-edge-cases.test.js +216 -0
  179. package/orm/tests/repository-expiration.test.d.ts +1 -0
  180. package/orm/tests/repository-expiration.test.js +153 -0
  181. package/orm/tests/repository-extra-coverage.test.d.ts +1 -0
  182. package/orm/tests/repository-extra-coverage.test.js +546 -0
  183. package/orm/tests/repository-mapping.test.d.ts +1 -0
  184. package/orm/tests/repository-mapping.test.js +71 -0
  185. package/orm/tests/repository-regression.test.d.ts +1 -0
  186. package/orm/tests/repository-regression.test.js +330 -0
  187. package/orm/tests/repository-search-coverage.test.d.ts +1 -0
  188. package/orm/tests/repository-search-coverage.test.js +129 -0
  189. package/orm/tests/repository-search.test.d.ts +1 -0
  190. package/orm/tests/repository-search.test.js +116 -0
  191. package/orm/tests/repository-soft-delete.test.d.ts +1 -0
  192. package/orm/tests/repository-soft-delete.test.js +143 -0
  193. package/orm/tests/repository-transactions-nested.test.d.ts +1 -0
  194. package/orm/tests/repository-transactions-nested.test.js +202 -0
  195. package/orm/tests/repository-types.test.d.ts +1 -0
  196. package/orm/tests/repository-types.test.js +218 -0
  197. package/orm/tests/schema-converter.test.d.ts +1 -0
  198. package/orm/tests/schema-converter.test.js +81 -0
  199. package/orm/tests/schema-generation.test.d.ts +1 -0
  200. package/orm/tests/schema-generation.test.js +127 -0
  201. package/orm/tests/sql-helpers.test.d.ts +1 -0
  202. package/orm/tests/sql-helpers.test.js +67 -0
  203. package/orm/tests/transaction-safety.test.d.ts +1 -0
  204. package/orm/tests/transaction-safety.test.js +81 -0
  205. package/orm/tests/transactional.test.d.ts +1 -0
  206. package/orm/tests/transactional.test.js +224 -0
  207. package/orm/tests/utils.test.d.ts +1 -0
  208. package/orm/tests/utils.test.js +70 -0
  209. package/orm/utils.d.ts +7 -0
  210. package/orm/utils.js +26 -6
  211. package/package.json +12 -7
  212. package/pool/pool.js +1 -1
  213. package/rate-limit/index.d.ts +2 -0
  214. package/rate-limit/index.js +2 -0
  215. package/rate-limit/postgres/drizzle/0000_watery_rage.sql +7 -0
  216. package/{queue → rate-limit}/postgres/drizzle/meta/0000_snapshot.json +14 -39
  217. package/rate-limit/postgres/drizzle/meta/_journal.json +13 -0
  218. package/{queue → rate-limit}/postgres/drizzle.config.js +1 -1
  219. package/rate-limit/postgres/index.d.ts +4 -0
  220. package/rate-limit/postgres/index.js +4 -0
  221. package/rate-limit/postgres/module.d.ts +12 -0
  222. package/rate-limit/postgres/module.js +28 -0
  223. package/rate-limit/postgres/postgres-rate-limiter.d.ts +9 -0
  224. package/rate-limit/postgres/postgres-rate-limiter.js +56 -0
  225. package/rate-limit/postgres/rate-limit.model.d.ts +8 -0
  226. package/rate-limit/postgres/rate-limit.model.js +35 -0
  227. package/rate-limit/postgres/rate-limiter.provider.d.ts +6 -0
  228. package/rate-limit/postgres/rate-limiter.provider.js +21 -0
  229. package/rate-limit/postgres/schemas.d.ts +3 -0
  230. package/rate-limit/postgres/schemas.js +4 -0
  231. package/rate-limit/provider.d.ts +9 -0
  232. package/rate-limit/provider.js +2 -0
  233. package/rate-limit/rate-limiter.d.ts +35 -0
  234. package/rate-limit/rate-limiter.js +3 -0
  235. package/rate-limit/tests/postgres-rate-limiter.test.d.ts +1 -0
  236. package/rate-limit/tests/postgres-rate-limiter.test.js +92 -0
  237. package/signals/implementation/configure.d.ts +3 -0
  238. package/signals/implementation/configure.js +3 -0
  239. package/sse/data-stream-source.d.ts +1 -1
  240. package/sse/data-stream-source.js +6 -6
  241. package/task-queue/enqueue-batch.d.ts +17 -0
  242. package/task-queue/enqueue-batch.js +24 -0
  243. package/{queue → task-queue}/index.d.ts +1 -1
  244. package/{queue → task-queue}/index.js +1 -1
  245. package/task-queue/postgres/drizzle/0000_thin_black_panther.sql +74 -0
  246. package/task-queue/postgres/drizzle/meta/0000_snapshot.json +592 -0
  247. package/task-queue/postgres/drizzle/meta/_journal.json +13 -0
  248. package/task-queue/postgres/drizzle.config.d.ts +2 -0
  249. package/task-queue/postgres/drizzle.config.js +11 -0
  250. package/task-queue/postgres/index.d.ts +4 -0
  251. package/task-queue/postgres/index.js +4 -0
  252. package/task-queue/postgres/module.d.ts +12 -0
  253. package/task-queue/postgres/module.js +28 -0
  254. package/task-queue/postgres/schemas.d.ts +16 -0
  255. package/task-queue/postgres/schemas.js +8 -0
  256. package/task-queue/postgres/task-queue.d.ts +83 -0
  257. package/task-queue/postgres/task-queue.js +1054 -0
  258. package/task-queue/postgres/task-queue.provider.d.ts +7 -0
  259. package/{queue/postgres/queue.provider.js → task-queue/postgres/task-queue.provider.js} +8 -8
  260. package/task-queue/postgres/task.model.d.ts +39 -0
  261. package/task-queue/postgres/task.model.js +178 -0
  262. package/{queue → task-queue}/provider.d.ts +3 -3
  263. package/task-queue/provider.js +2 -0
  264. package/{queue → task-queue}/task-context.d.ts +7 -7
  265. package/{queue → task-queue}/task-context.js +8 -8
  266. package/{queue/queue.d.ts → task-queue/task-queue.d.ts} +128 -59
  267. package/task-queue/task-queue.js +200 -0
  268. package/task-queue/tests/complex.test.d.ts +1 -0
  269. package/task-queue/tests/complex.test.js +299 -0
  270. package/task-queue/tests/dependencies.test.d.ts +1 -0
  271. package/task-queue/tests/dependencies.test.js +174 -0
  272. package/task-queue/tests/queue.test.d.ts +1 -0
  273. package/task-queue/tests/queue.test.js +334 -0
  274. package/task-queue/tests/worker.test.d.ts +1 -0
  275. package/task-queue/tests/worker.test.js +163 -0
  276. package/test1.js +1 -1
  277. package/test4.js +2 -2
  278. package/unit-test/index.d.ts +1 -0
  279. package/unit-test/index.js +1 -0
  280. package/unit-test/integration-setup.d.ts +55 -0
  281. package/unit-test/integration-setup.js +182 -0
  282. package/utils/patterns.d.ts +3 -0
  283. package/utils/patterns.js +6 -1
  284. package/audit/drizzle/0001_previous_network.sql +0 -2
  285. package/audit/drizzle/meta/0001_snapshot.json +0 -195
  286. package/queue/enqueue-batch.d.ts +0 -17
  287. package/queue/enqueue-batch.js +0 -18
  288. package/queue/postgres/drizzle/0000_zippy_moondragon.sql +0 -11
  289. package/queue/postgres/drizzle/0001_certain_wild_pack.sql +0 -2
  290. package/queue/postgres/drizzle/0002_dear_meggan.sql +0 -2
  291. package/queue/postgres/drizzle/0003_tricky_venom.sql +0 -30
  292. package/queue/postgres/drizzle/meta/0001_snapshot.json +0 -103
  293. package/queue/postgres/drizzle/meta/0002_snapshot.json +0 -90
  294. package/queue/postgres/drizzle/meta/0003_snapshot.json +0 -288
  295. package/queue/postgres/drizzle/meta/_journal.json +0 -34
  296. package/queue/postgres/index.d.ts +0 -4
  297. package/queue/postgres/index.js +0 -4
  298. package/queue/postgres/module.d.ts +0 -9
  299. package/queue/postgres/module.js +0 -29
  300. package/queue/postgres/queue.d.ts +0 -60
  301. package/queue/postgres/queue.js +0 -681
  302. package/queue/postgres/queue.provider.d.ts +0 -7
  303. package/queue/postgres/schemas.d.ts +0 -14
  304. package/queue/postgres/schemas.js +0 -6
  305. package/queue/postgres/task.model.d.ts +0 -24
  306. package/queue/postgres/task.model.js +0 -115
  307. package/queue/provider.js +0 -2
  308. package/queue/queue.js +0 -131
  309. package/queue/tests/queue.test.js +0 -623
  310. package/test3.d.ts +0 -1
  311. package/test3.js +0 -47
  312. /package/{queue/tests/queue.test.d.ts → api/server/tests/csrf.middleware.test.d.ts} +0 -0
  313. /package/circuit-breaker/postgres/drizzle/{0000_hard_shocker.sql → 0000_cooing_korath.sql} +0 -0
  314. /package/{queue → rate-limit}/postgres/drizzle.config.d.ts +0 -0
@@ -0,0 +1,303 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { Injector, runInInjectionContext } from '../../injector/index.js';
11
+ import { StringProperty } from '../../schema/index.js';
12
+ import { sql } from 'drizzle-orm';
13
+ import { beforeAll, describe, expect, test } from 'vitest';
14
+ import { ChildEntity, Column, Inheritance, Table } from '../decorators.js';
15
+ import { BaseEntity, Entity } from '../entity.js';
16
+ import { configureOrm, Database } from '../server/index.js';
17
+ import { injectRepository } from '../server/repository.js';
18
+ describe('ORM Repository Coverage', () => {
19
+ let injector;
20
+ let db;
21
+ const schema = 'test_orm_coverage';
22
+ let BaseItem = class BaseItem extends Entity {
23
+ type;
24
+ name;
25
+ };
26
+ __decorate([
27
+ StringProperty(),
28
+ Column({ name: 'type' }),
29
+ __metadata("design:type", String)
30
+ ], BaseItem.prototype, "type", void 0);
31
+ __decorate([
32
+ StringProperty(),
33
+ Column({ name: 'name' }),
34
+ __metadata("design:type", String)
35
+ ], BaseItem.prototype, "name", void 0);
36
+ BaseItem = __decorate([
37
+ Table('items', { schema }),
38
+ Inheritance({ strategy: 'joined', discriminatorColumn: 'type' })
39
+ ], BaseItem);
40
+ let PremiumItem = class PremiumItem extends BaseItem {
41
+ code;
42
+ };
43
+ __decorate([
44
+ StringProperty(),
45
+ Column({ name: 'code' }),
46
+ __metadata("design:type", String)
47
+ ], PremiumItem.prototype, "code", void 0);
48
+ PremiumItem = __decorate([
49
+ Table('premium_items', { schema }),
50
+ ChildEntity('premium')
51
+ ], PremiumItem);
52
+ let SimpleItem = class SimpleItem extends Entity {
53
+ label;
54
+ };
55
+ __decorate([
56
+ StringProperty(),
57
+ Column({ name: 'label' }),
58
+ __metadata("design:type", String)
59
+ ], SimpleItem.prototype, "label", void 0);
60
+ SimpleItem = __decorate([
61
+ Table('simple_items', { schema })
62
+ ], SimpleItem);
63
+ let PlainItem = class PlainItem extends BaseEntity {
64
+ description;
65
+ };
66
+ __decorate([
67
+ StringProperty(),
68
+ Column({ name: 'description' }),
69
+ __metadata("design:type", String)
70
+ ], PlainItem.prototype, "description", void 0);
71
+ PlainItem = __decorate([
72
+ Table('plain_items', { schema })
73
+ ], PlainItem);
74
+ beforeAll(async () => {
75
+ injector = new Injector('TestCoverage');
76
+ configureOrm({
77
+ repositoryConfig: { schema },
78
+ connection: {
79
+ host: '127.0.0.1',
80
+ port: 5432,
81
+ user: 'tstdl',
82
+ password: 'wf7rq6glrk5jykne',
83
+ database: 'tstdl',
84
+ }
85
+ });
86
+ db = injector.resolve(Database);
87
+ await db.execute(sql `CREATE SCHEMA IF NOT EXISTS ${sql.identifier(schema)}`);
88
+ await db.execute(sql `DROP TABLE IF EXISTS ${sql.identifier(schema)}.${sql.identifier('premium_items')} CASCADE`);
89
+ await db.execute(sql `DROP TABLE IF EXISTS ${sql.identifier(schema)}.${sql.identifier('items')} CASCADE`);
90
+ await db.execute(sql `DROP TABLE IF EXISTS ${sql.identifier(schema)}.${sql.identifier('simple_items')} CASCADE`);
91
+ await db.execute(sql `DROP TABLE IF EXISTS ${sql.identifier(schema)}.${sql.identifier('plain_items')} CASCADE`);
92
+ await db.execute(sql `
93
+ CREATE TABLE ${sql.identifier(schema)}.${sql.identifier('items')} (
94
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
95
+ type TEXT NOT NULL,
96
+ name TEXT NOT NULL,
97
+ revision INTEGER NOT NULL,
98
+ revision_timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
99
+ create_timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
100
+ delete_timestamp TIMESTAMP WITH TIME ZONE,
101
+ attributes JSONB NOT NULL DEFAULT '{}',
102
+ UNIQUE (id, type)
103
+ )
104
+ `);
105
+ await db.execute(sql `
106
+ CREATE TABLE ${sql.identifier(schema)}.${sql.identifier('premium_items')} (
107
+ id UUID PRIMARY KEY,
108
+ type TEXT NOT NULL CHECK (type = 'premium'),
109
+ code TEXT NOT NULL,
110
+ FOREIGN KEY (id, type) REFERENCES ${sql.identifier(schema)}.${sql.identifier('items')} (id, type) ON DELETE CASCADE
111
+ )
112
+ `);
113
+ await db.execute(sql `
114
+ CREATE TABLE ${sql.identifier(schema)}.${sql.identifier('simple_items')} (
115
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
116
+ label TEXT NOT NULL,
117
+ revision INTEGER NOT NULL,
118
+ revision_timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
119
+ create_timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
120
+ delete_timestamp TIMESTAMP WITH TIME ZONE,
121
+ attributes JSONB NOT NULL DEFAULT '{}'
122
+ )
123
+ `);
124
+ await db.execute(sql `
125
+ CREATE TABLE ${sql.identifier(schema)}.${sql.identifier('plain_items')} (
126
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
127
+ description TEXT NOT NULL
128
+ )
129
+ `);
130
+ });
131
+ test('upsertMany on CTI without update object (default update)', async () => {
132
+ await runInInjectionContext(injector, async () => {
133
+ const repository = injectRepository(PremiumItem);
134
+ const item1 = Object.assign(new PremiumItem(), { name: 'Item 1', code: 'C1' });
135
+ const inserted = await repository.insert(item1);
136
+ // Create a conflict by using the same ID
137
+ const conflictItem = Object.assign(new PremiumItem(), { id: inserted.id, name: 'Item 1 Updated', code: 'C1' });
138
+ // This should trigger the code path where `update` is undefined in upsertManyCTI
139
+ const upserted = await repository.upsertMany(['id'], [conflictItem]);
140
+ expect(upserted).toHaveLength(1);
141
+ expect(upserted[0].name).toBe('Item 1 Updated');
142
+ expect(upserted[0].metadata.revision).toBeGreaterThan(inserted.metadata.revision);
143
+ });
144
+ });
145
+ test('upsertMany with empty array', async () => {
146
+ await runInInjectionContext(injector, async () => {
147
+ const repository = injectRepository(PremiumItem);
148
+ const result = await repository.upsertMany(['id'], []);
149
+ expect(result).toHaveLength(0);
150
+ });
151
+ });
152
+ test('updateManyByQuery on CTI with no matching rows', async () => {
153
+ await runInInjectionContext(injector, async () => {
154
+ const repository = injectRepository(PremiumItem);
155
+ // Query matching nothing
156
+ const results = await repository.updateManyByQuery({ name: 'NonExistent' }, { name: 'NewName' });
157
+ expect(results).toEqual([]);
158
+ });
159
+ });
160
+ test('tryUpdate returning undefined (non-CTI, no metadata)', async () => {
161
+ await runInInjectionContext(injector, async () => {
162
+ const repository = injectRepository(PlainItem);
163
+ const result = await repository.tryUpdate('00000000-0000-0000-0000-000000000000', { description: 'New Desc' });
164
+ expect(result).toBeUndefined();
165
+ });
166
+ });
167
+ test('tryUpdate returning undefined (CTI)', async () => {
168
+ await runInInjectionContext(injector, async () => {
169
+ const repository = injectRepository(PremiumItem);
170
+ const result = await repository.tryUpdate('00000000-0000-0000-0000-000000000000', { name: 'New Name' });
171
+ expect(result).toBeUndefined();
172
+ });
173
+ });
174
+ test('tryUpdate returning undefined (CTI) - child field only', async () => {
175
+ // This hits line 1163 in tryUpdateCTI (else block where mappedUpdate is empty for base table)
176
+ await runInInjectionContext(injector, async () => {
177
+ const repository = injectRepository(PremiumItem);
178
+ // Update ONLY 'code' (Child field).
179
+ // Base table update will be empty.
180
+ const result = await repository.tryUpdate('00000000-0000-0000-0000-000000000000', { code: 'New Code' });
181
+ expect(result).toBeUndefined();
182
+ });
183
+ });
184
+ test('tryDelete returning undefined (non-CTI, has metadata)', async () => {
185
+ await runInInjectionContext(injector, async () => {
186
+ const repository = injectRepository(SimpleItem);
187
+ const result = await repository.tryDelete('00000000-0000-0000-0000-000000000000');
188
+ expect(result).toBeUndefined();
189
+ });
190
+ });
191
+ test('tryDelete returning undefined (non-CTI, no metadata)', async () => {
192
+ await runInInjectionContext(injector, async () => {
193
+ const repository = injectRepository(PlainItem);
194
+ // This hits tryHardDelete
195
+ const result = await repository.tryDelete('00000000-0000-0000-0000-000000000000');
196
+ expect(result).toBeUndefined();
197
+ });
198
+ });
199
+ test('tryDeleteByQuery returning undefined (non-CTI, has metadata)', async () => {
200
+ await runInInjectionContext(injector, async () => {
201
+ const repository = injectRepository(SimpleItem);
202
+ const result = await repository.tryDeleteByQuery({ label: 'NonExistent' });
203
+ expect(result).toBeUndefined();
204
+ });
205
+ });
206
+ test('tryDeleteByQuery returning undefined (non-CTI, no metadata)', async () => {
207
+ await runInInjectionContext(injector, async () => {
208
+ const repository = injectRepository(PlainItem);
209
+ // This hits tryHardDeleteByQuery
210
+ const result = await repository.tryDeleteByQuery({ description: 'NonExistent' });
211
+ expect(result).toBeUndefined();
212
+ });
213
+ });
214
+ test('tryUpsertCTI returning undefined when update condition fails', async () => {
215
+ await runInInjectionContext(injector, async () => {
216
+ const repository = injectRepository(PremiumItem);
217
+ const item = Object.assign(new PremiumItem(), { name: 'Condition Item', code: 'COND' });
218
+ const inserted = await repository.insert(item);
219
+ const conflictItem = Object.assign(new PremiumItem(), { id: inserted.id, name: 'Should Not Update', code: 'COND' });
220
+ // Upsert with a condition that evaluates to false
221
+ const result = await repository.tryUpsert(['id'], conflictItem, undefined, { set: { name: 'Impossible Name' } } // This query condition on the existing row must fail
222
+ );
223
+ expect(result).toBeUndefined();
224
+ const loaded = await repository.load(inserted.id);
225
+ expect(loaded.name).toBe('Condition Item'); // Should not have changed
226
+ });
227
+ });
228
+ test('Discriminator mismatch throws error', async () => {
229
+ await runInInjectionContext(injector, async () => {
230
+ const repository = injectRepository(PremiumItem);
231
+ // Simulate a row returned from DB that has wrong type
232
+ // PremiumItem expects type='premium'
233
+ const corruptRow = {
234
+ id: 'some-id',
235
+ type: 'wrong_type',
236
+ name: 'Test',
237
+ code: 'C1',
238
+ revision: 1,
239
+ revision_timestamp: new Date(),
240
+ create_timestamp: new Date(),
241
+ delete_timestamp: null,
242
+ attributes: {},
243
+ };
244
+ await expect(repository.mapToEntity(corruptRow)).rejects.toThrow('Discriminator mismatch');
245
+ });
246
+ });
247
+ test('updateManyByQuery (CTI) should return empty array if no IDs found', async () => {
248
+ // This hits line 1524
249
+ await runInInjectionContext(injector, async () => {
250
+ const repository = injectRepository(PremiumItem);
251
+ // Query that returns nothing
252
+ const result = await repository.updateManyByQuery({ name: 'Ghost' }, { name: 'Buster' });
253
+ expect(result).toHaveLength(0);
254
+ });
255
+ });
256
+ test('updateManyByQuery on Non-CTI', async () => {
257
+ await runInInjectionContext(injector, async () => {
258
+ const repository = injectRepository(SimpleItem);
259
+ await repository.insert(Object.assign(new SimpleItem(), { label: 'To Update' }));
260
+ const results = await repository.updateManyByQuery({ label: 'To Update' }, { label: 'Updated' });
261
+ expect(results).toHaveLength(1);
262
+ expect(results[0].label).toBe('Updated');
263
+ });
264
+ });
265
+ test('updateByQuery throws NotFoundError', async () => {
266
+ await runInInjectionContext(injector, async () => {
267
+ const repository = injectRepository(SimpleItem);
268
+ await expect(repository.updateByQuery({ label: 'Ghost' }, { label: 'Buster' })).rejects.toThrow('SimpleItem not found');
269
+ });
270
+ });
271
+ test('tryUpdateByQuery returns undefined (CTI)', async () => {
272
+ await runInInjectionContext(injector, async () => {
273
+ const repository = injectRepository(PremiumItem);
274
+ const result = await repository.tryUpdateByQuery({ name: 'Ghost' }, { name: 'Buster' });
275
+ expect(result).toBeUndefined();
276
+ });
277
+ });
278
+ test('tryUpdateByQuery updates entity (CTI)', async () => {
279
+ await runInInjectionContext(injector, async () => {
280
+ const repository = injectRepository(PremiumItem);
281
+ const item = await repository.insert(Object.assign(new PremiumItem(), { name: 'Target', code: 'T1' }));
282
+ const result = await repository.tryUpdateByQuery({ name: 'Target' }, { name: 'Updated Target' });
283
+ expect(result).toBeDefined();
284
+ expect(result.name).toBe('Updated Target');
285
+ });
286
+ });
287
+ test('deleteManyByQuery (Soft Delete)', async () => {
288
+ await runInInjectionContext(injector, async () => {
289
+ const repository = injectRepository(SimpleItem);
290
+ await repository.insert(Object.assign(new SimpleItem(), { label: 'To Delete' }));
291
+ const results = await repository.deleteManyByQuery({ label: 'To Delete' });
292
+ expect(results).toHaveLength(1);
293
+ expect(results[0].label).toBe('To Delete');
294
+ expect(results[0].metadata.deleteTimestamp).not.toBeNull();
295
+ });
296
+ });
297
+ test('deleteByQuery throws NotFoundError', async () => {
298
+ await runInInjectionContext(injector, async () => {
299
+ const repository = injectRepository(SimpleItem);
300
+ await expect(repository.deleteByQuery({ label: 'Ghost' })).rejects.toThrow('SimpleItem not found');
301
+ });
302
+ });
303
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,170 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { sql } from 'drizzle-orm';
11
+ import { beforeAll, describe, expect, test } from 'vitest';
12
+ import { Injector, runInInjectionContext } from '../../injector/index.js';
13
+ import { StringProperty } from '../../schema/index.js';
14
+ import { ChildEntity, Inheritance, Table } from '../decorators.js';
15
+ import { Entity } from '../entity.js';
16
+ import { configureOrm, Database } from '../server/index.js';
17
+ import { injectRepository } from '../server/repository.js';
18
+ describe('ORM Repository CTI Complex', () => {
19
+ let injector;
20
+ let db;
21
+ const schema = 'test_orm_cti_complex';
22
+ let BaseEntity = class BaseEntity extends Entity {
23
+ type;
24
+ baseName;
25
+ };
26
+ __decorate([
27
+ StringProperty(),
28
+ __metadata("design:type", String)
29
+ ], BaseEntity.prototype, "type", void 0);
30
+ __decorate([
31
+ StringProperty(),
32
+ __metadata("design:type", String)
33
+ ], BaseEntity.prototype, "baseName", void 0);
34
+ BaseEntity = __decorate([
35
+ Table('base_entities', { schema }),
36
+ Inheritance({ strategy: 'joined', discriminatorColumn: 'type' })
37
+ ], BaseEntity);
38
+ let MiddleEntity = class MiddleEntity extends BaseEntity {
39
+ middleName;
40
+ };
41
+ __decorate([
42
+ StringProperty(),
43
+ __metadata("design:type", String)
44
+ ], MiddleEntity.prototype, "middleName", void 0);
45
+ MiddleEntity = __decorate([
46
+ Table('middle_entities', { schema }),
47
+ ChildEntity('middle')
48
+ ], MiddleEntity);
49
+ let LeafEntity = class LeafEntity extends MiddleEntity {
50
+ leafName;
51
+ };
52
+ __decorate([
53
+ StringProperty(),
54
+ __metadata("design:type", String)
55
+ ], LeafEntity.prototype, "leafName", void 0);
56
+ LeafEntity = __decorate([
57
+ Table('leaf_entities', { schema }),
58
+ ChildEntity('leaf')
59
+ ], LeafEntity);
60
+ beforeAll(async () => {
61
+ injector = new Injector('Test');
62
+ configureOrm({
63
+ repositoryConfig: { schema },
64
+ connection: {
65
+ host: '127.0.0.1', port: 5432, user: 'tstdl', password: 'wf7rq6glrk5jykne', database: 'tstdl',
66
+ },
67
+ });
68
+ db = injector.resolve(Database);
69
+ await db.execute(sql `CREATE SCHEMA IF NOT EXISTS ${sql.identifier(schema)}`);
70
+ await db.execute(sql `DROP TABLE IF EXISTS ${sql.identifier(schema)}.${sql.identifier('leaf_entities')} CASCADE`);
71
+ await db.execute(sql `DROP TABLE IF EXISTS ${sql.identifier(schema)}.${sql.identifier('middle_entities')} CASCADE`);
72
+ await db.execute(sql `DROP TABLE IF EXISTS ${sql.identifier(schema)}.${sql.identifier('base_entities')} CASCADE`);
73
+ await db.execute(sql `
74
+ CREATE TABLE ${sql.identifier(schema)}.${sql.identifier('base_entities')} (
75
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
76
+ type TEXT NOT NULL,
77
+ base_name TEXT NOT NULL,
78
+ revision INTEGER NOT NULL,
79
+ revision_timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
80
+ create_timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
81
+ delete_timestamp TIMESTAMP WITH TIME ZONE,
82
+ attributes JSONB NOT NULL DEFAULT '{}',
83
+ UNIQUE (id, type)
84
+ )
85
+ `);
86
+ await db.execute(sql `
87
+ CREATE TABLE ${sql.identifier(schema)}.${sql.identifier('middle_entities')} (
88
+ id UUID PRIMARY KEY,
89
+ type TEXT NOT NULL CHECK (type = 'middle' OR type = 'leaf'),
90
+ middle_name TEXT NOT NULL,
91
+ UNIQUE (id, type),
92
+ FOREIGN KEY (id, type) REFERENCES ${sql.identifier(schema)}.${sql.identifier('base_entities')}(id, type) ON DELETE CASCADE
93
+ )
94
+ `);
95
+ await db.execute(sql `
96
+ CREATE TABLE ${sql.identifier(schema)}.${sql.identifier('leaf_entities')} (
97
+ id UUID PRIMARY KEY,
98
+ type TEXT NOT NULL CHECK (type = 'leaf'),
99
+ leaf_name TEXT NOT NULL,
100
+ FOREIGN KEY (id, type) REFERENCES ${sql.identifier(schema)}.${sql.identifier('middle_entities')}(id, type) ON DELETE CASCADE
101
+ )
102
+ `);
103
+ });
104
+ test('should support deep inheritance (3 levels)', async () => {
105
+ await runInInjectionContext(injector, async () => {
106
+ const repository = injectRepository(LeafEntity);
107
+ const leaf = Object.assign(new LeafEntity(), {
108
+ baseName: 'Base',
109
+ middleName: 'Middle',
110
+ leafName: 'Leaf',
111
+ });
112
+ const inserted = await repository.insert(leaf);
113
+ expect(inserted.id).toBeDefined();
114
+ expect(inserted.baseName).toBe('Base');
115
+ expect(inserted.middleName).toBe('Middle');
116
+ expect(inserted.leafName).toBe('Leaf');
117
+ const loaded = await repository.load(inserted.id);
118
+ expect(loaded).toBeInstanceOf(LeafEntity);
119
+ expect(loaded.baseName).toBe('Base');
120
+ expect(loaded.middleName).toBe('Middle');
121
+ expect(loaded.leafName).toBe('Leaf');
122
+ });
123
+ });
124
+ test('should throw error on discriminator mismatch', async () => {
125
+ await runInInjectionContext(injector, async () => {
126
+ const middleRepository = injectRepository(MiddleEntity);
127
+ const leafRepository = injectRepository(LeafEntity);
128
+ const middle = await middleRepository.insert(Object.assign(new MiddleEntity(), {
129
+ baseName: 'B',
130
+ middleName: 'M',
131
+ }));
132
+ // Try to load middle as leaf
133
+ await expect(leafRepository.load(middle.id)).rejects.toThrow();
134
+ });
135
+ });
136
+ test('should upsert correctly on child entities', async () => {
137
+ await runInInjectionContext(injector, async () => {
138
+ const repository = injectRepository(MiddleEntity);
139
+ const e1 = Object.assign(new MiddleEntity(), { baseName: 'B1', middleName: 'M1' });
140
+ const inserted = await repository.insert(e1);
141
+ const update = Object.assign(new MiddleEntity(), { id: inserted.id, baseName: 'B1_Updated', middleName: 'M1_Updated' });
142
+ const upserted = await repository.upsert('id', update);
143
+ expect(upserted.id).toBe(inserted.id);
144
+ expect(upserted.baseName).toBe('B1_Updated');
145
+ expect(upserted.middleName).toBe('M1_Updated');
146
+ });
147
+ });
148
+ test('should handle upsert when parent exists but child does not', async () => {
149
+ await runInInjectionContext(injector, async () => {
150
+ const baseRepository = injectRepository(BaseEntity);
151
+ const middleRepository = injectRepository(MiddleEntity);
152
+ // Manually insert into base table only
153
+ const id = '00000000-0000-0000-0000-000000000001';
154
+ await db.execute(sql `
155
+ INSERT INTO ${sql.identifier(schema)}.${sql.identifier('base_entities')} (id, type, base_name, revision, revision_timestamp, create_timestamp, attributes)
156
+ VALUES (${id}, 'middle', 'OnlyBase', 1, now(), now(), '{}')
157
+ `);
158
+ // Now upsert via middle repository
159
+ const update = Object.assign(new MiddleEntity(), { id, baseName: 'Updated', middleName: 'NewMiddle' });
160
+ // This is expected to fail or behave unexpectedly if not handled,
161
+ // because upsert (onConflictDoUpdate) usually targets one table.
162
+ // In CTI, we might need special handling.
163
+ const upserted = await middleRepository.upsert('id', update);
164
+ expect(upserted.id).toBe(id);
165
+ expect(upserted.middleName).toBe('NewMiddle');
166
+ const loaded = await middleRepository.load(id);
167
+ expect(loaded.middleName).toBe('NewMiddle');
168
+ });
169
+ });
170
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,188 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { Injector, runInInjectionContext } from '../../injector/index.js';
11
+ import { StringProperty } from '../../schema/index.js';
12
+ import { sql } from 'drizzle-orm';
13
+ import { beforeAll, describe, expect, test } from 'vitest';
14
+ import { ChildEntity, Column, EmbeddedProperty, Inheritance, Table } from '../decorators.js';
15
+ import { Entity } from '../entity.js';
16
+ import { configureOrm, Database } from '../server/index.js';
17
+ import { injectRepository } from '../server/repository.js';
18
+ describe('ORM Repository CTI Embedded (Integration)', () => {
19
+ let injector;
20
+ let db;
21
+ const schema = 'test_orm_cti_embedded';
22
+ class Address {
23
+ street;
24
+ city;
25
+ }
26
+ __decorate([
27
+ StringProperty(),
28
+ __metadata("design:type", String)
29
+ ], Address.prototype, "street", void 0);
30
+ __decorate([
31
+ StringProperty(),
32
+ __metadata("design:type", String)
33
+ ], Address.prototype, "city", void 0);
34
+ class Contact {
35
+ phone;
36
+ email;
37
+ }
38
+ __decorate([
39
+ StringProperty(),
40
+ __metadata("design:type", String)
41
+ ], Contact.prototype, "phone", void 0);
42
+ __decorate([
43
+ StringProperty(),
44
+ __metadata("design:type", String)
45
+ ], Contact.prototype, "email", void 0);
46
+ let EntityWithAddress = class EntityWithAddress extends Entity {
47
+ type;
48
+ address;
49
+ };
50
+ __decorate([
51
+ StringProperty(),
52
+ Column({ name: 'type' }),
53
+ __metadata("design:type", String)
54
+ ], EntityWithAddress.prototype, "type", void 0);
55
+ __decorate([
56
+ EmbeddedProperty(Address, { prefix: 'addr_' }),
57
+ __metadata("design:type", Address)
58
+ ], EntityWithAddress.prototype, "address", void 0);
59
+ EntityWithAddress = __decorate([
60
+ Table('entities_with_address', { schema }),
61
+ Inheritance({ strategy: 'joined', discriminatorColumn: 'type' })
62
+ ], EntityWithAddress);
63
+ let UserWithContact = class UserWithContact extends EntityWithAddress {
64
+ name;
65
+ contact;
66
+ };
67
+ __decorate([
68
+ StringProperty(),
69
+ __metadata("design:type", String)
70
+ ], UserWithContact.prototype, "name", void 0);
71
+ __decorate([
72
+ EmbeddedProperty(Contact, { prefix: 'contact_' }),
73
+ __metadata("design:type", Contact)
74
+ ], UserWithContact.prototype, "contact", void 0);
75
+ UserWithContact = __decorate([
76
+ Table('users_with_contact', { schema }),
77
+ ChildEntity('user')
78
+ ], UserWithContact);
79
+ beforeAll(async () => {
80
+ injector = new Injector('Test');
81
+ configureOrm({
82
+ repositoryConfig: { schema },
83
+ connection: {
84
+ host: '127.0.0.1',
85
+ port: 5432,
86
+ user: 'tstdl',
87
+ password: 'wf7rq6glrk5jykne',
88
+ database: 'tstdl',
89
+ },
90
+ });
91
+ db = injector.resolve(Database);
92
+ await db.execute(sql `CREATE SCHEMA IF NOT EXISTS ${sql.identifier(schema)}`);
93
+ await db.execute(sql `DROP TABLE IF EXISTS ${sql.identifier(schema)}.${sql.identifier('users_with_contact')} CASCADE`);
94
+ await db.execute(sql `DROP TABLE IF EXISTS ${sql.identifier(schema)}.${sql.identifier('entities_with_address')} CASCADE`);
95
+ await db.execute(sql `
96
+ CREATE TABLE ${sql.identifier(schema)}.${sql.identifier('entities_with_address')} (
97
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
98
+ type TEXT NOT NULL,
99
+ addr_street TEXT NOT NULL,
100
+ addr_city TEXT NOT NULL,
101
+ revision INTEGER NOT NULL,
102
+ revision_timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
103
+ create_timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
104
+ delete_timestamp TIMESTAMP WITH TIME ZONE,
105
+ attributes JSONB NOT NULL DEFAULT '{}',
106
+ UNIQUE (id, type)
107
+ )
108
+ `);
109
+ await db.execute(sql `
110
+ CREATE TABLE ${sql.identifier(schema)}.${sql.identifier('users_with_contact')} (
111
+ id UUID PRIMARY KEY,
112
+ type TEXT NOT NULL CHECK (type = 'user'),
113
+ name TEXT NOT NULL,
114
+ contact_phone TEXT NOT NULL,
115
+ contact_email TEXT NOT NULL,
116
+ FOREIGN KEY (id, type) REFERENCES ${sql.identifier(schema)}.${sql.identifier('entities_with_address')} (id, type) ON DELETE CASCADE
117
+ )
118
+ `);
119
+ });
120
+ test('should insert and load entities with embedded properties in CTI', async () => {
121
+ await runInInjectionContext(injector, async () => {
122
+ const repository = injectRepository(UserWithContact);
123
+ const user = new UserWithContact();
124
+ user.address = { street: 'Main St', city: 'London' };
125
+ user.contact = { phone: '12345', email: 'test@example.com' };
126
+ user.name = 'John Doe';
127
+ const inserted = await repository.insert(user);
128
+ expect(inserted.address.street).toBe('Main St');
129
+ expect(inserted.contact.email).toBe('test@example.com');
130
+ const loaded = await repository.load(inserted.id);
131
+ expect(loaded.address.city).toBe('London');
132
+ expect(loaded.contact.phone).toBe('12345');
133
+ expect(loaded.name).toBe('John Doe');
134
+ });
135
+ });
136
+ test('should load polymorphically with embedded properties', async () => {
137
+ await runInInjectionContext(injector, async () => {
138
+ const baseRepo = injectRepository(EntityWithAddress);
139
+ const userRepo = injectRepository(UserWithContact);
140
+ await userRepo.insert(Object.assign(new UserWithContact(), {
141
+ name: 'Jane',
142
+ address: { street: 'High St', city: 'Paris' },
143
+ contact: { phone: '999', email: 'jane@test.com' },
144
+ }));
145
+ const all = await baseRepo.loadAll({ includeSubclasses: true });
146
+ const jane = all.find((u) => (u instanceof UserWithContact) && (u.name == 'Jane'));
147
+ expect(jane).toBeDefined();
148
+ expect(jane.address.city).toBe('Paris');
149
+ expect(jane.contact.email).toBe('jane@test.com');
150
+ });
151
+ });
152
+ test('should update embedded properties in both tables', async () => {
153
+ await runInInjectionContext(injector, async () => {
154
+ const repository = injectRepository(UserWithContact);
155
+ const user = await repository.insert(Object.assign(new UserWithContact(), {
156
+ name: 'UpdateMe',
157
+ address: { street: 'Old St', city: 'Old City' },
158
+ contact: { phone: '000', email: 'old@test.com' },
159
+ }));
160
+ await repository.update(user.id, {
161
+ address: { street: 'New St', city: 'New City' },
162
+ contact: { email: 'new@test.com' },
163
+ });
164
+ const updated = await repository.load(user.id);
165
+ expect(updated.address.street).toBe('New St');
166
+ expect(updated.address.city).toBe('New City');
167
+ expect(updated.contact.phone).toBe('000'); // Unchanged
168
+ expect(updated.contact.email).toBe('new@test.com');
169
+ });
170
+ });
171
+ test('should filter by embedded properties across tables', async () => {
172
+ await runInInjectionContext(injector, async () => {
173
+ const repository = injectRepository(UserWithContact);
174
+ await repository.insert(Object.assign(new UserWithContact(), {
175
+ name: 'Target',
176
+ address: { street: 'Secret St', city: 'Hidden' },
177
+ contact: { phone: '123', email: 'target@test.com' },
178
+ }));
179
+ // Filter by address (parent table) and contact (child table)
180
+ const results = await repository.loadManyByQuery({
181
+ address: { city: 'Hidden' },
182
+ contact: { email: 'target@test.com' },
183
+ }); // Type cast might be needed if Query doesn't perfectly map embedded deep objects yet
184
+ expect(results).toHaveLength(1);
185
+ expect(results[0].name).toBe('Target');
186
+ });
187
+ });
188
+ });
@@ -0,0 +1 @@
1
+ export {};