@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,127 @@
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 { describe, expect, test } from 'vitest';
11
+ import { getTableConfig } from 'drizzle-orm/pg-core';
12
+ import { StringProperty } from '../../schema/index.js';
13
+ import { Entity } from '../entity.js';
14
+ import { Column, Inheritance, ChildEntity, Table, ParadeIndex } from '../decorators.js';
15
+ import { getDrizzleTableFromType } from '../server/drizzle/schema-converter.js';
16
+ describe('ORM Schema Generation (CTI)', () => {
17
+ test('should generate correct parent table with discriminator and unique constraint', () => {
18
+ let BaseUser = class BaseUser extends Entity {
19
+ type;
20
+ name;
21
+ };
22
+ __decorate([
23
+ StringProperty(),
24
+ Column({ name: 'type' }),
25
+ __metadata("design:type", String)
26
+ ], BaseUser.prototype, "type", void 0);
27
+ __decorate([
28
+ StringProperty(),
29
+ Column({ name: 'name' }),
30
+ __metadata("design:type", String)
31
+ ], BaseUser.prototype, "name", void 0);
32
+ BaseUser = __decorate([
33
+ Table('users', { schema: 'test' }),
34
+ Inheritance({ strategy: 'joined', discriminatorColumn: 'type' })
35
+ ], BaseUser);
36
+ const table = getDrizzleTableFromType(BaseUser);
37
+ const config = getTableConfig(table);
38
+ // Check columns
39
+ const columnNames = config.columns.map(c => c.name);
40
+ expect(columnNames).toContain('id');
41
+ expect(columnNames).toContain('type');
42
+ expect(columnNames).toContain('name');
43
+ // Check unique constraint
44
+ const uniqueConstraints = config.uniqueConstraints;
45
+ const hasCompositeUnique = uniqueConstraints.some(uc => uc.columns.map(c => c.name).sort().join(',') === 'id,type');
46
+ expect(hasCompositeUnique).toBe(true);
47
+ });
48
+ test('should generate correct child table with only own columns and constraints', () => {
49
+ let BaseUser = class BaseUser extends Entity {
50
+ type;
51
+ name;
52
+ };
53
+ __decorate([
54
+ StringProperty(),
55
+ Column({ name: 'type' }),
56
+ __metadata("design:type", String)
57
+ ], BaseUser.prototype, "type", void 0);
58
+ __decorate([
59
+ StringProperty(),
60
+ Column({ name: 'name' }),
61
+ __metadata("design:type", String)
62
+ ], BaseUser.prototype, "name", void 0);
63
+ BaseUser = __decorate([
64
+ Table('users', { schema: 'test' }),
65
+ Inheritance({ strategy: 'joined', discriminatorColumn: 'type' })
66
+ ], BaseUser);
67
+ let Admin = class Admin extends BaseUser {
68
+ role;
69
+ };
70
+ __decorate([
71
+ StringProperty(),
72
+ Column({ name: 'role' }),
73
+ __metadata("design:type", String)
74
+ ], Admin.prototype, "role", void 0);
75
+ Admin = __decorate([
76
+ Table('admins', { schema: 'test' }),
77
+ ChildEntity('admin')
78
+ ], Admin);
79
+ const table = getDrizzleTableFromType(Admin);
80
+ const config = getTableConfig(table);
81
+ // Check columns: should have id, type, role but NOT name
82
+ const columnNames = config.columns.map(c => c.name);
83
+ expect(columnNames).toContain('id');
84
+ expect(columnNames).toContain('type');
85
+ expect(columnNames).toContain('role');
86
+ expect(columnNames).not.toContain('name');
87
+ expect(columnNames).not.toContain('create_timestamp'); // from Entity
88
+ // Check check constraint
89
+ expect(config.checks.length).toBeGreaterThan(0);
90
+ const typeCheck = config.checks.find(c => c.name.includes('type_check') || c.name.includes('check'));
91
+ expect(typeCheck).toBeDefined();
92
+ // Check foreign key
93
+ expect(config.foreignKeys.length).toBeGreaterThan(0);
94
+ const compositeFk = config.foreignKeys.find(fk => fk.reference().columns.length === 2);
95
+ expect(compositeFk).toBeDefined();
96
+ expect(compositeFk?.reference().columns.map(c => c.name).sort()).toEqual(['id', 'type']);
97
+ });
98
+ test('should generate BM25 index with correct config', () => {
99
+ let SearchableItem = class SearchableItem extends Entity {
100
+ title;
101
+ body;
102
+ };
103
+ __decorate([
104
+ StringProperty(),
105
+ __metadata("design:type", String)
106
+ ], SearchableItem.prototype, "title", void 0);
107
+ __decorate([
108
+ StringProperty(),
109
+ __metadata("design:type", String)
110
+ ], SearchableItem.prototype, "body", void 0);
111
+ SearchableItem = __decorate([
112
+ Table('searchable', { schema: 'test' }),
113
+ ParadeIndex({
114
+ columns: ['title', ['body', { tokenizer: 'simple' }]],
115
+ naming: 'abbreviated-table'
116
+ })
117
+ ], SearchableItem);
118
+ const table = getDrizzleTableFromType(SearchableItem);
119
+ const config = getTableConfig(table);
120
+ // console.log('Indexes:', JSON.stringify(config.indexes, null, 2));
121
+ const paradeIdx = config.indexes.find(i => i.config.using === 'bm25' || i.config.method === 'bm25');
122
+ expect(paradeIdx).toBeDefined();
123
+ const extraConfig = paradeIdx.config.with;
124
+ expect(extraConfig).toBeDefined();
125
+ expect(extraConfig.key_field).toBe("'id'");
126
+ });
127
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,67 @@
1
+ import { describe, expect, test } from 'vitest';
2
+ import { sql, Column, Table as DrizzleTable } from 'drizzle-orm';
3
+ import { PgDialect, pgTable, text, integer } from 'drizzle-orm/pg-core';
4
+ import { exclusiveColumn, enumerationCaseWhen, interval, coalesce, numNulls, numNonNulls, greatest, least } from '../sqls/sqls.js';
5
+ import { defineEnum } from '../../enumeration/index.js';
6
+ describe('ORM SQL Helpers', () => {
7
+ const dialect = new PgDialect();
8
+ const TestEnum = defineEnum('TestEnum', { A: 'a', B: 'b' });
9
+ const testTable = pgTable('test', {
10
+ id: text('id').primaryKey(),
11
+ type: text('type'),
12
+ colA: text('col_a'),
13
+ colB: text('col_b'),
14
+ val: integer('val')
15
+ });
16
+ test('exclusiveColumn should generate correct CASE statement', () => {
17
+ const query = exclusiveColumn(TestEnum, testTable.type, {
18
+ [TestEnum.A]: testTable.colA,
19
+ [TestEnum.B]: testTable.colB,
20
+ });
21
+ const sqlStr = dialect.sqlToQuery(query).sql.toLowerCase();
22
+ expect(sqlStr).toContain('case "test"."type"');
23
+ expect(sqlStr).toContain("when 'a'");
24
+ expect(sqlStr).toContain("col_a\" is not null");
25
+ expect(sqlStr).toContain("col_b\" is null");
26
+ expect(sqlStr).toContain("when 'b'");
27
+ expect(sqlStr).toContain("col_b\" is not null");
28
+ expect(sqlStr).toContain("col_a\" is null");
29
+ expect(sqlStr).toContain('else false end');
30
+ });
31
+ test('enumerationCaseWhen should map enum values to conditions', () => {
32
+ const query = enumerationCaseWhen(TestEnum, testTable.type, {
33
+ [TestEnum.A]: true,
34
+ [TestEnum.B]: sql `"val" > 10`
35
+ });
36
+ const sqlStr = dialect.sqlToQuery(query).sql;
37
+ expect(sqlStr).toContain('WHEN \'a\'');
38
+ expect(sqlStr).toContain('THEN TRUE');
39
+ expect(sqlStr).toContain('WHEN \'b\'');
40
+ expect(sqlStr).toContain('"val" > 10');
41
+ });
42
+ test('interval should generate postgres interval syntax', () => {
43
+ const i = interval(5, 'days');
44
+ const sqlStr = dialect.sqlToQuery(i).sql;
45
+ expect(sqlStr).toContain("||' days')::interval");
46
+ });
47
+ test('coalesce should join multiple columns', () => {
48
+ const c = coalesce(testTable.colA, testTable.colB, sql `'default'`);
49
+ const sqlStr = dialect.sqlToQuery(c).sql;
50
+ expect(sqlStr).toContain('coalesce(');
51
+ expect(sqlStr).toContain('"test"."col_a"');
52
+ expect(sqlStr).toContain('"test"."col_b"');
53
+ expect(sqlStr).toContain("'default'");
54
+ });
55
+ test('numNulls and numNonNulls', () => {
56
+ const n = numNulls(testTable.colA, testTable.colB);
57
+ expect(dialect.sqlToQuery(n).sql).toContain('num_nulls(');
58
+ const nn = numNonNulls(testTable.colA, testTable.colB);
59
+ expect(dialect.sqlToQuery(nn).sql).toContain('num_nonnulls(');
60
+ });
61
+ test('greatest and least', () => {
62
+ const g = greatest(testTable.val, 100);
63
+ expect(dialect.sqlToQuery(g).sql).toContain('greatest(');
64
+ const l = least(testTable.val, sql `0`);
65
+ expect(dialect.sqlToQuery(l).sql).toContain('least(');
66
+ });
67
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,81 @@
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, Singleton, runInInjectionContext } from '../../injector/index.js';
11
+ import { StringProperty } from '../../schema/index.js';
12
+ import { dropTables, setupIntegrationTest } from '../../unit-test/index.js';
13
+ import { sql } from 'drizzle-orm';
14
+ import { beforeAll, describe, expect, test } from 'vitest';
15
+ import { Entity, Table } from '../index.js';
16
+ import { Database, Transactional, injectRepository } from '../server/index.js';
17
+ describe('Transaction Safety (Integration)', () => {
18
+ let injector;
19
+ let database;
20
+ const schema = 'test_orm_tx';
21
+ let TxEntity = class TxEntity extends Entity {
22
+ val;
23
+ };
24
+ __decorate([
25
+ StringProperty(),
26
+ __metadata("design:type", String)
27
+ ], TxEntity.prototype, "val", void 0);
28
+ TxEntity = __decorate([
29
+ Table('tx_test', { schema })
30
+ ], TxEntity);
31
+ let TxService = class TxService extends Transactional {
32
+ repo = injectRepository(TxEntity);
33
+ async successOp() {
34
+ await this.transaction(async (tx) => {
35
+ await this.repo.withTransaction(tx).insert({ val: 'success' });
36
+ });
37
+ }
38
+ async failOp() {
39
+ return await this.transaction(async (tx) => {
40
+ await this.repo.withTransaction(tx).insert({ val: 'should_rollback' });
41
+ throw new Error('Planned Failure');
42
+ });
43
+ }
44
+ };
45
+ TxService = __decorate([
46
+ Singleton()
47
+ ], TxService);
48
+ beforeAll(async () => {
49
+ ({ injector, database } = await setupIntegrationTest({ orm: { schema } }));
50
+ await dropTables(database, schema, ['tx_test']);
51
+ await database.execute(sql `
52
+ CREATE TABLE ${sql.identifier(schema)}.${sql.identifier('tx_test')} (
53
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
54
+ val TEXT NOT NULL,
55
+ revision INTEGER NOT NULL,
56
+ revision_timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
57
+ create_timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
58
+ delete_timestamp TIMESTAMP WITH TIME ZONE,
59
+ attributes JSONB NOT NULL DEFAULT '{}'
60
+ )
61
+ `);
62
+ });
63
+ test('should rollback changes on error', async () => {
64
+ await runInInjectionContext(injector, async () => {
65
+ const service = injector.resolve(TxService);
66
+ const startCount = await service.repo.count();
67
+ await expect(service.failOp()).rejects.toThrow('Planned Failure');
68
+ const endCount = await service.repo.count();
69
+ expect(endCount).toBe(startCount);
70
+ });
71
+ });
72
+ test('should commit changes on success', async () => {
73
+ await runInInjectionContext(injector, async () => {
74
+ const service = injector.resolve(TxService);
75
+ const startCount = await service.repo.count();
76
+ await service.successOp();
77
+ const endCount = await service.repo.count();
78
+ expect(endCount).toBe(startCount + 1);
79
+ });
80
+ });
81
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,224 @@
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 { Injector, runInInjectionContext, Singleton } from '../../injector/index.js';
12
+ import { StringProperty } from '../../schema/index.js';
13
+ import { beforeAll, describe, expect, test } from 'vitest';
14
+ import { Table } from '../decorators.js';
15
+ import { Entity } from '../entity.js';
16
+ import { configureOrm, Database } from '../server/index.js';
17
+ import { getRepository } from '../server/repository.js';
18
+ import { Transactional } from '../server/transactional.js';
19
+ describe('ORM Transactional (Integration)', () => {
20
+ let injector;
21
+ let db;
22
+ const schema = 'test_orm_transactional';
23
+ let TransactionalItem = class TransactionalItem extends Entity {
24
+ name;
25
+ };
26
+ __decorate([
27
+ StringProperty(),
28
+ __metadata("design:type", String)
29
+ ], TransactionalItem.prototype, "name", void 0);
30
+ TransactionalItem = __decorate([
31
+ Table('transactional_items', { schema })
32
+ ], TransactionalItem);
33
+ let TransactionalService = class TransactionalService extends Transactional {
34
+ repository = getRepository(TransactionalItem);
35
+ async create(name) {
36
+ const repo = injector.resolve(this.repository).withSession(this.session);
37
+ const item = new TransactionalItem();
38
+ item.name = name;
39
+ return await repo.insert(item);
40
+ }
41
+ async count() {
42
+ const repo = injector.resolve(this.repository).withSession(this.session);
43
+ return await repo.count();
44
+ }
45
+ };
46
+ TransactionalService = __decorate([
47
+ Singleton()
48
+ ], TransactionalService);
49
+ beforeAll(async () => {
50
+ injector = new Injector('Test');
51
+ const encryptionSecret = new Uint8Array(32).fill(1);
52
+ configureOrm({
53
+ repositoryConfig: { schema },
54
+ connection: {
55
+ host: '127.0.0.1',
56
+ port: 5432,
57
+ user: 'tstdl',
58
+ password: 'wf7rq6glrk5jykne',
59
+ database: 'tstdl',
60
+ },
61
+ encryptionSecret,
62
+ });
63
+ db = injector.resolve(Database);
64
+ await db.execute(sql `CREATE SCHEMA IF NOT EXISTS ${sql.identifier(schema)}`);
65
+ await db.execute(sql `DROP TABLE IF EXISTS ${sql.identifier(schema)}.${sql.identifier('transactional_items')} CASCADE`);
66
+ await db.execute(sql `
67
+ CREATE TABLE ${sql.identifier(schema)}.${sql.identifier('transactional_items')} (
68
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
69
+ name TEXT NOT NULL,
70
+ revision INTEGER NOT NULL,
71
+ revision_timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
72
+ create_timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
73
+ delete_timestamp TIMESTAMP WITH TIME ZONE,
74
+ attributes JSONB NOT NULL DEFAULT '{}'
75
+ )
76
+ `);
77
+ injector.register(TransactionalService, { useClass: TransactionalService });
78
+ });
79
+ test('should handle nested transactions (savepoints by default)', async () => {
80
+ await db.execute(sql `TRUNCATE TABLE ${sql.identifier(schema)}.${sql.identifier('transactional_items')} CASCADE`);
81
+ await runInInjectionContext(injector, async () => {
82
+ const service = injector.resolve(TransactionalService);
83
+ await service.transaction(async (tx1) => {
84
+ await service.withTransaction(tx1).create('Outer');
85
+ await service.withTransaction(tx1).transaction(async (tx2) => {
86
+ // Default behavior: create new transaction (savepoint)
87
+ expect(tx1).not.toBe(tx2);
88
+ await service.withTransaction(tx2).create('Inner');
89
+ });
90
+ });
91
+ const count = await service.count();
92
+ expect(count).toBe(2);
93
+ });
94
+ });
95
+ test('should handle nested transactions with rollback (savepoints by default)', async () => {
96
+ await db.execute(sql `TRUNCATE TABLE ${sql.identifier(schema)}.${sql.identifier('transactional_items')} CASCADE`);
97
+ await runInInjectionContext(injector, async () => {
98
+ const service = injector.resolve(TransactionalService);
99
+ await service.transaction(async (tx1) => {
100
+ await service.withTransaction(tx1).create('Outer');
101
+ try {
102
+ await service.withTransaction(tx1).transaction(async (tx2) => {
103
+ await service.withTransaction(tx2).create('Inner');
104
+ throw new Error('Fail Inner');
105
+ });
106
+ }
107
+ catch (e) {
108
+ expect(e.message).toBe('Fail Inner');
109
+ }
110
+ });
111
+ // Should roll back only inner (savepoint), keeping Outer
112
+ const count = await service.count();
113
+ expect(count).toBe(1);
114
+ });
115
+ });
116
+ test('should handle independent transactions (savepoints) with useExisting: false', async () => {
117
+ await db.execute(sql `TRUNCATE TABLE ${sql.identifier(schema)}.${sql.identifier('transactional_items')} CASCADE`);
118
+ await runInInjectionContext(injector, async () => {
119
+ const service = injector.resolve(TransactionalService);
120
+ await service.transaction(async (tx1) => {
121
+ await service.withTransaction(tx1).create('Outer');
122
+ await service.withTransaction(tx1).transaction(async (tx2) => {
123
+ expect(tx1).not.toBe(tx2); // Should be different wrapper (savepoint)
124
+ await service.withTransaction(tx2).create('Inner');
125
+ }, { useExisting: false });
126
+ });
127
+ const count = await service.count();
128
+ expect(count).toBe(2);
129
+ });
130
+ });
131
+ test('should rollback only inner transaction when useExisting: false', async () => {
132
+ await db.execute(sql `TRUNCATE TABLE ${sql.identifier(schema)}.${sql.identifier('transactional_items')} CASCADE`);
133
+ await runInInjectionContext(injector, async () => {
134
+ const service = injector.resolve(TransactionalService);
135
+ await service.transaction(async (tx1) => {
136
+ await service.withTransaction(tx1).create('Outer');
137
+ try {
138
+ await service.withTransaction(tx1).transaction(async (tx2) => {
139
+ await service.withTransaction(tx2).create('Inner');
140
+ throw new Error('Fail Inner');
141
+ }, { useExisting: false });
142
+ }
143
+ catch {
144
+ // Swallow error to allow outer to continue
145
+ }
146
+ });
147
+ const count = await service.count();
148
+ // Outer should exist, Inner should be rolled back (savepoint behavior)
149
+ expect(count).toBe(1);
150
+ const repo = injector.resolve(service.repository);
151
+ const items = await repo.loadAll();
152
+ expect(items[0].name).toBe('Outer');
153
+ });
154
+ });
155
+ test('should reuse existing transaction when useExisting: true', async () => {
156
+ await db.execute(sql `TRUNCATE TABLE ${sql.identifier(schema)}.${sql.identifier('transactional_items')} CASCADE`);
157
+ await runInInjectionContext(injector, async () => {
158
+ const service = injector.resolve(TransactionalService);
159
+ await service.transaction(async (tx1) => {
160
+ await service.withTransaction(tx1).transaction(async (tx2) => {
161
+ expect(tx1).toBe(tx2);
162
+ }, { useExisting: true });
163
+ });
164
+ });
165
+ });
166
+ test('should defer afterCommit of nested transaction until root commits', async () => {
167
+ await db.execute(sql `TRUNCATE TABLE ${sql.identifier(schema)}.${sql.identifier('transactional_items')} CASCADE`);
168
+ await runInInjectionContext(injector, async () => {
169
+ const service = injector.resolve(TransactionalService);
170
+ let innerCommitted = false;
171
+ let outerCommitted = false;
172
+ await service.transaction(async (tx1) => {
173
+ tx1.afterCommit.register(() => { outerCommitted = true; });
174
+ await service.withTransaction(tx1).transaction(async (tx2) => {
175
+ tx2.afterCommit.register(() => { innerCommitted = true; });
176
+ await service.withTransaction(tx2).create('Inner');
177
+ });
178
+ // Inner transaction finished, but should not have triggered hooks yet
179
+ expect(innerCommitted).toBe(false);
180
+ });
181
+ expect(outerCommitted).toBe(true);
182
+ expect(innerCommitted).toBe(true);
183
+ });
184
+ });
185
+ test('should NOT trigger afterCommit if outer transaction rolls back', async () => {
186
+ await db.execute(sql `TRUNCATE TABLE ${sql.identifier(schema)}.${sql.identifier('transactional_items')} CASCADE`);
187
+ await runInInjectionContext(injector, async () => {
188
+ const service = injector.resolve(TransactionalService);
189
+ let innerCommitted = false;
190
+ try {
191
+ await service.transaction(async (tx1) => {
192
+ await service.withTransaction(tx1).transaction(async (tx2) => {
193
+ tx2.afterCommit.register(() => { innerCommitted = true; });
194
+ await service.withTransaction(tx2).create('Inner');
195
+ });
196
+ // Inner committed successfully.
197
+ // Now rollback outer.
198
+ throw new Error('Rollback Outer');
199
+ });
200
+ }
201
+ catch {
202
+ // Ignore
203
+ }
204
+ // Hook should not have fired
205
+ expect(innerCommitted).toBe(false);
206
+ });
207
+ });
208
+ test('should support withManualCommit', async () => {
209
+ await db.execute(sql `TRUNCATE TABLE ${sql.identifier(schema)}.${sql.identifier('transactional_items')} CASCADE`);
210
+ await runInInjectionContext(injector, async () => {
211
+ const service = injector.resolve(TransactionalService);
212
+ await service.transaction(async (tx) => {
213
+ tx.withManualCommit();
214
+ await service.create('Manual');
215
+ // If we don't commit, it would hang if we tried to exit?
216
+ // Or if we check DB outside, it's locked?
217
+ // We just verify it works when we DO commit.
218
+ await tx.commit();
219
+ });
220
+ const count = await service.count();
221
+ expect(count).toBe(1);
222
+ });
223
+ });
224
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,70 @@
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 { describe, expect, test } from 'vitest';
11
+ import { Entity } from '../entity.js';
12
+ import { Column, Inheritance, ChildEntity } from '../decorators.js';
13
+ import { getOwnProperties } from '../utils.js';
14
+ describe('ORM Utils', () => {
15
+ describe('getOwnProperties', () => {
16
+ test('should return only own properties and primary key for child entity', () => {
17
+ let Vehicle = class Vehicle extends Entity {
18
+ type;
19
+ model;
20
+ };
21
+ __decorate([
22
+ Column({}),
23
+ __metadata("design:type", String)
24
+ ], Vehicle.prototype, "type", void 0);
25
+ __decorate([
26
+ Column({ name: 'model' }),
27
+ __metadata("design:type", String)
28
+ ], Vehicle.prototype, "model", void 0);
29
+ Vehicle = __decorate([
30
+ Inheritance({ strategy: 'joined', discriminatorColumn: 'type' })
31
+ ], Vehicle);
32
+ let Car = class Car extends Vehicle {
33
+ doors;
34
+ };
35
+ __decorate([
36
+ Column({ name: 'doors' }),
37
+ __metadata("design:type", Number)
38
+ ], Car.prototype, "doors", void 0);
39
+ Car = __decorate([
40
+ ChildEntity('car')
41
+ ], Car);
42
+ const ownProps = getOwnProperties(Car);
43
+ const propKeys = ownProps.map(p => p.key);
44
+ expect(propKeys).toContain('id'); // Inherited PK is required
45
+ expect(propKeys).toContain('doors'); // Own property
46
+ expect(propKeys).not.toContain('model'); // Inherited property should be excluded
47
+ });
48
+ test('should return all properties for base entity', () => {
49
+ let Vehicle = class Vehicle extends Entity {
50
+ type;
51
+ model;
52
+ };
53
+ __decorate([
54
+ Column({}),
55
+ __metadata("design:type", String)
56
+ ], Vehicle.prototype, "type", void 0);
57
+ __decorate([
58
+ Column({ name: 'model' }),
59
+ __metadata("design:type", String)
60
+ ], Vehicle.prototype, "model", void 0);
61
+ Vehicle = __decorate([
62
+ Inheritance({ strategy: 'joined', discriminatorColumn: 'type' })
63
+ ], Vehicle);
64
+ const ownProps = getOwnProperties(Vehicle);
65
+ const propKeys = ownProps.map(p => p.key);
66
+ expect(propKeys).toContain('id');
67
+ expect(propKeys).toContain('model');
68
+ });
69
+ });
70
+ });
package/orm/utils.d.ts CHANGED
@@ -2,6 +2,9 @@
2
2
  * @module
3
3
  * Provides utility functions for working with ORM entities.
4
4
  */
5
+ import { type PropertyMetadata } from '../reflection/registry.js';
6
+ import type { AbstractConstructor } from '../types/index.js';
7
+ import type { InheritanceMetadata } from './decorators.js';
5
8
  import type { BaseEntity, Entity } from './entity.js';
6
9
  /**
7
10
  * Converts an array of entities into a Map keyed by entity ID.
@@ -10,6 +13,7 @@ import type { BaseEntity, Entity } from './entity.js';
10
13
  * @returns A Map where keys are entity IDs and values are the corresponding entities.
11
14
  */
12
15
  export declare function getEntityMap<T extends Entity | BaseEntity>(entities: T[]): Map<string, T>;
16
+ export declare function getEntityMap<T extends Entity | BaseEntity, S>(entities: T[], selector: (entity: T) => S): Map<S, T>;
13
17
  /**
14
18
  * Extracts the IDs from an array of entities.
15
19
  * @template T - The entity type, must extend `Entity` (i.e., have an `id` property).
@@ -17,3 +21,6 @@ export declare function getEntityMap<T extends Entity | BaseEntity>(entities: T[
17
21
  * @returns An array containing the IDs of the entities.
18
22
  */
19
23
  export declare function getEntityIds(entities: (Entity | BaseEntity)[]): string[];
24
+ export declare function isChildEntity(type: AbstractConstructor): boolean;
25
+ export declare function getInheritanceMetadata(type: AbstractConstructor): InheritanceMetadata | undefined;
26
+ export declare function getOwnProperties(type: AbstractConstructor): PropertyMetadata[];
package/orm/utils.js CHANGED
@@ -1,11 +1,12 @@
1
1
  /**
2
- * Converts an array of entities into a Map keyed by entity ID.
3
- * @template T - The entity type, must extend `Entity` (i.e., have an `id` property).
4
- * @param entities - An array of entities.
5
- * @returns A Map where keys are entity IDs and values are the corresponding entities.
2
+ * @module
3
+ * Provides utility functions for working with ORM entities.
6
4
  */
7
- export function getEntityMap(entities) {
8
- return new Map(entities.map((entity) => [entity.id, entity]));
5
+ import { reflectionRegistry } from '../reflection/registry.js';
6
+ import { isDefined, isNotNullOrUndefined, isUndefined } from '../utils/type-guards.js';
7
+ export function getEntityMap(entities, selector = (entity) => entity.id) {
8
+ const entries = entities.map((entity) => [selector(entity), entity]);
9
+ return new Map(entries);
9
10
  }
10
11
  /**
11
12
  * Extracts the IDs from an array of entities.
@@ -16,3 +17,22 @@ export function getEntityMap(entities) {
16
17
  export function getEntityIds(entities) {
17
18
  return entities.map((entity) => entity.id);
18
19
  }
20
+ export function isChildEntity(type) {
21
+ return isDefined(reflectionRegistry.getMetadata(type)?.data.tryGet('orm')?.childEntity);
22
+ }
23
+ export function getInheritanceMetadata(type) {
24
+ for (let currentMetadata = reflectionRegistry.getMetadata(type); isNotNullOrUndefined(currentMetadata); currentMetadata = isNotNullOrUndefined(currentMetadata.parent) ? reflectionRegistry.getMetadata(currentMetadata.parent) : undefined) {
25
+ const inheritance = currentMetadata.data.tryGet('orm')?.inheritance;
26
+ if (isDefined(inheritance)) {
27
+ return inheritance;
28
+ }
29
+ }
30
+ return undefined;
31
+ }
32
+ export function getOwnProperties(type) {
33
+ const metadata = reflectionRegistry.getMetadata(type);
34
+ if (isUndefined(metadata)) {
35
+ return [];
36
+ }
37
+ return [...metadata.properties.values()].filter((property) => !property.inherited || (property.key == 'id'));
38
+ }