@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,216 @@
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 { NotFoundError } from '../../errors/not-found.error.js';
13
+ import { Injector, runInInjectionContext } from '../../injector/index.js';
14
+ import { StringProperty } from '../../schema/index.js';
15
+ import { ChildEntity, Column, Inheritance, Table } from '../decorators.js';
16
+ import { Entity } from '../entity.js';
17
+ import { configureOrm, Database } from '../server/index.js';
18
+ import { injectRepository } from '../server/repository.js';
19
+ describe('ORM Repository Edge Cases', () => {
20
+ let injector;
21
+ let db;
22
+ const schema = 'test_orm_edge_cases';
23
+ let BaseItem = class BaseItem extends Entity {
24
+ type;
25
+ name;
26
+ };
27
+ __decorate([
28
+ StringProperty(),
29
+ Column({ name: 'type' }),
30
+ __metadata("design:type", String)
31
+ ], BaseItem.prototype, "type", void 0);
32
+ __decorate([
33
+ StringProperty(),
34
+ __metadata("design:type", String)
35
+ ], BaseItem.prototype, "name", void 0);
36
+ BaseItem = __decorate([
37
+ Table('base_items', { schema }),
38
+ Inheritance({ strategy: 'joined', discriminatorColumn: 'type' })
39
+ ], BaseItem);
40
+ let DerivedItem = class DerivedItem extends BaseItem {
41
+ description;
42
+ };
43
+ __decorate([
44
+ StringProperty(),
45
+ __metadata("design:type", String)
46
+ ], DerivedItem.prototype, "description", void 0);
47
+ DerivedItem = __decorate([
48
+ Table('derived_items', { schema }),
49
+ ChildEntity('derived')
50
+ ], DerivedItem);
51
+ beforeAll(async () => {
52
+ injector = new Injector('Test');
53
+ configureOrm({
54
+ repositoryConfig: { schema },
55
+ connection: {
56
+ host: '127.0.0.1', port: 5432, user: 'tstdl', password: 'wf7rq6glrk5jykne', database: 'tstdl',
57
+ },
58
+ });
59
+ db = injector.resolve(Database);
60
+ await db.execute(sql `CREATE SCHEMA IF NOT EXISTS ${sql.identifier(schema)}`);
61
+ await db.execute(sql `DROP TABLE IF EXISTS ${sql.identifier(schema)}.${sql.identifier('derived_items')} CASCADE`);
62
+ await db.execute(sql `DROP TABLE IF EXISTS ${sql.identifier(schema)}.${sql.identifier('base_items')} CASCADE`);
63
+ await db.execute(sql `
64
+ CREATE TABLE ${sql.identifier(schema)}.${sql.identifier('base_items')} (
65
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
66
+ type TEXT NOT NULL,
67
+ name TEXT NOT NULL,
68
+ revision INTEGER NOT NULL,
69
+ revision_timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
70
+ create_timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
71
+ delete_timestamp TIMESTAMP WITH TIME ZONE,
72
+ attributes JSONB NOT NULL DEFAULT '{}',
73
+ UNIQUE (id, type)
74
+ )
75
+ `);
76
+ await db.execute(sql `
77
+ CREATE TABLE ${sql.identifier(schema)}.${sql.identifier('derived_items')} (
78
+ id UUID PRIMARY KEY,
79
+ type TEXT NOT NULL CHECK (type = 'derived'),
80
+ description TEXT NOT NULL,
81
+ FOREIGN KEY (id, type) REFERENCES ${sql.identifier(schema)}.${sql.identifier('base_items')} (id, type) ON DELETE CASCADE
82
+ )
83
+ `);
84
+ });
85
+ test('should rollback transaction on insertMany failure', async () => {
86
+ await runInInjectionContext(injector, async () => {
87
+ const repo = injectRepository(BaseItem);
88
+ const id = '00000000-0000-0000-0000-000000000001';
89
+ try {
90
+ await repo.insertMany([
91
+ Object.assign(new BaseItem(), { id, name: 'Success', type: 'base' }),
92
+ Object.assign(new BaseItem(), { id, name: 'Fail', type: 'base' }) // Duplicate ID
93
+ ]);
94
+ }
95
+ catch {
96
+ // Expected
97
+ }
98
+ const count = await repo.count();
99
+ expect(count).toBe(0);
100
+ });
101
+ });
102
+ test('should rollback transaction on updateMany failure', async () => {
103
+ await runInInjectionContext(injector, async () => {
104
+ const repo = injectRepository(BaseItem);
105
+ await repo.insert(Object.assign(new BaseItem(), { name: 'Item 1', type: 'base' }));
106
+ try {
107
+ await repo.transaction(async (tx) => {
108
+ const txRepo = repo.withTransaction(tx);
109
+ await txRepo.updateManyByQuery({}, { name: 'Updated' });
110
+ throw new Error('Rollback');
111
+ });
112
+ }
113
+ catch {
114
+ // Expected
115
+ }
116
+ const item = await repo.loadByQuery({ name: 'Item 1' });
117
+ expect(item.name).toBe('Item 1');
118
+ });
119
+ });
120
+ test('should throw on negative offset', async () => {
121
+ await runInInjectionContext(injector, async () => {
122
+ const repo = injectRepository(BaseItem);
123
+ await expect(repo.loadAll({ offset: -1 })).rejects.toThrow();
124
+ });
125
+ });
126
+ test('should fail when unique constraint is violated even if soft deleted', async () => {
127
+ await runInInjectionContext(injector, async () => {
128
+ const repo = injectRepository(BaseItem);
129
+ const id = '00000000-0000-0000-0000-000000000002';
130
+ await repo.insert(Object.assign(new BaseItem(), { id, name: 'A', type: 'base' }));
131
+ await repo.delete(id);
132
+ // Attempt to insert same ID again (Unique violation)
133
+ await expect(repo.insert(Object.assign(new BaseItem(), { id, name: 'B', type: 'base' }))).rejects.toThrow();
134
+ });
135
+ });
136
+ test('should fail loading if child row is missing (data corruption)', async () => {
137
+ await runInInjectionContext(injector, async () => {
138
+ const derivedRepo = injectRepository(DerivedItem);
139
+ const baseRepo = injectRepository(BaseItem);
140
+ const derived = await derivedRepo.insert(Object.assign(new DerivedItem(), { name: 'Derived', description: 'Desc' }));
141
+ // Manually delete child row
142
+ await db.execute(sql `DELETE FROM ${sql.identifier(schema)}.${sql.identifier('derived_items')} WHERE id = ${derived.id}`);
143
+ // Verify deletion
144
+ const { rows } = await db.execute(sql `SELECT * FROM ${sql.identifier(schema)}.${sql.identifier('derived_items')} WHERE id = ${derived.id}`);
145
+ expect(rows).toHaveLength(0);
146
+ // Child repo should fail because primary table row is missing
147
+ await expect(derivedRepo.load(derived.id)).rejects.toThrow(NotFoundError);
148
+ // Base repo should succeed (returning corrupted entity) because base row exists and it uses left join for subclasses
149
+ const loadedBase = await baseRepo.load(derived.id, { includeSubclasses: true });
150
+ expect(loadedBase).toBeInstanceOf(DerivedItem);
151
+ expect(loadedBase.description).toBeNull();
152
+ });
153
+ });
154
+ test('should throw NotFoundError when update target does not exist', async () => {
155
+ await runInInjectionContext(injector, async () => {
156
+ const repo = injectRepository(BaseItem);
157
+ await expect(repo.update('00000000-0000-0000-0000-000000000000', { name: 'New' })).rejects.toThrow(NotFoundError);
158
+ });
159
+ });
160
+ test('should throw NotFoundError when updateByQuery matches nothing', async () => {
161
+ await runInInjectionContext(injector, async () => {
162
+ const repo = injectRepository(BaseItem);
163
+ await expect(repo.updateByQuery({ name: 'Missing' }, { name: 'New' })).rejects.toThrow(NotFoundError);
164
+ });
165
+ });
166
+ test('should throw NotFoundError when delete target does not exist', async () => {
167
+ await runInInjectionContext(injector, async () => {
168
+ const repo = injectRepository(BaseItem);
169
+ await expect(repo.delete('00000000-0000-0000-0000-000000000000')).rejects.toThrow(NotFoundError);
170
+ });
171
+ });
172
+ test('should throw NotFoundError when deleteByQuery matches nothing', async () => {
173
+ await runInInjectionContext(injector, async () => {
174
+ const repo = injectRepository(BaseItem);
175
+ await expect(repo.deleteByQuery({ name: 'Missing' })).rejects.toThrow(NotFoundError);
176
+ });
177
+ });
178
+ test('should throw NotFoundError when hardDelete target does not exist', async () => {
179
+ await runInInjectionContext(injector, async () => {
180
+ const repo = injectRepository(BaseItem);
181
+ await expect(repo.hardDelete('00000000-0000-0000-0000-000000000000')).rejects.toThrow(NotFoundError);
182
+ });
183
+ });
184
+ test('should throw NotFoundError when hardDeleteByQuery matches nothing', async () => {
185
+ await runInInjectionContext(injector, async () => {
186
+ const repo = injectRepository(BaseItem);
187
+ await expect(repo.hardDeleteByQuery({ name: 'Missing' })).rejects.toThrow(NotFoundError);
188
+ });
189
+ });
190
+ test('should handle empty updates gracefully', async () => {
191
+ await runInInjectionContext(injector, async () => {
192
+ const repo = injectRepository(BaseItem);
193
+ const item = await repo.insert(Object.assign(new BaseItem(), { name: 'EmptyUpdate', type: 'base' }));
194
+ const updated = await repo.update(item.id, {});
195
+ expect(updated.metadata.revision).toBeGreaterThan(item.metadata.revision);
196
+ expect(updated.name).toBe('EmptyUpdate');
197
+ });
198
+ });
199
+ test('should handle unknown properties in query gracefully (throw error)', async () => {
200
+ await runInInjectionContext(injector, async () => {
201
+ const repo = injectRepository(BaseItem);
202
+ await expect(repo.loadByQuery({ unknownProp: 'value' })).rejects.toThrow('Could not map property unknownProp');
203
+ });
204
+ });
205
+ test('should prevent updating discriminator column via update', async () => {
206
+ await runInInjectionContext(injector, async () => {
207
+ const repo = injectRepository(BaseItem);
208
+ const item = await repo.insert(Object.assign(new BaseItem(), { name: 'TypeCheck', type: 'base' }));
209
+ // Try to change type to 'derived'
210
+ await repo.update(item.id, { type: 'derived' });
211
+ const reloaded = await repo.load(item.id);
212
+ // It should change if not blocked
213
+ expect(reloaded.type).toBe('derived');
214
+ });
215
+ });
216
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,153 @@
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 { Expires, Table, TimeToLive } from '../decorators.js';
15
+ import { Entity } from '../entity.js';
16
+ import { TimestampProperty } from '../schemas/index.js';
17
+ import { configureOrm, Database } from '../server/index.js';
18
+ import { injectRepository } from '../server/repository.js';
19
+ describe('ORM Repository Expiration', () => {
20
+ let injector;
21
+ let db;
22
+ const schema = 'test_orm_expiration';
23
+ let ExpirationEntity = class ExpirationEntity extends Entity {
24
+ name;
25
+ softExpireAt;
26
+ hardExpireAt;
27
+ };
28
+ __decorate([
29
+ StringProperty(),
30
+ __metadata("design:type", String)
31
+ ], ExpirationEntity.prototype, "name", void 0);
32
+ __decorate([
33
+ TimestampProperty(),
34
+ Expires({ after: 0, mode: 'soft' }),
35
+ __metadata("design:type", Number)
36
+ ], ExpirationEntity.prototype, "softExpireAt", void 0);
37
+ __decorate([
38
+ TimestampProperty(),
39
+ Expires({ after: 0, mode: 'hard' }),
40
+ __metadata("design:type", Number)
41
+ ], ExpirationEntity.prototype, "hardExpireAt", void 0);
42
+ ExpirationEntity = __decorate([
43
+ Table('expiration_entities', { schema })
44
+ ], ExpirationEntity);
45
+ let TtlEntity = class TtlEntity extends Entity {
46
+ name;
47
+ };
48
+ __decorate([
49
+ StringProperty(),
50
+ __metadata("design:type", String)
51
+ ], TtlEntity.prototype, "name", void 0);
52
+ TtlEntity = __decorate([
53
+ Table('ttl_entities', { schema }),
54
+ TimeToLive(1000, 'hard') // 1s TTL
55
+ ], TtlEntity);
56
+ beforeAll(async () => {
57
+ injector = new Injector('Test');
58
+ configureOrm({
59
+ repositoryConfig: { schema },
60
+ connection: {
61
+ host: '127.0.0.1', port: 5432, user: 'tstdl', password: 'wf7rq6glrk5jykne', database: 'tstdl',
62
+ },
63
+ });
64
+ db = injector.resolve(Database);
65
+ await db.execute(sql `CREATE SCHEMA IF NOT EXISTS ${sql.identifier(schema)}`);
66
+ await db.execute(sql `DROP TABLE IF EXISTS ${sql.identifier(schema)}.${sql.identifier('expiration_entities')} CASCADE`);
67
+ await db.execute(sql `DROP TABLE IF EXISTS ${sql.identifier(schema)}.${sql.identifier('ttl_entities')} CASCADE`);
68
+ await db.execute(sql `
69
+ CREATE TABLE ${sql.identifier(schema)}.${sql.identifier('expiration_entities')} (
70
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
71
+ name TEXT NOT NULL,
72
+ soft_expire_at TIMESTAMP WITH TIME ZONE,
73
+ hard_expire_at TIMESTAMP WITH TIME ZONE,
74
+ revision INTEGER NOT NULL,
75
+ revision_timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
76
+ create_timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
77
+ delete_timestamp TIMESTAMP WITH TIME ZONE,
78
+ attributes JSONB NOT NULL DEFAULT '{}'
79
+ )
80
+ `);
81
+ await db.execute(sql `
82
+ CREATE TABLE ${sql.identifier(schema)}.${sql.identifier('ttl_entities')} (
83
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
84
+ name TEXT NOT NULL,
85
+ revision INTEGER NOT NULL,
86
+ revision_timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
87
+ create_timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
88
+ delete_timestamp TIMESTAMP WITH TIME ZONE,
89
+ attributes JSONB NOT NULL DEFAULT '{}'
90
+ )
91
+ `);
92
+ });
93
+ test('should support TimeToLive decorator', async () => {
94
+ await db.execute(sql `TRUNCATE TABLE ${sql.identifier(schema)}.${sql.identifier('ttl_entities')} CASCADE`);
95
+ await runInInjectionContext(injector, async () => {
96
+ const repository = injectRepository(TtlEntity);
97
+ const e1 = await repository.insert(Object.assign(new TtlEntity(), { name: 'Valid' }));
98
+ // Wait 1.1s for expiration
99
+ await new Promise((resolve) => setTimeout(resolve, 1100));
100
+ await repository.processExpirations();
101
+ const all = await repository.loadAll({ withDeleted: true });
102
+ expect(all).toHaveLength(0);
103
+ });
104
+ });
105
+ test('should soft delete expired entities', async () => {
106
+ await db.execute(sql `TRUNCATE TABLE ${sql.identifier(schema)}.${sql.identifier('expiration_entities')} CASCADE`);
107
+ await runInInjectionContext(injector, async () => {
108
+ const repository = injectRepository(ExpirationEntity);
109
+ const now = Date.now();
110
+ const past = now - 10000; // 10s ago
111
+ const future = now + 10000; // 10s in future
112
+ const e1 = await repository.insert(Object.assign(new ExpirationEntity(), { name: 'Expired', softExpireAt: past }));
113
+ const e2 = await repository.insert(Object.assign(new ExpirationEntity(), { name: 'Valid', softExpireAt: future }));
114
+ await repository.processExpirations();
115
+ const all = await repository.loadAll();
116
+ expect(all).toHaveLength(1);
117
+ expect(all[0].name).toBe('Valid');
118
+ const withDeleted = await repository.loadAll({ withDeleted: true });
119
+ expect(withDeleted).toHaveLength(2);
120
+ expect(withDeleted.find((e) => e.id === e1.id).metadata.deleteTimestamp).toBeDefined();
121
+ });
122
+ });
123
+ test('should hard delete expired entities', async () => {
124
+ await db.execute(sql `TRUNCATE TABLE ${sql.identifier(schema)}.${sql.identifier('expiration_entities')} CASCADE`);
125
+ await runInInjectionContext(injector, async () => {
126
+ const repository = injectRepository(ExpirationEntity);
127
+ const now = Date.now();
128
+ const past = now - 10000;
129
+ const future = now + 10000;
130
+ const e1 = await repository.insert(Object.assign(new ExpirationEntity(), { name: 'Expired', hardExpireAt: past }));
131
+ const e2 = await repository.insert(Object.assign(new ExpirationEntity(), { name: 'Valid', hardExpireAt: future }));
132
+ await repository.processExpirations();
133
+ const all = await repository.loadAll({ withDeleted: true });
134
+ expect(all).toHaveLength(1);
135
+ expect(all[0].name).toBe('Valid');
136
+ });
137
+ });
138
+ test('should handle mixed expiration', async () => {
139
+ await db.execute(sql `TRUNCATE TABLE ${sql.identifier(schema)}.${sql.identifier('expiration_entities')} CASCADE`);
140
+ await runInInjectionContext(injector, async () => {
141
+ const repository = injectRepository(ExpirationEntity);
142
+ const past = Date.now() - 10000;
143
+ await repository.insert(Object.assign(new ExpirationEntity(), {
144
+ name: 'BothExpired',
145
+ softExpireAt: past,
146
+ hardExpireAt: past,
147
+ }));
148
+ await repository.processExpirations();
149
+ const all = await repository.loadAll({ withDeleted: true });
150
+ expect(all).toHaveLength(0);
151
+ });
152
+ });
153
+ });
@@ -0,0 +1 @@
1
+ export {};