alepha 0.18.2 → 0.18.3

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 (397) hide show
  1. package/assets/devtools-ui/200.html +2 -2
  2. package/assets/devtools-ui/200.html.br +0 -0
  3. package/assets/devtools-ui/404.html +2 -2
  4. package/assets/devtools-ui/404.html.br +0 -0
  5. package/assets/devtools-ui/{asset.BfSBZ5Dd.css → asset.hG_f8HuK.css} +1 -1
  6. package/assets/devtools-ui/asset.hG_f8HuK.css.br +0 -0
  7. package/assets/devtools-ui/chunk.B3au4Lhg.js +1 -0
  8. package/assets/devtools-ui/chunk.B3au4Lhg.js.br +0 -0
  9. package/assets/devtools-ui/chunk.BLOrlnMB.js +1 -0
  10. package/assets/devtools-ui/chunk.BLOrlnMB.js.br +0 -0
  11. package/assets/devtools-ui/chunk.BLR01ljW.js +1 -0
  12. package/assets/devtools-ui/chunk.BLR01ljW.js.br +0 -0
  13. package/assets/devtools-ui/chunk.BTXaIUlA.js +1 -0
  14. package/assets/devtools-ui/chunk.BTXaIUlA.js.br +0 -0
  15. package/assets/devtools-ui/{chunk.lJL-lgnW.js → chunk.BhJaxmm8.js} +1 -1
  16. package/assets/devtools-ui/chunk.BhJaxmm8.js.br +0 -0
  17. package/assets/devtools-ui/chunk.BtoNxFuL.js +1 -0
  18. package/assets/devtools-ui/chunk.BtoNxFuL.js.br +0 -0
  19. package/assets/devtools-ui/chunk.C8YUV2Wd.js +1 -0
  20. package/assets/devtools-ui/chunk.C8YUV2Wd.js.br +0 -0
  21. package/assets/devtools-ui/{chunk.M6wyKO_3.js → chunk.CBbIgDzE.js} +2 -2
  22. package/assets/devtools-ui/chunk.CBbIgDzE.js.br +0 -0
  23. package/assets/devtools-ui/chunk.CFqIniwA.js +1 -0
  24. package/assets/devtools-ui/chunk.CFqIniwA.js.br +0 -0
  25. package/assets/devtools-ui/chunk.CLFF7f7-.js +1 -0
  26. package/assets/devtools-ui/chunk.CLFF7f7-.js.br +0 -0
  27. package/assets/devtools-ui/chunk.CRsBbA10.js +1 -0
  28. package/assets/devtools-ui/chunk.CRsBbA10.js.br +0 -0
  29. package/assets/devtools-ui/{chunk.DbEH1oOB.js → chunk.CZPo6v95.js} +1 -1
  30. package/assets/devtools-ui/chunk.CZPo6v95.js.br +0 -0
  31. package/assets/devtools-ui/chunk.D0fWgNos.js +1 -0
  32. package/assets/devtools-ui/chunk.D0fWgNos.js.br +1 -0
  33. package/assets/devtools-ui/chunk.D7-0ziQ6.js +1 -0
  34. package/assets/devtools-ui/chunk.D7-0ziQ6.js.br +0 -0
  35. package/assets/devtools-ui/chunk.DAewe0vm.js +1 -0
  36. package/assets/devtools-ui/chunk.DAewe0vm.js.br +0 -0
  37. package/assets/devtools-ui/chunk.DJRQEYqK.js +1 -0
  38. package/assets/devtools-ui/chunk.DJRQEYqK.js.br +0 -0
  39. package/assets/devtools-ui/{chunk.CZl6J9DF.js → chunk.DMAxv14p.js} +1 -1
  40. package/assets/devtools-ui/chunk.DMAxv14p.js.br +0 -0
  41. package/assets/devtools-ui/{chunk.BT2IiBkZ.js → chunk.DMImnNjU.js} +1 -1
  42. package/assets/devtools-ui/chunk.DMImnNjU.js.br +0 -0
  43. package/assets/devtools-ui/chunk.DeeQsidk.js +9 -0
  44. package/assets/devtools-ui/chunk.DeeQsidk.js.br +0 -0
  45. package/assets/devtools-ui/chunk.DqEwn9Vj.js +7 -0
  46. package/assets/devtools-ui/chunk.DqEwn9Vj.js.br +0 -0
  47. package/assets/devtools-ui/chunk.Dt8OsQey.js +1 -0
  48. package/assets/devtools-ui/chunk.Dt8OsQey.js.br +0 -0
  49. package/assets/devtools-ui/{chunk.B9pX3zit.js → chunk.Dtp8oa_f.js} +1 -1
  50. package/assets/devtools-ui/chunk.Dtp8oa_f.js.br +0 -0
  51. package/assets/devtools-ui/chunk.Dx3JzAYM.js +1 -0
  52. package/assets/devtools-ui/chunk.Dx3JzAYM.js.br +0 -0
  53. package/assets/devtools-ui/chunk.GCOj1-5E.js +1 -0
  54. package/assets/devtools-ui/chunk.GCOj1-5E.js.br +0 -0
  55. package/assets/devtools-ui/chunk.IC1LD8BH.js +1 -0
  56. package/assets/devtools-ui/chunk.IC1LD8BH.js.br +0 -0
  57. package/assets/devtools-ui/chunk.IwuB_TqW.js +1 -0
  58. package/assets/devtools-ui/chunk.IwuB_TqW.js.br +0 -0
  59. package/assets/devtools-ui/chunk.Qqapj2zq.js +1 -0
  60. package/assets/devtools-ui/chunk.Qqapj2zq.js.br +0 -0
  61. package/assets/devtools-ui/{chunk.C79YouPp.js → chunk.TKKKndOy.js} +1 -1
  62. package/assets/devtools-ui/chunk.TKKKndOy.js.br +0 -0
  63. package/assets/devtools-ui/chunk.YHTVhFQT.js +1 -0
  64. package/assets/devtools-ui/chunk.YHTVhFQT.js.br +0 -0
  65. package/assets/devtools-ui/chunk.fnod6uEi.js +1 -0
  66. package/assets/devtools-ui/chunk.fnod6uEi.js.br +0 -0
  67. package/assets/devtools-ui/chunk.mOCRmXjo.js +1 -0
  68. package/assets/devtools-ui/chunk.mOCRmXjo.js.br +0 -0
  69. package/assets/devtools-ui/chunk.qZTNEAK0.js +1 -0
  70. package/assets/devtools-ui/chunk.qZTNEAK0.js.br +0 -0
  71. package/assets/devtools-ui/chunk.rc9m0y4-.js +1 -0
  72. package/assets/devtools-ui/chunk.rc9m0y4-.js.br +0 -0
  73. package/assets/devtools-ui/entry.Cxc5QLCU.js +80 -0
  74. package/assets/devtools-ui/entry.Cxc5QLCU.js.br +0 -0
  75. package/assets/devtools-ui/index.html +2 -2
  76. package/assets/devtools-ui/index.html.br +0 -0
  77. package/assets/swagger-ui/swagger-ui-bundle.js +1 -1
  78. package/assets/swagger-ui/swagger-ui.css +1 -1
  79. package/dist/api/audits/index.d.ts +61 -5
  80. package/dist/api/audits/index.d.ts.map +1 -1
  81. package/dist/api/files/index.d.ts +61 -5
  82. package/dist/api/files/index.d.ts.map +1 -1
  83. package/dist/api/jobs/index.d.ts +61 -5
  84. package/dist/api/jobs/index.d.ts.map +1 -1
  85. package/dist/api/jobs/index.js +4 -2
  86. package/dist/api/jobs/index.js.map +1 -1
  87. package/dist/api/keys/index.d.ts +5 -5
  88. package/dist/api/notifications/index.browser.js +44 -1
  89. package/dist/api/notifications/index.browser.js.map +1 -1
  90. package/dist/api/notifications/index.d.ts +187 -2
  91. package/dist/api/notifications/index.d.ts.map +1 -1
  92. package/dist/api/notifications/index.js +143 -8
  93. package/dist/api/notifications/index.js.map +1 -1
  94. package/dist/api/parameters/index.d.ts +61 -5
  95. package/dist/api/parameters/index.d.ts.map +1 -1
  96. package/dist/api/users/index.d.ts +330 -93
  97. package/dist/api/users/index.d.ts.map +1 -1
  98. package/dist/api/users/index.js +27 -36
  99. package/dist/api/users/index.js.map +1 -1
  100. package/dist/cli/config/index.d.ts +46 -0
  101. package/dist/cli/config/index.d.ts.map +1 -0
  102. package/dist/cli/config/index.js +20 -0
  103. package/dist/cli/config/index.js.map +1 -0
  104. package/dist/cli/core/index.d.ts +69 -66
  105. package/dist/cli/core/index.d.ts.map +1 -1
  106. package/dist/cli/core/index.js +329 -196
  107. package/dist/cli/core/index.js.map +1 -1
  108. package/dist/cli/platform/index.d.ts +302 -63
  109. package/dist/cli/platform/index.d.ts.map +1 -1
  110. package/dist/cli/platform/index.js +455 -25
  111. package/dist/cli/platform/index.js.map +1 -1
  112. package/dist/core/index.browser.js +125 -87
  113. package/dist/core/index.browser.js.map +1 -1
  114. package/dist/core/index.d.ts +62 -53
  115. package/dist/core/index.d.ts.map +1 -1
  116. package/dist/core/index.js +125 -87
  117. package/dist/core/index.js.map +1 -1
  118. package/dist/core/index.native.js +125 -87
  119. package/dist/core/index.native.js.map +1 -1
  120. package/dist/core/index.workerd.js +125 -87
  121. package/dist/core/index.workerd.js.map +1 -1
  122. package/dist/crypto/index.d.ts +18 -1
  123. package/dist/crypto/index.d.ts.map +1 -1
  124. package/dist/crypto/index.js +29 -3
  125. package/dist/crypto/index.js.map +1 -1
  126. package/dist/devtools/index.js +3 -12
  127. package/dist/devtools/index.js.map +1 -1
  128. package/dist/logger/index.d.ts +10 -1
  129. package/dist/logger/index.d.ts.map +1 -1
  130. package/dist/logger/index.js +19 -9
  131. package/dist/logger/index.js.map +1 -1
  132. package/dist/orm/core/index.browser.js +57 -1
  133. package/dist/orm/core/index.browser.js.map +1 -1
  134. package/dist/orm/core/index.bun.js +378 -19
  135. package/dist/orm/core/index.bun.js.map +1 -1
  136. package/dist/orm/core/index.d.ts +328 -9
  137. package/dist/orm/core/index.d.ts.map +1 -1
  138. package/dist/orm/core/index.js +384 -21
  139. package/dist/orm/core/index.js.map +1 -1
  140. package/dist/orm/postgres/index.bun.js +49 -17
  141. package/dist/orm/postgres/index.bun.js.map +1 -1
  142. package/dist/orm/postgres/index.d.ts +47 -21
  143. package/dist/orm/postgres/index.d.ts.map +1 -1
  144. package/dist/orm/postgres/index.js +52 -17
  145. package/dist/orm/postgres/index.js.map +1 -1
  146. package/dist/react/core/index.d.ts +1 -1
  147. package/dist/react/core/index.d.ts.map +1 -1
  148. package/dist/react/core/index.js +6 -1
  149. package/dist/react/core/index.js.map +1 -1
  150. package/dist/react/form/index.d.ts +28 -18
  151. package/dist/react/form/index.d.ts.map +1 -1
  152. package/dist/react/form/index.js +92 -56
  153. package/dist/react/form/index.js.map +1 -1
  154. package/dist/react/router/index.browser.js +448 -116
  155. package/dist/react/router/index.browser.js.map +1 -1
  156. package/dist/react/router/index.d.ts +102 -40
  157. package/dist/react/router/index.d.ts.map +1 -1
  158. package/dist/react/router/index.js +453 -92
  159. package/dist/react/router/index.js.map +1 -1
  160. package/dist/security/index.d.ts +3 -11
  161. package/dist/security/index.d.ts.map +1 -1
  162. package/dist/security/index.js +6 -11
  163. package/dist/security/index.js.map +1 -1
  164. package/dist/server/auth/index.d.ts +22 -24
  165. package/dist/server/auth/index.d.ts.map +1 -1
  166. package/dist/server/auth/index.js +102 -82
  167. package/dist/server/auth/index.js.map +1 -1
  168. package/dist/server/cookies/index.d.ts +7 -4
  169. package/dist/server/cookies/index.d.ts.map +1 -1
  170. package/dist/server/cookies/index.js +13 -12
  171. package/dist/server/cookies/index.js.map +1 -1
  172. package/dist/server/core/index.d.ts +288 -4
  173. package/dist/server/core/index.d.ts.map +1 -1
  174. package/dist/server/core/index.js +375 -2
  175. package/dist/server/core/index.js.map +1 -1
  176. package/dist/server/links/index.browser.js +10 -71
  177. package/dist/server/links/index.browser.js.map +1 -1
  178. package/dist/server/links/index.d.ts +32 -49
  179. package/dist/server/links/index.d.ts.map +1 -1
  180. package/dist/server/links/index.js +73 -100
  181. package/dist/server/links/index.js.map +1 -1
  182. package/dist/system/index.browser.js +221 -2
  183. package/dist/system/index.browser.js.map +1 -1
  184. package/dist/system/index.d.ts +63 -1
  185. package/dist/system/index.d.ts.map +1 -1
  186. package/dist/system/index.js +221 -1
  187. package/dist/system/index.js.map +1 -1
  188. package/dist/system/index.workerd.js +224 -4
  189. package/dist/system/index.workerd.js.map +1 -1
  190. package/package.json +10 -5
  191. package/src/api/jobs/providers/JobProvider.ts +6 -3
  192. package/src/api/notifications/controllers/AdminNotificationController.ts +83 -0
  193. package/src/api/notifications/index.browser.ts +3 -0
  194. package/src/api/notifications/index.ts +14 -2
  195. package/src/api/notifications/jobs/NotificationJobs.ts +11 -2
  196. package/src/api/notifications/schemas/notificationDetailResourceSchema.ts +20 -0
  197. package/src/api/notifications/schemas/notificationQuerySchema.ts +19 -0
  198. package/src/api/notifications/schemas/notificationResourceSchema.ts +18 -0
  199. package/src/api/notifications/services/NotificationSenderService.ts +15 -2
  200. package/src/api/users/atoms/realmAuthSettingsAtom.ts +28 -32
  201. package/src/api/users/buckets/UserBuckets.ts +1 -1
  202. package/src/api/users/jobs/UserJobs.ts +1 -1
  203. package/src/api/users/primitives/$realm.ts +8 -49
  204. package/src/api/users/providers/RealmProvider.ts +2 -3
  205. package/src/api/users/services/RegistrationService.spec.ts +7 -7
  206. package/src/api/users/services/RegistrationService.ts +3 -3
  207. package/src/api/users/services/SessionService.spec.ts +4 -4
  208. package/src/api/users/services/SessionService.ts +3 -3
  209. package/src/cli/{core → config}/defineConfig.ts +14 -20
  210. package/src/cli/config/index.ts +1 -0
  211. package/src/cli/core/commands/db.ts +65 -1
  212. package/src/cli/core/commands/dev.ts +1 -0
  213. package/src/cli/core/commands/init.ts +2 -192
  214. package/src/cli/core/index.ts +34 -11
  215. package/src/cli/core/providers/ViteDevServerProvider.ts +52 -13
  216. package/src/cli/core/services/PackageManagerUtils.ts +43 -21
  217. package/src/cli/core/services/ProjectScaffolder.ts +214 -2
  218. package/src/cli/core/services/ViteUtils.ts +57 -0
  219. package/src/cli/core/tasks/BuildClientTask.ts +7 -2
  220. package/src/cli/core/tasks/BuildCloudflareTask.ts +4 -12
  221. package/src/cli/core/tasks/BuildServerTask.ts +2 -0
  222. package/src/cli/core/tasks/BuildVercelTask.ts +165 -168
  223. package/src/cli/core/templates/alephaConfigTs.ts +1 -1
  224. package/src/cli/core/templates/apiAppSecurityTs.ts +5 -8
  225. package/src/cli/core/templates/tsconfigJson.ts +6 -1
  226. package/src/cli/platform/adapters/CloudflareAdapter.spec.ts +1 -1
  227. package/src/cli/platform/adapters/CloudflareAdapter.ts +30 -29
  228. package/src/cli/platform/atoms/platformOptions.ts +21 -0
  229. package/src/cli/platform/commands/SecretsCommand.spec.ts +298 -0
  230. package/src/cli/platform/commands/SecretsCommand.ts +283 -0
  231. package/src/cli/platform/commands/platform.ts +12 -0
  232. package/src/cli/platform/index.ts +14 -28
  233. package/src/cli/platform/providers/GitHubSecretStore.spec.ts +153 -0
  234. package/src/cli/platform/providers/GitHubSecretStore.ts +112 -0
  235. package/src/cli/platform/providers/MemorySecretStore.ts +114 -0
  236. package/src/cli/platform/providers/SecretStoreProvider.ts +39 -0
  237. package/src/cli/platform/schemas/cloudflare.ts +2 -0
  238. package/src/cli/platform/services/CloudflareApi.ts +5 -2
  239. package/src/cli/platform/services/DockerComposeGenerator.spec.ts +115 -0
  240. package/src/cli/platform/services/DockerComposeGenerator.ts +46 -1
  241. package/src/cli/platform/services/SecretFilterService.spec.ts +111 -0
  242. package/src/cli/platform/services/SecretFilterService.ts +54 -0
  243. package/src/core/Alepha.ts +94 -25
  244. package/src/core/__tests__/Alepha-parseEnv.spec.ts +20 -0
  245. package/src/core/primitives/$memoize.ts +38 -26
  246. package/src/core/providers/AlsProvider.ts +2 -0
  247. package/src/core/providers/EventManager.ts +4 -0
  248. package/src/core/providers/KeylessJsonSchemaCodec.spec.ts +1 -4
  249. package/src/core/providers/KeylessJsonSchemaCodec.ts +19 -125
  250. package/src/core/providers/SchemaValidator.spec.ts +36 -0
  251. package/src/core/providers/SchemaValidator.ts +9 -0
  252. package/src/crypto/index.ts +6 -1
  253. package/src/crypto/providers/SecretProvider.ts +36 -0
  254. package/src/devtools/providers/DevToolsProvider.ts +3 -12
  255. package/src/logger/index.ts +33 -6
  256. package/src/logger/providers/PrettyFormatterProvider.ts +5 -3
  257. package/src/orm/__tests__/orm-next-tests.ts +492 -0
  258. package/src/orm/__tests__/orm-next.spec.ts +140 -0
  259. package/src/orm/core/constants/PG_SYMBOLS.ts +17 -0
  260. package/src/orm/core/index.bun.ts +3 -6
  261. package/src/orm/core/index.shared-server.ts +2 -0
  262. package/src/orm/core/index.shared.ts +2 -0
  263. package/src/orm/core/index.ts +5 -7
  264. package/src/orm/core/interfaces/AggregateQuery.ts +103 -0
  265. package/src/orm/core/interfaces/PgQueryWhere.ts +7 -0
  266. package/src/orm/core/primitives/$entity.ts +8 -0
  267. package/src/orm/core/primitives/$repository.ts +6 -3
  268. package/src/orm/core/primitives/$view.ts +88 -0
  269. package/src/orm/core/providers/DbCacheProvider.ts +66 -0
  270. package/src/orm/core/providers/DrizzleKitProvider.ts +42 -0
  271. package/src/orm/core/providers/drivers/BunSqliteProvider.ts +2 -3
  272. package/src/orm/core/providers/drivers/CloudflareD1Provider.ts +12 -0
  273. package/src/orm/core/providers/drivers/DatabaseProvider.ts +39 -0
  274. package/src/orm/core/providers/drivers/NodeSqliteProvider.ts +2 -3
  275. package/src/orm/core/schemas/databaseEnvSchema.ts +31 -0
  276. package/src/orm/core/schemas/insertSchema.ts +13 -3
  277. package/src/orm/core/schemas/updateSchema.ts +14 -3
  278. package/src/orm/core/services/ModelBuilder.ts +26 -14
  279. package/src/orm/core/services/QueryManager.ts +13 -0
  280. package/src/orm/core/services/Repository.ts +307 -5
  281. package/src/orm/core/services/SqliteModelBuilder.ts +38 -0
  282. package/src/orm/postgres/index.bun.ts +4 -7
  283. package/src/orm/postgres/index.ts +4 -7
  284. package/src/orm/postgres/providers/BunPostgresProvider.ts +12 -2
  285. package/src/orm/postgres/providers/NodePostgresProvider.ts +7 -0
  286. package/src/orm/postgres/providers/PglitePostgresProvider.ts +10 -17
  287. package/src/orm/postgres/providers/PostgresProvider.ts +7 -36
  288. package/src/orm/postgres/schemas/postgresEnvSchema.ts +32 -0
  289. package/src/orm/postgres/services/PostgresModelBuilder.ts +40 -0
  290. package/src/react/core/components/ErrorBoundary.tsx +5 -2
  291. package/src/react/form/hooks/useFieldValue.ts +34 -0
  292. package/src/react/form/hooks/useForm.browser.spec.tsx +94 -9
  293. package/src/react/form/hooks/useForm.ts +14 -2
  294. package/src/react/form/hooks/useFormState.ts +10 -10
  295. package/src/react/form/hooks/useFormValues.ts +29 -0
  296. package/src/react/form/index.ts +3 -1
  297. package/src/react/form/services/FormModel.ts +53 -122
  298. package/src/react/router/components/ErrorViewer.tsx +333 -34
  299. package/src/react/router/components/NestedView.tsx +10 -3
  300. package/src/react/router/primitives/$page.browser.spec.tsx +34 -0
  301. package/src/react/router/primitives/$page.spec.tsx +20 -0
  302. package/src/react/router/primitives/$page.ts +24 -0
  303. package/src/react/router/providers/ReactBrowserRouterProvider.ts +14 -2
  304. package/src/react/router/providers/ReactPageProvider.ts +156 -73
  305. package/src/react/router/providers/ReactServerProvider.ts +40 -2
  306. package/src/react/router/providers/ReactServerTemplateProvider.ts +13 -1
  307. package/src/security/providers/SecurityProvider.ts +5 -27
  308. package/src/server/auth/primitives/$auth.ts +52 -19
  309. package/src/server/auth/providers/ServerAuthProvider.ts +145 -139
  310. package/src/server/cookies/providers/ServerCookiesProvider.ts +12 -24
  311. package/src/server/core/index.ts +3 -1
  312. package/src/server/core/primitives/$sse.spec.ts +315 -0
  313. package/src/server/core/primitives/$sse.ts +715 -0
  314. package/src/server/links/index.browser.ts +1 -3
  315. package/src/server/links/index.ts +0 -3
  316. package/src/server/links/providers/LinkProvider.spec.ts +12 -21
  317. package/src/server/links/providers/LinkProvider.ts +20 -52
  318. package/src/server/links/providers/ServerLinksProvider.spec.ts +106 -0
  319. package/src/server/links/providers/ServerLinksProvider.ts +113 -73
  320. package/src/server/links/schemas/apiLinksResponseSchema.ts +4 -21
  321. package/src/server/links/services/BatchCollector.ts +5 -3
  322. package/src/system/index.browser.ts +1 -0
  323. package/src/system/index.ts +3 -0
  324. package/src/system/index.workerd.ts +39 -1
  325. package/src/system/providers/WorkerdFileSystemProvider.ts +365 -0
  326. package/assets/devtools-ui/asset.BfSBZ5Dd.css.br +0 -0
  327. package/assets/devtools-ui/chunk.2NYaoqWt.js +0 -1
  328. package/assets/devtools-ui/chunk.2NYaoqWt.js.br +0 -0
  329. package/assets/devtools-ui/chunk.B052Z_xQ.js +0 -1
  330. package/assets/devtools-ui/chunk.B052Z_xQ.js.br +0 -0
  331. package/assets/devtools-ui/chunk.B4kVY90C.js +0 -1
  332. package/assets/devtools-ui/chunk.B4kVY90C.js.br +0 -0
  333. package/assets/devtools-ui/chunk.B7QJXctB.js +0 -1
  334. package/assets/devtools-ui/chunk.B7QJXctB.js.br +0 -0
  335. package/assets/devtools-ui/chunk.B9pX3zit.js.br +0 -0
  336. package/assets/devtools-ui/chunk.BKF9JxIo.js +0 -1
  337. package/assets/devtools-ui/chunk.BKF9JxIo.js.br +0 -0
  338. package/assets/devtools-ui/chunk.BOHgdTP-.js +0 -1
  339. package/assets/devtools-ui/chunk.BOHgdTP-.js.br +0 -0
  340. package/assets/devtools-ui/chunk.BOVFxkYC.js +0 -1
  341. package/assets/devtools-ui/chunk.BOVFxkYC.js.br +0 -0
  342. package/assets/devtools-ui/chunk.BR842zj5.js +0 -1
  343. package/assets/devtools-ui/chunk.BR842zj5.js.br +0 -0
  344. package/assets/devtools-ui/chunk.BT2IiBkZ.js.br +0 -0
  345. package/assets/devtools-ui/chunk.C79YouPp.js.br +0 -0
  346. package/assets/devtools-ui/chunk.C8mlBrjW.js +0 -9
  347. package/assets/devtools-ui/chunk.C8mlBrjW.js.br +0 -0
  348. package/assets/devtools-ui/chunk.CK0ow3AZ.js +0 -1
  349. package/assets/devtools-ui/chunk.CK0ow3AZ.js.br +0 -0
  350. package/assets/devtools-ui/chunk.CZl6J9DF.js.br +0 -0
  351. package/assets/devtools-ui/chunk.CdNr0YzS.js +0 -1
  352. package/assets/devtools-ui/chunk.CdNr0YzS.js.br +0 -0
  353. package/assets/devtools-ui/chunk.Ce6_6iIF.js +0 -1
  354. package/assets/devtools-ui/chunk.Ce6_6iIF.js.br +0 -0
  355. package/assets/devtools-ui/chunk.CpyDMr6O.js +0 -1
  356. package/assets/devtools-ui/chunk.CpyDMr6O.js.br +0 -0
  357. package/assets/devtools-ui/chunk.CyPmvPnY.js +0 -1
  358. package/assets/devtools-ui/chunk.CyPmvPnY.js.br +0 -0
  359. package/assets/devtools-ui/chunk.DTI_geWu.js +0 -1
  360. package/assets/devtools-ui/chunk.DTI_geWu.js.br +0 -0
  361. package/assets/devtools-ui/chunk.DbEH1oOB.js.br +0 -0
  362. package/assets/devtools-ui/chunk.Ddeqj5gv.js +0 -1
  363. package/assets/devtools-ui/chunk.Ddeqj5gv.js.br +0 -0
  364. package/assets/devtools-ui/chunk.DpRnB4vJ.js +0 -1
  365. package/assets/devtools-ui/chunk.DpRnB4vJ.js.br +0 -0
  366. package/assets/devtools-ui/chunk.DxPGTlsg.js +0 -1
  367. package/assets/devtools-ui/chunk.DxPGTlsg.js.br +0 -0
  368. package/assets/devtools-ui/chunk.G7_MMBJS.js +0 -1
  369. package/assets/devtools-ui/chunk.G7_MMBJS.js.br +0 -0
  370. package/assets/devtools-ui/chunk.M6wyKO_3.js.br +0 -0
  371. package/assets/devtools-ui/chunk.OUxNGmQ6.js +0 -1
  372. package/assets/devtools-ui/chunk.OUxNGmQ6.js.br +0 -0
  373. package/assets/devtools-ui/chunk.T1kle-fF.js +0 -1
  374. package/assets/devtools-ui/chunk.T1kle-fF.js.br +0 -0
  375. package/assets/devtools-ui/chunk.WjpsbQAv.js +0 -1
  376. package/assets/devtools-ui/chunk.WjpsbQAv.js.br +0 -0
  377. package/assets/devtools-ui/chunk.c6YgVx86.js +0 -1
  378. package/assets/devtools-ui/chunk.c6YgVx86.js.br +0 -0
  379. package/assets/devtools-ui/chunk.dwU3E_MU.js +0 -1
  380. package/assets/devtools-ui/chunk.dwU3E_MU.js.br +0 -0
  381. package/assets/devtools-ui/chunk.lJL-lgnW.js.br +0 -0
  382. package/assets/devtools-ui/chunk.lPWRmvA-.js +0 -7
  383. package/assets/devtools-ui/chunk.lPWRmvA-.js.br +0 -0
  384. package/assets/devtools-ui/chunk.p3HJvugM.js +0 -1
  385. package/assets/devtools-ui/chunk.p3HJvugM.js.br +0 -0
  386. package/assets/devtools-ui/chunk.r_Xoa_CI.js +0 -1
  387. package/assets/devtools-ui/chunk.r_Xoa_CI.js.br +0 -0
  388. package/assets/devtools-ui/chunk.sRNuTYXb.js +0 -1
  389. package/assets/devtools-ui/chunk.sRNuTYXb.js.br +0 -0
  390. package/assets/devtools-ui/chunk.tUjcyX5C.js +0 -1
  391. package/assets/devtools-ui/chunk.tUjcyX5C.js.br +0 -0
  392. package/assets/devtools-ui/chunk.thjBxvCA.js +0 -1
  393. package/assets/devtools-ui/chunk.thjBxvCA.js.br +0 -0
  394. package/assets/devtools-ui/entry.GYhBVRpC.js +0 -78
  395. package/assets/devtools-ui/entry.GYhBVRpC.js.br +0 -0
  396. package/src/server/links/services/DefinitionsPool.spec.ts +0 -86
  397. package/src/server/links/services/DefinitionsPool.ts +0 -43
@@ -0,0 +1,492 @@
1
+ import { type Alepha, AlephaError, t } from "alepha";
2
+ import { sql } from "drizzle-orm";
3
+ import { expect } from "vitest";
4
+ import { PG_GENERATED } from "../core/constants/PG_SYMBOLS.ts";
5
+ import { $entity, $repository, $view, db, pgAttr } from "../core/index.ts";
6
+
7
+ // ============================================================================
8
+ // Shared entity definitions
9
+ // ============================================================================
10
+
11
+ const orderEntity = $entity({
12
+ name: "orders",
13
+ schema: t.object({
14
+ id: db.primaryKey(),
15
+ category: t.text(),
16
+ amount: t.number(),
17
+ status: t.text(),
18
+ }),
19
+ });
20
+
21
+ // ============================================================================
22
+ // Feature 1: Partial Indexes
23
+ // ============================================================================
24
+
25
+ export const testPartialIndex = async (alepha: Alepha) => {
26
+ const entity = $entity({
27
+ name: "items_partial_idx",
28
+ schema: t.object({
29
+ id: db.primaryKey(),
30
+ email: t.text(),
31
+ active: t.boolean(),
32
+ }),
33
+ indexes: [
34
+ {
35
+ column: "email",
36
+ unique: true,
37
+ where: sql`active = true`,
38
+ },
39
+ ],
40
+ });
41
+
42
+ class App {
43
+ repo = $repository(entity);
44
+ }
45
+
46
+ const app = alepha.inject(App);
47
+ await alepha.start();
48
+
49
+ // Create an active item — unique constraint applies
50
+ const a = await app.repo.create({ email: "alice@test.com", active: true });
51
+ expect(a.email).toBe("alice@test.com");
52
+
53
+ // Deactivate it — no longer covered by partial index
54
+ await app.repo.updateById(a.id, { active: false });
55
+
56
+ // Insert same email as active — allowed because first one is inactive
57
+ const b = await app.repo.create({ email: "alice@test.com", active: true });
58
+ expect(b.email).toBe("alice@test.com");
59
+ expect(b.id).not.toBe(a.id);
60
+ };
61
+
62
+ export const testPartialCompositeIndex = async (alepha: Alepha) => {
63
+ const entity = $entity({
64
+ name: "items_partial_comp_idx",
65
+ schema: t.object({
66
+ id: db.primaryKey(),
67
+ category: t.text(),
68
+ name: t.text(),
69
+ active: t.boolean(),
70
+ }),
71
+ indexes: [
72
+ {
73
+ columns: ["category", "name"],
74
+ unique: true,
75
+ where: sql`active = true`,
76
+ },
77
+ ],
78
+ });
79
+
80
+ class App {
81
+ repo = $repository(entity);
82
+ }
83
+
84
+ const app = alepha.inject(App);
85
+ await alepha.start();
86
+
87
+ await app.repo.create({ category: "A", name: "foo", active: true });
88
+
89
+ // Same category+name but inactive — allowed by partial index
90
+ await app.repo.create({ category: "A", name: "foo", active: false });
91
+
92
+ const all = await app.repo.findMany();
93
+ expect(all).toHaveLength(2);
94
+ };
95
+
96
+ // ============================================================================
97
+ // Feature 2: Subqueries (exists / notExists)
98
+ // ============================================================================
99
+
100
+ export const testExistsSubquery = async (alepha: Alepha) => {
101
+ const parentEntity = $entity({
102
+ name: "parents_exist",
103
+ schema: t.object({
104
+ id: db.primaryKey(),
105
+ name: t.text(),
106
+ }),
107
+ });
108
+
109
+ const childEntity = $entity({
110
+ name: "children_exist",
111
+ schema: t.object({
112
+ id: db.primaryKey(),
113
+ parentId: t.integer(),
114
+ label: t.text(),
115
+ }),
116
+ });
117
+
118
+ class App {
119
+ parents = $repository(parentEntity);
120
+ children = $repository(childEntity);
121
+ }
122
+
123
+ const app = alepha.inject(App);
124
+ await alepha.start();
125
+
126
+ const p1 = await app.parents.create({ name: "P1" });
127
+ const p2 = await app.parents.create({ name: "P2" });
128
+ await app.children.create({ parentId: p1.id, label: "C1" });
129
+
130
+ // parents that have at least one child
131
+ const withChildren = await app.parents.findMany({
132
+ where: {
133
+ exists: sql`(SELECT 1 FROM children_exist WHERE children_exist.parent_id = parents_exist.id)`,
134
+ },
135
+ });
136
+ expect(withChildren).toHaveLength(1);
137
+ expect(withChildren[0].name).toBe("P1");
138
+
139
+ // parents that have NO children
140
+ const withoutChildren = await app.parents.findMany({
141
+ where: {
142
+ notExists: sql`(SELECT 1 FROM children_exist WHERE children_exist.parent_id = parents_exist.id)`,
143
+ },
144
+ });
145
+ expect(withoutChildren).toHaveLength(1);
146
+ expect(withoutChildren[0].name).toBe("P2");
147
+ };
148
+
149
+ // ============================================================================
150
+ // Feature 4: Aggregate Functions
151
+ // ============================================================================
152
+
153
+ export const testAggregateBasic = async (alepha: Alepha) => {
154
+ class App {
155
+ orders = $repository(orderEntity);
156
+ }
157
+
158
+ const app = alepha.inject(App);
159
+ await alepha.start();
160
+
161
+ await app.orders.createMany([
162
+ { category: "A", amount: 100, status: "paid" },
163
+ { category: "A", amount: 200, status: "paid" },
164
+ { category: "B", amount: 50, status: "paid" },
165
+ { category: "B", amount: 150, status: "pending" },
166
+ ]);
167
+
168
+ // Basic grouped aggregation
169
+ const result = await app.orders.aggregate({
170
+ select: { category: true, amount: { sum: true, avg: true } },
171
+ groupBy: ["category"],
172
+ orderBy: "category",
173
+ });
174
+
175
+ expect(result).toHaveLength(2);
176
+ expect(result[0].category).toBe("A");
177
+ expect(result[0].amount.sum).toBe(300);
178
+ expect(result[0].amount.avg).toBe(150);
179
+ expect(result[1].category).toBe("B");
180
+ expect(result[1].amount.sum).toBe(200);
181
+ };
182
+
183
+ export const testAggregateMinMaxCount = async (alepha: Alepha) => {
184
+ class App {
185
+ orders = $repository(orderEntity);
186
+ }
187
+
188
+ const app = alepha.inject(App);
189
+ await alepha.start();
190
+
191
+ await app.orders.createMany([
192
+ { category: "X", amount: 10, status: "paid" },
193
+ { category: "X", amount: 30, status: "paid" },
194
+ { category: "X", amount: 50, status: "paid" },
195
+ ]);
196
+
197
+ const result = await app.orders.aggregate({
198
+ select: {
199
+ category: true,
200
+ amount: { min: true, max: true, count: true },
201
+ },
202
+ groupBy: ["category"],
203
+ });
204
+
205
+ expect(result).toHaveLength(1);
206
+ expect(result[0].amount.min).toBe(10);
207
+ expect(result[0].amount.max).toBe(50);
208
+ expect(result[0].amount.count).toBe(3);
209
+ };
210
+
211
+ export const testAggregateHaving = async (alepha: Alepha) => {
212
+ class App {
213
+ orders = $repository(orderEntity);
214
+ }
215
+
216
+ const app = alepha.inject(App);
217
+ await alepha.start();
218
+
219
+ await app.orders.createMany([
220
+ { category: "A", amount: 10, status: "paid" },
221
+ { category: "A", amount: 20, status: "paid" },
222
+ { category: "B", amount: 500, status: "paid" },
223
+ { category: "B", amount: 600, status: "paid" },
224
+ ]);
225
+
226
+ // Only groups where sum > 100
227
+ const result = await app.orders.aggregate({
228
+ select: { category: true, amount: { sum: true } },
229
+ groupBy: ["category"],
230
+ having: { amount: { sum: { gt: 100 } } },
231
+ });
232
+
233
+ expect(result).toHaveLength(1);
234
+ expect(result[0].category).toBe("B");
235
+ expect(result[0].amount.sum).toBe(1100);
236
+ };
237
+
238
+ export const testAggregateOrderByDotNotation = async (alepha: Alepha) => {
239
+ class App {
240
+ orders = $repository(orderEntity);
241
+ }
242
+
243
+ const app = alepha.inject(App);
244
+ await alepha.start();
245
+
246
+ await app.orders.createMany([
247
+ { category: "A", amount: 500, status: "paid" },
248
+ { category: "B", amount: 100, status: "paid" },
249
+ { category: "C", amount: 300, status: "paid" },
250
+ ]);
251
+
252
+ const result = await app.orders.aggregate({
253
+ select: { category: true, amount: { sum: true } },
254
+ groupBy: ["category"],
255
+ orderBy: { column: "amount.sum", direction: "desc" },
256
+ });
257
+
258
+ expect(result).toHaveLength(3);
259
+ expect(result[0].category).toBe("A");
260
+ expect(result[1].category).toBe("C");
261
+ expect(result[2].category).toBe("B");
262
+ };
263
+
264
+ // ============================================================================
265
+ // Feature 6: Generated Columns (SQLite only — virtual)
266
+ // ============================================================================
267
+
268
+ export const testGeneratedColumnSqlite = async (alepha: Alepha) => {
269
+ const entity = $entity({
270
+ name: "generated_col",
271
+ schema: t.object({
272
+ id: db.primaryKey(),
273
+ firstName: t.text(),
274
+ lastName: t.text(),
275
+ fullName: pgAttr(t.text(), PG_GENERATED, {
276
+ expression: sql`first_name || ' ' || last_name`,
277
+ mode: "virtual",
278
+ }),
279
+ }),
280
+ });
281
+
282
+ class App {
283
+ repo = $repository(entity);
284
+ }
285
+
286
+ const app = alepha.inject(App);
287
+ await alepha.start();
288
+
289
+ // Insert without fullName — it's computed
290
+ const created = await app.repo.create({
291
+ firstName: "John",
292
+ lastName: "Doe",
293
+ } as any);
294
+
295
+ expect(created.fullName).toBe("John Doe");
296
+
297
+ // Verify findMany also returns the computed value
298
+ const all = await app.repo.findMany();
299
+ expect(all).toHaveLength(1);
300
+ expect(all[0].fullName).toBe("John Doe");
301
+ };
302
+
303
+ export const testGeneratedColumnPostgres = async (alepha: Alepha) => {
304
+ const entity = $entity({
305
+ name: "generated_col_pg",
306
+ schema: t.object({
307
+ id: db.primaryKey(),
308
+ firstName: t.text(),
309
+ lastName: t.text(),
310
+ fullName: pgAttr(t.text(), PG_GENERATED, {
311
+ expression: sql`first_name || ' ' || last_name`,
312
+ mode: "stored",
313
+ }),
314
+ }),
315
+ });
316
+
317
+ class App {
318
+ repo = $repository(entity);
319
+ }
320
+
321
+ const app = alepha.inject(App);
322
+ await alepha.start();
323
+
324
+ const created = await app.repo.create({
325
+ firstName: "Jane",
326
+ lastName: "Smith",
327
+ } as any);
328
+
329
+ expect(created.fullName).toBe("Jane Smith");
330
+
331
+ const all = await app.repo.findMany();
332
+ expect(all).toHaveLength(1);
333
+ expect(all[0].fullName).toBe("Jane Smith");
334
+ };
335
+
336
+ export const testGeneratedColumnExcludedFromInsertSchema = async (
337
+ alepha: Alepha,
338
+ ) => {
339
+ const entity = $entity({
340
+ name: "generated_schema_test",
341
+ schema: t.object({
342
+ id: db.primaryKey(),
343
+ a: t.text(),
344
+ b: t.text(),
345
+ computed: pgAttr(t.text(), PG_GENERATED, {
346
+ expression: sql`a || b`,
347
+ mode: "virtual",
348
+ }),
349
+ }),
350
+ });
351
+
352
+ // Verify insertSchema does not contain generated column
353
+ const insertProps = Object.keys(entity.insertSchema.properties);
354
+ expect(insertProps).toContain("a");
355
+ expect(insertProps).toContain("b");
356
+ expect(insertProps).not.toContain("computed");
357
+
358
+ // Verify updateSchema does not contain generated column
359
+ const updateProps = Object.keys(entity.updateSchema.properties);
360
+ expect(updateProps).toContain("a");
361
+ expect(updateProps).toContain("b");
362
+ expect(updateProps).not.toContain("computed");
363
+ };
364
+
365
+ // ============================================================================
366
+ // Feature 7: Query Caching
367
+ // ============================================================================
368
+
369
+ export const testQueryCache = async (alepha: Alepha) => {
370
+ class App {
371
+ orders = $repository(orderEntity);
372
+ }
373
+
374
+ const app = alepha.inject(App);
375
+ await alepha.start();
376
+
377
+ await app.orders.create({ category: "A", amount: 100, status: "paid" });
378
+
379
+ // First call — hits DB
380
+ const first = await app.orders.findMany(
381
+ { where: { category: { eq: "A" } } },
382
+ { cache: { ttl: 60_000 } },
383
+ );
384
+ expect(first).toHaveLength(1);
385
+
386
+ // Insert another — won't be in cache (cache was invalidated by write)
387
+ await app.orders.create({ category: "A", amount: 200, status: "paid" });
388
+
389
+ // This should hit DB again (cache was invalidated by the create above)
390
+ const afterInsert = await app.orders.findMany(
391
+ { where: { category: { eq: "A" } } },
392
+ { cache: { ttl: 60_000 } },
393
+ );
394
+ expect(afterInsert).toHaveLength(2);
395
+
396
+ // This should return cached result (no writes since last query)
397
+ const cached = await app.orders.findMany(
398
+ { where: { category: { eq: "A" } } },
399
+ { cache: { ttl: 60_000 } },
400
+ );
401
+ expect(cached).toHaveLength(2);
402
+ };
403
+
404
+ export const testQueryCacheCustomKey = async (alepha: Alepha) => {
405
+ class App {
406
+ orders = $repository(orderEntity);
407
+ }
408
+
409
+ const app = alepha.inject(App);
410
+ await alepha.start();
411
+
412
+ await app.orders.create({ category: "A", amount: 100, status: "paid" });
413
+
414
+ // Use custom cache key
415
+ const result = await app.orders.findMany(
416
+ {},
417
+ { cache: { ttl: 60_000, key: "all-orders" } },
418
+ );
419
+ expect(result).toHaveLength(1);
420
+
421
+ // Same custom key returns cached result
422
+ const cached = await app.orders.findMany(
423
+ {},
424
+ { cache: { ttl: 60_000, key: "all-orders" } },
425
+ );
426
+ expect(cached).toHaveLength(1);
427
+ };
428
+
429
+ // ============================================================================
430
+ // Feature 8: Database Views
431
+ // ============================================================================
432
+
433
+ export const testViewReadOnly = async (alepha: Alepha) => {
434
+ // Create the underlying table
435
+ const itemEntity = $entity({
436
+ name: "view_items",
437
+ schema: t.object({
438
+ id: db.primaryKey(),
439
+ name: t.text(),
440
+ price: t.number(),
441
+ }),
442
+ });
443
+
444
+ // Create a view
445
+ const itemView = $view({
446
+ name: "view_items_summary",
447
+ schema: t.object({
448
+ id: t.integer(),
449
+ name: t.text(),
450
+ price: t.number(),
451
+ }),
452
+ query: sql`SELECT id, name, price FROM view_items`,
453
+ });
454
+
455
+ class App {
456
+ items = $repository(itemEntity);
457
+ summary = $repository(itemView);
458
+ }
459
+
460
+ const app = alepha.inject(App);
461
+ await alepha.start();
462
+
463
+ // Verify the repository detects it's a view
464
+ expect(app.summary.isReadOnly).toBe(true);
465
+ expect(app.items.isReadOnly).toBe(false);
466
+
467
+ // Write operations should throw on views
468
+ await expect(
469
+ app.summary.create({ id: 1, name: "test", price: 10 } as any),
470
+ ).rejects.toThrow(AlephaError);
471
+ };
472
+
473
+ export const testViewRefreshThrowsForNonMaterialized = async (
474
+ alepha: Alepha,
475
+ ) => {
476
+ const view = $view({
477
+ name: "non_mat_view",
478
+ schema: t.object({
479
+ id: t.integer(),
480
+ }),
481
+ query: sql`SELECT 1 as id`,
482
+ });
483
+
484
+ class App {
485
+ repo = $repository(view);
486
+ }
487
+
488
+ const app = alepha.inject(App);
489
+ await alepha.start();
490
+
491
+ await expect(app.repo.refresh()).rejects.toThrow(AlephaError);
492
+ };
@@ -0,0 +1,140 @@
1
+ import { Alepha } from "alepha";
2
+ import { describe, it } from "vitest";
3
+ import { AlephaOrmPostgres } from "../postgres/index.ts";
4
+ import {
5
+ testAggregateBasic,
6
+ testAggregateHaving,
7
+ testAggregateMinMaxCount,
8
+ testAggregateOrderByDotNotation,
9
+ testExistsSubquery,
10
+ testGeneratedColumnExcludedFromInsertSchema,
11
+ testGeneratedColumnPostgres,
12
+ testGeneratedColumnSqlite,
13
+ testPartialCompositeIndex,
14
+ testPartialIndex,
15
+ testQueryCache,
16
+ testQueryCacheCustomKey,
17
+ testViewReadOnly,
18
+ testViewRefreshThrowsForNonMaterialized,
19
+ } from "./orm-next-tests.ts";
20
+
21
+ const sqlite = () =>
22
+ Alepha.create({ env: { DATABASE_URL: "sqlite://:memory:" } });
23
+ const postgres = () => Alepha.create().with(AlephaOrmPostgres);
24
+
25
+ // =============================================================================
26
+ // Feature 1: Partial Indexes
27
+ // =============================================================================
28
+
29
+ describe("partial indexes", () => {
30
+ it("should support partial unique index (sqlite)", async () => {
31
+ await testPartialIndex(sqlite());
32
+ });
33
+ it("should support partial unique index (postgres)", async () => {
34
+ await testPartialIndex(postgres());
35
+ });
36
+ it("should support partial composite index (sqlite)", async () => {
37
+ await testPartialCompositeIndex(sqlite());
38
+ });
39
+ it("should support partial composite index (postgres)", async () => {
40
+ await testPartialCompositeIndex(postgres());
41
+ });
42
+ });
43
+
44
+ // =============================================================================
45
+ // Feature 2: Subqueries (exists / notExists)
46
+ // =============================================================================
47
+
48
+ describe("subqueries", () => {
49
+ it("should support exists and notExists (sqlite)", async () => {
50
+ await testExistsSubquery(sqlite());
51
+ });
52
+ it("should support exists and notExists (postgres)", async () => {
53
+ await testExistsSubquery(postgres());
54
+ });
55
+ });
56
+
57
+ // =============================================================================
58
+ // Feature 4: Aggregate Functions
59
+ // =============================================================================
60
+
61
+ describe("aggregates", () => {
62
+ it("should compute sum and avg grouped by column (sqlite)", async () => {
63
+ await testAggregateBasic(sqlite());
64
+ });
65
+ it("should compute sum and avg grouped by column (postgres)", async () => {
66
+ await testAggregateBasic(postgres());
67
+ });
68
+ it("should compute min, max, and count (sqlite)", async () => {
69
+ await testAggregateMinMaxCount(sqlite());
70
+ });
71
+ it("should compute min, max, and count (postgres)", async () => {
72
+ await testAggregateMinMaxCount(postgres());
73
+ });
74
+ it("should filter groups with having clause (sqlite)", async () => {
75
+ await testAggregateHaving(sqlite());
76
+ });
77
+ it("should filter groups with having clause (postgres)", async () => {
78
+ await testAggregateHaving(postgres());
79
+ });
80
+ it("should order by aggregate with dot notation (sqlite)", async () => {
81
+ await testAggregateOrderByDotNotation(sqlite());
82
+ });
83
+ it("should order by aggregate with dot notation (postgres)", async () => {
84
+ await testAggregateOrderByDotNotation(postgres());
85
+ });
86
+ });
87
+
88
+ // =============================================================================
89
+ // Feature 6: Generated Columns
90
+ // =============================================================================
91
+
92
+ describe("generated columns", () => {
93
+ it("should compute virtual generated column (sqlite)", async () => {
94
+ await testGeneratedColumnSqlite(sqlite());
95
+ });
96
+ it("should compute stored generated column (postgres)", async () => {
97
+ await testGeneratedColumnPostgres(postgres());
98
+ });
99
+ it("should exclude generated columns from insert and update schemas", async () => {
100
+ await testGeneratedColumnExcludedFromInsertSchema(sqlite());
101
+ });
102
+ });
103
+
104
+ // =============================================================================
105
+ // Feature 7: Query Caching
106
+ // =============================================================================
107
+
108
+ describe("query caching", () => {
109
+ it("should cache and invalidate on write (sqlite)", async () => {
110
+ await testQueryCache(sqlite());
111
+ });
112
+ it("should cache and invalidate on write (postgres)", async () => {
113
+ await testQueryCache(postgres());
114
+ });
115
+ it("should support custom cache keys (sqlite)", async () => {
116
+ await testQueryCacheCustomKey(sqlite());
117
+ });
118
+ it("should support custom cache keys (postgres)", async () => {
119
+ await testQueryCacheCustomKey(postgres());
120
+ });
121
+ });
122
+
123
+ // =============================================================================
124
+ // Feature 8: Database Views
125
+ // =============================================================================
126
+
127
+ describe("database views", () => {
128
+ it("should block writes on view repositories (sqlite)", async () => {
129
+ await testViewReadOnly(sqlite());
130
+ });
131
+ it("should block writes on view repositories (postgres)", async () => {
132
+ await testViewReadOnly(postgres());
133
+ });
134
+ it("should throw on refresh for non-materialized view (sqlite)", async () => {
135
+ await testViewRefreshThrowsForNonMaterialized(sqlite());
136
+ });
137
+ it("should throw on refresh for non-materialized view (postgres)", async () => {
138
+ await testViewRefreshThrowsForNonMaterialized(postgres());
139
+ });
140
+ });
@@ -1,3 +1,4 @@
1
+ import type { SQL } from "drizzle-orm";
1
2
  import type {
2
3
  PgSequenceOptions,
3
4
  UpdateDeleteAction,
@@ -13,6 +14,7 @@ export const PG_VERSION = Symbol.for("Alepha.Postgres.Version");
13
14
  export const PG_IDENTITY = Symbol.for("Alepha.Postgres.Identity");
14
15
  export const PG_ENUM = Symbol.for("Alepha.Postgres.Enum");
15
16
  export const PG_REF = Symbol.for("Alepha.Postgres.Ref");
17
+ export const PG_GENERATED = Symbol.for("Alepha.Postgres.Generated");
16
18
 
17
19
  /**
18
20
  * @deprecated Use `PG_IDENTITY` instead.
@@ -33,6 +35,7 @@ export type PgSymbols = {
33
35
  [PG_IDENTITY]: PgIdentityOptions;
34
36
  [PG_REF]: PgRefOptions;
35
37
  [PG_ENUM]: PgEnumOptions;
38
+ [PG_GENERATED]: PgGeneratedOptions;
36
39
 
37
40
  /**
38
41
  * @deprecated Use `PG_IDENTITY` instead.
@@ -53,6 +56,20 @@ export interface PgEnumOptions {
53
56
  description?: string;
54
57
  }
55
58
 
59
+ export interface PgGeneratedOptions {
60
+ /**
61
+ * SQL expression for the generated column.
62
+ */
63
+ expression: SQL;
64
+
65
+ /**
66
+ * Storage mode for the generated column.
67
+ * - `"stored"` — value is computed on write and stored on disk (default for PostgreSQL).
68
+ * - `"virtual"` — value is computed on read (default for SQLite).
69
+ */
70
+ mode?: "stored" | "virtual";
71
+ }
72
+
56
73
  export interface PgRefOptions {
57
74
  ref: () => {
58
75
  name: string;
@@ -1,4 +1,4 @@
1
- import { $module, type Alepha, t } from "alepha";
1
+ import { $module, type Alepha } from "alepha";
2
2
  import { AlephaDateTime } from "alepha/datetime";
3
3
  import { $entity } from "./primitives/$entity.ts";
4
4
  import { $sequence } from "./primitives/$sequence.ts";
@@ -7,6 +7,7 @@ import { BunSqliteProvider } from "./providers/drivers/BunSqliteProvider.ts";
7
7
  import { CloudflareD1Provider } from "./providers/drivers/CloudflareD1Provider.ts";
8
8
  import { DatabaseProvider } from "./providers/drivers/DatabaseProvider.ts";
9
9
  import { RepositoryProvider } from "./providers/RepositoryProvider.ts";
10
+ import { databaseEnvSchema } from "./schemas/databaseEnvSchema.ts";
10
11
  import { PgRelationManager } from "./services/PgRelationManager.ts";
11
12
  import { QueryManager } from "./services/QueryManager.ts";
12
13
  import { Repository } from "./services/Repository.ts";
@@ -33,11 +34,7 @@ export const AlephaOrm = $module({
33
34
  QueryManager,
34
35
  ],
35
36
  register: (alepha: Alepha) => {
36
- const env = alepha.parseEnv(
37
- t.object({
38
- DATABASE_URL: t.optional(t.text()),
39
- }),
40
- );
37
+ const env = alepha.parseEnv(databaseEnvSchema);
41
38
 
42
39
  alepha.with(DrizzleKitProvider);
43
40
  alepha.with(RepositoryProvider);