alepha 0.13.6 → 0.13.8
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.
- package/README.md +5 -2
- package/assets/swagger-ui/swagger-ui-bundle.js +1 -1
- package/assets/swagger-ui/swagger-ui-standalone-preset.js +1 -1
- package/assets/swagger-ui/swagger-ui.css +1 -1
- package/dist/api/audits/index.browser.js +116 -0
- package/dist/api/audits/index.browser.js.map +1 -0
- package/dist/api/audits/index.d.ts +1194 -0
- package/dist/api/audits/index.js +674 -0
- package/dist/api/audits/index.js.map +1 -0
- package/dist/{api-files → api/files}/index.browser.js +5 -5
- package/dist/api/files/index.browser.js.map +1 -0
- package/dist/{api-files → api/files}/index.d.ts +16 -9
- package/dist/{api-files → api/files}/index.js +10 -10
- package/dist/api/files/index.js.map +1 -0
- package/dist/{api-jobs → api/jobs}/index.browser.js +5 -5
- package/dist/api/jobs/index.browser.js.map +1 -0
- package/dist/{api-jobs → api/jobs}/index.d.ts +35 -35
- package/dist/{api-jobs → api/jobs}/index.js +9 -9
- package/dist/api/jobs/index.js.map +1 -0
- package/dist/{api-notifications → api/notifications}/index.browser.js +11 -11
- package/dist/api/notifications/index.browser.js.map +1 -0
- package/dist/api/notifications/index.d.ts +327 -0
- package/dist/{api-notifications → api/notifications}/index.js +11 -11
- package/dist/api/notifications/index.js.map +1 -0
- package/dist/api/parameters/index.browser.js +60 -0
- package/dist/api/parameters/index.browser.js.map +1 -0
- package/dist/api/parameters/index.d.ts +761 -0
- package/dist/api/parameters/index.js +877 -0
- package/dist/api/parameters/index.js.map +1 -0
- package/dist/{api-users → api/users}/index.browser.js +6 -6
- package/dist/api/users/index.browser.js.map +1 -0
- package/dist/{api-users → api/users}/index.d.ts +259 -247
- package/dist/{api-users → api/users}/index.js +125 -112
- package/dist/api/users/index.js.map +1 -0
- package/dist/{api-verifications → api/verifications}/index.browser.js +5 -5
- package/dist/api/verifications/index.browser.js.map +1 -0
- package/dist/api/verifications/index.d.ts +248 -0
- package/dist/{api-verifications → api/verifications}/index.js +13 -12
- package/dist/api/verifications/index.js.map +1 -0
- package/dist/bin/index.js +1 -0
- package/dist/bin/index.js.map +1 -1
- package/dist/cache/{index.d.ts → core/index.d.ts} +4 -4
- package/dist/cache/{index.js → core/index.js} +5 -5
- package/dist/cache/core/index.js.map +1 -0
- package/dist/{cache-redis → cache/redis}/index.d.ts +2 -2
- package/dist/{cache-redis → cache/redis}/index.js +2 -2
- package/dist/cache/redis/index.js.map +1 -0
- package/dist/cli/index.d.ts +71 -9
- package/dist/cli/index.js +280 -79
- package/dist/cli/index.js.map +1 -1
- package/dist/command/index.d.ts +63 -2
- package/dist/command/index.js +30 -3
- package/dist/command/index.js.map +1 -1
- package/dist/core/index.browser.js +241 -61
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +170 -90
- package/dist/core/index.js +264 -67
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js +248 -65
- package/dist/core/index.native.js.map +1 -1
- package/dist/email/index.js +15 -10554
- package/dist/email/index.js.map +1 -1
- package/dist/lock/{index.d.ts → core/index.d.ts} +5 -5
- package/dist/lock/{index.js → core/index.js} +5 -5
- package/dist/lock/core/index.js.map +1 -0
- package/dist/{lock-redis → lock/redis}/index.d.ts +2 -2
- package/dist/{lock-redis → lock/redis}/index.js +2 -2
- package/dist/lock/redis/index.js.map +1 -0
- package/dist/logger/index.d.ts +4 -4
- package/dist/logger/index.js +77 -72
- package/dist/logger/index.js.map +1 -1
- package/dist/orm/index.d.ts +5 -1
- package/dist/orm/index.js +24 -7
- package/dist/orm/index.js.map +1 -1
- package/dist/queue/core/index.d.ts +548 -0
- package/dist/queue/core/index.js +391 -0
- package/dist/queue/core/index.js.map +1 -0
- package/dist/queue/redis/index.d.ts +28 -0
- package/dist/queue/redis/index.js +43 -0
- package/dist/queue/redis/index.js.map +1 -0
- package/dist/scheduler/index.d.ts +7 -7
- package/dist/scheduler/index.js +1 -393
- package/dist/scheduler/index.js.map +1 -1
- package/dist/security/index.d.ts +1 -1
- package/dist/security/index.js +2 -1413
- package/dist/security/index.js.map +1 -1
- package/dist/{server-auth → server/auth}/index.browser.js +6 -6
- package/dist/server/auth/index.browser.js.map +1 -0
- package/dist/{server-auth → server/auth}/index.d.ts +175 -164
- package/dist/server/auth/index.js +742 -0
- package/dist/server/auth/index.js.map +1 -0
- package/dist/{server-cache → server/cache}/index.d.ts +2 -2
- package/dist/{server-cache → server/cache}/index.js +2 -2
- package/dist/server/cache/index.js.map +1 -0
- package/dist/{server-compress → server/compress}/index.d.ts +2 -2
- package/dist/{server-compress → server/compress}/index.js +2 -2
- package/dist/server/compress/index.js.map +1 -0
- package/dist/{server-cookies → server/cookies}/index.browser.js +3 -3
- package/dist/server/cookies/index.browser.js.map +1 -0
- package/dist/{server-cookies → server/cookies}/index.d.ts +4 -4
- package/dist/{server-cookies → server/cookies}/index.js +9 -5
- package/dist/server/cookies/index.js.map +1 -0
- package/dist/server/{index.browser.js → core/index.browser.js} +14 -14
- package/dist/server/core/index.browser.js.map +1 -0
- package/dist/server/{index.d.ts → core/index.d.ts} +46 -37
- package/dist/server/{index.js → core/index.js} +47 -33
- package/dist/server/core/index.js.map +1 -0
- package/dist/{server-cors → server/cors}/index.d.ts +3 -3
- package/dist/{server-cors → server/cors}/index.js +3 -3
- package/dist/server/cors/index.js.map +1 -0
- package/dist/{server-health → server/health}/index.d.ts +3 -3
- package/dist/{server-health → server/health}/index.js +3 -3
- package/dist/server/health/index.js.map +1 -0
- package/dist/{server-helmet → server/helmet}/index.d.ts +2 -2
- package/dist/{server-helmet → server/helmet}/index.js +2 -2
- package/dist/server/helmet/index.js.map +1 -0
- package/dist/{server-links → server/links}/index.browser.js +5 -5
- package/dist/server/links/index.browser.js.map +1 -0
- package/dist/{server-links → server/links}/index.d.ts +40 -40
- package/dist/{server-links → server/links}/index.js +7 -7
- package/dist/server/links/index.js.map +1 -0
- package/dist/{server-metrics → server/metrics}/index.d.ts +2 -2
- package/dist/server/metrics/index.js +74 -0
- package/dist/server/metrics/index.js.map +1 -0
- package/dist/{server-multipart → server/multipart}/index.d.ts +2 -2
- package/dist/{server-multipart → server/multipart}/index.js +2 -2
- package/dist/server/multipart/index.js.map +1 -0
- package/dist/{server-proxy → server/proxy}/index.d.ts +3 -3
- package/dist/{server-proxy → server/proxy}/index.js +3 -3
- package/dist/server/proxy/index.js.map +1 -0
- package/dist/{server-rate-limit → server/rate-limit}/index.d.ts +4 -4
- package/dist/{server-rate-limit → server/rate-limit}/index.js +4 -4
- package/dist/server/rate-limit/index.js.map +1 -0
- package/dist/{server-security → server/security}/index.browser.js +1 -1
- package/dist/server/security/index.browser.js.map +1 -0
- package/dist/{server-security → server/security}/index.d.ts +4 -4
- package/dist/{server-security → server/security}/index.js +4 -4
- package/dist/server/security/index.js.map +1 -0
- package/dist/{server-static → server/static}/index.d.ts +3 -3
- package/dist/{server-static → server/static}/index.js +3 -3
- package/dist/server/static/index.js.map +1 -0
- package/dist/{server-swagger → server/swagger}/index.d.ts +3 -3
- package/dist/{server-swagger → server/swagger}/index.js +4 -4
- package/dist/server/swagger/index.js.map +1 -0
- package/dist/thread/index.js +2 -2
- package/dist/thread/index.js.map +1 -1
- package/dist/topic/{index.d.ts → core/index.d.ts} +6 -6
- package/dist/topic/{index.js → core/index.js} +6 -6
- package/dist/topic/core/index.js.map +1 -0
- package/dist/{topic-redis → topic/redis}/index.d.ts +2 -2
- package/dist/{topic-redis → topic/redis}/index.js +2 -2
- package/dist/topic/redis/index.js.map +1 -0
- package/dist/vite/index.d.ts +13 -2
- package/dist/vite/index.js +114 -50
- package/dist/vite/index.js.map +1 -1
- package/dist/websocket/index.browser.js +3 -3
- package/dist/websocket/index.browser.js.map +1 -1
- package/dist/websocket/index.js +4 -4
- package/dist/websocket/index.js.map +1 -1
- package/package.json +160 -156
- package/src/api/audits/controllers/AuditController.ts +186 -0
- package/src/api/audits/entities/audits.ts +132 -0
- package/src/api/audits/index.browser.ts +18 -0
- package/src/api/audits/index.ts +58 -0
- package/src/api/audits/primitives/$audit.ts +159 -0
- package/src/api/audits/schemas/auditQuerySchema.ts +23 -0
- package/src/api/audits/schemas/auditResourceSchema.ts +9 -0
- package/src/api/audits/schemas/createAuditSchema.ts +27 -0
- package/src/api/audits/services/AuditService.ts +412 -0
- package/src/{api-files → api/files}/index.ts +1 -0
- package/src/api/parameters/controllers/ConfigController.ts +324 -0
- package/src/api/parameters/entities/parameters.ts +113 -0
- package/src/api/parameters/index.ts +60 -0
- package/src/api/parameters/primitives/$config.ts +351 -0
- package/src/api/parameters/schedulers/ConfigActivationScheduler.ts +30 -0
- package/src/api/parameters/services/ConfigStore.ts +491 -0
- package/src/{api-users → api/users}/atoms/realmAuthSettingsAtom.ts +19 -0
- package/src/{api-users → api/users}/controllers/UserRealmController.ts +0 -2
- package/src/{api-users → api/users}/index.ts +2 -0
- package/src/{api-users → api/users}/primitives/$userRealm.ts +18 -3
- package/src/{api-users → api/users}/providers/UserRealmProvider.ts +12 -10
- package/src/{api-users → api/users}/services/RegistrationService.ts +2 -1
- package/src/{api-users → api/users}/services/SessionService.ts +4 -0
- package/src/{api-users → api/users}/services/UserService.ts +3 -0
- package/src/{api-verifications → api/verifications}/index.ts +9 -1
- package/src/bin/index.ts +1 -0
- package/src/cli/apps/AlephaPackageBuilderCli.ts +73 -48
- package/src/cli/assets/appRouterTs.ts +1 -1
- package/src/cli/assets/biomeJson.ts +2 -2
- package/src/cli/assets/dummySpecTs.ts +7 -0
- package/src/cli/assets/editorconfig.ts +13 -0
- package/src/cli/assets/indexHtml.ts +1 -1
- package/src/cli/assets/mainBrowserTs.ts +1 -1
- package/src/cli/assets/mainTs.ts +14 -0
- package/src/cli/assets/viteConfigTs.ts +1 -1
- package/src/cli/commands/BiomeCommands.ts +2 -0
- package/src/cli/commands/CoreCommands.ts +38 -15
- package/src/cli/commands/VerifyCommands.ts +6 -2
- package/src/cli/commands/ViteCommands.ts +28 -18
- package/src/cli/services/AlephaCliUtils.ts +243 -37
- package/src/command/helpers/Asker.ts +0 -1
- package/src/command/primitives/$command.ts +67 -0
- package/src/command/providers/CliProvider.ts +39 -8
- package/src/core/Alepha.ts +40 -30
- package/src/core/helpers/jsonSchemaToTypeBox.ts +307 -0
- package/src/core/index.shared.ts +1 -0
- package/src/core/index.ts +30 -3
- package/src/core/providers/EventManager.ts +1 -1
- package/src/core/providers/SchemaValidator.ts +1 -1
- package/src/core/providers/StateManager.ts +23 -12
- package/src/core/providers/TypeProvider.ts +26 -34
- package/src/logger/index.ts +8 -6
- package/src/logger/primitives/$logger.ts +1 -1
- package/src/logger/providers/{SimpleFormatterProvider.ts → PrettyFormatterProvider.ts} +10 -1
- package/src/orm/index.ts +6 -0
- package/src/orm/services/PgRelationManager.ts +2 -2
- package/src/orm/services/PostgresModelBuilder.ts +11 -7
- package/src/orm/services/Repository.ts +16 -7
- package/src/orm/services/SqliteModelBuilder.ts +10 -0
- package/src/queue/{index.ts → core/index.ts} +2 -3
- package/src/queue/{primitives → core/primitives}/$queue.ts +17 -162
- package/src/queue/core/providers/MemoryQueueProvider.ts +19 -0
- package/src/queue/core/providers/QueueProvider.ts +23 -0
- package/src/queue/core/providers/WorkerProvider.ts +244 -0
- package/src/queue/redis/providers/RedisQueueProvider.ts +31 -0
- package/src/{server-auth → server/auth}/primitives/$auth.ts +7 -0
- package/src/{server-auth → server/auth}/providers/ServerAuthProvider.ts +51 -8
- package/src/{server-cookies → server/cookies}/index.ts +2 -1
- package/src/server/{index.ts → core/index.ts} +7 -0
- package/src/server/{primitives → core/primitives}/$action.ts +10 -1
- package/src/server/{providers → core/providers}/ServerBodyParserProvider.ts +11 -5
- package/src/server/{providers → core/providers}/ServerRouterProvider.ts +13 -7
- package/src/{server-rate-limit → server/rate-limit}/index.ts +1 -1
- package/src/{server-swagger → server/swagger}/providers/ServerSwaggerProvider.ts +1 -0
- package/src/thread/primitives/$thread.ts +2 -2
- package/src/vite/index.ts +0 -2
- package/src/vite/tasks/buildServer.ts +3 -4
- package/src/vite/tasks/copyAssets.ts +32 -8
- package/src/vite/tasks/generateCloudflare.ts +35 -19
- package/src/vite/tasks/generateDocker.ts +18 -4
- package/src/vite/tasks/generateSitemap.ts +5 -7
- package/src/vite/tasks/generateVercel.ts +76 -41
- package/src/vite/tasks/runAlepha.ts +16 -1
- package/src/websocket/providers/NodeWebSocketServerProvider.ts +3 -11
- package/src/websocket/services/WebSocketClient.ts +3 -3
- package/dist/api-files/index.browser.js.map +0 -1
- package/dist/api-files/index.js.map +0 -1
- package/dist/api-jobs/index.browser.js.map +0 -1
- package/dist/api-jobs/index.js.map +0 -1
- package/dist/api-notifications/index.browser.js.map +0 -1
- package/dist/api-notifications/index.d.ts +0 -327
- package/dist/api-notifications/index.js.map +0 -1
- package/dist/api-parameters/index.browser.js +0 -29
- package/dist/api-parameters/index.browser.js.map +0 -1
- package/dist/api-parameters/index.d.ts +0 -83
- package/dist/api-parameters/index.js +0 -63
- package/dist/api-parameters/index.js.map +0 -1
- package/dist/api-users/index.browser.js.map +0 -1
- package/dist/api-users/index.js.map +0 -1
- package/dist/api-verifications/index.browser.js.map +0 -1
- package/dist/api-verifications/index.d.ts +0 -229
- package/dist/api-verifications/index.js.map +0 -1
- package/dist/cache/index.js.map +0 -1
- package/dist/cache-redis/index.js.map +0 -1
- package/dist/cli/dist-BlfFtOk2.js +0 -2770
- package/dist/cli/dist-BlfFtOk2.js.map +0 -1
- package/dist/lock/index.js.map +0 -1
- package/dist/lock-redis/index.js.map +0 -1
- package/dist/queue/index.d.ts +0 -1265
- package/dist/queue/index.js +0 -1037
- package/dist/queue/index.js.map +0 -1
- package/dist/queue-redis/index.d.ts +0 -82
- package/dist/queue-redis/index.js +0 -872
- package/dist/queue-redis/index.js.map +0 -1
- package/dist/server/index.browser.js.map +0 -1
- package/dist/server/index.js.map +0 -1
- package/dist/server-auth/index.browser.js.map +0 -1
- package/dist/server-auth/index.js +0 -1943
- package/dist/server-auth/index.js.map +0 -1
- package/dist/server-cache/index.js.map +0 -1
- package/dist/server-compress/index.js.map +0 -1
- package/dist/server-cookies/index.browser.js.map +0 -1
- package/dist/server-cookies/index.js.map +0 -1
- package/dist/server-cors/index.js.map +0 -1
- package/dist/server-health/index.js.map +0 -1
- package/dist/server-helmet/index.js.map +0 -1
- package/dist/server-links/index.browser.js.map +0 -1
- package/dist/server-links/index.js.map +0 -1
- package/dist/server-metrics/index.js +0 -4532
- package/dist/server-metrics/index.js.map +0 -1
- package/dist/server-multipart/index.js.map +0 -1
- package/dist/server-proxy/index.js.map +0 -1
- package/dist/server-rate-limit/index.js.map +0 -1
- package/dist/server-security/index.browser.js.map +0 -1
- package/dist/server-security/index.js.map +0 -1
- package/dist/server-static/index.js.map +0 -1
- package/dist/server-swagger/index.js.map +0 -1
- package/dist/topic/index.js.map +0 -1
- package/dist/topic-redis/index.js.map +0 -1
- package/src/api-parameters/controllers/ParameterController.ts +0 -45
- package/src/api-parameters/entities/parameters.ts +0 -30
- package/src/api-parameters/index.ts +0 -21
- package/src/api-parameters/primitives/$config.ts +0 -79
- package/src/api-parameters/services/ParameterStore.ts +0 -23
- package/src/queue/interfaces/QueueJob.ts +0 -459
- package/src/queue/providers/MemoryQueueProvider.ts +0 -850
- package/src/queue/providers/QueueProvider.ts +0 -319
- package/src/queue/providers/WorkerProvider.ts +0 -344
- package/src/queue-redis/providers/RedisQueueProvider.ts +0 -1209
- /package/src/{api-files → api/files}/controllers/FileController.ts +0 -0
- /package/src/{api-files → api/files}/controllers/StorageStatsController.ts +0 -0
- /package/src/{api-files → api/files}/entities/files.ts +0 -0
- /package/src/{api-files → api/files}/index.browser.ts +0 -0
- /package/src/{api-files → api/files}/jobs/FileJobs.ts +0 -0
- /package/src/{api-files → api/files}/schemas/fileQuerySchema.ts +0 -0
- /package/src/{api-files → api/files}/schemas/fileResourceSchema.ts +0 -0
- /package/src/{api-files → api/files}/schemas/storageStatsSchema.ts +0 -0
- /package/src/{api-files → api/files}/services/FileService.ts +0 -0
- /package/src/{api-jobs → api/jobs}/controllers/JobController.ts +0 -0
- /package/src/{api-jobs → api/jobs}/entities/jobExecutions.ts +0 -0
- /package/src/{api-jobs → api/jobs}/index.browser.ts +0 -0
- /package/src/{api-jobs → api/jobs}/index.ts +0 -0
- /package/src/{api-jobs → api/jobs}/primitives/$job.ts +0 -0
- /package/src/{api-jobs → api/jobs}/providers/JobProvider.ts +0 -0
- /package/src/{api-jobs → api/jobs}/schemas/jobExecutionQuerySchema.ts +0 -0
- /package/src/{api-jobs → api/jobs}/schemas/jobExecutionResourceSchema.ts +0 -0
- /package/src/{api-jobs → api/jobs}/schemas/triggerJobSchema.ts +0 -0
- /package/src/{api-jobs → api/jobs}/services/JobService.ts +0 -0
- /package/src/{api-notifications → api/notifications}/controllers/NotificationController.ts +0 -0
- /package/src/{api-notifications → api/notifications}/entities/notifications.ts +0 -0
- /package/src/{api-notifications → api/notifications}/index.browser.ts +0 -0
- /package/src/{api-notifications → api/notifications}/index.ts +0 -0
- /package/src/{api-notifications → api/notifications}/jobs/NotificationJobs.ts +0 -0
- /package/src/{api-notifications → api/notifications}/primitives/$notification.ts +0 -0
- /package/src/{api-notifications → api/notifications}/queues/NotificationQueues.ts +0 -0
- /package/src/{api-notifications → api/notifications}/schemas/notificationContactPreferencesSchema.ts +0 -0
- /package/src/{api-notifications → api/notifications}/schemas/notificationContactSchema.ts +0 -0
- /package/src/{api-notifications → api/notifications}/schemas/notificationCreateSchema.ts +0 -0
- /package/src/{api-notifications → api/notifications}/schemas/notificationQuerySchema.ts +0 -0
- /package/src/{api-notifications → api/notifications}/services/NotificationSenderService.ts +0 -0
- /package/src/{api-notifications → api/notifications}/services/NotificationService.ts +0 -0
- /package/src/{api-parameters → api/parameters}/index.browser.ts +0 -0
- /package/src/{api-users → api/users}/controllers/IdentityController.ts +0 -0
- /package/src/{api-users → api/users}/controllers/SessionController.ts +0 -0
- /package/src/{api-users → api/users}/controllers/UserController.ts +0 -0
- /package/src/{api-users → api/users}/entities/identities.ts +0 -0
- /package/src/{api-users → api/users}/entities/sessions.ts +0 -0
- /package/src/{api-users → api/users}/entities/users.ts +0 -0
- /package/src/{api-users → api/users}/index.browser.ts +0 -0
- /package/src/{api-users → api/users}/notifications/UserNotifications.ts +0 -0
- /package/src/{api-users → api/users}/schemas/completePasswordResetRequestSchema.ts +0 -0
- /package/src/{api-users → api/users}/schemas/completeRegistrationRequestSchema.ts +0 -0
- /package/src/{api-users → api/users}/schemas/createUserSchema.ts +0 -0
- /package/src/{api-users → api/users}/schemas/identityQuerySchema.ts +0 -0
- /package/src/{api-users → api/users}/schemas/identityResourceSchema.ts +0 -0
- /package/src/{api-users → api/users}/schemas/loginSchema.ts +0 -0
- /package/src/{api-users → api/users}/schemas/passwordResetIntentResponseSchema.ts +0 -0
- /package/src/{api-users → api/users}/schemas/registerQuerySchema.ts +0 -0
- /package/src/{api-users → api/users}/schemas/registerRequestSchema.ts +0 -0
- /package/src/{api-users → api/users}/schemas/registerResponseSchema.ts +0 -0
- /package/src/{api-users → api/users}/schemas/registerSchema.ts +0 -0
- /package/src/{api-users → api/users}/schemas/registrationIntentResponseSchema.ts +0 -0
- /package/src/{api-users → api/users}/schemas/resetPasswordSchema.ts +0 -0
- /package/src/{api-users → api/users}/schemas/sessionQuerySchema.ts +0 -0
- /package/src/{api-users → api/users}/schemas/sessionResourceSchema.ts +0 -0
- /package/src/{api-users → api/users}/schemas/updateUserSchema.ts +0 -0
- /package/src/{api-users → api/users}/schemas/userQuerySchema.ts +0 -0
- /package/src/{api-users → api/users}/schemas/userRealmConfigSchema.ts +0 -0
- /package/src/{api-users → api/users}/schemas/userResourceSchema.ts +0 -0
- /package/src/{api-users → api/users}/services/CredentialService.ts +0 -0
- /package/src/{api-users → api/users}/services/IdentityService.ts +0 -0
- /package/src/{api-users → api/users}/services/SessionCrudService.ts +0 -0
- /package/src/{api-verifications → api/verifications}/controllers/VerificationController.ts +0 -0
- /package/src/{api-verifications → api/verifications}/entities/verifications.ts +0 -0
- /package/src/{api-verifications → api/verifications}/index.browser.ts +0 -0
- /package/src/{api-verifications → api/verifications}/jobs/VerificationJobs.ts +0 -0
- /package/src/{api-verifications → api/verifications}/parameters/VerificationParameters.ts +0 -0
- /package/src/{api-verifications → api/verifications}/schemas/requestVerificationCodeResponseSchema.ts +0 -0
- /package/src/{api-verifications → api/verifications}/schemas/validateVerificationCodeResponseSchema.ts +0 -0
- /package/src/{api-verifications → api/verifications}/schemas/verificationSettingsSchema.ts +0 -0
- /package/src/{api-verifications → api/verifications}/schemas/verificationTypeEnumSchema.ts +0 -0
- /package/src/{api-verifications → api/verifications}/services/VerificationService.ts +0 -0
- /package/src/cache/{errors → core/errors}/CacheError.ts +0 -0
- /package/src/cache/{index.ts → core/index.ts} +0 -0
- /package/src/cache/{primitives → core/primitives}/$cache.ts +0 -0
- /package/src/cache/{providers → core/providers}/CacheProvider.ts +0 -0
- /package/src/cache/{providers → core/providers}/MemoryCacheProvider.ts +0 -0
- /package/src/{cache-redis → cache/redis}/index.ts +0 -0
- /package/src/{cache-redis → cache/redis}/providers/RedisCacheProvider.ts +0 -0
- /package/src/lock/{index.ts → core/index.ts} +0 -0
- /package/src/lock/{primitives → core/primitives}/$lock.ts +0 -0
- /package/src/lock/{providers → core/providers}/LockProvider.ts +0 -0
- /package/src/lock/{providers → core/providers}/LockTopicProvider.ts +0 -0
- /package/src/lock/{providers → core/providers}/MemoryLockProvider.ts +0 -0
- /package/src/{lock-redis → lock/redis}/index.ts +0 -0
- /package/src/{lock-redis → lock/redis}/providers/RedisLockProvider.ts +0 -0
- /package/src/queue/{primitives → core/primitives}/$consumer.ts +0 -0
- /package/src/{queue-redis → queue/redis}/index.ts +0 -0
- /package/src/{server-auth → server/auth}/constants/routes.ts +0 -0
- /package/src/{server-auth → server/auth}/index.browser.ts +0 -0
- /package/src/{server-auth → server/auth}/index.shared.ts +0 -0
- /package/src/{server-auth → server/auth}/index.ts +0 -0
- /package/src/{server-auth → server/auth}/primitives/$authApple.ts +0 -0
- /package/src/{server-auth → server/auth}/primitives/$authCredentials.ts +0 -0
- /package/src/{server-auth → server/auth}/primitives/$authGithub.ts +0 -0
- /package/src/{server-auth → server/auth}/primitives/$authGoogle.ts +0 -0
- /package/src/{server-auth → server/auth}/schemas/authenticationProviderSchema.ts +0 -0
- /package/src/{server-auth → server/auth}/schemas/tokenResponseSchema.ts +0 -0
- /package/src/{server-auth → server/auth}/schemas/tokensSchema.ts +0 -0
- /package/src/{server-auth → server/auth}/schemas/userinfoResponseSchema.ts +0 -0
- /package/src/{server-cache → server/cache}/index.ts +0 -0
- /package/src/{server-cache → server/cache}/providers/ServerCacheProvider.ts +0 -0
- /package/src/{server-compress → server/compress}/index.ts +0 -0
- /package/src/{server-compress → server/compress}/providers/ServerCompressProvider.ts +0 -0
- /package/src/{server-cookies → server/cookies}/index.browser.ts +0 -0
- /package/src/{server-cookies → server/cookies}/primitives/$cookie.browser.ts +0 -0
- /package/src/{server-cookies → server/cookies}/primitives/$cookie.ts +0 -0
- /package/src/{server-cookies → server/cookies}/providers/ServerCookiesProvider.ts +0 -0
- /package/src/{server-cookies → server/cookies}/services/CookieParser.ts +0 -0
- /package/src/server/{constants → core/constants}/routeMethods.ts +0 -0
- /package/src/server/{errors → core/errors}/BadRequestError.ts +0 -0
- /package/src/server/{errors → core/errors}/ConflictError.ts +0 -0
- /package/src/server/{errors → core/errors}/ForbiddenError.ts +0 -0
- /package/src/server/{errors → core/errors}/HttpError.ts +0 -0
- /package/src/server/{errors → core/errors}/NotFoundError.ts +0 -0
- /package/src/server/{errors → core/errors}/UnauthorizedError.ts +0 -0
- /package/src/server/{errors → core/errors}/ValidationError.ts +0 -0
- /package/src/server/{helpers → core/helpers}/ServerReply.ts +0 -0
- /package/src/server/{helpers → core/helpers}/isMultipart.ts +0 -0
- /package/src/server/{index.browser.ts → core/index.browser.ts} +0 -0
- /package/src/server/{index.shared.ts → core/index.shared.ts} +0 -0
- /package/src/server/{interfaces → core/interfaces}/ServerRequest.ts +0 -0
- /package/src/server/{primitives → core/primitives}/$route.ts +0 -0
- /package/src/server/{providers → core/providers}/BunHttpServerProvider.ts +0 -0
- /package/src/server/{providers → core/providers}/NodeHttpServerProvider.ts +0 -0
- /package/src/server/{providers → core/providers}/ServerLoggerProvider.ts +0 -0
- /package/src/server/{providers → core/providers}/ServerNotReadyProvider.ts +0 -0
- /package/src/server/{providers → core/providers}/ServerProvider.ts +0 -0
- /package/src/server/{providers → core/providers}/ServerTimingProvider.ts +0 -0
- /package/src/server/{schemas → core/schemas}/errorSchema.ts +0 -0
- /package/src/server/{schemas → core/schemas}/okSchema.ts +0 -0
- /package/src/server/{services → core/services}/HttpClient.ts +0 -0
- /package/src/server/{services → core/services}/ServerRequestParser.ts +0 -0
- /package/src/server/{services → core/services}/UserAgentParser.ts +0 -0
- /package/src/{server-cors → server/cors}/index.ts +0 -0
- /package/src/{server-cors → server/cors}/primitives/$cors.ts +0 -0
- /package/src/{server-cors → server/cors}/providers/ServerCorsProvider.ts +0 -0
- /package/src/{server-health → server/health}/index.ts +0 -0
- /package/src/{server-health → server/health}/providers/ServerHealthProvider.ts +0 -0
- /package/src/{server-health → server/health}/schemas/healthSchema.ts +0 -0
- /package/src/{server-helmet → server/helmet}/index.ts +0 -0
- /package/src/{server-helmet → server/helmet}/providers/ServerHelmetProvider.ts +0 -0
- /package/src/{server-links → server/links}/index.browser.ts +0 -0
- /package/src/{server-links → server/links}/index.ts +0 -0
- /package/src/{server-links → server/links}/primitives/$client.ts +0 -0
- /package/src/{server-links → server/links}/primitives/$remote.ts +0 -0
- /package/src/{server-links → server/links}/providers/LinkProvider.ts +0 -0
- /package/src/{server-links → server/links}/providers/RemotePrimitiveProvider.ts +0 -0
- /package/src/{server-links → server/links}/providers/ServerLinksProvider.ts +0 -0
- /package/src/{server-links → server/links}/schemas/apiLinksResponseSchema.ts +0 -0
- /package/src/{server-metrics → server/metrics}/index.ts +0 -0
- /package/src/{server-metrics → server/metrics}/providers/ServerMetricsProvider.ts +0 -0
- /package/src/{server-multipart → server/multipart}/index.ts +0 -0
- /package/src/{server-multipart → server/multipart}/providers/ServerMultipartProvider.ts +0 -0
- /package/src/{server-proxy → server/proxy}/index.ts +0 -0
- /package/src/{server-proxy → server/proxy}/primitives/$proxy.ts +0 -0
- /package/src/{server-proxy → server/proxy}/providers/ServerProxyProvider.ts +0 -0
- /package/src/{server-rate-limit → server/rate-limit}/primitives/$rateLimit.ts +0 -0
- /package/src/{server-rate-limit → server/rate-limit}/providers/ServerRateLimitProvider.ts +0 -0
- /package/src/{server-security → server/security}/index.browser.ts +0 -0
- /package/src/{server-security → server/security}/index.ts +0 -0
- /package/src/{server-security → server/security}/primitives/$basicAuth.ts +0 -0
- /package/src/{server-security → server/security}/providers/ServerBasicAuthProvider.ts +0 -0
- /package/src/{server-security → server/security}/providers/ServerSecurityProvider.ts +0 -0
- /package/src/{server-static → server/static}/index.ts +0 -0
- /package/src/{server-static → server/static}/primitives/$serve.ts +0 -0
- /package/src/{server-static → server/static}/providers/ServerStaticProvider.ts +0 -0
- /package/src/{server-swagger → server/swagger}/index.ts +0 -0
- /package/src/{server-swagger → server/swagger}/primitives/$swagger.ts +0 -0
- /package/src/topic/{errors → core/errors}/TopicTimeoutError.ts +0 -0
- /package/src/topic/{index.ts → core/index.ts} +0 -0
- /package/src/topic/{primitives → core/primitives}/$subscriber.ts +0 -0
- /package/src/topic/{primitives → core/primitives}/$topic.ts +0 -0
- /package/src/topic/{providers → core/providers}/MemoryTopicProvider.ts +0 -0
- /package/src/topic/{providers → core/providers}/TopicProvider.ts +0 -0
- /package/src/{topic-redis → topic/redis}/index.ts +0 -0
- /package/src/{topic-redis → topic/redis}/providers/RedisTopicProvider.ts +0 -0
package/dist/orm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["newProperties: Record<string, any>","newProperties: Record<string, any>","schema","alias","cols: Partial<EntityColumns<T>>","fields: Array<PgAttrField>","schema","schema","isSQLWrapper","schema","jsonValue: SQL","conditions: SQL[]","sql","results: Array<{ path: string[]; operator: FilterOperators<any> }>","schema","currentSchema: any","conditions: SQL[]","sql","operations: SQL[]","schema","schema","entity: any","fields: Record<string, any>","joins: Array<PgJoin>","schema: TObject","tasks: Promise<any>[]","sortMetadata:\n | Array<{ column: string; direction: \"asc\" | \"desc\" }>\n | undefined","where: any","cleanRow: Record<string, unknown>","joinedData: Record<string, unknown>","sql","prev","curr","models: Record<string, unknown>","sql","configs: TConfig[]","schema","pg","envSchema","sql","drizzle","schema","pg","envSchema","sql","drizzle","migrate","drizzle","migrate","path: string[]","values: any[]","filterOp: any","result: any","parts","parts: string[]","pageSchema"],"sources":["../../src/orm/constants/PG_SYMBOLS.ts","../../src/orm/types/schema.ts","../../src/orm/schemas/insertSchema.ts","../../src/orm/schemas/updateSchema.ts","../../src/orm/primitives/$entity.ts","../../src/orm/errors/DbError.ts","../../src/orm/errors/DbConflictError.ts","../../src/orm/errors/DbEntityNotFoundError.ts","../../src/orm/errors/DbVersionMismatchError.ts","../../src/orm/helpers/pgAttr.ts","../../src/orm/providers/drivers/DatabaseProvider.ts","../../src/orm/services/PgRelationManager.ts","../../src/orm/services/PgJsonQueryManager.ts","../../src/orm/services/QueryManager.ts","../../src/orm/services/Repository.ts","../../src/orm/providers/RepositoryProvider.ts","../../src/orm/primitives/$repository.ts","../../src/orm/primitives/$sequence.ts","../../src/orm/providers/DrizzleKitProvider.ts","../../src/orm/errors/DbMigrationError.ts","../../src/orm/types/byte.ts","../../src/orm/services/ModelBuilder.ts","../../src/orm/services/PostgresModelBuilder.ts","../../src/orm/providers/drivers/NodePostgresProvider.ts","../../src/orm/services/SqliteModelBuilder.ts","../../src/orm/providers/drivers/NodeSqliteProvider.ts","../../src/orm/providers/drivers/PglitePostgresProvider.ts","../../src/orm/helpers/parseQueryString.ts","../../src/orm/primitives/$transaction.ts","../../src/orm/providers/PostgresTypeProvider.ts","../../src/orm/schemas/legacyIdSchema.ts","../../src/orm/index.ts"],"sourcesContent":["import type {\n PgSequenceOptions,\n UpdateDeleteAction,\n} from \"drizzle-orm/pg-core\";\nimport type { EntityPrimitive } from \"../primitives/$entity.ts\";\n\nexport const PG_DEFAULT = Symbol.for(\"Alepha.Postgres.Default\");\nexport const PG_PRIMARY_KEY = Symbol.for(\"Alepha.Postgres.PrimaryKey\");\nexport const PG_CREATED_AT = Symbol.for(\"Alepha.Postgres.CreatedAt\");\nexport const PG_UPDATED_AT = Symbol.for(\"Alepha.Postgres.UpdatedAt\");\nexport const PG_DELETED_AT = Symbol.for(\"Alepha.Postgres.DeletedAt\");\nexport const PG_VERSION = Symbol.for(\"Alepha.Postgres.Version\");\nexport const PG_IDENTITY = Symbol.for(\"Alepha.Postgres.Identity\");\nexport const PG_ENUM = Symbol.for(\"Alepha.Postgres.Enum\");\nexport const PG_REF = Symbol.for(\"Alepha.Postgres.Ref\");\n\n/**\n * @deprecated Use `PG_IDENTITY` instead.\n */\nexport const PG_SERIAL = Symbol.for(\"Alepha.Postgres.Serial\");\n\nexport type PgDefault = typeof PG_DEFAULT;\nexport type PgRef = typeof PG_REF;\nexport type PgPrimaryKey = typeof PG_PRIMARY_KEY;\n\nexport type PgSymbols = {\n [PG_DEFAULT]: {};\n [PG_PRIMARY_KEY]: {};\n [PG_CREATED_AT]: {};\n [PG_UPDATED_AT]: {};\n [PG_DELETED_AT]: {};\n [PG_VERSION]: {};\n [PG_IDENTITY]: PgIdentityOptions;\n [PG_REF]: PgRefOptions;\n [PG_ENUM]: PgEnumOptions;\n\n /**\n * @deprecated Use `PG_IDENTITY` instead.\n */\n [PG_SERIAL]: {};\n};\n\nexport type PgSymbolKeys = keyof PgSymbols;\n\nexport type PgIdentityOptions = {\n mode: \"always\" | \"byDefault\";\n} & PgSequenceOptions & {\n name?: string;\n };\n\nexport interface PgEnumOptions {\n name?: string;\n description?: string;\n}\n\nexport interface PgRefOptions {\n ref: () => {\n name: string;\n entity: EntityPrimitive;\n };\n actions?: {\n onUpdate?: UpdateDeleteAction;\n onDelete?: UpdateDeleteAction;\n };\n}\n","import type { Static, TSchema } from \"alepha\";\nimport { customType } from \"drizzle-orm/pg-core\";\n\n/**\n * Postgres schema type.\n */\nexport const schema = <TDocument extends TSchema>(\n name: string,\n document: TDocument,\n) =>\n customType<{\n data: Static<TDocument>;\n driverData: string;\n config: { document: TDocument };\n configRequired: true;\n }>({\n dataType: () => \"jsonb\",\n toDriver: (value) => JSON.stringify(value),\n fromDriver: (value: TDocument | string) =>\n value && typeof value === \"string\" ? JSON.parse(value) : value,\n })(name, { document }).$type<Static<TDocument>>();\n","import type { TObject, TOptional } from \"alepha\";\nimport { t } from \"alepha\";\nimport { PG_DEFAULT } from \"../constants/PG_SYMBOLS.ts\";\nimport { schema } from \"../types/schema.ts\";\n\n/**\n * Transforms a TObject schema for insert operations.\n * All default properties at the root level are made optional.\n *\n * @example\n * Before: { name: string; age: number(default=0); }\n * After: { name: string; age?: number; }\n */\nexport type TObjectInsert<T extends TObject> = TObject<{\n [K in keyof T[\"properties\"]]: T[\"properties\"][K] extends\n | { [PG_DEFAULT]: any }\n | { \"~optional\": true }\n ? TOptional<T[\"properties\"][K]>\n : T[\"properties\"][K];\n}>;\n\nexport const insertSchema = <T extends TObject>(obj: T): TObjectInsert<T> => {\n const newProperties: Record<string, any> = {};\n\n for (const key in obj.properties) {\n const prop = obj.properties[key];\n\n if (PG_DEFAULT in prop) {\n newProperties[key] = t.optional(prop);\n } else {\n newProperties[key] = prop;\n }\n }\n\n return t.object(\n newProperties,\n \"options\" in schema && typeof schema.options === \"object\"\n ? { ...schema.options }\n : {},\n ) as TObjectInsert<T>;\n};\n","import {\n type TNull,\n type TObject,\n type TOptional,\n type TUnion,\n t,\n} from \"alepha\";\n\n/**\n * Transforms a TObject schema for update operations.\n * All optional properties at the root level are made nullable (i.e., `T | null`).\n * This allows an API endpoint to explicitly accept `null` to clear an optional field in the database.\n *\n * @example\n * Before: { name?: string; age: number; }\n * After: { name?: string | null; age: number; }\n */\nexport type TObjectUpdate<T extends TObject> = TObject<{\n [K in keyof T[\"properties\"]]: T[\"properties\"][K] extends TOptional<infer U>\n ? TOptional<TUnion<[U, TNull]>>\n : T[\"properties\"][K];\n}>;\n\nexport const updateSchema = <T extends TObject>(\n schema: T,\n): TObjectUpdate<T> => {\n const newProperties: Record<string, any> = {};\n\n for (const key in schema.properties) {\n const prop = schema.properties[key];\n if (t.schema.isOptional(prop)) {\n newProperties[key] = t.optional(t.union([prop, t.raw.Null()]));\n } else {\n newProperties[key] = prop;\n }\n }\n\n return t.object(\n newProperties,\n \"options\" in schema && typeof schema.options === \"object\"\n ? { ...schema.options }\n : {},\n ) as TObjectUpdate<T>;\n};\n","import { KIND, type Static, type TObject } from \"alepha\";\nimport type { BuildExtraConfigColumns, SQL } from \"drizzle-orm\";\nimport type {\n PgColumn,\n PgColumnBuilderBase,\n PgTableExtraConfigValue,\n} from \"drizzle-orm/pg-core\";\nimport { insertSchema, type TObjectInsert } from \"../schemas/insertSchema.ts\";\nimport { type TObjectUpdate, updateSchema } from \"../schemas/updateSchema.ts\";\n\n/**\n * Creates a database entity primitive that defines table structure using TypeBox schemas.\n *\n * @example\n * ```ts\n * import { t } from \"alepha\";\n * import { $entity } from \"alepha/orm\";\n *\n * const userEntity = $entity({\n * name: \"users\",\n * schema: t.object({\n * id: pg.primaryKey(),\n * name: t.text(),\n * email: t.email(),\n * }),\n * });\n * ```\n */\nexport const $entity = <TSchema extends TObject>(\n options: EntityPrimitiveOptions<TSchema>,\n): EntityPrimitive<TSchema> => {\n return new EntityPrimitive<TSchema>(options);\n};\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface EntityPrimitiveOptions<\n T extends TObject,\n Keys = keyof Static<T>,\n> {\n /**\n * The database table name that will be created for this entity.\n * If not provided, name will be inferred from the $repository variable name.\n */\n name: string;\n\n /**\n * TypeBox schema defining the table structure and column types.\n */\n schema: T;\n\n /**\n * Database indexes to create for query optimization.\n */\n indexes?: (\n | Keys\n | {\n /**\n * Single column to index.\n */\n column: Keys;\n /**\n * Whether this should be a unique index (enforces uniqueness constraint).\n */\n unique?: boolean;\n /**\n * Custom name for the index. If not provided, generates name automatically.\n */\n name?: string;\n }\n | {\n /**\n * Multiple columns for composite index (order matters for query optimization).\n */\n columns: Keys[];\n /**\n * Whether this should be a unique index (enforces uniqueness constraint).\n */\n unique?: boolean;\n /**\n * Custom name for the index. If not provided, generates name automatically.\n */\n name?: string;\n }\n )[];\n\n /**\n * Foreign key constraints to maintain referential integrity.\n */\n foreignKeys?: Array<{\n /**\n * Optional name for the foreign key constraint.\n */\n name?: string;\n /**\n * Local columns that reference the foreign table.\n */\n columns: Array<keyof Static<T>>;\n /**\n * Referenced columns in the foreign table.\n * Must be EntityColumn references from other entities.\n */\n foreignColumns: Array<() => EntityColumn<any>>;\n }>;\n\n /**\n * Additional table constraints for data validation.\n *\n * Constraints enforce business rules at the database level, providing\n * an additional layer of data integrity beyond application validation.\n *\n * **Constraint Types**:\n * - **Unique constraints**: Prevent duplicate values across columns\n * - **Check constraints**: Enforce custom validation rules with SQL expressions\n *\n * @example\n * ```ts\n * constraints: [\n * {\n * name: \"unique_user_email\",\n * columns: [\"email\"],\n * unique: true\n * },\n * {\n * name: \"valid_age_range\",\n * columns: [\"age\"],\n * check: sql`age >= 0 AND age <= 150`\n * },\n * {\n * name: \"unique_user_username_per_tenant\",\n * columns: [\"tenantId\", \"username\"],\n * unique: true\n * }\n * ]\n * ```\n */\n constraints?: Array<{\n /**\n * Columns involved in this constraint.\n */\n columns: Array<keyof Static<T>>;\n /**\n * Optional name for the constraint.\n */\n name?: string;\n /**\n * Whether this is a unique constraint.\n */\n unique?: boolean | {} /* options */;\n /**\n * SQL expression for check constraint validation.\n */\n check?: SQL;\n }>;\n\n /**\n * Advanced Drizzle ORM configuration for complex table setups.\n */\n config?: (\n self: BuildExtraConfigColumns<string, FromSchema<T>, \"pg\">,\n ) => PgTableExtraConfigValue[];\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport class EntityPrimitive<T extends TObject = TObject> {\n public readonly options: EntityPrimitiveOptions<T>;\n\n constructor(options: EntityPrimitiveOptions<T>) {\n this.options = options;\n }\n\n alias(alias: string): this {\n const aliased = new EntityPrimitive<T>(this.options);\n return new Proxy(aliased, {\n get(target, prop, receiver) {\n if (prop === \"$alias\") {\n return alias;\n }\n return Reflect.get(target, prop, receiver);\n },\n }) as this;\n }\n\n get cols(): EntityColumns<T> {\n const cols: Partial<EntityColumns<T>> = {};\n for (const key of Object.keys(this.schema.properties) as Array<\n keyof T[\"properties\"]\n >) {\n cols[key] = {\n name: key as string,\n entity: this,\n };\n }\n\n return cols as EntityColumns<T>;\n }\n\n get name(): string {\n return this.options.name;\n }\n\n get schema(): T {\n return this.options.schema;\n }\n\n get insertSchema(): TObjectInsert<T> {\n return insertSchema(this.options.schema);\n }\n\n get updateSchema(): TObjectUpdate<T> {\n return updateSchema(this.options.schema);\n }\n}\n\n$entity[KIND] = EntityPrimitive;\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Convert a schema to columns.\n */\nexport type FromSchema<T extends TObject> = {\n [key in keyof T[\"properties\"]]: PgColumnBuilderBase;\n};\n\nexport type SchemaToTableConfig<T extends TObject> = {\n name: string;\n schema: string | undefined;\n columns: {\n [key in keyof T[\"properties\"]]: PgColumn;\n };\n dialect: string;\n};\n\nexport type EntityColumn<T extends TObject> = {\n name: string;\n entity: EntityPrimitive<T>;\n};\n\nexport type EntityColumns<T extends TObject> = {\n [key in keyof T[\"properties\"]]: EntityColumn<T>;\n};\n","import { AlephaError } from \"alepha\";\n\nexport class DbError extends AlephaError {\n name = \"DbError\";\n\n constructor(message: string, cause?: unknown) {\n super(message, { cause });\n }\n}\n","import { DbError } from \"./DbError.ts\";\n\nexport class DbConflictError extends DbError {\n readonly name = \"DbConflictError\";\n readonly status = 409;\n}\n","import { DbError } from \"./DbError.ts\";\n\nexport class DbEntityNotFoundError extends DbError {\n readonly name = \"DbEntityNotFoundError\";\n readonly status = 404;\n\n constructor(entityName: string) {\n super(`Entity from '${entityName}' was not found`);\n }\n}\n","import { DbError } from \"./DbError.ts\";\n\n/**\n * Error thrown when there is a version mismatch.\n * It's thrown by {@link Repository#save} when the updated entity version does not match the one in the database.\n * This is used for optimistic concurrency control.\n */\nexport class DbVersionMismatchError extends DbError {\n readonly name = \"DbVersionMismatchError\";\n\n constructor(table: string, id: any) {\n super(`Version mismatch for table '${table}' and id '${id}'`);\n }\n}\n","import type { TObject, TSchema } from \"alepha\";\nimport type { PgSymbolKeys, PgSymbols } from \"../constants/PG_SYMBOLS.ts\";\n\n/**\n * Decorates a typebox schema with a Postgres attribute.\n *\n * > It's just a fancy way to add Symbols to a field.\n *\n * @example\n * ```ts\n * import { t } from \"alepha\";\n * import { PG_UPDATED_AT } from \"../constants/PG_SYMBOLS\";\n *\n * export const updatedAtSchema = pgAttr(\n * t.datetime(), PG_UPDATED_AT,\n * );\n * ```\n */\nexport const pgAttr = <T extends TSchema, Attr extends PgSymbolKeys>(\n type: T,\n attr: Attr,\n value?: PgSymbols[Attr],\n): PgAttr<T, Attr> => {\n Object.assign(type, { [attr]: value ?? {} });\n return type as PgAttr<T, Attr>;\n};\n\n/**\n * Retrieves the fields of a schema that have a specific attribute.\n */\nexport const getAttrFields = (\n schema: TObject,\n name: PgSymbolKeys,\n): PgAttrField[] => {\n const fields: Array<PgAttrField> = [];\n\n for (const key of Object.keys(schema.properties)) {\n const value = schema.properties[key];\n if (name in value) {\n fields.push({\n type: value as TSchema,\n key: key,\n data: (value as any)[name],\n });\n }\n }\n\n return fields;\n};\n\n/**\n * Type representation.\n */\nexport type PgAttr<T extends TSchema, TAttr extends PgSymbolKeys> = T & {\n [K in TAttr]: PgSymbols[K];\n};\n\nexport interface PgAttrField {\n key: string;\n type: TSchema;\n data: any;\n nested?: any[];\n one?: boolean;\n}\n","import { stat } from \"node:fs/promises\";\nimport {\n $inject,\n Alepha,\n AlephaError,\n type Static,\n type TObject,\n} from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport type { SQLWrapper } from \"drizzle-orm\";\nimport {\n alias,\n type PgDatabase,\n type PgTableWithColumns,\n} from \"drizzle-orm/pg-core\";\nimport { DbError } from \"../../errors/DbError.ts\";\nimport type {\n EntityPrimitive,\n SchemaToTableConfig,\n} from \"../../primitives/$entity.ts\";\nimport type { SequencePrimitive } from \"../../primitives/$sequence.ts\";\nimport type { ModelBuilder } from \"../../services/ModelBuilder.ts\";\nimport type { DrizzleKitProvider } from \"../DrizzleKitProvider.ts\";\n\nexport type SQLLike = SQLWrapper | string;\n\nexport abstract class DatabaseProvider {\n protected readonly alepha = $inject(Alepha);\n protected readonly log = $logger();\n protected abstract readonly builder: ModelBuilder;\n protected abstract readonly kit: DrizzleKitProvider;\n public abstract readonly db: PgDatabase<any>;\n public abstract readonly dialect: \"postgresql\" | \"sqlite\";\n public abstract readonly url: string;\n\n public readonly enums = new Map<string, unknown>();\n public readonly tables = new Map<string, unknown>();\n public readonly sequences = new Map<string, unknown>();\n\n public get name() {\n return \"default\";\n }\n\n public get schema() {\n return \"public\";\n }\n\n public table<T extends TObject>(\n entity: EntityPrimitive<T>,\n ): PgTableWithColumns<SchemaToTableConfig<T>> {\n const table = this.tables.get(entity.name);\n if (!table) {\n throw new AlephaError(`Table '${entity.name}' is not registered`);\n }\n\n const hasAlias = (entity as any).$alias;\n\n if (hasAlias) {\n return alias(\n table as PgTableWithColumns<SchemaToTableConfig<T>>,\n hasAlias,\n ) as PgTableWithColumns<SchemaToTableConfig<T>>;\n }\n\n return table as PgTableWithColumns<SchemaToTableConfig<T>>;\n }\n\n public registerEntity(entity: EntityPrimitive) {\n this.builder.buildTable(entity, this);\n }\n\n public registerSequence(sequence: SequencePrimitive) {\n this.builder.buildSequence(sequence, this);\n }\n\n public abstract execute(\n statement: SQLLike,\n ): Promise<Record<string, unknown>[]>;\n\n public async run<T extends TObject>(\n statement: SQLLike,\n schema: T,\n ): Promise<Array<Static<T>>> {\n const result = await this.execute(statement);\n return result.map((row) => this.alepha.codec.decode(schema, row));\n }\n\n /**\n * Get migrations folder path - can be overridden\n */\n protected getMigrationsFolder(): string {\n return `migrations/${this.name}`;\n }\n\n /**\n * Base migration orchestration - handles environment logic\n */\n protected async migrateDatabase(): Promise<void> {\n const migrationsFolder = this.getMigrationsFolder();\n\n // Handle different environments\n if (this.alepha.isProduction()) {\n await this.runProductionMigration(migrationsFolder);\n } else if (this.alepha.isTest()) {\n await this.runTestMigration();\n } else {\n await this.runDevelopmentMigration(migrationsFolder);\n }\n }\n\n /**\n * Production: run migrations from folder\n */\n protected async runProductionMigration(\n migrationsFolder: string,\n ): Promise<void> {\n // Check folder exists\n const exists = await stat(migrationsFolder).catch(() => false);\n\n if (!exists) {\n this.log.warn(\"Migration SKIPPED - no migrations found\");\n return;\n }\n\n this.log.debug(`Migrate from '${migrationsFolder}' directory ...`);\n\n // Delegate to provider-specific implementation\n await this.executeMigrations(migrationsFolder);\n\n this.log.info(\"Migration OK\");\n }\n\n /**\n * Test: always synchronize\n */\n protected async runTestMigration(): Promise<void> {\n await this.synchronizeSchema();\n }\n\n /**\n * Development: default to synchronize (can be overridden)\n */\n protected async runDevelopmentMigration(\n migrationsFolder: string,\n ): Promise<void> {\n // try migrations silently first\n try {\n // exclude in-memory databases (there is nothing to migrate!)\n if (!this.url.includes(\":memory:\")) {\n await this.executeMigrations(migrationsFolder);\n }\n } catch {\n // Ignore errors\n }\n\n // then synchronize\n await this.synchronizeSchema();\n }\n\n /**\n * Common synchronization with error handling\n */\n protected async synchronizeSchema(): Promise<void> {\n try {\n await this.kit.synchronize(this);\n } catch (error) {\n throw new DbError(\n `Failed to synchronize ${this.dialect} database schema`,\n error as Error,\n );\n }\n }\n\n /**\n * Provider-specific migration execution\n * MUST be implemented by each provider\n */\n protected abstract executeMigrations(migrationsFolder: string): Promise<void>;\n}\n","import { type TObject, TypeBoxValue, t } from \"alepha\";\nimport { getTableName, type SQL, sql } from \"drizzle-orm\";\nimport type { PgSelectBase, PgTableWithColumns } from \"drizzle-orm/pg-core\";\nimport { isSQLWrapper } from \"drizzle-orm/sql/sql\";\nimport type { PgRelationMap } from \"../interfaces/PgQuery.ts\";\nimport type { EntityPrimitive } from \"../primitives/$entity.ts\";\nimport type { DatabaseProvider } from \"../providers/drivers/DatabaseProvider.ts\";\nimport type { PgJoin } from \"./QueryManager.ts\";\n\nexport class PgRelationManager {\n /**\n * Recursively build joins for the query builder based on the relations map\n */\n public buildJoins(\n provider: DatabaseProvider,\n builder: PgSelectBase<any, any, any>,\n joins: Array<PgJoin>,\n withRelations: PgRelationMap<TObject>,\n table: PgTableWithColumns<any>,\n parentKey?: string,\n ) {\n for (const [key, join] of Object.entries(withRelations)) {\n const from = provider.table(join.join as EntityPrimitive);\n const on = isSQLWrapper(join.on)\n ? (join.on as SQL)\n : sql`${table[join.on[0] as string]} = ${from[join.on[1].name]}`;\n\n if (join.type === \"right\") {\n builder.rightJoin(from, on);\n } else if (join.type === \"inner\") {\n builder.innerJoin(from, on);\n } else {\n builder.leftJoin(from, on);\n }\n\n joins.push({\n key,\n table: getTableName(from),\n schema: join.join.schema,\n col: (name: string) => from[name],\n parent: parentKey,\n });\n\n if (join.with) {\n this.buildJoins(\n provider,\n builder,\n joins,\n join.with,\n from,\n parentKey ? `${parentKey}.${key}` : key,\n );\n }\n }\n }\n\n /**\n * Map a row with its joined relations based on the joins definition\n */\n public mapRowWithJoins(\n record: Record<string, unknown>,\n row: Record<string, unknown>,\n schema: TObject,\n joins: PgJoin[],\n parentKey?: string,\n ) {\n for (const join of joins) {\n if (join.parent === parentKey) {\n const joinedData = row[join.table];\n // Set to undefined if all values in the joined table are null (left join with no match)\n if (this.isAllNull(joinedData)) {\n record[join.key] = undefined;\n } else {\n record[join.key] = joinedData;\n // Only process nested joins if the parent join has data\n this.mapRowWithJoins(\n record[join.key] as Record<string, unknown>,\n row,\n schema, // Don't need to pass modified schema, just for recursion\n joins,\n parentKey ? `${parentKey}.${join.key}` : join.key,\n );\n }\n }\n }\n return record;\n }\n\n /**\n * Check if all values in an object are null (indicates a left join with no match)\n */\n private isAllNull(obj: unknown): boolean {\n if (obj === null || obj === undefined) return true;\n if (typeof obj !== \"object\") return false;\n return Object.values(obj).every((val) => val === null);\n }\n\n /**\n * Build a schema that includes all join properties recursively\n */\n public buildSchemaWithJoins(\n baseSchema: TObject,\n joins: PgJoin[],\n parentPath?: string,\n ): TObject {\n const schema = TypeBoxValue.Clone(baseSchema) as TObject;\n\n // Group joins by parent\n const joinsAtThisLevel = joins.filter((j) => j.parent === parentPath);\n\n for (const join of joinsAtThisLevel) {\n // Build the path for this join\n const joinPath = parentPath ? `${parentPath}.${join.key}` : join.key;\n\n // Find child joins\n const childJoins = joins.filter((j) => j.parent === joinPath);\n\n // If there are child joins, recursively build the schema\n let joinSchema = join.schema;\n if (childJoins.length > 0) {\n joinSchema = this.buildSchemaWithJoins(join.schema, joins, joinPath);\n }\n\n // Make the join optional (left joins may return null)\n schema.properties[join.key] = t.optional(joinSchema);\n }\n\n return schema;\n }\n}\n","import type { TObject } from \"alepha\";\nimport { type SQL, sql } from \"drizzle-orm\";\nimport type { PgColumn } from \"drizzle-orm/pg-core\";\nimport type { FilterOperators } from \"../interfaces/FilterOperators.ts\";\nimport type { PgQueryWhere } from \"../interfaces/PgQueryWhere.ts\";\n\n/**\n * Manages JSONB query generation for nested object and array queries in PostgreSQL.\n * This class handles complex nested queries using PostgreSQL's JSONB operators.\n */\nexport class PgJsonQueryManager {\n /**\n * Check if a query contains nested JSONB queries.\n * A nested query is when the value is an object with operator keys.\n */\n public hasNestedQuery(where: PgQueryWhere<TObject>): boolean {\n for (const [key, value] of Object.entries(where)) {\n // Skip logical operators\n if (key === \"and\" || key === \"or\" || key === \"not\") {\n continue;\n }\n\n // Check if value is an object with nested properties\n if (value && typeof value === \"object\" && !Array.isArray(value)) {\n // Check if it has operator keys or nested object keys\n const keys = Object.keys(value);\n const hasOperators = keys.some((k) =>\n [\n \"eq\",\n \"ne\",\n \"gt\",\n \"gte\",\n \"lt\",\n \"lte\",\n \"like\",\n \"ilike\",\n \"isNull\",\n \"isNotNull\",\n \"inArray\",\n \"notInArray\",\n ].includes(k),\n );\n\n // If it doesn't have operators, it might be a nested query\n if (!hasOperators && keys.length > 0) {\n return true;\n }\n }\n }\n return false;\n }\n\n /**\n * Build a JSONB query condition for nested object queries.\n * Supports deep nesting like: { profile: { contact: { email: { eq: \"test@example.com\" } } } }\n *\n * @param column The JSONB column\n * @param path The path to the nested property (e.g., ['profile', 'contact', 'email'])\n * @param operator The filter operator (e.g., { eq: \"test@example.com\" })\n * @param dialect Database dialect (postgresql or sqlite)\n * @param columnSchema Optional schema of the JSON column for type inference\n * @returns SQL condition\n */\n public buildJsonbCondition(\n column: PgColumn,\n path: string[],\n operator: FilterOperators<any>,\n dialect: \"postgresql\" | \"sqlite\",\n columnSchema?: any,\n ): SQL | undefined {\n if (path.length === 0) {\n return undefined;\n }\n\n // Check if operator is an array operator that needs JSONB (not text extraction)\n const isArrayOperator =\n operator.arrayContains !== undefined ||\n operator.arrayContained !== undefined ||\n operator.arrayOverlaps !== undefined;\n\n let jsonValue: SQL;\n\n if (dialect === \"sqlite\") {\n // SQLite: json_extract(column, '$.path.to.field')\n const pathStr = `$.${path.join(\".\")}`;\n jsonValue = sql`json_extract(${column}, ${pathStr})`;\n } else {\n // PostgreSQL: Build the JSON path\n let jsonPath = sql`${column}`;\n\n // Navigate through all path elements except the last\n for (let i = 0; i < path.length - 1; i++) {\n jsonPath = sql`${jsonPath}->${path[i]}`;\n }\n\n // For the last element:\n // - Use -> to keep as JSONB for array operators\n // - Use ->> to extract as text for other operators\n const lastPath = path[path.length - 1];\n if (isArrayOperator) {\n jsonValue = sql`${jsonPath}->${lastPath}`;\n } else {\n jsonValue = sql`${jsonPath}->>${lastPath}`;\n }\n }\n\n // Get field type for smart casting\n const fieldType = columnSchema\n ? this.getFieldType(columnSchema, path)\n : undefined;\n\n // Apply the operator\n return this.applyOperatorToJsonValue(\n jsonValue,\n operator,\n dialect,\n fieldType,\n );\n }\n\n /**\n * Build JSONB array query conditions.\n * Supports queries like: { addresses: { city: { eq: \"Wonderland\" } } }\n * which translates to: EXISTS (SELECT 1 FROM jsonb_array_elements(addresses) elem WHERE elem->>'city' = 'Wonderland')\n *\n * @param dialect Database dialect (postgresql or sqlite)\n * Note: SQLite array queries are not yet supported\n */\n public buildJsonbArrayCondition(\n column: PgColumn,\n path: string[],\n arrayPath: string,\n operator: FilterOperators<any>,\n dialect: \"postgresql\" | \"sqlite\",\n ): SQL | undefined {\n if (dialect === \"sqlite\") {\n throw new Error(\n \"Array queries in JSON columns are not yet supported for SQLite. \" +\n \"Please use PostgreSQL for complex JSON array queries, or restructure your data.\",\n );\n }\n\n if (path.length === 0) {\n return undefined;\n }\n\n // Build the base JSONB path to the array\n let jsonPath = sql`${column}`;\n if (arrayPath) {\n jsonPath = sql`${jsonPath}->${arrayPath}`;\n }\n\n // Build the condition for array elements\n const lastPath = path[0];\n const elemCondition = sql`elem->>${lastPath}`;\n const condition = this.applyOperatorToJsonValue(\n elemCondition,\n operator,\n dialect,\n );\n\n if (!condition) {\n return undefined;\n }\n\n // Wrap in EXISTS with jsonb_array_elements\n return sql`EXISTS (SELECT 1 FROM jsonb_array_elements(${jsonPath}) AS elem WHERE ${condition})`;\n }\n\n /**\n * Apply a filter operator to a JSONB value.\n * @param dialect Database dialect for appropriate casting syntax\n * @param fieldType Optional field type from schema for smart casting\n */\n private applyOperatorToJsonValue(\n jsonValue: SQL,\n operator: FilterOperators<any>,\n dialect: \"postgresql\" | \"sqlite\",\n fieldType?: string,\n ): SQL | undefined {\n // Helper to cast for numeric comparisons based on dialect and field type\n const castForNumeric = (value: SQL): SQL => {\n if (dialect === \"sqlite\") {\n // Use INTEGER for int types, REAL for number types\n if (fieldType === \"integer\" || fieldType === \"int\") {\n return sql`CAST(${value} AS INTEGER)`;\n }\n // Default to REAL for numeric comparisons\n return sql`CAST(${value} AS REAL)`;\n }\n // PostgreSQL\n return sql`(${value})::numeric`;\n };\n\n if (typeof operator !== \"object\") {\n // Direct value comparison\n return sql`${jsonValue} = ${operator}`;\n }\n\n const conditions: SQL[] = [];\n\n if (operator.eq !== undefined) {\n conditions.push(sql`${jsonValue} = ${operator.eq}`);\n }\n\n if (operator.ne !== undefined) {\n conditions.push(sql`${jsonValue} != ${operator.ne}`);\n }\n\n if (operator.gt !== undefined) {\n // Cast to numeric for comparison\n conditions.push(sql`${castForNumeric(jsonValue)} > ${operator.gt}`);\n }\n\n if (operator.gte !== undefined) {\n conditions.push(sql`${castForNumeric(jsonValue)} >= ${operator.gte}`);\n }\n\n if (operator.lt !== undefined) {\n conditions.push(sql`${castForNumeric(jsonValue)} < ${operator.lt}`);\n }\n\n if (operator.lte !== undefined) {\n conditions.push(sql`${castForNumeric(jsonValue)} <= ${operator.lte}`);\n }\n\n if (operator.like !== undefined) {\n conditions.push(sql`${jsonValue} LIKE ${operator.like}`);\n }\n\n if (operator.ilike !== undefined) {\n // SQLite: LIKE is case-insensitive by default, so use LIKE\n // PostgreSQL: Use ILIKE\n if (dialect === \"sqlite\") {\n conditions.push(sql`${jsonValue} LIKE ${operator.ilike}`);\n } else {\n conditions.push(sql`${jsonValue} ILIKE ${operator.ilike}`);\n }\n }\n\n if (operator.notLike !== undefined) {\n conditions.push(sql`${jsonValue} NOT LIKE ${operator.notLike}`);\n }\n\n if (operator.notIlike !== undefined) {\n // SQLite: LIKE is case-insensitive by default, so use NOT LIKE\n // PostgreSQL: Use NOT ILIKE\n if (dialect === \"sqlite\") {\n conditions.push(sql`${jsonValue} NOT LIKE ${operator.notIlike}`);\n } else {\n conditions.push(sql`${jsonValue} NOT ILIKE ${operator.notIlike}`);\n }\n }\n\n if (operator.isNull !== undefined) {\n conditions.push(sql`${jsonValue} IS NULL`);\n }\n\n if (operator.isNotNull !== undefined) {\n conditions.push(sql`${jsonValue} IS NOT NULL`);\n }\n\n if (operator.inArray !== undefined && Array.isArray(operator.inArray)) {\n conditions.push(\n sql`${jsonValue} IN (${sql.join(\n operator.inArray.map((v) => sql`${v}`),\n sql`, `,\n )})`,\n );\n }\n\n if (\n operator.notInArray !== undefined &&\n Array.isArray(operator.notInArray)\n ) {\n conditions.push(\n sql`${jsonValue} NOT IN (${sql.join(\n operator.notInArray.map((v) => sql`${v}`),\n sql`, `,\n )})`,\n );\n }\n\n // Handle array operators for JSONB arrays\n // When these operators are used, jsonValue will be a JSONB value (not text extracted)\n if (operator.arrayContains !== undefined) {\n if (dialect === \"postgresql\") {\n // PostgreSQL @> operator: checks if left JSONB contains right JSONB\n // JSON.stringify ensures the value is properly escaped as a JSON string\n const jsonArray = JSON.stringify(\n Array.isArray(operator.arrayContains)\n ? operator.arrayContains\n : [operator.arrayContains],\n );\n // The value is safely parameterized via sql template, preventing SQL injection\n conditions.push(sql`${jsonValue} @> ${jsonArray}::jsonb`);\n }\n }\n\n if (operator.arrayContained !== undefined) {\n if (dialect === \"postgresql\") {\n // PostgreSQL <@ operator: checks if left JSONB is contained in right JSONB\n const jsonArray = JSON.stringify(\n Array.isArray(operator.arrayContained)\n ? operator.arrayContained\n : [operator.arrayContained],\n );\n conditions.push(sql`${jsonValue} <@ ${jsonArray}::jsonb`);\n }\n }\n\n if (operator.arrayOverlaps !== undefined) {\n if (dialect === \"postgresql\") {\n // PostgreSQL ?| operator: checks if any of the array elements exist as top-level keys\n // Note: For JSONB arrays, we need to use a different approach\n // Convert the JSONB array to text array for the ?| operator\n const values = Array.isArray(operator.arrayOverlaps)\n ? operator.arrayOverlaps\n : [operator.arrayOverlaps];\n\n // Build an OR condition to check if any value exists in the array\n // This is safer than using ?| with dynamic values\n const overlapConditions = values.map((val) => {\n const jsonVal = JSON.stringify(val);\n return sql`${jsonValue} @> ${jsonVal}::jsonb`;\n });\n\n if (overlapConditions.length > 0) {\n conditions.push(sql`(${sql.join(overlapConditions, sql` OR `)})`);\n }\n }\n }\n\n if (conditions.length === 0) {\n return undefined;\n }\n\n if (conditions.length === 1) {\n return conditions[0];\n }\n\n // Multiple conditions - AND them together\n return sql.join(conditions, sql` AND `);\n }\n\n /**\n * Parse a nested query object and extract the path and operator.\n * For example: { profile: { contact: { email: { eq: \"test@example.com\" } } } }\n * Returns: { path: ['profile', 'contact', 'email'], operator: { eq: \"test@example.com\" } }\n */\n public parseNestedQuery(\n nestedQuery: any,\n currentPath: string[] = [],\n ): Array<{ path: string[]; operator: FilterOperators<any> }> {\n const results: Array<{ path: string[]; operator: FilterOperators<any> }> =\n [];\n\n for (const [key, value] of Object.entries(nestedQuery)) {\n if (value && typeof value === \"object\" && !Array.isArray(value)) {\n // Check if this is an operator object\n const keys = Object.keys(value);\n const hasOperators = keys.some((k) =>\n [\n \"eq\",\n \"ne\",\n \"gt\",\n \"gte\",\n \"lt\",\n \"lte\",\n \"like\",\n \"ilike\",\n \"notLike\",\n \"notIlike\",\n \"isNull\",\n \"isNotNull\",\n \"inArray\",\n \"notInArray\",\n \"arrayContains\",\n \"arrayContained\",\n \"arrayOverlaps\",\n ].includes(k),\n );\n\n if (hasOperators) {\n // This is an operator, add to results\n results.push({\n path: [...currentPath, key],\n operator: value as FilterOperators<any>,\n });\n } else {\n // This is a nested object, recurse\n const nestedResults = this.parseNestedQuery(value, [\n ...currentPath,\n key,\n ]);\n results.push(...nestedResults);\n }\n }\n }\n\n return results;\n }\n\n /**\n * Determine if a property is a JSONB column based on the schema.\n * A column is JSONB if it's defined as an object or array in the TypeBox schema.\n */\n public isJsonbColumn(schema: TObject, columnName: string): boolean {\n const property = schema.properties[columnName];\n if (!property) {\n return false;\n }\n\n // Check if it's an object or array type\n return (\n (property as any).type === \"object\" || (property as any).type === \"array\"\n );\n }\n\n /**\n * Check if an array property contains primitive types (string, number, boolean, etc.)\n * rather than objects. Primitive arrays should use native Drizzle operators.\n * @returns true if the array contains primitives, false if it contains objects\n */\n public isPrimitiveArray(schema: TObject, columnName: string): boolean {\n const property = schema.properties[columnName];\n if (!property || (property as any).type !== \"array\") {\n return false;\n }\n\n // Check the items type\n const items = (property as any).items;\n if (!items) {\n return false;\n }\n\n // If items is an object type, it's not a primitive array\n // Primitive types are: string, number, integer, boolean, null\n const itemType = items.type;\n return (\n itemType === \"string\" ||\n itemType === \"number\" ||\n itemType === \"integer\" ||\n itemType === \"boolean\" ||\n itemType === \"null\"\n );\n }\n\n /**\n * Get the type of a field by navigating through a schema path.\n * Used for smart type casting in SQL queries.\n *\n * @param columnSchema The schema of the JSON column (e.g., t.object({ age: t.integer() }))\n * @param path The path to navigate (e.g., ['contact', 'email'])\n * @returns The type string (e.g., 'integer', 'number', 'string') or undefined if not found\n */\n private getFieldType(columnSchema: any, path: string[]): string | undefined {\n let current = columnSchema;\n\n for (const segment of path) {\n // Navigate into object properties\n if (current.type === \"object\" && current.properties) {\n current = current.properties[segment];\n if (!current) {\n return undefined;\n }\n } else {\n // Path segment doesn't exist or current is not an object\n return undefined;\n }\n }\n\n return current.type;\n }\n\n /**\n * Check if a nested path points to an array property.\n */\n public isArrayProperty(schema: TObject, path: string[]): boolean {\n if (path.length === 0) {\n return false;\n }\n\n let currentSchema: any = schema.properties[path[0]];\n if (!currentSchema) {\n return false;\n }\n\n // If first element is an array, return true\n if (currentSchema.type === \"array\") {\n return true;\n }\n\n // Navigate through nested objects\n for (let i = 1; i < path.length; i++) {\n if (currentSchema.type === \"object\" && currentSchema.properties) {\n currentSchema = currentSchema.properties[path[i]];\n if (!currentSchema) {\n return false;\n }\n if (currentSchema.type === \"array\") {\n return true;\n }\n } else {\n return false;\n }\n }\n\n return false;\n }\n}\n","import {\n $inject,\n Alepha,\n AlephaError,\n createPagination,\n type TObject,\n} from \"alepha\";\nimport {\n and,\n arrayContained,\n arrayContains,\n arrayOverlaps,\n between,\n eq,\n gt,\n gte,\n ilike,\n inArray,\n isNotNull,\n isNull,\n isSQLWrapper,\n like,\n lt,\n lte,\n ne,\n not,\n notBetween,\n notIlike,\n notInArray,\n notLike,\n or,\n type SQL,\n sql,\n} from \"drizzle-orm\";\nimport type { PgColumn } from \"drizzle-orm/pg-core\";\nimport type { FilterOperators } from \"../interfaces/FilterOperators.ts\";\nimport type {\n PgQueryWhere,\n PgQueryWhereOrSQL,\n} from \"../interfaces/PgQueryWhere.ts\";\nimport { PgJsonQueryManager } from \"./PgJsonQueryManager.ts\";\n\nexport class QueryManager {\n protected readonly jsonQueryManager = $inject(PgJsonQueryManager);\n protected readonly alepha = $inject(Alepha);\n\n /**\n * Convert a query object to a SQL query.\n */\n public toSQL(\n query: PgQueryWhereOrSQL<TObject>,\n options: {\n schema: TObject;\n col: (key: string) => PgColumn;\n joins?: PgJoin[];\n dialect: \"postgresql\" | \"sqlite\";\n },\n ): SQL | undefined {\n const { schema, col, joins } = options;\n const conditions: SQL[] = [];\n\n if (isSQLWrapper(query)) {\n conditions.push(query as SQL);\n } else {\n const keys = Object.keys(query) as Array<\n keyof PgQueryWhere<TObject> & string\n >;\n\n for (const key of keys) {\n const operator = query[key] as SQL;\n\n // Handle joins - check if this key matches a join at the current level\n if (\n typeof query[key] === \"object\" &&\n query[key] != null &&\n !Array.isArray(query[key]) &&\n joins?.length\n ) {\n // Find the join that matches this key (at the current level, without parent filtering)\n const matchingJoins = joins.filter((j) => j.key === key);\n if (matchingJoins.length > 0) {\n // Use the first matching join (they should all have the same schema)\n const join = matchingJoins[0];\n\n // Build the full path to this join\n const joinPath = join.parent ? `${join.parent}.${key}` : key;\n\n // Find child joins: those whose parent starts with this join's path\n const childJoins = joins.filter((j) => {\n if (!j.parent) return false;\n // Child's parent should be exactly our path, or start with our path + \".\"\n return (\n j.parent === joinPath || j.parent.startsWith(`${joinPath}.`)\n );\n });\n\n // For recursion, we need to restructure child joins\n // Remove the current path prefix from parent keys\n const recursiveJoins = childJoins.map((j) => {\n const newParent =\n j.parent === joinPath\n ? undefined\n : j.parent!.substring(joinPath.length + 1);\n return {\n ...j,\n parent: newParent,\n };\n });\n\n const sql = this.toSQL(query[key], {\n schema: join.schema,\n col: join.col,\n joins: recursiveJoins.length > 0 ? recursiveJoins : undefined,\n dialect: options.dialect,\n });\n if (sql) {\n conditions.push(sql);\n }\n continue;\n }\n }\n\n if (Array.isArray(operator)) {\n const operations: SQL[] = operator\n .map((it) => {\n if (isSQLWrapper(it)) {\n return it as SQL;\n }\n return this.toSQL(it as PgQueryWhere<TObject>, {\n schema,\n col,\n joins, // Pass joins through recursively\n dialect: options.dialect,\n });\n })\n .filter((it) => it != null);\n\n if (key === \"and\") {\n return and(...operations);\n }\n\n if (key === \"or\") {\n return or(...operations);\n }\n }\n\n if (key === \"not\") {\n const where = this.toSQL(operator as PgQueryWhereOrSQL<TObject>, {\n schema,\n col,\n joins, // Pass joins through recursively\n dialect: options.dialect,\n });\n if (where) {\n return not(where);\n }\n }\n\n if (operator) {\n // Check if this is a JSONB column with nested query\n // BUT skip primitive arrays - they should use native Drizzle operators\n if (\n this.jsonQueryManager.isJsonbColumn(schema, key) &&\n !this.jsonQueryManager.isPrimitiveArray(schema, key) &&\n typeof operator === \"object\" &&\n !Array.isArray(operator) &&\n this.jsonQueryManager.hasNestedQuery({ [key]: operator })\n ) {\n // Handle JSONB nested queries for objects and arrays of objects\n const column = col(key);\n const jsonbSql = this.buildJsonbQuery(\n column,\n operator,\n schema,\n key,\n options.dialect,\n );\n if (jsonbSql) {\n conditions.push(jsonbSql);\n }\n } else {\n // Regular column query (including primitive arrays)\n const column = col(key);\n const sql = this.mapOperatorToSql(\n operator,\n column,\n schema,\n key,\n options.dialect,\n );\n if (sql) {\n conditions.push(sql);\n }\n }\n }\n }\n }\n\n if (conditions.length === 1) {\n return conditions[0];\n }\n\n return and(...conditions);\n }\n\n /**\n * Build a JSONB query for nested object/array queries.\n */\n protected buildJsonbQuery(\n column: PgColumn,\n nestedQuery: any,\n schema: TObject,\n columnName: string,\n dialect: \"postgresql\" | \"sqlite\",\n ): SQL | undefined {\n // Parse the nested query to extract paths and operators\n const queries = this.jsonQueryManager.parseNestedQuery(nestedQuery);\n\n if (queries.length === 0) {\n return undefined;\n }\n\n // Get the column schema for type inference\n const columnSchema = schema.properties[columnName];\n\n // Build conditions for each parsed query\n const conditions: SQL[] = [];\n\n for (const { path, operator } of queries) {\n // Check if the operator is an array operator (arrayContains, arrayContained, arrayOverlaps)\n const isArrayOperator =\n operator.arrayContains !== undefined ||\n operator.arrayContained !== undefined ||\n operator.arrayOverlaps !== undefined;\n\n // Check if this is an array property\n const isArrayProp = this.jsonQueryManager.isArrayProperty(schema, [\n columnName,\n ...path,\n ]);\n\n if (isArrayProp && isArrayOperator) {\n // Array operators on JSONB arrays should use buildJsonbCondition\n // This handles cases like: { metadata: { permissions: { arrayContains: [...] } } }\n const condition = this.jsonQueryManager.buildJsonbCondition(\n column,\n path,\n operator,\n dialect,\n columnSchema,\n );\n if (condition) {\n conditions.push(condition);\n }\n } else if (isArrayProp && !isArrayOperator) {\n // Non-array operators on array properties use buildJsonbArrayCondition\n // This handles cases like: { addresses: { city: { eq: \"Wonderland\" } } }\n const condition = this.jsonQueryManager.buildJsonbArrayCondition(\n column,\n path,\n \"\",\n operator,\n dialect,\n );\n if (condition) {\n conditions.push(condition);\n }\n } else {\n // Handle object queries\n const condition = this.jsonQueryManager.buildJsonbCondition(\n column,\n path,\n operator,\n dialect,\n columnSchema,\n );\n if (condition) {\n conditions.push(condition);\n }\n }\n }\n\n if (conditions.length === 0) {\n return undefined;\n }\n\n if (conditions.length === 1) {\n return conditions[0];\n }\n\n // Multiple conditions - AND them together\n return and(...conditions);\n }\n\n /**\n * Check if an object has any filter operator properties.\n */\n protected hasFilterOperatorProperties(obj: any): boolean {\n if (!obj || typeof obj !== \"object\") return false;\n\n const filterOperatorKeys = [\n \"eq\",\n \"ne\",\n \"gt\",\n \"gte\",\n \"lt\",\n \"lte\",\n \"inArray\",\n \"notInArray\",\n \"isNull\",\n \"isNotNull\",\n \"like\",\n \"notLike\",\n \"ilike\",\n \"notIlike\",\n \"contains\",\n \"startsWith\",\n \"endsWith\",\n \"between\",\n \"notBetween\",\n \"arrayContains\",\n \"arrayContained\",\n \"arrayOverlaps\",\n ];\n\n return filterOperatorKeys.some((key) => key in obj);\n }\n\n /**\n * Map a filter operator to a SQL query.\n */\n public mapOperatorToSql(\n operator: FilterOperators<any> | any,\n column: PgColumn,\n columnSchema?: TObject,\n columnName?: string,\n dialect: \"postgresql\" | \"sqlite\" = \"postgresql\",\n ): SQL | undefined {\n // Helper function to encode a value for the specific column\n const encodeValue = (value: any): any => {\n if (value == null) {\n return value;\n }\n\n // If we have schema information, encode the value properly\n if (columnSchema && columnName) {\n try {\n const fieldSchema = columnSchema.properties[columnName];\n if (fieldSchema) {\n // Encode the value using the drizzle codec\n // This converts application values (like Dayjs) to database values (like ISO strings)\n return this.alepha.codec.encode(fieldSchema, value, {\n encoder: \"drizzle\",\n });\n }\n } catch (error) {\n // If encoding fails, fall back to the original value\n // This ensures backward compatibility\n }\n }\n\n return value;\n };\n\n // Helper function to encode array values\n const encodeArray = (values: any[]): any[] => {\n return values.map((v) => encodeValue(v));\n };\n\n // If operator is not an object, OR it's an object but doesn't have any filter operator properties,\n // treat it as a direct value (e.g., string, number, Date, Dayjs, etc.)\n if (\n typeof operator !== \"object\" ||\n operator == null ||\n !this.hasFilterOperatorProperties(operator)\n ) {\n return eq(column, encodeValue(operator));\n }\n\n const conditions: SQL[] = [];\n\n if (operator?.eq != null) {\n conditions.push(eq(column, encodeValue(operator.eq)));\n }\n\n if (operator?.ne != null) {\n conditions.push(ne(column, encodeValue(operator.ne)));\n }\n\n if (operator?.gt != null) {\n conditions.push(gt(column, encodeValue(operator.gt)));\n }\n\n if (operator?.gte != null) {\n conditions.push(gte(column, encodeValue(operator.gte)));\n }\n\n if (operator?.lt != null) {\n conditions.push(lt(column, encodeValue(operator.lt)));\n }\n\n if (operator?.lte != null) {\n conditions.push(lte(column, encodeValue(operator.lte)));\n }\n\n if (operator?.inArray != null) {\n if (!Array.isArray(operator.inArray) || operator.inArray.length === 0) {\n throw new AlephaError(\"inArray operator requires at least one value\");\n }\n conditions.push(inArray(column, encodeArray(operator.inArray)));\n }\n\n if (operator?.notInArray != null) {\n if (\n !Array.isArray(operator.notInArray) ||\n operator.notInArray.length === 0\n ) {\n throw new AlephaError(\n \"notInArray operator requires at least one value\",\n );\n }\n conditions.push(notInArray(column, encodeArray(operator.notInArray)));\n }\n\n if (operator?.isNull != null) {\n conditions.push(isNull(column));\n }\n\n if (operator?.isNotNull != null) {\n conditions.push(isNotNull(column));\n }\n\n if (operator?.like != null) {\n conditions.push(like(column, encodeValue(operator.like)));\n }\n\n if (operator?.notLike != null) {\n conditions.push(notLike(column, encodeValue(operator.notLike)));\n }\n\n if (operator?.ilike != null) {\n conditions.push(ilike(column, encodeValue(operator.ilike)));\n }\n\n if (operator?.notIlike != null) {\n conditions.push(notIlike(column, encodeValue(operator.notIlike)));\n }\n\n if (operator?.contains != null) {\n // Escape LIKE special characters to prevent wildcard injection\n const escapedValue = String(operator.contains)\n .replace(/\\\\/g, \"\\\\\\\\\") // Escape backslash first\n .replace(/%/g, \"\\\\%\") // Escape %\n .replace(/_/g, \"\\\\_\"); // Escape _\n\n if (dialect === \"sqlite\") {\n // SQLite doesn't have ilike, use LOWER() for case-insensitive matching\n conditions.push(\n sql`LOWER(${column}) LIKE LOWER(${encodeValue(`%${escapedValue}%`)})`,\n );\n } else {\n conditions.push(ilike(column, encodeValue(`%${escapedValue}%`)));\n }\n }\n\n if (operator?.startsWith != null) {\n // Escape LIKE special characters to prevent wildcard injection\n const escapedValue = String(operator.startsWith)\n .replace(/\\\\/g, \"\\\\\\\\\") // Escape backslash first\n .replace(/%/g, \"\\\\%\") // Escape %\n .replace(/_/g, \"\\\\_\"); // Escape _\n\n if (dialect === \"sqlite\") {\n // SQLite doesn't have ilike, use LOWER() for case-insensitive matching\n conditions.push(\n sql`LOWER(${column}) LIKE LOWER(${encodeValue(`${escapedValue}%`)})`,\n );\n } else {\n conditions.push(ilike(column, encodeValue(`${escapedValue}%`)));\n }\n }\n\n if (operator?.endsWith != null) {\n // Escape LIKE special characters to prevent wildcard injection\n const escapedValue = String(operator.endsWith)\n .replace(/\\\\/g, \"\\\\\\\\\") // Escape backslash first\n .replace(/%/g, \"\\\\%\") // Escape %\n .replace(/_/g, \"\\\\_\"); // Escape _\n\n if (dialect === \"sqlite\") {\n // SQLite doesn't have ilike, use LOWER() for case-insensitive matching\n conditions.push(\n sql`LOWER(${column}) LIKE LOWER(${encodeValue(`%${escapedValue}`)})`,\n );\n } else {\n conditions.push(ilike(column, encodeValue(`%${escapedValue}`)));\n }\n }\n\n if (operator?.between != null) {\n if (!Array.isArray(operator.between) || operator.between.length !== 2) {\n throw new Error(\n \"between operator requires exactly 2 values [min, max]\",\n );\n }\n conditions.push(\n between(\n column,\n encodeValue(operator.between[0]),\n encodeValue(operator.between[1]),\n ),\n );\n }\n\n if (operator?.notBetween != null) {\n if (\n !Array.isArray(operator.notBetween) ||\n operator.notBetween.length !== 2\n ) {\n throw new Error(\n \"notBetween operator requires exactly 2 values [min, max]\",\n );\n }\n conditions.push(\n notBetween(\n column,\n encodeValue(operator.notBetween[0]),\n encodeValue(operator.notBetween[1]),\n ),\n );\n }\n\n if (operator?.arrayContains != null) {\n conditions.push(\n arrayContains(column, encodeValue(operator.arrayContains)),\n );\n }\n\n if (operator?.arrayContained != null) {\n conditions.push(\n arrayContained(column, encodeValue(operator.arrayContained)),\n );\n }\n\n if (operator?.arrayOverlaps != null) {\n conditions.push(\n arrayOverlaps(column, encodeValue(operator.arrayOverlaps)),\n );\n }\n\n if (conditions.length === 0) {\n return undefined;\n }\n\n if (conditions.length === 1) {\n return conditions[0];\n }\n\n return and(...conditions);\n }\n\n /**\n * Parse pagination sort string to orderBy format.\n * Format: \"firstName,-lastName\" -> [{ column: \"firstName\", direction: \"asc\" }, { column: \"lastName\", direction: \"desc\" }]\n * - Columns separated by comma\n * - Prefix with '-' for DESC direction\n *\n * @param sort Pagination sort string\n * @returns OrderBy array or single object\n */\n public parsePaginationSort(\n sort: string,\n ):\n | Array<{ column: string; direction: \"asc\" | \"desc\" }>\n | { column: string; direction: \"asc\" | \"desc\" } {\n const fields = sort.split(\",\").map((field) => field.trim());\n\n const orderByClauses = fields.map((field) => {\n if (field.startsWith(\"-\")) {\n return {\n column: field.substring(1),\n direction: \"desc\" as const,\n };\n }\n return {\n column: field,\n direction: \"asc\" as const,\n };\n });\n\n // Return single object if only one field, array if multiple\n return orderByClauses.length === 1 ? orderByClauses[0] : orderByClauses;\n }\n\n /**\n * Normalize orderBy parameter to array format.\n * Supports 3 modes:\n * 1. String: \"name\" -> [{ column: \"name\", direction: \"asc\" }]\n * 2. Object: { column: \"name\", direction: \"desc\" } -> [{ column: \"name\", direction: \"desc\" }]\n * 3. Array: [{ column: \"name\" }, { column: \"age\", direction: \"desc\" }] -> normalized array\n *\n * @param orderBy The orderBy parameter\n * @returns Normalized array of order by clauses\n */\n public normalizeOrderBy(\n orderBy: any,\n ): Array<{ column: string; direction: \"asc\" | \"desc\" }> {\n // Mode 1: String -> single column, ASC by default\n if (typeof orderBy === \"string\") {\n return [{ column: orderBy, direction: \"asc\" }];\n }\n\n // Mode 2: Single object -> convert to array\n if (!Array.isArray(orderBy) && typeof orderBy === \"object\") {\n return [\n {\n column: orderBy.column,\n direction: orderBy.direction ?? \"asc\",\n },\n ];\n }\n\n // Mode 3: Array -> normalize each item with default direction\n if (Array.isArray(orderBy)) {\n return orderBy.map((item) => ({\n column: item.column,\n direction: item.direction ?? \"asc\",\n }));\n }\n\n return [];\n }\n\n /**\n * Create a pagination object.\n *\n * @deprecated Use `createPagination` from alepha instead.\n * This method now delegates to the framework-level helper.\n *\n * @param entities The entities to paginate.\n * @param limit The limit of the pagination.\n * @param offset The offset of the pagination.\n * @param sort Optional sort metadata to include in response.\n */\n public createPagination<T>(\n entities: T[],\n limit = 10,\n offset = 0,\n sort?: Array<{ column: string; direction: \"asc\" | \"desc\" }>,\n ) {\n return createPagination(entities, limit, offset, sort);\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface PgJoin {\n table: string;\n schema: TObject;\n key: string;\n col: (key: string) => PgColumn;\n parent?: string;\n}\n","import {\n $inject,\n Alepha,\n AlephaError,\n type Page,\n type PageQuery,\n type Static,\n type StaticEncode,\n type TObject,\n type TSchema,\n t,\n} from \"alepha\";\nimport { type DateTime, DateTimeProvider } from \"alepha/datetime\";\nimport { asc, desc, isSQLWrapper, type SQL } from \"drizzle-orm\";\nimport type {\n LockConfig,\n LockStrength,\n PgColumn,\n PgDatabase,\n PgInsertValue,\n PgTable,\n PgTableWithColumns,\n PgTransaction,\n PgUpdateSetSource,\n} from \"drizzle-orm/pg-core\";\nimport type { PgTransactionConfig } from \"drizzle-orm/pg-core/session\";\nimport {\n PG_DELETED_AT,\n PG_PRIMARY_KEY,\n PG_UPDATED_AT,\n PG_VERSION,\n} from \"../constants/PG_SYMBOLS.ts\";\nimport { DbConflictError } from \"../errors/DbConflictError.ts\";\nimport { DbEntityNotFoundError } from \"../errors/DbEntityNotFoundError.ts\";\nimport { DbError } from \"../errors/DbError.ts\";\nimport { DbVersionMismatchError } from \"../errors/DbVersionMismatchError.ts\";\nimport { getAttrFields, type PgAttrField } from \"../helpers/pgAttr.ts\";\nimport type {\n PgQuery,\n PgQueryRelations,\n PgRelationMap,\n PgStatic,\n} from \"../interfaces/PgQuery.ts\";\nimport type {\n PgQueryWhere,\n PgQueryWhereOrSQL,\n} from \"../interfaces/PgQueryWhere.ts\";\nimport type {\n EntityPrimitive,\n SchemaToTableConfig,\n} from \"../primitives/$entity.ts\";\nimport {\n DatabaseProvider,\n type SQLLike,\n} from \"../providers/drivers/DatabaseProvider.ts\";\nimport type { TObjectInsert } from \"../schemas/insertSchema.ts\";\nimport type { TObjectUpdate } from \"../schemas/updateSchema.ts\";\nimport { PgRelationManager } from \"./PgRelationManager.ts\";\nimport { type PgJoin, QueryManager } from \"./QueryManager.ts\";\n\nexport abstract class Repository<T extends TObject> {\n public readonly entity: EntityPrimitive<T>;\n public readonly provider: DatabaseProvider;\n\n protected readonly relationManager = $inject(PgRelationManager);\n protected readonly queryManager = $inject(QueryManager);\n protected readonly dateTimeProvider = $inject(DateTimeProvider);\n protected readonly alepha = $inject(Alepha);\n\n constructor(entity: EntityPrimitive<T>, provider = DatabaseProvider) {\n this.entity = entity;\n this.provider = this.alepha.inject(provider);\n this.provider.registerEntity(entity as EntityPrimitive);\n }\n\n /**\n * Represents the primary key of the table.\n * - Key is the name of the primary key column.\n * - Type is the type (TypeBox) of the primary key column.\n *\n * ID is mandatory. If the table does not have a primary key, it will throw an error.\n */\n public get id(): {\n type: TSchema;\n key: keyof T[\"properties\"];\n col: PgColumn;\n } {\n return this.getPrimaryKey(this.entity.schema);\n }\n\n /**\n * Get Drizzle table object.\n */\n public get table(): PgTableWithColumns<SchemaToTableConfig<T>> {\n return this.provider.table(this.entity);\n }\n\n /**\n * Get SQL table name. (from Drizzle table object)\n */\n public get tableName(): string {\n return this.entity.name;\n }\n\n /**\n * Getter for the database connection from the database provider.\n */\n protected get db(): PgDatabase<any> {\n return this.provider.db;\n }\n\n /**\n * Execute a SQL query.\n *\n * This method allows executing raw SQL queries against the database.\n * This is by far the easiest way to run custom queries that are not covered by the repository's built-in methods!\n *\n * You must use the `sql` tagged template function from Drizzle ORM to create the query. https://orm.drizzle.team/docs/sql\n *\n * @example\n * ```ts\n * class App {\n * repository = $repository({ ... });\n * async getAdults() {\n * const users = repository.table; // Drizzle table object\n * await repository.query(sql`SELECT * FROM ${users} WHERE ${users.age} > ${18}`);\n * // or better\n * await repository.query((users) => sql`SELECT * FROM ${users} WHERE ${users.age} > ${18}`);\n * }\n * }\n * ```\n */\n public async query<R extends TObject = T>(\n query:\n | SQLLike\n | ((\n table: PgTableWithColumns<SchemaToTableConfig<T>>,\n db: PgDatabase<any>,\n ) => SQLLike),\n schema?: R,\n ): Promise<Static<R>[]> {\n const raw =\n typeof query === \"function\" ? query(this.table, this.db) : query;\n\n if (typeof raw === \"string\" && raw.includes(\"[object Object]\")) {\n throw new AlephaError(\n \"Invalid SQL query. Did you forget to call the 'sql' function?\",\n );\n }\n\n const rows = await this.provider.execute(raw);\n\n return rows.map((it) => {\n return this.clean(\n this.mapRawFieldsToEntity(it),\n schema ?? this.entity.schema,\n ) as Static<R>;\n });\n }\n\n /**\n * Map raw database fields to entity fields. (handles column name differences)\n */\n protected mapRawFieldsToEntity(row: Record<string, unknown>) {\n const entity: any = {};\n\n for (const key of Object.keys(row)) {\n entity[key] = row[key];\n for (const colKey of Object.keys(this.table)) {\n if (this.table[colKey].name === key) {\n entity[colKey] = row[key];\n break;\n }\n }\n }\n\n return entity;\n }\n\n /**\n * Get a Drizzle column from the table by his name.\n */\n protected col(name: keyof StaticEncode<T>): PgColumn {\n const column = (this.table as any)[name];\n if (!column) {\n throw new AlephaError(\n `Invalid access. Column ${String(name)} not found in table ${this.tableName}`,\n );\n }\n\n return column;\n }\n\n /**\n * Run a transaction.\n */\n public async transaction<T>(\n transaction: (\n tx: PgTransaction<any, Record<string, any>, any>,\n ) => Promise<T>,\n config?: PgTransactionConfig,\n ): Promise<T> {\n return await this.db.transaction(transaction, config);\n }\n\n // -------------------------------------------------------------------------------------------------------------------\n\n /**\n * Start a SELECT query on the table.\n */\n protected rawSelect(opts: StatementOptions = {}) {\n return (opts.tx ?? this.db).select().from(this.table as PgTable);\n }\n\n /**\n * Start a SELECT DISTINCT query on the table.\n */\n protected rawSelectDistinct(\n opts: StatementOptions = {},\n columns: (keyof Static<T>)[] = [],\n ) {\n const db = opts.tx ?? this.db;\n const table = this.table as PgTable;\n\n const fields: Record<string, any> = {};\n for (const column of columns) {\n if (typeof column === \"string\") {\n fields[column] = this.col(column);\n }\n }\n\n return db.selectDistinct(fields).from(table);\n }\n\n /**\n * Start an INSERT query on the table.\n */\n protected rawInsert(opts: StatementOptions = {}) {\n return (opts.tx ?? this.db).insert(this.table);\n }\n\n /**\n * Start an UPDATE query on the table.\n */\n protected rawUpdate(opts: StatementOptions = {}) {\n return (opts.tx ?? this.db).update(this.table);\n }\n\n /**\n * Start a DELETE query on the table.\n */\n protected rawDelete(opts: StatementOptions = {}) {\n return (opts.tx ?? this.db).delete(this.table);\n }\n\n // -------------------------------------------------------------------------------------------------------------------\n\n /**\n * Create a Drizzle `select` query based on a JSON query object.\n *\n * > This method is the base for `find`, `findOne`, `findById`, and `paginate`.\n */\n public async findMany<R extends PgRelationMap<T>>(\n query: PgQueryRelations<T, R> = {},\n opts: StatementOptions = {},\n ): Promise<PgStatic<T, R>[]> {\n await this.alepha.events.emit(\"repository:read:before\", {\n tableName: this.tableName,\n query,\n });\n\n const columns = query.columns ?? query.distinct;\n const builder = query.distinct\n ? this.rawSelectDistinct(opts, query.distinct)\n : this.rawSelect(opts);\n\n const joins: Array<PgJoin> = [];\n if (query.with) {\n this.relationManager.buildJoins(\n this.provider,\n builder,\n joins,\n query.with,\n this.table,\n );\n }\n\n const where = this.withDeletedAt(\n (query.where ?? {}) as PgQueryWhere<T>,\n opts,\n );\n\n builder.where(() => this.toSQL(where, joins));\n\n if (query.offset) {\n builder.offset(query.offset);\n\n // SQLite requires LIMIT when OFFSET is used\n if (this.provider.dialect === \"sqlite\" && !query.limit) {\n query.limit = 1000;\n }\n }\n\n if (query.limit) {\n builder.limit(query.limit);\n }\n\n if (query.orderBy) {\n const orderByClauses = this.queryManager.normalizeOrderBy(query.orderBy);\n builder.orderBy(\n ...orderByClauses.map((clause) =>\n clause.direction === \"desc\"\n ? desc(this.col(clause.column as string))\n : asc(this.col(clause.column as string)),\n ),\n );\n }\n\n if (query.groupBy) {\n builder.groupBy(...query.groupBy.map((key) => this.col(key as string)));\n }\n\n if (opts.for) {\n if (typeof opts.for === \"string\") {\n builder.for(opts.for);\n } else if (opts.for) {\n builder.for(opts.for.strength, opts.for.config);\n }\n }\n\n try {\n let rows = await builder.execute();\n\n let schema: TObject = this.entity.schema;\n if (columns) {\n schema = t.pick(schema, columns);\n }\n\n if (joins.length) {\n rows = rows.map((row: any) => {\n // Clone schema for each row to avoid mutation\n const rowSchema = { ...schema, properties: { ...schema.properties } };\n return this.relationManager.mapRowWithJoins(\n row[this.tableName],\n row,\n rowSchema,\n joins,\n );\n });\n }\n\n rows = rows.map((row) => {\n // For joined queries, build a schema that includes all nested joins\n if (joins.length) {\n const joinedSchema = this.relationManager.buildSchemaWithJoins(\n schema,\n joins,\n );\n // Clean the row with the full joined schema (including nested relations)\n return this.cleanWithJoins(row, joinedSchema, joins);\n }\n return this.clean(row, schema);\n });\n\n await this.alepha.events.emit(\"repository:read:after\", {\n tableName: this.tableName,\n query,\n entities: rows,\n });\n\n return rows as PgStatic<T, R>[];\n } catch (error) {\n throw new DbError(\"Query select has failed\", error as Error);\n }\n }\n\n /**\n * Find a single entity.\n */\n public async findOne<R extends PgRelationMap<T>>(\n query: Pick<PgQueryRelations<T, R>, \"with\" | \"where\">,\n opts: StatementOptions = {},\n ): Promise<PgStatic<T, R>> {\n const [entity] = await this.findMany({ limit: 1, ...query }, opts);\n\n if (!entity) {\n // TODO: enhance error message when finding by ID\n throw new DbEntityNotFoundError(this.tableName);\n }\n\n return entity as PgStatic<T, R>;\n }\n\n /**\n * Find entities with pagination.\n *\n * It uses the same parameters as `find()`, but adds pagination metadata to the response.\n *\n * > Pagination CAN also do a count query to get the total number of elements.\n */\n public async paginate<R extends PgRelationMap<T>>(\n pagination: PageQuery = {},\n query: PgQueryRelations<T, R> = {},\n opts: StatementOptions & { count?: boolean } = {},\n ): Promise<Page<PgStatic<T, R>>> {\n const limit = query.limit ?? pagination.size ?? 10;\n const page = pagination.page ?? 0;\n const offset = query.offset ?? page * limit;\n\n let orderBy = query.orderBy;\n if (!query.orderBy && pagination.sort) {\n orderBy = this.queryManager.parsePaginationSort(pagination.sort) as any;\n }\n\n const now = Date.now();\n const timers = {\n query: now,\n count: now,\n };\n\n const tasks: Promise<any>[] = [];\n\n tasks.push(\n this.findMany(\n {\n offset,\n limit: limit + 1,\n orderBy,\n ...query,\n },\n opts,\n ).then((it) => {\n timers.query = Date.now() - timers.query;\n return it;\n }),\n );\n\n if (opts.count) {\n const where = isSQLWrapper(query.where)\n ? query.where\n : query.where\n ? this.toSQL(query.where)\n : undefined;\n\n tasks.push(\n this.db.$count(this.table, where as SQL).then((it) => {\n timers.count = Date.now() - timers.count;\n return it;\n }),\n );\n }\n\n const [entities, countResult] = await Promise.all(tasks);\n\n // Normalize orderBy to get sort metadata\n let sortMetadata:\n | Array<{ column: string; direction: \"asc\" | \"desc\" }>\n | undefined;\n if (orderBy) {\n sortMetadata = this.queryManager.normalizeOrderBy(orderBy);\n }\n\n const response = this.queryManager.createPagination<T>(\n entities,\n limit,\n offset,\n sortMetadata,\n );\n\n response.page.totalElements = countResult;\n if (countResult != null) {\n response.page.totalPages = Math.ceil(countResult / limit);\n }\n\n return response as Page<PgStatic<T, R>>;\n }\n\n /**\n * Find an entity by ID.\n *\n * This is a convenience method for `findOne` with a where clause on the primary key.\n * If you need more complex queries, use `findOne` instead.\n */\n public async findById(\n id: string | number,\n opts: StatementOptions = {},\n ): Promise<Static<T>> {\n return await this.findOne(\n {\n where: this.getWhereId(id),\n },\n opts,\n );\n }\n\n /**\n * Helper to create a type-safe query object.\n */\n public createQuery(): PgQuery<T> {\n return {};\n }\n\n /**\n * Helper to create a type-safe where clause.\n */\n public createQueryWhere(): PgQueryWhere<T> {\n return {};\n }\n\n // -------------------------------------------------------------------------------------------------------------------\n\n /**\n * Create an entity.\n *\n * @param data The entity to create.\n * @param opts The options for creating the entity.\n * @returns The ID of the created entity.\n */\n public async create(\n data: Static<TObjectInsert<T>>,\n opts: StatementOptions = {},\n ): Promise<Static<T>> {\n await this.alepha.events.emit(\"repository:create:before\", {\n tableName: this.tableName,\n data,\n });\n\n try {\n const entity = await this.rawInsert(opts)\n .values(this.cast(data ?? {}, true))\n .returning(this.table)\n .then(([it]) => this.clean(it, this.entity.schema));\n\n await this.alepha.events.emit(\"repository:create:after\", {\n tableName: this.tableName,\n data,\n entity,\n });\n\n return entity;\n } catch (error) {\n throw this.handleError(error, \"Insert query has failed\");\n }\n }\n\n /**\n * Create many entities.\n *\n * @param values The entities to create.\n * @param opts The statement options.\n * @returns The created entities.\n */\n public async createMany(\n values: Array<Static<TObjectInsert<T>>>,\n opts: StatementOptions = {},\n ): Promise<Static<T>[]> {\n if (values.length === 0) {\n return [];\n }\n\n await this.alepha.events.emit(\"repository:create:before\", {\n tableName: this.tableName,\n data: values,\n });\n\n try {\n const entities = await this.rawInsert(opts)\n .values(values.map((data) => this.cast(data, true)))\n .returning(this.table)\n .then((rows) => rows.map((it) => this.clean(it, this.entity.schema)));\n\n await this.alepha.events.emit(\"repository:create:after\", {\n tableName: this.tableName,\n data: values,\n entity: entities,\n });\n\n return entities;\n } catch (error) {\n throw this.handleError(error, \"Insert query has failed\");\n }\n }\n\n // -------------------------------------------------------------------------------------------------------------------\n\n /**\n * Find an entity and update it.\n */\n public async updateOne(\n where: PgQueryWhereOrSQL<T>,\n data: Partial<Static<TObjectUpdate<T>>>,\n opts: StatementOptions = {},\n ): Promise<Static<T>> {\n await this.alepha.events.emit(\"repository:update:before\", {\n tableName: this.tableName,\n where,\n data,\n });\n\n let row = data as any;\n\n const updatedAtField = getAttrFields(\n this.entity.schema,\n PG_UPDATED_AT,\n )?.[0];\n\n if (updatedAtField) {\n row[updatedAtField.key] = this.dateTimeProvider\n .of(opts.now)\n .toISOString();\n }\n\n where = this.withDeletedAt(where, opts);\n row = this.cast(row, false) as any;\n\n // do not update the ID field\n delete row[this.id.key];\n\n const response = await this.rawUpdate(opts)\n .set(row)\n .where(this.toSQL(where))\n .returning(this.table)\n .catch((error) => {\n throw this.handleError(error, \"Update query has failed\");\n });\n\n if (!response[0]) {\n throw new DbEntityNotFoundError(this.tableName);\n }\n\n try {\n const entity = this.clean(response[0], this.entity.schema);\n\n await this.alepha.events.emit(\"repository:update:after\", {\n tableName: this.tableName,\n where,\n data,\n entities: [entity],\n });\n\n return entity;\n } catch (error) {\n throw this.handleError(error, \"Update query has failed\");\n }\n }\n\n /**\n * Save a given entity.\n *\n * @example\n * ```ts\n * const entity = await repository.findById(1);\n * entity.name = \"New Name\"; // update a field\n * delete entity.description; // delete a field\n * await repository.save(entity);\n * ```\n *\n * Difference with `updateById/updateOne`:\n *\n * - requires the entity to be fetched first (whole object is expected)\n * - check pg.version() if present -> optimistic locking\n * - validate entity against schema\n * - undefined values will be set to null, not ignored!\n *\n * @see {@link DbVersionMismatchError}\n */\n public async save(\n entity: Static<T>,\n opts: StatementOptions = {},\n ): Promise<void> {\n const row = entity as any;\n\n const id = row[this.id.key];\n if (id == null) {\n throw new AlephaError(\n \"Cannot save entity without ID - missing primary key in value\",\n );\n }\n\n // in save mode, we do not ignore undefined values, but set them to null\n for (const key of Object.keys(this.entity.schema.properties)) {\n if (row[key] === undefined) {\n row[key] = null;\n }\n }\n\n let where: any = this.createQueryWhere();\n\n where.id = { eq: id };\n\n const versionField = getAttrFields(this.entity.schema, PG_VERSION)?.[0];\n if (versionField && typeof row[versionField.key] === \"number\") {\n where = {\n and: [\n where,\n {\n [versionField.key]: {\n eq: row[versionField.key],\n },\n },\n ],\n } as PgQueryWhere<T>;\n\n row[versionField.key] += 1;\n }\n\n try {\n const newValue = await this.updateOne(where, row, opts);\n for (const key of Object.keys(this.entity.schema.properties)) {\n row[key] = undefined;\n }\n Object.assign(row, newValue);\n } catch (error) {\n if (error instanceof DbEntityNotFoundError && versionField) {\n // Verify entity still exists to differentiate between not-found vs version mismatch\n try {\n // If findById succeeds, entity exists and this was a version mismatch\n await this.findById(id);\n throw new DbVersionMismatchError(this.tableName, id);\n } catch (lookupError) {\n // If it's still not found, propagate the original not found error\n if (lookupError instanceof DbEntityNotFoundError) {\n throw error; // Original error\n }\n // If it's a version mismatch error, propagate it\n if (lookupError instanceof DbVersionMismatchError) {\n throw lookupError;\n }\n // Other errors (network, timeout, etc.) should be re-thrown\n throw lookupError;\n }\n }\n throw error;\n }\n }\n\n /**\n * Find an entity by ID and update it.\n */\n public async updateById(\n id: string | number,\n data: Partial<Static<TObjectUpdate<T>>>,\n opts: StatementOptions = {},\n ): Promise<Static<T>> {\n return await this.updateOne(this.getWhereId(id), data, opts);\n }\n\n /**\n * Find many entities and update all of them.\n */\n public async updateMany(\n where: PgQueryWhereOrSQL<T>,\n data: Partial<Static<TObjectUpdate<T>>>,\n opts: StatementOptions = {},\n ): Promise<Array<number | string>> {\n await this.alepha.events.emit(\"repository:update:before\", {\n tableName: this.tableName,\n where,\n data,\n });\n\n const updatedAtField = getAttrFields(\n this.entity.schema,\n PG_UPDATED_AT,\n )?.[0];\n\n if (updatedAtField) {\n (data as any)[updatedAtField.key] = this.dateTimeProvider\n .of(opts.now)\n .toISOString();\n }\n\n where = this.withDeletedAt(where, opts);\n data = this.cast(data, false) as any;\n try {\n const entities = await this.rawUpdate(opts)\n .set(\n data as PgUpdateSetSource<PgTableWithColumns<SchemaToTableConfig<T>>>,\n )\n .where(this.toSQL(where))\n .returning();\n\n await this.alepha.events.emit(\"repository:update:after\", {\n tableName: this.tableName,\n where,\n data,\n entities,\n });\n\n return entities.map((it: any) => it[this.id.key]);\n } catch (error) {\n throw this.handleError(error, \"Update query has failed\");\n }\n }\n\n /**\n * Find many and delete all of them.\n * @returns Array of deleted entity IDs\n */\n public async deleteMany(\n where: PgQueryWhereOrSQL<T> = {},\n opts: StatementOptions = {},\n ): Promise<Array<number | string>> {\n const deletedAt = this.deletedAt();\n if (deletedAt && !opts.force) {\n return await this.updateMany(\n where,\n {\n [deletedAt.key]: opts.now ?? this.dateTimeProvider.nowISOString(),\n } as any,\n opts,\n );\n }\n\n await this.alepha.events.emit(\"repository:delete:before\", {\n tableName: this.tableName,\n where,\n });\n\n try {\n const result = await this.rawDelete(opts)\n .where(this.toSQL(where))\n .returning({ id: (this.table as any)[this.id.key] });\n const ids = result.map((row) => row.id);\n\n await this.alepha.events.emit(\"repository:delete:after\", {\n tableName: this.tableName,\n where,\n ids,\n });\n\n return ids;\n } catch (error) {\n throw new DbError(\"Delete query has failed\", error as Error);\n }\n }\n\n /**\n * Delete all entities.\n * @returns Array of deleted entity IDs\n */\n public clear(opts: StatementOptions = {}): Promise<Array<number | string>> {\n return this.deleteMany({}, opts);\n }\n\n /**\n * Delete the given entity.\n *\n * You must fetch the entity first in order to delete it.\n * @returns Array containing the deleted entity ID\n */\n public async destroy(\n entity: Static<T>,\n opts: StatementOptions = {},\n ): Promise<Array<number | string>> {\n const id = (entity as any)[this.id.key];\n if (id == null) {\n throw new AlephaError(\"Cannot destroy entity without ID\");\n }\n\n const deletedAt = this.deletedAt();\n if (deletedAt && !opts.force) {\n opts.now ??= this.dateTimeProvider.nowISOString();\n (entity as any)[deletedAt.key] = opts.now;\n }\n\n return await this.deleteById(id, opts);\n }\n\n /**\n * Find an entity and delete it.\n * @returns Array of deleted entity IDs (should contain at most one ID)\n */\n public async deleteOne(\n where: PgQueryWhereOrSQL<T> = {},\n opts: StatementOptions = {},\n ): Promise<Array<number | string>> {\n return await this.deleteMany(where, opts);\n }\n\n /**\n * Find an entity by ID and delete it.\n * @returns Array containing the deleted entity ID\n * @throws DbEntityNotFoundError if the entity is not found\n */\n public async deleteById(\n id: string | number,\n opts: StatementOptions = {},\n ): Promise<Array<number | string>> {\n const result = await this.deleteMany(this.getWhereId(id), opts);\n if (result.length === 0) {\n throw new DbEntityNotFoundError(\n `Entity with ID ${id} not found in ${this.tableName}`,\n );\n }\n return result;\n }\n\n /**\n * Count entities.\n */\n public async count(\n where: PgQueryWhereOrSQL<T> = {},\n opts: StatementOptions = {},\n ): Promise<number> {\n where = this.withDeletedAt(where, opts);\n return (opts.tx ?? this.db).$count(this.table, this.toSQL(where));\n }\n\n // -------------------------------------------------------------------------------------------------------------------\n\n protected conflictMessagePattern =\n \"duplicate key value violates unique constraint\";\n\n protected handleError(error: unknown, message: string): DbError {\n if (!(error instanceof Error)) {\n return new DbError(message);\n }\n\n if (\n (error.cause as Error)?.message.includes(this.conflictMessagePattern) ||\n error.message.includes(this.conflictMessagePattern)\n ) {\n return new DbConflictError(message, error);\n }\n\n return new DbError(message, error);\n }\n\n protected withDeletedAt(\n where: PgQueryWhereOrSQL<T>,\n opts: {\n force?: boolean;\n } = {},\n ): PgQueryWhereOrSQL<T> {\n if (opts.force) {\n return where;\n }\n\n const deletedAt = this.deletedAt();\n if (!deletedAt) {\n return where;\n }\n\n return {\n and: [\n where,\n {\n [deletedAt.key]: {\n isNull: true,\n },\n } as any,\n ],\n } as PgQueryWhereOrSQL<T>;\n }\n\n protected deletedAt(): PgAttrField | undefined {\n const deletedAtFields = getAttrFields(this.entity.schema, PG_DELETED_AT);\n if (deletedAtFields.length > 0) {\n return deletedAtFields[0];\n }\n return undefined;\n }\n\n /**\n * Convert something to valid Pg Insert Value.\n */\n protected cast(\n data: any,\n insert: boolean,\n ): PgInsertValue<PgTableWithColumns<SchemaToTableConfig<T>>> {\n const schema = insert\n ? this.entity.insertSchema // insert\n : (t.partial(this.entity.updateSchema) as TObject); // update\n\n return this.alepha.codec.encode(schema, data) as PgInsertValue<\n PgTableWithColumns<SchemaToTableConfig<T>>\n >;\n }\n\n /**\n * Transform a row from the database into a clean entity.\n */\n protected clean<T extends TObject>(\n row: Record<string, unknown>,\n schema: T,\n ): Static<T> {\n for (const key of Object.keys(schema.properties)) {\n const value = schema.properties[key];\n\n // convert PG date-time and date to ISO strings\n if (typeof row[key] === \"string\") {\n if (t.schema.isDateTime(value)) {\n row[key] = this.dateTimeProvider.of(row[key]).toISOString();\n } else if (t.schema.isDate(value)) {\n row[key] = this.dateTimeProvider\n .of(`${row[key]}T00:00:00Z`)\n .toISOString()\n .split(\"T\")[0];\n }\n }\n\n // convert BigInt to string\n if (typeof row[key] === \"bigint\" && t.schema.isBigInt(value)) {\n row[key] = row[key].toString();\n }\n }\n\n return this.alepha.codec.decode(schema, row) as Static<T>;\n }\n\n // -------------------------------------------------------------------------------------------------------------------\n // INTERNAL METHODS\n\n /**\n * Clean a row with joins recursively\n */\n protected cleanWithJoins<T extends TObject>(\n row: Record<string, unknown>,\n schema: T,\n joins: PgJoin[],\n parentPath?: string,\n ): Static<T> {\n // Get joins at this level\n const joinsAtThisLevel = joins.filter((j) => j.parent === parentPath);\n\n // Create a copy of the row for cleaning, removing joined data temporarily\n const cleanRow: Record<string, unknown> = { ...row };\n const joinedData: Record<string, unknown> = {};\n\n for (const join of joinsAtThisLevel) {\n joinedData[join.key] = cleanRow[join.key];\n delete cleanRow[join.key];\n }\n\n // Clean the base entity without joined properties\n const entity = this.clean(cleanRow, schema);\n\n // Then recursively clean joined entities\n for (const join of joinsAtThisLevel) {\n const joinedValue = joinedData[join.key];\n // Only process if the joined value exists\n if (joinedValue != null) {\n // Build path for this join\n const joinPath = parentPath ? `${parentPath}.${join.key}` : join.key;\n // Find child joins\n const childJoins = joins.filter((j) => j.parent === joinPath);\n // Recursively clean if there are child joins\n if (childJoins.length > 0) {\n (entity as any)[join.key] = this.cleanWithJoins(\n joinedValue as Record<string, unknown>,\n join.schema,\n joins,\n joinPath,\n );\n } else {\n // No child joins, just clean this join\n (entity as any)[join.key] = this.clean(\n joinedValue as Record<string, unknown>,\n join.schema,\n );\n }\n } else {\n // Set to undefined if no data\n (entity as any)[join.key] = undefined;\n }\n }\n\n return entity as Static<T>;\n }\n\n /**\n * Convert a where clause to SQL.\n */\n protected toSQL(\n where: PgQueryWhereOrSQL<T>,\n joins?: PgJoin[],\n ): SQL | undefined {\n return this.queryManager.toSQL(where as PgQueryWhereOrSQL<T>, {\n schema: this.entity.schema,\n col: (name) => {\n return this.col(name);\n },\n joins,\n dialect: this.provider.dialect,\n });\n }\n\n /**\n * Get the where clause for an ID.\n *\n * @param id The ID to get the where clause for.\n * @returns The where clause for the ID.\n */\n protected getWhereId(id: string | number): PgQueryWhere<T> {\n return {\n [this.id.key]: {\n eq: t.schema.isString(this.id.type) ? String(id) : Number(id),\n },\n } as PgQueryWhere<T>;\n }\n\n /**\n * Find a primary key in the schema.\n */\n protected getPrimaryKey(schema: TObject) {\n const primaryKeys = getAttrFields(schema, PG_PRIMARY_KEY);\n if (primaryKeys.length === 0) {\n throw new AlephaError(\"Primary key not found in schema\");\n }\n\n if (primaryKeys.length > 1) {\n throw new AlephaError(\n `Multiple primary keys (${primaryKeys.length}) are not supported`,\n );\n }\n\n return {\n key: primaryKeys[0].key,\n col: this.col(primaryKeys[0].key),\n type: primaryKeys[0].type,\n };\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * The options for a statement.\n */\nexport interface StatementOptions {\n /**\n * Transaction to use.\n */\n tx?: PgTransaction<any, Record<string, any>>;\n\n /**\n * Lock strength.\n */\n for?: LockStrength | { config: LockConfig; strength: LockStrength };\n\n /**\n * If true, ignore soft delete.\n */\n force?: boolean;\n\n /**\n * Force the current time.\n */\n now?: DateTime | string;\n}\n","import { $inject, Alepha, type Service, type TObject } from \"alepha\";\nimport type { EntityPrimitive } from \"../primitives/$entity.ts\";\nimport { Repository } from \"../services/Repository.ts\";\nimport type { DatabaseProvider } from \"./drivers/DatabaseProvider.ts\";\n\nexport class RepositoryProvider {\n protected readonly alepha = $inject(Alepha);\n protected readonly registry = new Map<\n EntityPrimitive<any>,\n Service<Repository<any>>\n >();\n\n public getRepositories(provider?: DatabaseProvider) {\n const repositories = this.alepha.services(Repository);\n\n if (provider) {\n return repositories.filter((it) => it.provider === provider);\n }\n\n return repositories;\n }\n\n public getRepository<T extends TObject>(\n entity: EntityPrimitive<T>,\n ): Repository<T> {\n const RepositoryClass = this.createClassRepository(entity);\n return this.alepha.inject(RepositoryClass);\n }\n\n public createClassRepository<T extends TObject>(\n entity: EntityPrimitive<T>,\n ): Service<Repository<T>> {\n let name = entity.name.charAt(0).toUpperCase() + entity.name.slice(1);\n if (name.endsWith(\"s\")) {\n name = name.slice(0, -1);\n }\n name = `${name}Repository`;\n\n if (this.registry.has(entity)) {\n return this.registry.get(entity) as Service<Repository<T>>;\n }\n\n class GenericRepository extends Repository<T> {\n constructor() {\n super(entity);\n }\n }\n\n // for class name to entity.name + \"Repository\"\n Object.defineProperty(GenericRepository, \"name\", { value: name });\n\n this.registry.set(entity, GenericRepository as Service<Repository<T>>);\n\n return GenericRepository;\n }\n}\n","import { $context, $inject, type TObject } from \"alepha\";\nimport { RepositoryProvider } from \"../providers/RepositoryProvider.ts\";\nimport type { Repository } from \"../services/Repository.ts\";\nimport type { EntityPrimitive } from \"./$entity.ts\";\n\n/**\n * Get the repository for the given entity.\n */\nexport const $repository = <T extends TObject>(\n entity: EntityPrimitive<T>,\n): Repository<T> => {\n const { alepha } = $context();\n const repositoryProvider = alepha.inject(RepositoryProvider);\n return $inject(repositoryProvider.createClassRepository(entity));\n};\n","import { createPrimitive, KIND, Primitive } from \"alepha\";\nimport { sql } from \"drizzle-orm\";\nimport type { PgSequenceOptions } from \"drizzle-orm/pg-core\";\nimport { DatabaseProvider } from \"../providers/drivers/DatabaseProvider.ts\";\n\n/**\n * Creates a PostgreSQL sequence primitive for generating unique numeric values.\n */\nexport const $sequence = (\n options: SequencePrimitiveOptions = {},\n): SequencePrimitive => {\n return createPrimitive(SequencePrimitive, options);\n};\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface SequencePrimitiveOptions extends PgSequenceOptions {\n /**\n * The name of the sequence. If not provided, the property key will be used.\n */\n name?: string;\n\n provider?: DatabaseProvider;\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport class SequencePrimitive extends Primitive<SequencePrimitiveOptions> {\n public readonly provider = this.$provider();\n\n public onInit() {\n this.provider.registerSequence(this);\n }\n\n public get name(): string {\n return this.options.name ?? this.config.propertyKey;\n }\n\n public async next(): Promise<number> {\n return this.provider\n .execute(\n sql`SELECT nextval('${sql.raw(this.provider.schema)}.\"${sql.raw(this.name)}\"')`,\n )\n .then((rows) => Number(rows[0]?.nextval));\n }\n\n public async current(): Promise<number> {\n return this.provider\n .execute(\n sql`SELECT last_value FROM ${sql.raw(this.provider.schema)}.\"${sql.raw(this.name)}\"`,\n )\n .then((rows) => Number(rows[0]?.last_value));\n }\n\n protected $provider() {\n return this.options.provider ?? this.alepha.inject(DatabaseProvider);\n }\n}\n\n$sequence[KIND] = SequencePrimitive;\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { createRequire } from \"node:module\";\nimport { $inject, Alepha, AlephaError, type Static, t } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport type * as DrizzleKit from \"drizzle-kit/api\";\nimport { sql } from \"drizzle-orm\";\nimport type { DatabaseProvider } from \"./drivers/DatabaseProvider.ts\";\n\nexport class DrizzleKitProvider {\n protected readonly log = $logger();\n protected readonly alepha = $inject(Alepha);\n\n /**\n * Synchronize database with current schema definitions.\n *\n * In development mode, it will generate and execute migrations based on the current state.\n * In testing mode, it will generate migrations from scratch without applying them.\n *\n * Does nothing in production mode, you must handle migrations manually.\n */\n public async synchronize(provider: DatabaseProvider): Promise<void> {\n if (this.alepha.isProduction()) {\n this.log.warn(\"Synchronization skipped in production mode.\");\n return;\n }\n\n if (provider.schema !== \"public\") {\n await this.createSchemaIfNotExists(provider, provider.schema);\n }\n\n const now = Date.now();\n\n if (this.alepha.isTest()) {\n // -------------------------------------------------------------------------------------------------------------\n // testing area, generate migrations from scratch - no need to push schema\n const { statements } = await this.generateMigration(provider);\n await this.executeStatements(statements, provider);\n } else {\n // -------------------------------------------------------------------------------------------------------------\n // development area, generate migrations based on the current state\n const entry = await this.loadDevMigrations(provider);\n const { statements, snapshot } = await this.generateMigration(\n provider,\n entry?.snapshot ? JSON.parse(entry.snapshot) : undefined,\n );\n await this.executeStatements(statements, provider, true);\n await this.saveDevMigrations(provider, snapshot, entry);\n }\n\n this.log.info(\n `Db '${provider.name}' synchronization OK [${Date.now() - now}ms]`,\n );\n }\n\n /**\n * Mostly used for testing purposes. You can generate SQL migration statements without executing them.\n */\n public async generateMigration(\n provider: DatabaseProvider,\n prevSnapshot?: any,\n ): Promise<{\n statements: string[];\n models: Record<string, unknown>;\n snapshot?: any;\n }> {\n // import Drizzle Kit API\n const kit = this.importDrizzleKit();\n\n // load all models related to the given database connection provider\n const models = this.getModels(provider);\n\n // generate and return migrations if there are models\n if (Object.keys(models).length > 0) {\n if (provider.dialect === \"sqlite\") {\n const prev = prevSnapshot ?? (await kit.generateSQLiteDrizzleJson({}));\n const curr = await kit.generateSQLiteDrizzleJson(models);\n return {\n models,\n statements: await kit.generateSQLiteMigration(prev, curr),\n snapshot: curr,\n };\n }\n\n const prev = prevSnapshot ?? (await kit.generateDrizzleJson({}));\n const curr = await kit.generateDrizzleJson(models);\n return {\n models,\n statements: await kit.generateMigration(prev, curr),\n snapshot: curr,\n };\n }\n\n return {\n models,\n statements: [],\n snapshot: {},\n };\n }\n\n // -------------------------------------------------------------------------------------------------------------------\n\n /**\n * Load all tables, enums, sequences, etc. from the provider's repositories.\n */\n public getModels(provider: DatabaseProvider): Record<string, unknown> {\n const models: Record<string, unknown> = {};\n for (const [key, value] of provider.tables.entries()) {\n if (models[key]) {\n throw new AlephaError(\n `Model name conflict: '${key}' is already defined.`,\n );\n }\n models[key] = value;\n }\n for (const [key, value] of provider.enums.entries()) {\n if (models[key]) {\n throw new AlephaError(\n `Model name conflict: '${key}' is already defined.`,\n );\n }\n models[key] = value;\n }\n for (const [key, value] of provider.sequences.entries()) {\n if (models[key]) {\n throw new AlephaError(\n `Model name conflict: '${key}' is already defined.`,\n );\n }\n models[key] = value;\n }\n return models;\n }\n\n // -------------------------------------------------------------------------------------------------------------------\n\n /**\n * Load the migration snapshot from the database.\n */\n protected async loadDevMigrations(\n provider: DatabaseProvider,\n ): Promise<DevMigrations | undefined> {\n const name =\n `${this.alepha.env.APP_NAME ?? \"APP\"}-${provider.constructor.name}`.toLowerCase();\n\n if (provider.url.includes(\":memory:\")) {\n this.log.trace(\n `In-memory database detected for '${name}', skipping migration snapshot load.`,\n );\n return;\n }\n\n if (provider.dialect === \"sqlite\") {\n try {\n const text = await readFile(\n `node_modules/.alepha/sqlite-${name}.json`,\n \"utf-8\",\n );\n return this.alepha.codec.decode(devMigrationsSchema, text);\n } catch (e) {\n this.log.trace(`No existing migration snapshot for '${name}'`, e);\n }\n return;\n }\n\n await provider.execute(sql`CREATE SCHEMA IF NOT EXISTS \"drizzle\";`);\n await provider.execute(sql`\n\t\t\t\t\tCREATE TABLE IF NOT EXISTS \"drizzle\".\"__drizzle_dev_migrations\" (\n\t\t\t\t\t\t\"id\" SERIAL PRIMARY KEY,\n\t\t\t\t\t\t\"name\" TEXT NOT NULL,\n\t\t\t\t\t\t\"created_at\" TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n\t\t\t\t\t\t\"snapshot\" TEXT NOT NULL\n\t\t\t\t\t);\n\t\t\t\t`);\n\n const rows = await provider.run(\n sql`SELECT * FROM \"drizzle\".\"__drizzle_dev_migrations\" WHERE \"name\" = ${name} LIMIT 1`,\n devMigrationsSchema,\n );\n\n if (rows.length === 0) {\n this.log.trace(`No existing migration snapshot for '${name}'`);\n return;\n }\n\n return this.alepha.codec.decode(devMigrationsSchema, rows[0]);\n }\n\n protected async saveDevMigrations(\n provider: DatabaseProvider,\n curr: Record<string, any>,\n devMigrations?: DevMigrations,\n ) {\n if (provider.url.includes(\":memory:\")) {\n this.log.trace(\n `In-memory database detected for '${provider.constructor.name}', skipping migration snapshot save.`,\n );\n return;\n }\n\n const name =\n `${this.alepha.env.APP_NAME ?? \"APP\"}-${provider.constructor.name}`.toLowerCase();\n if (provider.dialect === \"sqlite\") {\n const filePath = `node_modules/.alepha/sqlite-${name}.json`;\n await mkdir(\"node_modules/.alepha\", { recursive: true }).catch(\n () => null,\n );\n await writeFile(\n filePath,\n JSON.stringify(\n {\n id: devMigrations?.id ?? 1,\n name,\n created_at: new Date(),\n snapshot: JSON.stringify(curr),\n },\n null,\n 2,\n ),\n );\n this.log.debug(`Saved migration snapshot to '${filePath}'`);\n return;\n }\n\n if (!devMigrations) {\n await provider.execute(\n sql`INSERT INTO \"drizzle\".\"__drizzle_dev_migrations\" (\"name\", \"snapshot\") VALUES (${name}, ${JSON.stringify(curr)})`,\n );\n } else {\n const newSnapshot = JSON.stringify(curr);\n if (devMigrations.snapshot !== newSnapshot) {\n await provider.execute(\n sql`UPDATE \"drizzle\".\"__drizzle_dev_migrations\" SET \"snapshot\" = ${newSnapshot} WHERE \"id\" = ${devMigrations.id}`,\n );\n }\n }\n }\n\n protected async executeStatements(\n statements: string[],\n provider: DatabaseProvider,\n catchErrors = false,\n ) {\n let nErrors = 0;\n for (const statement of statements) {\n // skip drop schema statements to avoid accidental data loss\n if (statement.startsWith(\"DROP SCHEMA\")) {\n continue;\n }\n\n try {\n await provider.execute(sql.raw(statement));\n } catch (error) {\n const errorMessage = `Error executing statement: ${statement}`;\n if (catchErrors) {\n nErrors++;\n this.log.warn(errorMessage, { context: [error] });\n } else {\n throw error;\n }\n }\n }\n if (nErrors > 0) {\n this.log.warn(\n `Executed ${statements.length} statements with ${nErrors} errors.`,\n );\n }\n }\n\n // -------------------------------------------------------------------------------------------------------------------\n\n protected async createSchemaIfNotExists(\n provider: DatabaseProvider,\n schemaName: string,\n ) {\n // Validate schema name to prevent SQL injection\n if (!/^[a-z0-9_]+$/i.test(schemaName)) {\n throw new Error(\n `Invalid schema name: ${schemaName}. Must only contain alphanumeric characters and underscores.`,\n );\n }\n\n const sqlSchema = sql.raw(schemaName);\n\n if (schemaName.startsWith(\"test_\")) {\n this.log.info(`Drop test schema '${schemaName}' ...`, schemaName);\n await provider.execute(sql`DROP SCHEMA IF EXISTS ${sqlSchema} CASCADE`);\n }\n\n // create schema if not exists\n this.log.debug(`Ensuring schema '${schemaName}' exists`);\n await provider.execute(sql`CREATE SCHEMA IF NOT EXISTS ${sqlSchema}`);\n }\n\n // -------------------------------------------------------------------------------------------------------------------\n\n /**\n * Try to load the official Drizzle Kit API.\n * If not available, fallback to the local kit import.\n */\n public importDrizzleKit(): typeof DrizzleKit {\n try {\n return createRequire(import.meta.url)(\"drizzle-kit/api\");\n } catch (_) {\n throw new Error(\n \"Drizzle Kit is not installed. Please install it with `npm install -D drizzle-kit`.\",\n );\n }\n }\n}\n\nconst devMigrationsSchema = t.object({\n id: t.number(),\n name: t.text(),\n snapshot: t.string(),\n created_at: t.string(),\n});\n\ntype DevMigrations = Static<typeof devMigrationsSchema>;\n","import { DbError } from \"./DbError.ts\";\n\nexport class DbMigrationError extends DbError {\n readonly name = \"DbMigrationError\";\n\n constructor(cause?: unknown) {\n super(\"Failed to migrate database\", cause);\n }\n}\n","import { customType } from \"drizzle-orm/pg-core\";\n\n/**\n * Postgres bytea type.\n */\nexport const byte = customType<{\n data: Buffer;\n}>({\n dataType: () => \"bytea\",\n});\n","import type { SQL } from \"drizzle-orm\";\nimport type { EntityPrimitive } from \"../primitives/$entity.ts\";\nimport type { SequencePrimitive } from \"../primitives/$sequence.ts\";\n\n/**\n * Database-specific table configuration functions\n */\nexport interface TableConfigBuilders<TConfig> {\n index: (name: string) => {\n on: (...columns: any[]) => TConfig;\n };\n uniqueIndex: (name: string) => {\n on: (...columns: any[]) => TConfig;\n };\n unique: (name: string) => {\n on: (...columns: any[]) => TConfig;\n };\n check: (name: string, sql: SQL) => TConfig;\n foreignKey: (config: {\n name: string;\n columns: any[];\n foreignColumns: any[];\n }) => TConfig;\n}\n\n/**\n * Abstract base class for transforming Alepha Primitives (Entity, Sequence, etc...)\n * into drizzle models (tables, enums, sequences, etc...).\n */\nexport abstract class ModelBuilder {\n /**\n * Build a table from an entity primitive.\n */\n abstract buildTable(\n entity: EntityPrimitive,\n options: {\n tables: Map<string, unknown>;\n enums: Map<string, unknown>;\n schema: string;\n },\n ): void;\n\n /**\n * Build a sequence from a sequence primitive.\n */\n abstract buildSequence(\n sequence: SequencePrimitive,\n options: {\n sequences: Map<string, unknown>;\n schema: string;\n },\n ): void;\n\n /**\n * Convert camelCase to snake_case for column names.\n */\n protected toColumnName(str: string): string {\n return (\n str[0].toLowerCase() +\n str.slice(1).replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`)\n );\n }\n\n /**\n * Build the table configuration function for any database.\n * This includes indexes, foreign keys, constraints, and custom config.\n *\n * @param entity - The entity primitive\n * @param builders - Database-specific builder functions\n * @param tableResolver - Function to resolve entity references to table columns\n * @param customConfigHandler - Optional handler for custom config\n */\n protected buildTableConfig<TConfig, TSelf>(\n entity: EntityPrimitive,\n builders: TableConfigBuilders<TConfig>,\n tableResolver?: (entityName: string) => any,\n customConfigHandler?: (config: any, self: TSelf) => TConfig[],\n ): ((self: TSelf) => TConfig[]) | undefined {\n // If no extra config is needed, return undefined\n if (\n !entity.options.indexes &&\n !entity.options.foreignKeys &&\n !entity.options.constraints &&\n !entity.options.config\n ) {\n return undefined;\n }\n\n return (self: TSelf) => {\n const configs: TConfig[] = [];\n\n // Build indexes\n if (entity.options.indexes) {\n for (const indexDef of entity.options.indexes) {\n if (typeof indexDef === \"string\") {\n const columnName = this.toColumnName(indexDef);\n const indexName = `${entity.name}_${columnName}_idx`;\n\n // Use original camelCase property name for lookup\n if ((self as any)[indexDef]) {\n configs.push(\n builders.index(indexName).on((self as any)[indexDef]),\n );\n }\n } else if (typeof indexDef === \"object\" && indexDef !== null) {\n if (\"column\" in indexDef) {\n const columnName = this.toColumnName(indexDef.column as string);\n const indexName =\n indexDef.name || `${entity.name}_${columnName}_idx`;\n\n // Use original camelCase property name for lookup\n if ((self as any)[indexDef.column]) {\n if (indexDef.unique) {\n configs.push(\n builders\n .uniqueIndex(indexName)\n .on((self as any)[indexDef.column]),\n );\n } else {\n configs.push(\n builders\n .index(indexName)\n .on((self as any)[indexDef.column]),\n );\n }\n }\n } else if (\"columns\" in indexDef) {\n const columnNames = indexDef.columns.map((col: any) =>\n this.toColumnName(col as string),\n );\n const indexName =\n indexDef.name || `${entity.name}_${columnNames.join(\"_\")}_idx`;\n\n // Use original camelCase property names for lookup\n const cols = indexDef.columns\n .map((col: any) => (self as any)[col])\n .filter(Boolean);\n\n if (cols.length === indexDef.columns.length) {\n if (indexDef.unique) {\n configs.push(builders.uniqueIndex(indexName).on(...cols));\n } else {\n configs.push(builders.index(indexName).on(...cols));\n }\n }\n }\n }\n }\n }\n\n // Build foreign keys\n if (entity.options.foreignKeys) {\n for (const fkDef of entity.options.foreignKeys) {\n const columnNames = fkDef.columns.map((col) =>\n this.toColumnName(col as string),\n );\n\n // Use original camelCase property names for lookup\n const cols = fkDef.columns\n .map((col) => (self as any)[col])\n .filter(Boolean);\n\n if (cols.length === fkDef.columns.length) {\n const fkName =\n fkDef.name || `${entity.name}_${columnNames.join(\"_\")}_fk`;\n\n // Resolve foreign column references\n const foreignColumns = fkDef.foreignColumns.map((colRef) => {\n const entityCol = colRef();\n if (!entityCol || !entityCol.entity || !entityCol.name) {\n throw new Error(\n `Invalid foreign column reference in ${entity.name}`,\n );\n }\n\n // If we have a table resolver, use it to get the actual table column\n if (tableResolver) {\n const foreignTable = tableResolver(entityCol.entity.name);\n if (!foreignTable) {\n throw new Error(\n `Foreign table ${entityCol.entity.name} not found for ${entity.name}`,\n );\n }\n // Use original camelCase property name for lookup in foreign table\n return foreignTable[entityCol.name];\n }\n\n // Fallback: return the entity column reference (will be resolved later)\n return entityCol;\n });\n\n configs.push(\n builders.foreignKey({\n name: fkName,\n columns: cols,\n foreignColumns,\n }),\n );\n }\n }\n }\n\n // Build constraints\n if (entity.options.constraints) {\n for (const constraintDef of entity.options.constraints) {\n const columnNames = constraintDef.columns.map((col) =>\n this.toColumnName(col as string),\n );\n\n // Use original camelCase property names for lookup\n const cols = constraintDef.columns\n .map((col) => (self as any)[col])\n .filter(Boolean);\n\n if (cols.length === constraintDef.columns.length) {\n if (constraintDef.unique) {\n const constraintName =\n constraintDef.name ||\n `${entity.name}_${columnNames.join(\"_\")}_unique`;\n\n configs.push(builders.unique(constraintName).on(...cols));\n }\n\n if (constraintDef.check) {\n const constraintName =\n constraintDef.name ||\n `${entity.name}_${columnNames.join(\"_\")}_check`;\n\n configs.push(builders.check(constraintName, constraintDef.check));\n }\n }\n }\n }\n\n // Add custom config if provided\n if (entity.options.config && customConfigHandler) {\n configs.push(...customConfigHandler(entity.options.config, self));\n } else if (entity.options.config) {\n // Default behavior: call the config function directly\n const customConfigs = entity.options.config(self as any);\n if (Array.isArray(customConfigs)) {\n configs.push(...(customConfigs as any));\n }\n }\n\n return configs;\n };\n }\n}\n","import { AlephaError, type TObject, type TSchema, t } from \"alepha\";\nimport type { BuildExtraConfigColumns } from \"drizzle-orm\";\nimport * as pg from \"drizzle-orm/pg-core\";\nimport {\n check,\n foreignKey,\n index,\n type PgEnum,\n type PgSchema,\n type PgTableExtraConfigValue,\n type PgTableWithColumns,\n pgEnum,\n pgSchema,\n pgTable,\n unique,\n uniqueIndex,\n} from \"drizzle-orm/pg-core\";\nimport {\n PG_CREATED_AT,\n PG_ENUM,\n PG_IDENTITY,\n PG_PRIMARY_KEY,\n PG_REF,\n PG_SERIAL,\n PG_UPDATED_AT,\n type PgEnumOptions,\n type PgIdentityOptions,\n type PgRefOptions,\n} from \"../constants/PG_SYMBOLS.ts\";\nimport type { EntityPrimitive, FromSchema } from \"../primitives/$entity.ts\";\nimport type { SequencePrimitive } from \"../primitives/$sequence.ts\";\nimport { byte } from \"../types/byte.ts\";\nimport { schema } from \"../types/schema.ts\";\nimport { ModelBuilder } from \"./ModelBuilder.ts\";\n\nexport class PostgresModelBuilder extends ModelBuilder {\n protected schemas = new Map<string, PgSchema>();\n\n protected getPgSchema(name: string) {\n if (!this.schemas.has(name) && name !== \"public\") {\n this.schemas.set(name, pgSchema(name));\n }\n\n const nsp =\n name !== \"public\"\n ? this.schemas.get(name)\n : ({\n enum: pgEnum,\n table: pgTable,\n } as any);\n\n if (!nsp) {\n throw new AlephaError(`Postgres schema ${name} not found`);\n }\n\n return nsp;\n }\n\n public buildTable(\n entity: EntityPrimitive<any>,\n options: {\n tables: Map<string, unknown>;\n enums: Map<string, unknown>;\n schema: string;\n },\n ) {\n const tableName = entity.name;\n if (options.tables.has(tableName)) {\n return;\n }\n\n const nsp = this.getPgSchema(options.schema);\n\n const columns = this.schemaToPgColumns(\n tableName,\n entity.schema,\n nsp,\n options.enums,\n options.tables,\n );\n\n // Build the config function that includes indexes, foreign keys, constraints, and custom config\n const configFn = this.getTableConfig(entity, options.tables);\n\n const table = nsp.table(tableName, columns, configFn);\n\n options.tables.set(tableName, table);\n }\n\n public buildSequence(\n sequence: SequencePrimitive,\n options: {\n sequences: Map<string, unknown>;\n schema: string;\n },\n ) {\n const sequenceName = sequence.name;\n if (options.sequences.has(sequenceName)) {\n return;\n }\n\n const nsp = this.getPgSchema(options.schema);\n\n options.sequences.set(\n sequenceName,\n nsp.sequence(sequenceName, sequence.options),\n );\n }\n\n // -------------------------------------------------------------------------------------------------------------------\n\n /**\n * Get PostgreSQL-specific config builder for the table.\n */\n protected getTableConfig(\n entity: EntityPrimitive,\n tables: Map<string, unknown>,\n ):\n | ((\n self: BuildExtraConfigColumns<string, any, \"pg\">,\n ) => PgTableExtraConfigValue[])\n | undefined {\n // PostgreSQL-specific builders\n const pgBuilders = {\n index,\n uniqueIndex,\n unique,\n check,\n foreignKey,\n };\n\n // Table resolver function\n const tableResolver = (entityName: string) => {\n return tables.get(entityName) as any;\n };\n\n return this.buildTableConfig<\n PgTableExtraConfigValue,\n BuildExtraConfigColumns<string, any, \"pg\">\n >(entity, pgBuilders as any, tableResolver);\n }\n\n schemaToPgColumns = <T extends TObject>(\n tableName: string,\n schema: T,\n nsp: PgSchema,\n enums: Map<string, unknown>,\n tables: Map<string, unknown>,\n ): FromSchema<T> => {\n return Object.entries(schema.properties).reduce<Partial<FromSchema<T>>>(\n (columns, [key, value]) => {\n let col = this.mapFieldToColumn(tableName, key, value, nsp, enums);\n\n if (\"default\" in value && value.default != null) {\n col = col.default(value.default as any);\n }\n\n if (PG_PRIMARY_KEY in value) {\n col = col.primaryKey();\n }\n\n if (PG_REF in value) {\n const config = value[PG_REF] as PgRefOptions;\n col = col.references(() => {\n const ref = config.ref();\n const table = tables.get(\n ref.entity.name,\n ) as PgTableWithColumns<any>;\n\n if (!table) {\n throw new AlephaError(\n `Referenced table ${ref.entity.name} not found for ${tableName}.${key}`,\n );\n }\n\n const target = table[ref.name];\n if (!target) {\n throw new AlephaError(\n `Referenced column ${ref.name} not found in table ${ref.entity.name} for ${tableName}.${key}`,\n );\n }\n\n return target;\n }, config.actions);\n }\n\n if (schema.required?.includes(key)) {\n col = col.notNull();\n }\n\n return {\n ...columns,\n [key]: col,\n };\n },\n {},\n ) as FromSchema<T>;\n };\n\n mapFieldToColumn = (\n tableName: string,\n fieldName: string,\n value: TSchema,\n nsp: PgSchema,\n enums: Map<string, any>,\n ) => {\n const key = this.toColumnName(fieldName);\n\n if (\n // is nullish ?\n \"anyOf\" in value &&\n Array.isArray(value.anyOf) &&\n value.anyOf.length === 2 &&\n value.anyOf.some((it: TSchema) => t.schema.isNull(it))\n ) {\n // then, remove nullish\n value = value.anyOf.find((it: TSchema) => !t.schema.isNull(it))!;\n }\n\n if (t.schema.isInteger(value)) {\n if (PG_SERIAL in value) {\n return pg.serial(key);\n }\n\n if (PG_IDENTITY in value) {\n const options = value[PG_IDENTITY] as PgIdentityOptions;\n if (options.mode === \"byDefault\") {\n return pg.integer().generatedByDefaultAsIdentity(options);\n }\n return pg.integer().generatedAlwaysAsIdentity(options);\n }\n\n return pg.integer(key);\n }\n\n if (t.schema.isBigInt(value)) {\n if (PG_IDENTITY in value) {\n const options = value[PG_IDENTITY] as PgIdentityOptions;\n if (options.mode === \"byDefault\") {\n return pg\n .bigint({ mode: \"bigint\" })\n .generatedByDefaultAsIdentity(options);\n }\n return pg.bigint({ mode: \"bigint\" }).generatedAlwaysAsIdentity(options);\n }\n }\n\n if (t.schema.isNumber(value)) {\n if (PG_IDENTITY in value) {\n const options = value[PG_IDENTITY] as PgIdentityOptions;\n if (options.mode === \"byDefault\") {\n return pg\n .bigint({ mode: \"number\" })\n .generatedByDefaultAsIdentity(options);\n }\n return pg.bigint({ mode: \"number\" }).generatedAlwaysAsIdentity(options);\n }\n\n if (value.format === \"int64\") {\n return pg.bigint(key, { mode: \"number\" });\n }\n\n return pg.numeric(key);\n }\n\n if (t.schema.isString(value)) {\n return this.mapStringToColumn(key, value);\n }\n\n if (t.schema.isBoolean(value)) {\n return pg.boolean(key);\n }\n\n if (t.schema.isObject(value)) {\n return schema(key, value);\n }\n\n if (t.schema.isRecord(value)) {\n return schema(key, value);\n }\n\n if (t.schema.isArray(value)) {\n if (t.schema.isObject(value.items)) {\n return schema(key, value);\n }\n if (t.schema.isRecord(value.items)) {\n return schema(key, value);\n }\n if (t.schema.isString(value.items)) {\n return pg.text(key).array();\n }\n if (t.schema.isInteger(value.items)) {\n return pg.integer(key).array();\n }\n if (t.schema.isNumber(value.items)) {\n return pg.numeric(key).array();\n }\n if (t.schema.isBoolean(value.items)) {\n return pg.boolean(key).array();\n }\n }\n\n // Enum handling\n if (\n t.schema.isUnsafe(value) &&\n \"type\" in value &&\n value.type === \"string\" &&\n \"enum\" in value &&\n Array.isArray(value.enum)\n ) {\n if (!value.enum.every((it) => typeof it === \"string\")) {\n throw new AlephaError(\n `Enum for ${fieldName} must be an array of strings, got ${JSON.stringify(\n value.enum,\n )}`,\n );\n }\n\n // SQL Enum\n if (PG_ENUM in value && value[PG_ENUM]) {\n const options = value[PG_ENUM] as PgEnumOptions;\n const enumName = options.name ?? `${tableName}_${key}_enum`;\n\n if (enums.has(enumName)) {\n const values = (\n enums.get(enumName) as PgEnum<[string]>\n ).enumValues.join(\",\");\n const newValues = value.enum.join(\",\");\n if (values !== newValues) {\n throw new AlephaError(\n `Enum name conflict for ${enumName}: [${values}] vs [${newValues}]`,\n );\n }\n }\n\n enums.set(enumName, nsp.enum(enumName, value.enum as [string]));\n\n return enums.get(enumName)(key);\n }\n\n // else, map to TEXT\n return this.mapStringToColumn(key, value);\n }\n\n throw new AlephaError(\n `Unsupported schema type for ${fieldName} as ${JSON.stringify(value)}`,\n );\n };\n\n /**\n * Map a string to a PG column.\n *\n * @param key The key of the field.\n * @param value The value of the field.\n */\n mapStringToColumn = (key: string, value: TSchema) => {\n if (\"format\" in value) {\n if (value.format === \"uuid\") {\n if (PG_PRIMARY_KEY in value) {\n return pg.uuid(key).defaultRandom();\n }\n\n return pg.uuid(key);\n }\n\n if (value.format === \"byte\") {\n return byte(key);\n }\n\n if (value.format === \"date-time\") {\n if (PG_CREATED_AT in value) {\n return pg\n .timestamp(key, { mode: \"string\", withTimezone: true })\n .defaultNow();\n }\n if (PG_UPDATED_AT in value) {\n return pg\n .timestamp(key, { mode: \"string\", withTimezone: true })\n .defaultNow();\n }\n return pg.timestamp(key, { mode: \"string\", withTimezone: true });\n }\n\n if (value.format === \"date\") {\n return pg.date(key, { mode: \"string\" });\n }\n }\n\n return pg.text(key);\n };\n}\n","import { $env, $hook, $inject, AlephaError, type Static, t } from \"alepha\";\nimport { $lock } from \"alepha/lock\";\nimport { $logger } from \"alepha/logger\";\nimport { sql } from \"drizzle-orm\";\nimport type { PostgresJsDatabase } from \"drizzle-orm/postgres-js\";\nimport { drizzle } from \"drizzle-orm/postgres-js\";\nimport { migrate } from \"drizzle-orm/postgres-js/migrator\";\nimport postgres from \"postgres\";\nimport { DbError } from \"../../errors/DbError.ts\";\nimport { DbMigrationError } from \"../../errors/DbMigrationError.ts\";\nimport { PostgresModelBuilder } from \"../../services/PostgresModelBuilder.ts\";\nimport { DrizzleKitProvider } from \"../DrizzleKitProvider.ts\";\nimport { DatabaseProvider, type SQLLike } from \"./DatabaseProvider.ts\";\n\ndeclare module \"alepha\" {\n interface Env extends Partial<Static<typeof envSchema>> {}\n}\n\nconst envSchema = t.object({\n /**\n * Main configuration for database connection.\n * Accept a string in the format of a Postgres connection URL.\n * Example: postgres://user:password@localhost:5432/database\n * or\n * Example: postgres://user:password@localhost:5432/database?sslmode=require\n */\n DATABASE_URL: t.optional(t.text()),\n\n /**\n * In addition to the DATABASE_URL, you can specify the postgres schema name.\n *\n * It will monkey patch drizzle tables.\n */\n POSTGRES_SCHEMA: t.optional(t.text()),\n});\n\nexport class NodePostgresProvider extends DatabaseProvider {\n static readonly SSL_MODES = [\n \"require\",\n \"allow\",\n \"prefer\",\n \"verify-full\",\n ] as const;\n\n protected readonly log = $logger();\n protected readonly env = $env(envSchema);\n protected readonly kit = $inject(DrizzleKitProvider);\n protected readonly builder = $inject(PostgresModelBuilder);\n protected client?: postgres.Sql;\n protected pg?: PostgresJsDatabase;\n\n public readonly dialect = \"postgresql\";\n\n public get name() {\n return \"postgres\";\n }\n\n /**\n * In testing mode, the schema name will be generated and deleted after the test.\n */\n protected schemaForTesting = this.alepha.isTest()\n ? this.env.POSTGRES_SCHEMA?.startsWith(\"test_\")\n ? this.env.POSTGRES_SCHEMA\n : this.generateTestSchemaName()\n : undefined;\n\n public override get url() {\n if (!this.env.DATABASE_URL) {\n throw new AlephaError(\"DATABASE_URL is not defined in the environment\");\n }\n\n return this.env.DATABASE_URL;\n }\n\n /**\n * Execute a SQL statement.\n */\n public override execute(\n statement: SQLLike,\n ): Promise<Array<Record<string, unknown>>> {\n try {\n return this.db.execute(statement);\n } catch (error) {\n throw new DbError(\"Error executing statement\", error);\n }\n }\n\n /**\n * Get Postgres schema used by this provider.\n */\n public override get schema(): string {\n if (this.schemaForTesting) {\n return this.schemaForTesting;\n }\n\n if (this.env.POSTGRES_SCHEMA) {\n return this.env.POSTGRES_SCHEMA;\n }\n\n return \"public\";\n }\n\n /**\n * Get the Drizzle Postgres database instance.\n */\n public override get db(): PostgresJsDatabase {\n if (!this.pg) {\n throw new AlephaError(\"Database not initialized\");\n }\n\n return this.pg;\n }\n\n protected override async executeMigrations(\n migrationsFolder: string,\n ): Promise<void> {\n await migrate(this.db, { migrationsFolder });\n }\n\n // -------------------------------------------------------------------------------------------------------------------\n\n protected readonly onStart = $hook({\n on: \"start\",\n handler: async () => {\n await this.connect();\n\n // never migrate in serverless mode (vercel, netlify, ...)\n if (!this.alepha.isServerless()) {\n try {\n await this.migrate.run();\n } catch (error) {\n throw new DbMigrationError(error);\n }\n }\n },\n });\n\n protected readonly onStop = $hook({\n on: \"stop\",\n handler: async () => {\n // cleanup test schema\n if (\n this.alepha.isTest() &&\n this.schemaForTesting &&\n this.schemaForTesting.startsWith(\"test_\")\n ) {\n // Additional validation: schema name must only contain safe characters\n if (!/^test_[a-z0-9_]+$/i.test(this.schemaForTesting)) {\n throw new AlephaError(\n `Invalid test schema name: ${this.schemaForTesting}. Must match pattern: test_[a-z0-9_]+`,\n );\n }\n\n this.log.warn(`Deleting test schema '${this.schemaForTesting}' ...`);\n // Use sql.raw without quotes (Drizzle handles identifier escaping)\n await this.execute(\n sql`DROP SCHEMA IF EXISTS ${sql.raw(this.schemaForTesting)} CASCADE`,\n );\n this.log.info(`Test schema '${this.schemaForTesting}' deleted`);\n }\n\n // close the connection\n await this.close();\n },\n });\n\n public async connect(): Promise<void> {\n this.log.debug(\"Connect ..\");\n\n const client = postgres(this.getClientOptions());\n await client`SELECT 1`; // test connection\n\n this.client = client;\n this.pg = drizzle(client, {\n logger: {\n // forward logs\n logQuery: (query: string, params: unknown[]) => {\n this.log.trace(query, { params });\n },\n },\n });\n\n this.log.info(\"Connection OK\");\n }\n\n public async close(): Promise<void> {\n if (this.client) {\n this.log.debug(\"Close...\");\n\n await this.client.end();\n\n this.client = undefined;\n this.pg = undefined;\n\n this.log.info(\"Connection closed\");\n }\n }\n\n protected migrate = $lock({\n handler: async () => {\n await this.migrateDatabase();\n },\n });\n\n /**\n * Map the DATABASE_URL to postgres client options.\n */\n protected getClientOptions(): postgres.Options<any> {\n const url = new URL(this.url);\n\n return {\n host: url.hostname,\n user: decodeURIComponent(url.username),\n database: decodeURIComponent(url.pathname.replace(\"/\", \"\")),\n password: decodeURIComponent(url.password),\n port: Number(url.port || 5432),\n ssl: this.ssl(url),\n onnotice: () => {\n // let drizzle handle logs\n },\n };\n }\n\n protected ssl(\n url: URL,\n ): \"require\" | \"allow\" | \"prefer\" | \"verify-full\" | undefined {\n const mode = url.searchParams.get(\"sslmode\");\n for (const it of NodePostgresProvider.SSL_MODES) {\n if (mode === it) {\n return it;\n }\n }\n }\n\n // -------------------------------------------------------------------------------------------------------------------\n\n /**\n * For testing purposes, generate a unique schema name.\n * The schema name will be generated based on the current date and time.\n * It will be in the format of `test_YYYYMMDD_HHMMSS_randomSuffix`.\n */\n protected generateTestSchemaName(): string {\n const pad = (n: number) => n.toString().padStart(2, \"0\");\n\n const now = new Date();\n const year = now.getUTCFullYear();\n const month = pad(now.getUTCMonth() + 1);\n const day = pad(now.getUTCDate());\n const hours = pad(now.getUTCHours());\n const minutes = pad(now.getUTCMinutes());\n const seconds = pad(now.getUTCSeconds());\n\n const timestamp = `${year}${month}${day}_${hours}${minutes}${seconds}`;\n\n const randomSuffix = Math.random().toString(36).slice(2, 6); // 4 alphanumeric chars\n\n return `test_${timestamp}_${randomSuffix}`;\n }\n}\n","import { randomUUID } from \"node:crypto\";\nimport {\n AlephaError,\n type Static,\n type TObject,\n type TSchema,\n type TString,\n t,\n} from \"alepha\";\nimport { type BuildColumns, sql } from \"drizzle-orm\";\nimport * as pg from \"drizzle-orm/sqlite-core\";\nimport {\n check,\n foreignKey,\n index,\n type SQLiteColumnBuilderBase,\n type SQLiteTableWithColumns,\n sqliteTable,\n unique,\n uniqueIndex,\n} from \"drizzle-orm/sqlite-core\";\nimport {\n PG_CREATED_AT,\n PG_IDENTITY,\n PG_PRIMARY_KEY,\n PG_REF,\n PG_SERIAL,\n PG_UPDATED_AT,\n type PgRefOptions,\n} from \"../constants/PG_SYMBOLS.ts\";\nimport type { EntityPrimitive } from \"../primitives/$entity.ts\";\nimport type { SequencePrimitive } from \"../primitives/$sequence.ts\";\nimport { ModelBuilder } from \"./ModelBuilder.ts\";\n\nexport class SqliteModelBuilder extends ModelBuilder {\n public buildTable(\n entity: EntityPrimitive<any>,\n options: {\n tables: Map<string, unknown>;\n enums: Map<string, unknown>;\n schema: string;\n },\n ) {\n const tableName = entity.name;\n if (options.tables.has(tableName)) {\n return;\n }\n\n const columns = this.schemaToSqliteColumns(\n tableName,\n entity.schema,\n options.enums,\n options.tables,\n );\n\n // Build the config function for SQLite\n const configFn = this.getTableConfig(entity, options.tables);\n\n const table = sqliteTable(tableName, columns, configFn);\n\n options.tables.set(tableName, table);\n }\n\n public buildSequence(\n sequence: SequencePrimitive,\n options: {\n sequences: Map<string, unknown>;\n schema: string;\n },\n ) {\n throw new AlephaError(\"SQLite does not support sequences\");\n }\n\n /**\n * Get SQLite-specific config builder for the table.\n */\n protected getTableConfig(\n entity: EntityPrimitive,\n tables: Map<string, unknown>,\n ): ((self: BuildColumns<string, any, \"sqlite\">) => any) | undefined {\n // SQLite-specific builders\n const sqliteBuilders = {\n index,\n uniqueIndex,\n unique,\n check,\n foreignKey,\n };\n\n // Table resolver function\n const tableResolver = (entityName: string) => {\n return tables.get(entityName) as any;\n };\n\n return this.buildTableConfig<any, BuildColumns<string, any, \"sqlite\">>(\n entity,\n sqliteBuilders,\n tableResolver,\n (config, self) => {\n // SQLite custom config handler\n const customConfigs = (config as any)(self);\n return Array.isArray(customConfigs) ? customConfigs : [];\n },\n );\n }\n\n // -------------------------------------------------------------------------------------------------------------------\n\n schemaToSqliteColumns = <T extends TObject>(\n tableName: string,\n schema: T,\n enums: Map<string, unknown>,\n tables: Map<string, unknown>,\n ): SchemaToSqliteBuilder<T> => {\n return Object.entries(schema.properties).reduce<\n Partial<SchemaToSqliteBuilder<T>>\n >((columns, [key, value]) => {\n let col = this.mapFieldToSqliteColumn(tableName, key, value, enums);\n\n if (\"default\" in value && value.default != null) {\n col = col.default(value.default as any);\n }\n\n if (PG_PRIMARY_KEY in value) {\n col = col.primaryKey();\n }\n\n if (PG_REF in value) {\n const config = value[PG_REF] as PgRefOptions;\n col = col.references(() => {\n const ref = config.ref();\n const table = tables.get(\n ref.entity.name,\n ) as SQLiteTableWithColumns<any>;\n\n if (!table) {\n throw new AlephaError(\n `Referenced table ${ref.entity.name} not found for ${tableName}.${key}`,\n );\n }\n\n const target = table[ref.name];\n if (!target) {\n throw new AlephaError(\n `Referenced column ${ref.name} not found in table ${ref.entity.name} for ${tableName}.${key}`,\n );\n }\n\n return target;\n }, config.actions);\n }\n\n if (schema.required?.includes(key)) {\n col = col.notNull();\n }\n\n return {\n ...columns,\n [key]: col,\n };\n }, {}) as SchemaToSqliteBuilder<T>;\n };\n\n mapFieldToSqliteColumn = (\n tableName: string,\n fieldName: string,\n value: TSchema,\n enums: Map<string, any>,\n ) => {\n const key = this.toColumnName(fieldName);\n\n if (\n // is nullish ?\n \"anyOf\" in value &&\n Array.isArray(value.anyOf) &&\n value.anyOf.length === 2 &&\n value.anyOf.some((it: TSchema) => t.schema.isNull(it))\n ) {\n // then, remove nullish\n value = value.anyOf.find((it: TSchema) => !t.schema.isNull(it))!;\n }\n\n if (t.schema.isInteger(value)) {\n if (PG_SERIAL in value || PG_IDENTITY in value) {\n return pg\n .integer(key, { mode: \"number\" })\n .primaryKey({ autoIncrement: true });\n }\n\n return pg.integer(key);\n }\n\n if (t.schema.isNumber(value)) {\n if (PG_IDENTITY in value) {\n return pg\n .integer(key, { mode: \"number\" })\n .primaryKey({ autoIncrement: true });\n }\n\n return pg.numeric(key);\n }\n\n if (t.schema.isString(value)) {\n return this.mapStringToSqliteColumn(key, value);\n }\n\n if (t.schema.isBoolean(value)) {\n return this.sqliteBool(key, value);\n }\n\n if (t.schema.isObject(value)) {\n return this.sqliteJson(key, value);\n }\n\n if (t.schema.isRecord(value)) {\n return this.sqliteJson(key, value);\n }\n\n if (t.schema.isAny(value)) {\n return this.sqliteJson(key, value);\n }\n\n if (t.schema.isArray(value)) {\n if (t.schema.isObject(value.items)) {\n return this.sqliteJson(key, value);\n }\n if (t.schema.isRecord(value.items)) {\n return this.sqliteJson(key, value);\n }\n if (t.schema.isAny(value.items)) {\n return this.sqliteJson(key, value);\n }\n if (t.schema.isString(value.items)) {\n return this.sqliteJson(key, value);\n }\n if (t.schema.isInteger(value.items)) {\n return this.sqliteJson(key, value);\n }\n if (t.schema.isNumber(value.items)) {\n return this.sqliteJson(key, value);\n }\n if (t.schema.isBoolean(value.items)) {\n return this.sqliteJson(key, value);\n }\n }\n\n if (\n t.schema.isUnsafe(value) &&\n \"type\" in value &&\n value.type === \"string\"\n ) {\n return this.mapStringToSqliteColumn(key, value as any);\n }\n\n throw new Error(\n `Unsupported schema for field '${tableName}.${fieldName}' (schema: ${JSON.stringify(value)})`,\n );\n };\n\n mapStringToSqliteColumn = (key: string, value: TString) => {\n if (value.format === \"uuid\") {\n if (PG_PRIMARY_KEY in value) {\n return pg\n .text(key)\n .primaryKey()\n .$defaultFn(() => randomUUID());\n }\n\n return pg.text(key);\n }\n\n if (value.format === \"byte\") {\n return this.sqliteJson(key, value);\n }\n\n if (value.format === \"date-time\") {\n if (PG_CREATED_AT in value) {\n return this.sqliteDateTime(key, {}).default(\n sql`(unixepoch('subsec') * 1000)`,\n );\n }\n if (PG_UPDATED_AT in value) {\n return this.sqliteDateTime(key, {}).default(\n sql`(unixepoch('subsec') * 1000)`,\n );\n }\n return this.sqliteDateTime(key, {});\n }\n\n if (value.format === \"date\") {\n return this.sqliteDate(key, {});\n }\n\n return pg.text(key);\n };\n\n sqliteJson = <TDocument extends TSchema>(name: string, document: TDocument) =>\n pg\n .customType<{\n data: Static<TDocument>;\n driverData: string;\n config: { document: TDocument };\n configRequired: true;\n }>({\n dataType: () => \"text\",\n toDriver: (value) => JSON.stringify(value),\n fromDriver: (value: TDocument | string) => {\n return value && typeof value === \"string\" ? JSON.parse(value) : value;\n },\n })(name, { document })\n .$type<Static<TDocument>>();\n\n sqliteDateTime = pg.customType<{\n data: string;\n driverData: number;\n configRequired: true;\n }>({\n dataType: () => \"integer\",\n toDriver: (value) => new Date(value).getTime(),\n fromDriver: (value) => {\n return new Date(value).toISOString();\n },\n });\n\n sqliteBool = pg.customType<{\n data: boolean;\n driverData: number;\n configRequired: true;\n }>({\n dataType: () => \"integer\",\n toDriver: (value) => (value ? 1 : 0),\n fromDriver: (value) => value === 1,\n });\n\n sqliteDate = pg.customType<{\n data: string;\n driverData: number;\n configRequired: true;\n }>({\n dataType: () => \"integer\",\n toDriver: (value) => new Date(value).getTime(),\n fromDriver: (value) => {\n return new Date(value).toISOString().split(\"T\")[0];\n },\n });\n}\n\nexport type SchemaToSqliteBuilder<T extends TObject> = {\n [key in keyof T[\"properties\"]]: SQLiteColumnBuilderBase;\n};\n","import { mkdir } from \"node:fs/promises\";\nimport type { DatabaseSync } from \"node:sqlite\";\nimport {\n $atom,\n $env,\n $hook,\n $inject,\n $use,\n AlephaError,\n type Static,\n t,\n} from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport type { PgDatabase } from \"drizzle-orm/pg-core\";\nimport { drizzle, type SqliteRemoteDatabase } from \"drizzle-orm/sqlite-proxy\";\nimport { migrate } from \"drizzle-orm/sqlite-proxy/migrator\";\nimport { SqliteModelBuilder } from \"../../services/SqliteModelBuilder.ts\";\nimport { DrizzleKitProvider } from \"../DrizzleKitProvider.ts\";\nimport { DatabaseProvider, type SQLLike } from \"./DatabaseProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nconst envSchema = t.object({\n DATABASE_URL: t.optional(t.text()),\n});\n\n/**\n * Configuration options for the Node.js SQLite database provider.\n */\nexport const nodeSqliteOptions = $atom({\n name: \"alepha.postgres.node-sqlite.options\",\n schema: t.object({\n path: t.optional(\n t.string({\n description:\n \"Filepath or :memory:. If empty, provider will use DATABASE_URL from env.\",\n }),\n ),\n }),\n default: {},\n});\n\nexport type NodeSqliteProviderOptions = Static<typeof nodeSqliteOptions.schema>;\n\ndeclare module \"alepha\" {\n interface State {\n [nodeSqliteOptions.key]: NodeSqliteProviderOptions;\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Add a fake support for SQLite in Node.js based on Postgres interfaces.\n *\n * This is NOT a real SQLite provider, it's a workaround to use SQLite with Drizzle ORM.\n * This is NOT recommended for production use.\n */\nexport class NodeSqliteProvider extends DatabaseProvider {\n protected readonly kit = $inject(DrizzleKitProvider);\n protected readonly log = $logger();\n protected readonly env = $env(envSchema);\n protected readonly builder = $inject(SqliteModelBuilder);\n protected readonly options = $use(nodeSqliteOptions);\n\n protected sqlite!: DatabaseSync;\n\n public get name() {\n return \"sqlite\";\n }\n\n public override readonly dialect = \"sqlite\";\n\n public override get url(): string {\n const path = this.options.path ?? this.env.DATABASE_URL;\n if (path) {\n if (path.startsWith(\"postgres://\")) {\n throw new AlephaError(\n \"Postgres URL is not supported for SQLite provider.\",\n );\n }\n return path;\n }\n\n if (this.alepha.isTest() || this.alepha.isServerless()) {\n return \":memory:\";\n } else {\n return \"node_modules/.alepha/sqlite.db\";\n }\n }\n\n public override async execute(\n query: SQLLike,\n ): Promise<Array<Record<string, unknown>>> {\n const all = (this.db as unknown as SqliteRemoteDatabase).all(query);\n const { sql, params, method } = all.getQuery();\n this.log.trace(`${sql}`, params);\n\n const statement = this.sqlite.prepare(sql);\n if (method === \"run\") {\n statement.run(...(params as any[]));\n return [];\n }\n\n if (method === \"get\") {\n const data = statement.get(...(params as any[]));\n return data ? [{ ...data }] : [];\n }\n\n return statement.all(...(params as any[]));\n }\n\n public readonly db = drizzle(async (sql, params, method) => {\n const statement = this.sqlite.prepare(sql);\n this.log.trace(`${sql}`, { params });\n\n if (method === \"get\") {\n const data = statement.get(...params);\n return { rows: data ? [{ ...data }] : [] };\n }\n\n if (method === \"run\") {\n statement.run(...params);\n return { rows: [] };\n }\n\n if (method === \"all\") {\n const rows = statement.all(...params);\n return {\n rows: rows.map((row) => Object.values(row)),\n };\n }\n\n if (method === \"values\") {\n const rows = statement.all(...params);\n return {\n rows: rows.map((row) => Object.values(row)),\n };\n }\n\n throw new AlephaError(`Unsupported method: ${method}`);\n }) as unknown as PgDatabase<any>;\n\n protected readonly onStart = $hook({\n on: \"start\",\n handler: async () => {\n const { DatabaseSync } = await import(\"node:sqlite\");\n const filepath = this.url.replace(\"sqlite://\", \"\");\n if (filepath !== \":memory:\" && filepath !== \"\") {\n const dirname = filepath.split(\"/\").slice(0, -1).join(\"/\");\n if (dirname) {\n await mkdir(dirname, { recursive: true }).catch(() => null);\n }\n }\n\n this.sqlite = new DatabaseSync(filepath);\n\n await this.migrateDatabase();\n\n this.log.info(`Using SQLite database at ${filepath}`);\n },\n });\n\n protected async executeMigrations(migrationsFolder: string): Promise<void> {\n await migrate(\n this.db as unknown as SqliteRemoteDatabase,\n async (migrationQueries: string[]) => {\n this.log.debug(\"Executing migration queries\", { migrationQueries });\n for (const query of migrationQueries) {\n this.sqlite.prepare(query).run();\n }\n },\n { migrationsFolder },\n );\n }\n}\n","import { mkdir } from \"node:fs/promises\";\nimport { createRequire } from \"node:module\";\nimport type { PGlite } from \"@electric-sql/pglite\";\nimport { $env, $hook, $inject, AlephaError, t } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport type { PgliteDatabase } from \"drizzle-orm/pglite\";\nimport { migrate } from \"drizzle-orm/pglite/migrator\";\nimport { PostgresModelBuilder } from \"../../services/PostgresModelBuilder.ts\";\nimport { DrizzleKitProvider } from \"../DrizzleKitProvider.ts\";\nimport { DatabaseProvider, type SQLLike } from \"./DatabaseProvider.ts\";\n\nconst envSchema = t.object({\n /**\n * Same as NodePostgresProvider connection string.\n * But, will accept only `file:` protocol for the database path.\n *\n * DATABASE_URL=memory://\n * DATABASE_URL=./db\n * DATABASE_URL=file://absolute/path/to/db\n */\n DATABASE_URL: t.optional(t.text()),\n});\n\nexport interface PgLiteModule {\n PGlite: typeof PGlite;\n}\n\nexport class PglitePostgresProvider extends DatabaseProvider {\n public static importPglite(): PgLiteModule | undefined {\n try {\n return createRequire(import.meta.url)(\"@electric-sql/pglite\");\n } catch {\n // ignored\n }\n }\n\n protected readonly env = $env(envSchema);\n protected readonly log = $logger();\n protected readonly kit = $inject(DrizzleKitProvider);\n protected readonly builder = $inject(PostgresModelBuilder);\n\n protected client?: PGlite;\n protected pglite?: PgliteDatabase;\n\n public get name() {\n return \"pglite\";\n }\n\n public override readonly dialect = \"postgresql\";\n\n public override get url(): string {\n let path = this.env.DATABASE_URL;\n\n if (!path) {\n if (this.alepha.isTest()) {\n path = \":memory:\"; // use in-memory database for tests by default\n } else {\n path = \"node_modules/.db\"; // default path for dev\n }\n } else {\n if (path.includes(\":memory:\")) {\n // like postgres://:memory: or pglite://:memory:\n path = \":memory:\";\n } else if (path.startsWith(\"file://\")) {\n path = path.replace(\"file://\", \"\");\n }\n }\n\n return path;\n }\n\n public override get db(): PgliteDatabase {\n if (!this.pglite) {\n throw new AlephaError(\"Database not initialized\");\n }\n\n return this.pglite;\n }\n\n public override async execute(\n statement: SQLLike,\n ): Promise<Array<Record<string, unknown>>> {\n const { rows } = await this.db.execute(statement);\n return rows;\n }\n\n protected readonly onStart = $hook({\n on: \"start\",\n handler: async () => {\n if (Object.keys(this.kit.getModels(this)).length === 0) {\n return;\n }\n\n const module = PglitePostgresProvider.importPglite();\n if (!module) {\n throw new AlephaError(\n \"@electric-sql/pglite is not installed. Please install it to use the pglite driver.\",\n );\n }\n\n const { drizzle } = createRequire(import.meta.url)(\"drizzle-orm/pglite\");\n const path = this.url;\n\n if (path !== \":memory:\") {\n await mkdir(path, { recursive: true }).catch(() => null);\n this.client = new module.PGlite(path);\n } else {\n this.client = new module.PGlite();\n }\n\n this.pglite = drizzle({\n client: this.client,\n });\n\n await this.migrateDatabase();\n\n this.log.info(`Using PGlite database at ${path}`);\n },\n });\n\n protected readonly onStop = $hook({\n on: \"stop\",\n handler: async () => {\n if (this.client) {\n this.log.debug(\"Closing PGlite connection...\");\n await this.client.close();\n this.client = undefined;\n this.pglite = undefined;\n this.log.info(\"PGlite connection closed\");\n }\n },\n });\n\n protected async executeMigrations(migrationsFolder: string): Promise<void> {\n await migrate(this.db, { migrationsFolder });\n }\n}\n","import { AlephaError, type TObject } from \"alepha\";\nimport type { PgQueryWhere } from \"../interfaces/PgQueryWhere.ts\";\n\n/**\n * Parse a string query into a PgQueryWhere object.\n *\n * Supported syntax:\n * - Simple equality: \"name=John\"\n * - Wildcard patterns: \"name=John*\" (startsWith), \"name=*John\" (endsWith), \"name=*John*\" (contains)\n * - Operators: \"age>18\", \"age>=18\", \"age<65\", \"age<=65\", \"status!=active\"\n * - NULL checks: \"deletedAt=null\", \"email!=null\"\n * - IN arrays: \"status=[pending,active]\"\n * - AND conditions: \"name=John&age>18\"\n * - OR conditions: \"name=John|email=john@example.com\"\n * - Nested AND/OR: \"(name=John|name=Jane)&age>18\"\n * - JSONB nested: \"profile.city=Paris\"\n *\n * @example\n * ```ts\n * // Simple equality\n * parseQueryString(\"name=John\")\n * // => { name: { eq: \"John\" } }\n *\n * // Wildcard patterns\n * parseQueryString(\"name=John*\") // startsWith\n * // => { name: { startsWith: \"John\" } }\n * parseQueryString(\"name=*Smith\") // endsWith\n * // => { name: { endsWith: \"Smith\" } }\n * parseQueryString(\"name=*oh*\") // contains\n * // => { name: { contains: \"oh\" } }\n *\n * // Multiple conditions\n * parseQueryString(\"name=John&age>18\")\n * // => { and: [{ name: { eq: \"John\" } }, { age: { gt: 18 } }] }\n *\n * // OR conditions\n * parseQueryString(\"status=active|status=pending\")\n * // => { or: [{ status: { eq: \"active\" } }, { status: { eq: \"pending\" } }] }\n *\n * // Complex nested\n * parseQueryString(\"(name=John|name=Jane)&age>18&status!=archived\")\n * // => { and: [\n * // { or: [{ name: { eq: \"John\" } }, { name: { eq: \"Jane\" } }] },\n * // { age: { gt: 18 } },\n * // { status: { ne: \"archived\" } }\n * // ] }\n *\n * // JSONB nested query\n * parseQueryString(\"profile.city=Paris&profile.age>25\")\n * // => { profile: { city: { eq: \"Paris\" }, age: { gt: 25 } } }\n * ```\n */\nexport function parseQueryString<T extends TObject>(\n query: string,\n): PgQueryWhere<T> {\n if (!query || query.trim() === \"\") {\n return {};\n }\n\n const parser = new QueryStringParser(query);\n return parser.parse() as PgQueryWhere<T>;\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nclass QueryStringParser {\n private pos = 0;\n private readonly query: string;\n\n constructor(query: string) {\n this.query = query.trim();\n }\n\n parse(): PgQueryWhere<any> {\n return this.parseExpression();\n }\n\n private parseExpression(): PgQueryWhere<any> {\n return this.parseOr();\n }\n\n private parseOr(): any {\n const left = this.parseAnd();\n\n // Check for OR operator (|)\n if (this.peek() === \"|\") {\n const conditions = [left];\n\n while (this.peek() === \"|\") {\n this.consume(\"|\");\n conditions.push(this.parseAnd());\n }\n\n return { or: conditions };\n }\n\n return left;\n }\n\n private parseAnd(): any {\n const left = this.parsePrimary();\n\n // Check for AND operator (&)\n if (this.peek() === \"&\") {\n const conditions = [left];\n\n while (this.peek() === \"&\") {\n this.consume(\"&\");\n conditions.push(this.parsePrimary());\n }\n\n return { and: conditions };\n }\n\n return left;\n }\n\n private parsePrimary(): any {\n this.skipWhitespace();\n\n // Handle parentheses\n if (this.peek() === \"(\") {\n this.consume(\"(\");\n const expr = this.parseExpression();\n this.consume(\")\");\n return expr;\n }\n\n // Parse field condition\n return this.parseCondition();\n }\n\n private parseCondition(): any {\n const field = this.parseFieldPath();\n this.skipWhitespace();\n\n // Get operator\n const operator = this.parseOperator();\n this.skipWhitespace();\n\n // Get value\n const value = this.parseValue();\n\n if (value === \"\") {\n throw new AlephaError(`Expected value for field '${field.join(\".\")}'`);\n }\n\n // Build the condition object\n return this.buildCondition(field, operator, value);\n }\n\n private parseFieldPath(): string[] {\n const path: string[] = [];\n let current = \"\";\n\n while (this.pos < this.query.length) {\n const ch = this.query[this.pos];\n\n if (ch === \".\" && current) {\n path.push(current);\n current = \"\";\n this.pos++;\n continue;\n }\n\n if (ch === \"=\" || ch === \"!\" || ch === \">\" || ch === \"<\" || ch === \" \") {\n break;\n }\n\n current += ch;\n this.pos++;\n }\n\n if (current) {\n path.push(current);\n }\n\n return path;\n }\n\n private parseOperator(): string {\n this.skipWhitespace();\n\n const remaining = this.query.slice(this.pos);\n\n // Two-character operators\n if (remaining.startsWith(\">=\")) {\n this.pos += 2;\n return \">=\";\n }\n if (remaining.startsWith(\"<=\")) {\n this.pos += 2;\n return \"<=\";\n }\n if (remaining.startsWith(\"!=\")) {\n this.pos += 2;\n return \"!=\";\n }\n\n // Single-character operators\n const ch = this.query[this.pos];\n if (ch === \"=\" || ch === \">\" || ch === \"<\") {\n this.pos++;\n return ch;\n }\n\n throw new Error(`Expected operator at position ${this.pos}`);\n }\n\n private parseValue(): any {\n this.skipWhitespace();\n\n // Handle null\n if (this.query.slice(this.pos, this.pos + 4).toLowerCase() === \"null\") {\n this.pos += 4;\n return null;\n }\n\n // Handle arrays [value1,value2,...]\n if (this.query[this.pos] === \"[\") {\n return this.parseArray();\n }\n\n // Handle quoted strings\n if (this.query[this.pos] === '\"' || this.query[this.pos] === \"'\") {\n return this.parseQuotedString();\n }\n\n // Parse unquoted value (until &, |, or ))\n let value = \"\";\n while (this.pos < this.query.length) {\n const ch = this.query[this.pos];\n if (ch === \"&\" || ch === \"|\" || ch === \")\") {\n break;\n }\n value += ch;\n this.pos++;\n }\n\n return this.coerceValue(value.trim());\n }\n\n private parseArray(): any[] {\n this.consume(\"[\");\n const values: any[] = [];\n\n while (this.pos < this.query.length && this.query[this.pos] !== \"]\") {\n this.skipWhitespace();\n\n // Handle quoted values\n if (this.query[this.pos] === '\"' || this.query[this.pos] === \"'\") {\n values.push(this.parseQuotedString());\n } else {\n // Parse until comma or ]\n let value = \"\";\n while (\n this.pos < this.query.length &&\n this.query[this.pos] !== \",\" &&\n this.query[this.pos] !== \"]\"\n ) {\n value += this.query[this.pos];\n this.pos++;\n }\n values.push(this.coerceValue(value.trim()));\n }\n\n this.skipWhitespace();\n if (this.query[this.pos] === \",\") {\n this.pos++;\n }\n }\n\n this.consume(\"]\");\n return values;\n }\n\n private parseQuotedString(): string {\n const quote = this.query[this.pos];\n this.pos++; // Skip opening quote\n\n let value = \"\";\n let escaped = false;\n\n while (this.pos < this.query.length) {\n const ch = this.query[this.pos];\n\n if (escaped) {\n value += ch;\n escaped = false;\n this.pos++;\n continue;\n }\n\n if (ch === \"\\\\\") {\n escaped = true;\n this.pos++;\n continue;\n }\n\n if (ch === quote) {\n this.pos++; // Skip closing quote\n break;\n }\n\n value += ch;\n this.pos++;\n }\n\n return value;\n }\n\n private coerceValue(value: string): any {\n // Try to parse as number\n if (/^-?\\d+$/.test(value)) {\n return parseInt(value, 10);\n }\n\n if (/^-?\\d+\\.\\d+$/.test(value)) {\n return parseFloat(value);\n }\n\n // Try to parse as boolean\n if (value.toLowerCase() === \"true\") {\n return true;\n }\n if (value.toLowerCase() === \"false\") {\n return false;\n }\n\n return value;\n }\n\n private buildCondition(path: string[], operator: string, value: any): any {\n // Map operator to filter operator\n let filterOp: any;\n\n if (operator === \"=\") {\n if (value === null) {\n filterOp = { isNull: true };\n } else if (Array.isArray(value)) {\n // Arrays should be treated as inArray regardless of content\n filterOp = { inArray: value };\n } else if (typeof value === \"string\" && value.includes(\"*\")) {\n // Handle wildcard patterns\n const startsWithAsterisk = value.startsWith(\"*\");\n const endsWithAsterisk = value.endsWith(\"*\");\n const cleanValue = value.replace(/^\\*|\\*$/g, \"\"); // Remove leading/trailing asterisks\n\n if (startsWithAsterisk && endsWithAsterisk) {\n // *text* -> contains\n filterOp = { contains: cleanValue };\n } else if (startsWithAsterisk) {\n // *text -> endsWith\n filterOp = { endsWith: cleanValue };\n } else if (endsWithAsterisk) {\n // text* -> startsWith\n filterOp = { startsWith: cleanValue };\n } else {\n // Has asterisk in the middle, treat as literal\n filterOp = { eq: value };\n }\n } else {\n filterOp = { eq: value };\n }\n } else if (operator === \"!=\") {\n if (value === null) {\n filterOp = { isNotNull: true };\n } else {\n filterOp = { ne: value };\n }\n } else if (operator === \">\") {\n filterOp = { gt: value };\n } else if (operator === \">=\") {\n filterOp = { gte: value };\n } else if (operator === \"<\") {\n filterOp = { lt: value };\n } else if (operator === \"<=\") {\n filterOp = { lte: value };\n } else {\n throw new Error(`Unsupported operator: ${operator}`);\n }\n\n // Build nested object for path\n if (path.length === 1) {\n return { [path[0]]: filterOp };\n }\n\n // Handle nested paths (JSONB)\n let result: any = filterOp;\n for (let i = path.length - 1; i >= 0; i--) {\n result = { [path[i]]: result };\n }\n\n return result;\n }\n\n private peek(): string {\n this.skipWhitespace();\n return this.query[this.pos] || \"\";\n }\n\n private consume(expected: string): void {\n this.skipWhitespace();\n if (this.query[this.pos] !== expected) {\n throw new Error(\n `Expected '${expected}' at position ${this.pos}, got '${this.query[this.pos]}'`,\n );\n }\n this.pos++;\n }\n\n private skipWhitespace(): void {\n while (this.pos < this.query.length && /\\s/.test(this.query[this.pos])) {\n this.pos++;\n }\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Helper function to build query strings programmatically\n *\n * @example\n * ```ts\n * buildQueryString({\n * and: [\n * { name: \"eq:John\" },\n * { age: \"gt:18\" }\n * ]\n * })\n * // => \"name=John&age>18\"\n * ```\n */\nexport function buildQueryString(where: any): string {\n if (!where || typeof where !== \"object\") {\n return \"\";\n }\n\n // Handle logical operators\n if (\"and\" in where && Array.isArray(where.and)) {\n return where.and.map((w: any) => buildQueryString(w)).join(\"&\");\n }\n\n if (\"or\" in where && Array.isArray(where.or)) {\n const parts = where.or.map((w: any) => buildQueryString(w));\n return parts.length > 1 ? `(${parts.join(\"|\")})` : parts[0];\n }\n\n if (\"not\" in where) {\n // Not operator is harder to represent in string form\n // For now, we'll skip it or you could add a syntax like \"!field=value\"\n return \"\";\n }\n\n // Handle field conditions\n const parts: string[] = [];\n\n for (const [field, condition] of Object.entries(where)) {\n if (typeof condition !== \"object\" || condition === null) {\n parts.push(`${field}=${condition}`);\n continue;\n }\n\n if (\"eq\" in condition) {\n parts.push(`${field}=${condition.eq}`);\n } else if (\"ne\" in condition) {\n parts.push(`${field}!=${condition.ne}`);\n } else if (\"gt\" in condition) {\n parts.push(`${field}>${condition.gt}`);\n } else if (\"gte\" in condition) {\n parts.push(`${field}>=${condition.gte}`);\n } else if (\"lt\" in condition) {\n parts.push(`${field}<${condition.lt}`);\n } else if (\"lte\" in condition) {\n parts.push(`${field}<=${condition.lte}`);\n } else if (\"contains\" in condition) {\n parts.push(`${field}=*${condition.contains}*`);\n } else if (\"startsWith\" in condition) {\n parts.push(`${field}=${condition.startsWith}*`);\n } else if (\"endsWith\" in condition) {\n parts.push(`${field}=*${condition.endsWith}`);\n } else if (\"isNull\" in condition && condition.isNull) {\n parts.push(`${field}=null`);\n } else if (\"isNotNull\" in condition && condition.isNotNull) {\n parts.push(`${field}!=null`);\n } else if (\"inArray\" in condition && Array.isArray(condition.inArray)) {\n const values = condition.inArray.map((v: any) =>\n typeof v === \"string\" ? `\"${v}\"` : v,\n );\n parts.push(`${field}=[${values.join(\",\")}]`);\n } else {\n // Nested object (JSONB)\n const nested = buildQueryString(condition);\n if (nested) {\n parts.push(`${field}.${nested}`);\n }\n }\n }\n\n return parts.join(\"&\");\n}\n","import { $context } from \"alepha\";\nimport { $retry } from \"alepha/retry\";\nimport type { PgTransaction } from \"drizzle-orm/pg-core\";\nimport type { PgTransactionConfig } from \"drizzle-orm/pg-core/session\";\nimport { DbVersionMismatchError } from \"../errors/DbVersionMismatchError.ts\";\nimport { DatabaseProvider } from \"../providers/drivers/DatabaseProvider.ts\";\n\n/**\n * Creates a transaction primitive for database operations requiring atomicity and consistency.\n *\n * This primitive provides a convenient way to wrap database operations in PostgreSQL\n * transactions, ensuring ACID properties and automatic retry logic for version conflicts.\n * It integrates seamlessly with the repository pattern and provides built-in handling\n * for optimistic locking scenarios with automatic retry on version mismatches.\n *\n * **Important Notes**:\n * - All operations within the transaction handler are atomic\n * - Automatic retry on `PgVersionMismatchError` for optimistic locking\n * - Pass `{ tx }` option to all repository operations within the transaction\n * - Transactions are automatically rolled back on any unhandled error\n * - Use appropriate isolation levels based on your consistency requirements\n */\nexport const $transaction = <T extends any[], R>(\n opts: TransactionPrimitiveOptions<T, R>,\n) => {\n const { alepha } = $context();\n const provider = alepha.inject(DatabaseProvider);\n\n return $retry({\n when: (err) => err instanceof DbVersionMismatchError,\n handler: (...args: T) =>\n provider.db.transaction(\n async (tx) => opts.handler(tx, ...args),\n opts.config,\n ),\n });\n};\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface TransactionPrimitiveOptions<T extends any[], R> {\n /**\n * Transaction handler function that contains all database operations to be executed atomically.\n *\n * This function:\n * - Receives a transaction object as the first parameter\n * - Should pass the transaction to all repository operations via `{ tx }` option\n * - All operations within are automatically rolled back if any error occurs\n * - Has access to the full Alepha dependency injection container\n * - Will be automatically retried if a `PgVersionMismatchError` occurs\n *\n * **Transaction Guidelines**:\n * - Keep transactions as short as possible to minimize lock contention\n * - Always pass the `tx` parameter to repository operations\n * - Handle expected business errors gracefully\n * - Log important operations for debugging and audit trails\n * - Consider the impact of long-running transactions on performance\n *\n * **Error Handling**:\n * - Throwing any error will automatically roll back the transaction\n * - `PgVersionMismatchError` triggers automatic retry logic\n * - Other database errors will be propagated after rollback\n * - Use try-catch within the handler for business-specific error handling\n *\n * @param tx - The PostgreSQL transaction object to use for all database operations\n * @param ...args - Additional arguments passed to the transaction function\n * @returns Promise resolving to the transaction result\n *\n * @example\n * ```ts\n * handler: async (tx, orderId: string, newStatus: string) => {\n * // Get the current order (with transaction)\n * const order = await this.orders.findById(orderId, { tx });\n *\n * // Validate business rules\n * if (!this.isValidStatusTransition(order.status, newStatus)) {\n * throw new Error(`Invalid status transition: ${order.status} -> ${newStatus}`);\n * }\n *\n * // Update order status (with transaction)\n * const updatedOrder = await this.orders.updateById(\n * orderId,\n * { status: newStatus },\n * { tx }\n * );\n *\n * // Create audit log (with transaction)\n * await this.auditLogs.create({\n * id: generateUUID(),\n * entityId: orderId,\n * action: 'status_change',\n * oldValue: order.status,\n * newValue: newStatus,\n * timestamp: new Date().toISOString()\n * }, { tx });\n *\n * return updatedOrder;\n * }\n * ```\n */\n handler: (tx: PgTransaction<any, any, any>, ...args: T) => Promise<R>;\n\n /**\n * PostgreSQL transaction configuration options.\n *\n * This allows you to customize transaction behavior including:\n * - **Isolation Level**: Controls visibility of concurrent transaction changes\n * - **Access Mode**: Whether the transaction is read-only or read-write\n * - **Deferrable**: For serializable transactions, allows deferring to avoid conflicts\n *\n * **Isolation Levels**:\n * - **read_uncommitted**: Lowest isolation, allows dirty reads (rarely used)\n * - **read_committed**: Default level, prevents dirty reads\n * - **repeatable_read**: Prevents dirty and non-repeatable reads\n * - **serializable**: Highest isolation, full ACID compliance\n *\n * **Access Modes**:\n * - **read_write**: Default, allows both read and write operations\n * - **read_only**: Only allows read operations, can provide performance benefits\n *\n * **When to Use Different Isolation Levels**:\n * - **read_committed**: Most common operations, good balance of consistency and performance\n * - **repeatable_read**: When you need consistent reads throughout the transaction\n * - **serializable**: Critical financial operations, when absolute consistency is required\n *\n * @example\n * ```ts\n * config: {\n * isolationLevel: 'serializable', // Highest consistency for financial operations\n * accessMode: 'read_write'\n * }\n * ```\n *\n * @example\n * ```ts\n * config: {\n * isolationLevel: 'read_committed', // Default level for most operations\n * accessMode: 'read_only' // Performance optimization for read-only operations\n * }\n * ```\n */\n config?: PgTransactionConfig;\n}\n\nexport type TransactionContext = PgTransaction<any, any, any>;\n","import {\n AlephaError,\n pageSchema,\n type Static,\n type TBigInt,\n type TInteger,\n type TNumber,\n type TNumberOptions,\n type TObject,\n type TObjectOptions,\n type TPage,\n type TSchema,\n type TString,\n type TStringOptions,\n type TUnsafe,\n t,\n} from \"alepha\";\nimport type { UpdateDeleteAction } from \"drizzle-orm/pg-core/foreign-keys\";\nimport {\n PG_CREATED_AT,\n PG_DEFAULT,\n PG_DELETED_AT,\n PG_ENUM,\n PG_IDENTITY,\n PG_PRIMARY_KEY,\n PG_REF,\n PG_UPDATED_AT,\n PG_VERSION,\n type PgDefault,\n type PgEnumOptions,\n type PgIdentityOptions,\n type PgPrimaryKey,\n type PgRef,\n} from \"../constants/PG_SYMBOLS.ts\";\nimport type { PgAttr } from \"../helpers/pgAttr.ts\";\nimport { pgAttr } from \"../helpers/pgAttr.ts\";\n\nexport class PostgresTypeProvider {\n public readonly attr = pgAttr;\n\n /**\n * Creates a primary key with an identity column.\n */\n public readonly identityPrimaryKey = (\n identity?: PgIdentityOptions,\n options?: TNumberOptions,\n ) =>\n pgAttr(\n pgAttr(pgAttr(t.integer(options), PG_PRIMARY_KEY), PG_IDENTITY, identity),\n PG_DEFAULT,\n );\n\n /**\n * Creates a primary key with a big identity column. (default)\n */\n public readonly bigIdentityPrimaryKey = (\n identity?: PgIdentityOptions,\n options?: TNumberOptions,\n ) =>\n pgAttr(\n pgAttr(pgAttr(t.int64(options), PG_PRIMARY_KEY), PG_IDENTITY, identity),\n PG_DEFAULT,\n );\n\n /**\n * Creates a primary key with a UUID column.\n */\n public readonly uuidPrimaryKey = () =>\n pgAttr(pgAttr(t.uuid(), PG_PRIMARY_KEY), PG_DEFAULT);\n\n /**\n * Creates a primary key for a given type. Supports:\n * - `t.integer()` -> PG INT (default)\n * - `t.bigint()` -> PG BIGINT\n * - `t.uuid()` -> PG UUID\n */\n public primaryKey(): PgAttr<PgAttr<TInteger, PgPrimaryKey>, PgDefault>;\n public primaryKey(\n type: TString,\n options?: TStringOptions,\n ): PgAttr<PgAttr<TString, PgPrimaryKey>, PgDefault>;\n public primaryKey(\n type: TInteger,\n options?: TNumberOptions,\n identity?: PgIdentityOptions,\n ): PgAttr<PgAttr<TInteger, PgPrimaryKey>, PgDefault>;\n public primaryKey(\n type: TNumber,\n options?: TNumberOptions,\n identity?: PgIdentityOptions,\n ): PgAttr<PgAttr<TNumber, PgPrimaryKey>, PgDefault>;\n public primaryKey(\n type: TBigInt,\n options?: TNumberOptions,\n identity?: PgIdentityOptions,\n ): PgAttr<PgAttr<TBigInt, PgPrimaryKey>, PgDefault>;\n public primaryKey(\n type?: TSchema,\n options?: TNumberOptions | TStringOptions,\n identity?: PgIdentityOptions,\n ): PgAttr<PgAttr<TSchema, PgPrimaryKey>, PgDefault> {\n if (!type || t.schema.isInteger(type)) {\n return pgAttr(\n pgAttr(\n pgAttr(t.integer(options), PG_PRIMARY_KEY),\n PG_IDENTITY,\n identity,\n ),\n PG_DEFAULT,\n );\n }\n\n if (t.schema.isString(type) && type.format === \"uuid\") {\n return pgAttr(pgAttr(t.uuid(), PG_PRIMARY_KEY), PG_DEFAULT);\n }\n\n if (t.schema.isNumber(type) && type.format === \"int64\") {\n return pgAttr(\n pgAttr(\n pgAttr(t.number(options), PG_PRIMARY_KEY),\n PG_IDENTITY,\n identity,\n ),\n PG_DEFAULT,\n );\n }\n\n if (t.schema.isBigInt(type)) {\n return pgAttr(\n pgAttr(\n pgAttr(t.bigint(options), PG_PRIMARY_KEY),\n PG_IDENTITY,\n identity,\n ),\n PG_DEFAULT,\n );\n }\n\n throw new AlephaError(`Unsupported type for primary key: ${type}`);\n }\n\n /**\n * Wrap a schema with \"default\" attribute.\n * This is used to set a default value for a column in the database.\n */\n public readonly default = <T extends TSchema>(\n type: T,\n value?: Static<T>,\n ): PgAttr<T, PgDefault> => {\n if (value != null) {\n Object.assign(type, { default: value });\n }\n\n return this.attr(type, PG_DEFAULT);\n };\n\n /**\n * Creates a column 'version'.\n *\n * This is used to track the version of a row in the database.\n *\n * You can use it for optimistic concurrency control (OCC) with {@link RepositoryPrimitive#save}.\n *\n * @see {@link RepositoryPrimitive#save}\n * @see {@link PgVersionMismatchError}\n */\n public readonly version = (options: TNumberOptions = {}) =>\n this.default(pgAttr(t.integer(options), PG_VERSION), 0);\n\n /**\n * Creates a column Created At. So just a datetime column with a default value of the current timestamp.\n */\n public readonly createdAt = (options?: TStringOptions) =>\n pgAttr(pgAttr(t.datetime(options), PG_CREATED_AT), PG_DEFAULT);\n\n /**\n * Creates a column Updated At. Like createdAt, but it is updated on every update of the row.\n */\n public readonly updatedAt = (options?: TStringOptions) =>\n pgAttr(pgAttr(t.datetime(options), PG_UPDATED_AT), PG_DEFAULT);\n\n /**\n * Creates a column Deleted At for soft delete functionality.\n * This is used to mark rows as deleted without actually removing them from the database.\n * The column is nullable - NULL means not deleted, timestamp means deleted.\n */\n public readonly deletedAt = (options?: TStringOptions) =>\n pgAttr(t.optional(t.datetime(options)), PG_DELETED_AT);\n\n /**\n * Creates a Postgres ENUM type.\n *\n * > By default, `t.enum()` is mapped to a TEXT column in Postgres.\n * > Using this method, you can create a real ENUM type in the database.\n *\n * @example\n * ```ts\n * const statusEnum = pg.enum([\"pending\", \"active\", \"archived\"], { name: \"status_enum\" });\n * ```\n */\n public readonly enum = <T extends string[]>(\n values: [...T],\n pgEnumOptions?: PgEnumOptions,\n typeOptions?: TStringOptions,\n ): PgAttr<TUnsafe<T[number]>, typeof PG_ENUM> => {\n return pgAttr(\n t.enum(values, {\n description: pgEnumOptions?.description,\n ...typeOptions,\n }),\n PG_ENUM,\n pgEnumOptions,\n );\n };\n\n /**\n * Creates a reference to another table or schema. Basically a foreign key.\n */\n public readonly ref = <T extends TSchema>(\n type: T,\n ref: () => any,\n actions?: {\n onUpdate?: UpdateDeleteAction;\n onDelete?: UpdateDeleteAction;\n },\n ): PgAttr<T, PgRef> => {\n // If actions are not provided, set default onDelete based on type\n const finalActions = actions ?? {\n onDelete: t.schema.isOptional(type) ? \"set null\" : \"cascade\",\n };\n\n return this.attr(type, PG_REF, {\n ref,\n actions: finalActions,\n });\n };\n\n // -------------------------------------------------------------------------------------------------------------------\n\n /**\n * Creates a page schema for a given object schema.\n * It's used by {@link RepositoryPrimitive#paginate} method.\n */\n public readonly page = <T extends TObject>(\n resource: T,\n options?: TObjectOptions,\n ): TPage<T> => {\n return pageSchema(resource, options);\n };\n}\n\nexport const pg = new PostgresTypeProvider();\n","import { t } from \"alepha\";\nimport {\n PG_DEFAULT,\n PG_PRIMARY_KEY,\n PG_SERIAL,\n} from \"../constants/PG_SYMBOLS.ts\";\nimport { pgAttr } from \"../helpers/pgAttr.ts\";\n\n/**\n * @deprecated Use `pg.primaryKey()` instead.\n */\nexport const legacyIdSchema = pgAttr(\n pgAttr(pgAttr(t.integer(), PG_PRIMARY_KEY), PG_SERIAL),\n PG_DEFAULT,\n);\n","import { $module, type Alepha, t } from \"alepha\";\nimport { AlephaDateTime } from \"alepha/datetime\";\nimport * as drizzle from \"drizzle-orm\";\nimport { $entity } from \"./primitives/$entity.ts\";\nimport { $repository } from \"./primitives/$repository.ts\";\nimport { $sequence } from \"./primitives/$sequence.ts\";\nimport { DrizzleKitProvider } from \"./providers/DrizzleKitProvider.ts\";\nimport { DatabaseProvider } from \"./providers/drivers/DatabaseProvider.ts\";\nimport { NodePostgresProvider } from \"./providers/drivers/NodePostgresProvider.ts\";\nimport { NodeSqliteProvider } from \"./providers/drivers/NodeSqliteProvider.ts\";\nimport { PglitePostgresProvider } from \"./providers/drivers/PglitePostgresProvider.ts\";\nimport { RepositoryProvider } from \"./providers/RepositoryProvider.ts\";\nimport { PostgresModelBuilder } from \"./services/PostgresModelBuilder.ts\";\nimport { Repository } from \"./services/Repository.ts\";\nimport { SqliteModelBuilder } from \"./services/SqliteModelBuilder.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\ndeclare module \"alepha\" {\n interface Hooks {\n /**\n * Fires before creating an entity in the repository.\n */\n \"repository:create:before\": {\n tableName: string;\n data: any;\n };\n /**\n * Fires after creating an entity in the repository.\n */\n \"repository:create:after\": {\n tableName: string;\n data: any;\n entity: any;\n };\n /**\n * Fires before updating entities in the repository.\n */\n \"repository:update:before\": {\n tableName: string;\n where: any;\n data: any;\n };\n /**\n * Fires after updating entities in the repository.\n */\n \"repository:update:after\": {\n tableName: string;\n where: any;\n data: any;\n entities: any[];\n };\n /**\n * Fires before deleting entities from the repository.\n */\n \"repository:delete:before\": {\n tableName: string;\n where: any;\n };\n /**\n * Fires after deleting entities from the repository.\n */\n \"repository:delete:after\": {\n tableName: string;\n where: any;\n ids: Array<string | number>;\n };\n /**\n * Fires before reading entities from the repository.\n */\n \"repository:read:before\": {\n tableName: string;\n query: any;\n };\n /**\n * Fires after reading entities from the repository.\n */\n \"repository:read:after\": {\n tableName: string;\n query: any;\n entities: any[];\n };\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport { drizzle };\nexport {\n type Page,\n type PageQuery,\n pageQuerySchema,\n pageSchema,\n} from \"alepha\";\nexport { sql } from \"drizzle-orm\";\nexport * from \"drizzle-orm/pg-core\";\nexport * from \"./constants/PG_SYMBOLS.ts\";\nexport * from \"./errors/DbConflictError.ts\";\nexport * from \"./errors/DbEntityNotFoundError.ts\";\nexport * from \"./errors/DbError.ts\";\nexport * from \"./errors/DbMigrationError.ts\";\nexport * from \"./errors/DbVersionMismatchError.ts\";\nexport * from \"./helpers/parseQueryString.ts\";\nexport * from \"./helpers/pgAttr.ts\";\nexport * from \"./interfaces/FilterOperators.ts\";\nexport * from \"./interfaces/PgQuery.ts\";\nexport * from \"./interfaces/PgQueryWhere.ts\";\nexport * from \"./primitives/$entity.ts\";\nexport * from \"./primitives/$repository.ts\";\nexport * from \"./primitives/$sequence.ts\";\nexport * from \"./primitives/$transaction.ts\";\nexport * from \"./providers/DrizzleKitProvider.ts\";\nexport * from \"./providers/drivers/DatabaseProvider.ts\";\nexport * from \"./providers/drivers/NodePostgresProvider.ts\";\nexport * from \"./providers/drivers/NodeSqliteProvider.ts\";\nexport * from \"./providers/PostgresTypeProvider.ts\";\nexport * from \"./providers/RepositoryProvider.ts\";\nexport * from \"./schemas/insertSchema.ts\";\nexport * from \"./schemas/legacyIdSchema.ts\";\nexport * from \"./schemas/updateSchema.ts\";\nexport * from \"./services/Repository.ts\";\nexport * from \"./types/schema.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Postgres client based on Drizzle ORM, Alepha type-safe friendly.\n *\n * ```ts\n * const users = $entity({\n * name: \"users\",\n * schema: t.object({\n * id: pg.primaryKey(),\n * name: t.text(),\n * email: t.text(),\n * }),\n * });\n *\n * class Db {\n * users = $repository(users);\n * }\n *\n * const db = alepha.inject(Db);\n * const user = await db.users.one({ name: { eq: \"John Doe\" } });\n * ```\n *\n * This is not a full ORM, but rather a set of tools to work with Postgres databases in a type-safe way.\n *\n * It provides:\n * - A type-safe way to define entities and repositories. (via `$entity` and `$repository`)\n * - Custom query builders and filters.\n * - Built-in special columns like `createdAt`, `updatedAt`, `deletedAt`, `version`.\n * - Automatic JSONB support.\n * - Automatic synchronization of entities with the database schema (for testing and development).\n * - Fallback to raw SQL via Drizzle ORM `sql` function.\n *\n * Migrations are supported via Drizzle ORM, you need to use the `drizzle-kit` CLI tool to generate and run migrations.\n *\n * @see {@link $entity}\n * @see {@link $sequence}\n * @see {@link $repository}\n * @see {@link $transaction}\n * @module alepha.postgres\n */\nexport const AlephaPostgres = $module({\n name: \"alepha.postgres\",\n primitives: [$sequence, $entity],\n services: [\n AlephaDateTime,\n DatabaseProvider,\n NodePostgresProvider,\n PglitePostgresProvider,\n NodeSqliteProvider,\n SqliteModelBuilder,\n PostgresModelBuilder,\n DrizzleKitProvider,\n RepositoryProvider,\n Repository,\n ],\n register: (alepha: Alepha) => {\n const env = alepha.parseEnv(\n t.object({\n DATABASE_URL: t.optional(t.text()),\n }),\n );\n\n alepha.with(DrizzleKitProvider);\n alepha.with(RepositoryProvider);\n\n const url = env.DATABASE_URL;\n const hasPGlite = !!PglitePostgresProvider.importPglite();\n const isPostgres = url?.startsWith(\"postgres:\");\n const isSqlite = url?.startsWith(\"sqlite:\");\n const isMemory = url?.includes(\":memory:\");\n const isFile = !!url && !isPostgres && !isMemory;\n\n if (hasPGlite && (isMemory || isFile || !url) && !isSqlite) {\n alepha.with({\n optional: true,\n provide: DatabaseProvider,\n use: PglitePostgresProvider,\n });\n return;\n }\n\n if (isPostgres) {\n alepha.with({\n optional: true,\n provide: DatabaseProvider,\n use: NodePostgresProvider,\n });\n return;\n }\n\n alepha.with({\n optional: true,\n provide: DatabaseProvider,\n use: NodeSqliteProvider,\n });\n },\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["newProperties: Record<string, any>","newProperties: Record<string, any>","schema","alias","cols: Partial<EntityColumns<T>>","fields: Array<PgAttrField>","schema","schema","isSQLWrapper","schema","jsonValue: SQL","conditions: SQL[]","sql","results: Array<{ path: string[]; operator: FilterOperators<any> }>","schema","currentSchema: any","conditions: SQL[]","sql","operations: SQL[]","schema","schema","entity: any","fields: Record<string, any>","joins: Array<PgJoin>","schema: TObject","tasks: Promise<any>[]","sortMetadata:\n | Array<{ column: string; direction: \"asc\" | \"desc\" }>\n | undefined","allEntities: Static<T>[]","where: any","cleanRow: Record<string, unknown>","joinedData: Record<string, unknown>","sql","prev","curr","models: Record<string, unknown>","sql","configs: TConfig[]","schema","pg","value","envSchema","sql","drizzle","schema","pg","envSchema","sql","drizzle","migrate","drizzle","migrate","path: string[]","values: any[]","filterOp: any","result: any","parts","parts: string[]","pageSchema"],"sources":["../../src/orm/constants/PG_SYMBOLS.ts","../../src/orm/types/schema.ts","../../src/orm/schemas/insertSchema.ts","../../src/orm/schemas/updateSchema.ts","../../src/orm/primitives/$entity.ts","../../src/orm/errors/DbError.ts","../../src/orm/errors/DbConflictError.ts","../../src/orm/errors/DbEntityNotFoundError.ts","../../src/orm/errors/DbVersionMismatchError.ts","../../src/orm/helpers/pgAttr.ts","../../src/orm/providers/drivers/DatabaseProvider.ts","../../src/orm/services/PgRelationManager.ts","../../src/orm/services/PgJsonQueryManager.ts","../../src/orm/services/QueryManager.ts","../../src/orm/services/Repository.ts","../../src/orm/providers/RepositoryProvider.ts","../../src/orm/primitives/$repository.ts","../../src/orm/primitives/$sequence.ts","../../src/orm/providers/DrizzleKitProvider.ts","../../src/orm/errors/DbMigrationError.ts","../../src/orm/types/byte.ts","../../src/orm/services/ModelBuilder.ts","../../src/orm/services/PostgresModelBuilder.ts","../../src/orm/providers/drivers/NodePostgresProvider.ts","../../src/orm/services/SqliteModelBuilder.ts","../../src/orm/providers/drivers/NodeSqliteProvider.ts","../../src/orm/providers/drivers/PglitePostgresProvider.ts","../../src/orm/helpers/parseQueryString.ts","../../src/orm/primitives/$transaction.ts","../../src/orm/providers/PostgresTypeProvider.ts","../../src/orm/schemas/legacyIdSchema.ts","../../src/orm/index.ts"],"sourcesContent":["import type {\n PgSequenceOptions,\n UpdateDeleteAction,\n} from \"drizzle-orm/pg-core\";\nimport type { EntityPrimitive } from \"../primitives/$entity.ts\";\n\nexport const PG_DEFAULT = Symbol.for(\"Alepha.Postgres.Default\");\nexport const PG_PRIMARY_KEY = Symbol.for(\"Alepha.Postgres.PrimaryKey\");\nexport const PG_CREATED_AT = Symbol.for(\"Alepha.Postgres.CreatedAt\");\nexport const PG_UPDATED_AT = Symbol.for(\"Alepha.Postgres.UpdatedAt\");\nexport const PG_DELETED_AT = Symbol.for(\"Alepha.Postgres.DeletedAt\");\nexport const PG_VERSION = Symbol.for(\"Alepha.Postgres.Version\");\nexport const PG_IDENTITY = Symbol.for(\"Alepha.Postgres.Identity\");\nexport const PG_ENUM = Symbol.for(\"Alepha.Postgres.Enum\");\nexport const PG_REF = Symbol.for(\"Alepha.Postgres.Ref\");\n\n/**\n * @deprecated Use `PG_IDENTITY` instead.\n */\nexport const PG_SERIAL = Symbol.for(\"Alepha.Postgres.Serial\");\n\nexport type PgDefault = typeof PG_DEFAULT;\nexport type PgRef = typeof PG_REF;\nexport type PgPrimaryKey = typeof PG_PRIMARY_KEY;\n\nexport type PgSymbols = {\n [PG_DEFAULT]: {};\n [PG_PRIMARY_KEY]: {};\n [PG_CREATED_AT]: {};\n [PG_UPDATED_AT]: {};\n [PG_DELETED_AT]: {};\n [PG_VERSION]: {};\n [PG_IDENTITY]: PgIdentityOptions;\n [PG_REF]: PgRefOptions;\n [PG_ENUM]: PgEnumOptions;\n\n /**\n * @deprecated Use `PG_IDENTITY` instead.\n */\n [PG_SERIAL]: {};\n};\n\nexport type PgSymbolKeys = keyof PgSymbols;\n\nexport type PgIdentityOptions = {\n mode: \"always\" | \"byDefault\";\n} & PgSequenceOptions & {\n name?: string;\n };\n\nexport interface PgEnumOptions {\n name?: string;\n description?: string;\n}\n\nexport interface PgRefOptions {\n ref: () => {\n name: string;\n entity: EntityPrimitive;\n };\n actions?: {\n onUpdate?: UpdateDeleteAction;\n onDelete?: UpdateDeleteAction;\n };\n}\n","import type { Static, TSchema } from \"alepha\";\nimport { customType } from \"drizzle-orm/pg-core\";\n\n/**\n * Postgres schema type.\n */\nexport const schema = <TDocument extends TSchema>(\n name: string,\n document: TDocument,\n) =>\n customType<{\n data: Static<TDocument>;\n driverData: string;\n config: { document: TDocument };\n configRequired: true;\n }>({\n dataType: () => \"jsonb\",\n toDriver: (value) => JSON.stringify(value),\n fromDriver: (value: TDocument | string) =>\n value && typeof value === \"string\" ? JSON.parse(value) : value,\n })(name, { document }).$type<Static<TDocument>>();\n","import type { TObject, TOptional } from \"alepha\";\nimport { t } from \"alepha\";\nimport { PG_DEFAULT } from \"../constants/PG_SYMBOLS.ts\";\nimport { schema } from \"../types/schema.ts\";\n\n/**\n * Transforms a TObject schema for insert operations.\n * All default properties at the root level are made optional.\n *\n * @example\n * Before: { name: string; age: number(default=0); }\n * After: { name: string; age?: number; }\n */\nexport type TObjectInsert<T extends TObject> = TObject<{\n [K in keyof T[\"properties\"]]: T[\"properties\"][K] extends\n | { [PG_DEFAULT]: any }\n | { \"~optional\": true }\n ? TOptional<T[\"properties\"][K]>\n : T[\"properties\"][K];\n}>;\n\nexport const insertSchema = <T extends TObject>(obj: T): TObjectInsert<T> => {\n const newProperties: Record<string, any> = {};\n\n for (const key in obj.properties) {\n const prop = obj.properties[key];\n\n if (PG_DEFAULT in prop) {\n newProperties[key] = t.optional(prop);\n } else {\n newProperties[key] = prop;\n }\n }\n\n return t.object(\n newProperties,\n \"options\" in schema && typeof schema.options === \"object\"\n ? { ...schema.options }\n : {},\n ) as TObjectInsert<T>;\n};\n","import {\n type TNull,\n type TObject,\n type TOptional,\n type TUnion,\n t,\n} from \"alepha\";\n\n/**\n * Transforms a TObject schema for update operations.\n * All optional properties at the root level are made nullable (i.e., `T | null`).\n * This allows an API endpoint to explicitly accept `null` to clear an optional field in the database.\n *\n * @example\n * Before: { name?: string; age: number; }\n * After: { name?: string | null; age: number; }\n */\nexport type TObjectUpdate<T extends TObject> = TObject<{\n [K in keyof T[\"properties\"]]: T[\"properties\"][K] extends TOptional<infer U>\n ? TOptional<TUnion<[U, TNull]>>\n : T[\"properties\"][K];\n}>;\n\nexport const updateSchema = <T extends TObject>(\n schema: T,\n): TObjectUpdate<T> => {\n const newProperties: Record<string, any> = {};\n\n for (const key in schema.properties) {\n const prop = schema.properties[key];\n if (t.schema.isOptional(prop)) {\n newProperties[key] = t.optional(t.union([prop, t.raw.Null()]));\n } else {\n newProperties[key] = prop;\n }\n }\n\n return t.object(\n newProperties,\n \"options\" in schema && typeof schema.options === \"object\"\n ? { ...schema.options }\n : {},\n ) as TObjectUpdate<T>;\n};\n","import { KIND, type Static, type TObject } from \"alepha\";\nimport type { BuildExtraConfigColumns, SQL } from \"drizzle-orm\";\nimport type {\n PgColumn,\n PgColumnBuilderBase,\n PgTableExtraConfigValue,\n} from \"drizzle-orm/pg-core\";\nimport { insertSchema, type TObjectInsert } from \"../schemas/insertSchema.ts\";\nimport { type TObjectUpdate, updateSchema } from \"../schemas/updateSchema.ts\";\n\n/**\n * Creates a database entity primitive that defines table structure using TypeBox schemas.\n *\n * @example\n * ```ts\n * import { t } from \"alepha\";\n * import { $entity } from \"alepha/orm\";\n *\n * const userEntity = $entity({\n * name: \"users\",\n * schema: t.object({\n * id: pg.primaryKey(),\n * name: t.text(),\n * email: t.email(),\n * }),\n * });\n * ```\n */\nexport const $entity = <TSchema extends TObject>(\n options: EntityPrimitiveOptions<TSchema>,\n): EntityPrimitive<TSchema> => {\n return new EntityPrimitive<TSchema>(options);\n};\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface EntityPrimitiveOptions<\n T extends TObject,\n Keys = keyof Static<T>,\n> {\n /**\n * The database table name that will be created for this entity.\n * If not provided, name will be inferred from the $repository variable name.\n */\n name: string;\n\n /**\n * TypeBox schema defining the table structure and column types.\n */\n schema: T;\n\n /**\n * Database indexes to create for query optimization.\n */\n indexes?: (\n | Keys\n | {\n /**\n * Single column to index.\n */\n column: Keys;\n /**\n * Whether this should be a unique index (enforces uniqueness constraint).\n */\n unique?: boolean;\n /**\n * Custom name for the index. If not provided, generates name automatically.\n */\n name?: string;\n }\n | {\n /**\n * Multiple columns for composite index (order matters for query optimization).\n */\n columns: Keys[];\n /**\n * Whether this should be a unique index (enforces uniqueness constraint).\n */\n unique?: boolean;\n /**\n * Custom name for the index. If not provided, generates name automatically.\n */\n name?: string;\n }\n )[];\n\n /**\n * Foreign key constraints to maintain referential integrity.\n */\n foreignKeys?: Array<{\n /**\n * Optional name for the foreign key constraint.\n */\n name?: string;\n /**\n * Local columns that reference the foreign table.\n */\n columns: Array<keyof Static<T>>;\n /**\n * Referenced columns in the foreign table.\n * Must be EntityColumn references from other entities.\n */\n foreignColumns: Array<() => EntityColumn<any>>;\n }>;\n\n /**\n * Additional table constraints for data validation.\n *\n * Constraints enforce business rules at the database level, providing\n * an additional layer of data integrity beyond application validation.\n *\n * **Constraint Types**:\n * - **Unique constraints**: Prevent duplicate values across columns\n * - **Check constraints**: Enforce custom validation rules with SQL expressions\n *\n * @example\n * ```ts\n * constraints: [\n * {\n * name: \"unique_user_email\",\n * columns: [\"email\"],\n * unique: true\n * },\n * {\n * name: \"valid_age_range\",\n * columns: [\"age\"],\n * check: sql`age >= 0 AND age <= 150`\n * },\n * {\n * name: \"unique_user_username_per_tenant\",\n * columns: [\"tenantId\", \"username\"],\n * unique: true\n * }\n * ]\n * ```\n */\n constraints?: Array<{\n /**\n * Columns involved in this constraint.\n */\n columns: Array<keyof Static<T>>;\n /**\n * Optional name for the constraint.\n */\n name?: string;\n /**\n * Whether this is a unique constraint.\n */\n unique?: boolean | {} /* options */;\n /**\n * SQL expression for check constraint validation.\n */\n check?: SQL;\n }>;\n\n /**\n * Advanced Drizzle ORM configuration for complex table setups.\n */\n config?: (\n self: BuildExtraConfigColumns<string, FromSchema<T>, \"pg\">,\n ) => PgTableExtraConfigValue[];\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport class EntityPrimitive<T extends TObject = TObject> {\n public readonly options: EntityPrimitiveOptions<T>;\n\n constructor(options: EntityPrimitiveOptions<T>) {\n this.options = options;\n }\n\n alias(alias: string): this {\n const aliased = new EntityPrimitive<T>(this.options);\n return new Proxy(aliased, {\n get(target, prop, receiver) {\n if (prop === \"$alias\") {\n return alias;\n }\n return Reflect.get(target, prop, receiver);\n },\n }) as this;\n }\n\n get cols(): EntityColumns<T> {\n const cols: Partial<EntityColumns<T>> = {};\n for (const key of Object.keys(this.schema.properties) as Array<\n keyof T[\"properties\"]\n >) {\n cols[key] = {\n name: key as string,\n entity: this,\n };\n }\n\n return cols as EntityColumns<T>;\n }\n\n get name(): string {\n return this.options.name;\n }\n\n get schema(): T {\n return this.options.schema;\n }\n\n get insertSchema(): TObjectInsert<T> {\n return insertSchema(this.options.schema);\n }\n\n get updateSchema(): TObjectUpdate<T> {\n return updateSchema(this.options.schema);\n }\n}\n\n$entity[KIND] = EntityPrimitive;\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Convert a schema to columns.\n */\nexport type FromSchema<T extends TObject> = {\n [key in keyof T[\"properties\"]]: PgColumnBuilderBase;\n};\n\nexport type SchemaToTableConfig<T extends TObject> = {\n name: string;\n schema: string | undefined;\n columns: {\n [key in keyof T[\"properties\"]]: PgColumn;\n };\n dialect: string;\n};\n\nexport type EntityColumn<T extends TObject> = {\n name: string;\n entity: EntityPrimitive<T>;\n};\n\nexport type EntityColumns<T extends TObject> = {\n [key in keyof T[\"properties\"]]: EntityColumn<T>;\n};\n","import { AlephaError } from \"alepha\";\n\nexport class DbError extends AlephaError {\n name = \"DbError\";\n\n constructor(message: string, cause?: unknown) {\n super(message, { cause });\n }\n}\n","import { DbError } from \"./DbError.ts\";\n\nexport class DbConflictError extends DbError {\n readonly name = \"DbConflictError\";\n readonly status = 409;\n}\n","import { DbError } from \"./DbError.ts\";\n\nexport class DbEntityNotFoundError extends DbError {\n readonly name = \"DbEntityNotFoundError\";\n readonly status = 404;\n\n constructor(entityName: string) {\n super(`Entity from '${entityName}' was not found`);\n }\n}\n","import { DbError } from \"./DbError.ts\";\n\n/**\n * Error thrown when there is a version mismatch.\n * It's thrown by {@link Repository#save} when the updated entity version does not match the one in the database.\n * This is used for optimistic concurrency control.\n */\nexport class DbVersionMismatchError extends DbError {\n readonly name = \"DbVersionMismatchError\";\n\n constructor(table: string, id: any) {\n super(`Version mismatch for table '${table}' and id '${id}'`);\n }\n}\n","import type { TObject, TSchema } from \"alepha\";\nimport type { PgSymbolKeys, PgSymbols } from \"../constants/PG_SYMBOLS.ts\";\n\n/**\n * Decorates a typebox schema with a Postgres attribute.\n *\n * > It's just a fancy way to add Symbols to a field.\n *\n * @example\n * ```ts\n * import { t } from \"alepha\";\n * import { PG_UPDATED_AT } from \"../constants/PG_SYMBOLS\";\n *\n * export const updatedAtSchema = pgAttr(\n * t.datetime(), PG_UPDATED_AT,\n * );\n * ```\n */\nexport const pgAttr = <T extends TSchema, Attr extends PgSymbolKeys>(\n type: T,\n attr: Attr,\n value?: PgSymbols[Attr],\n): PgAttr<T, Attr> => {\n Object.assign(type, { [attr]: value ?? {} });\n return type as PgAttr<T, Attr>;\n};\n\n/**\n * Retrieves the fields of a schema that have a specific attribute.\n */\nexport const getAttrFields = (\n schema: TObject,\n name: PgSymbolKeys,\n): PgAttrField[] => {\n const fields: Array<PgAttrField> = [];\n\n for (const key of Object.keys(schema.properties)) {\n const value = schema.properties[key];\n if (name in value) {\n fields.push({\n type: value as TSchema,\n key: key,\n data: (value as any)[name],\n });\n }\n }\n\n return fields;\n};\n\n/**\n * Type representation.\n */\nexport type PgAttr<T extends TSchema, TAttr extends PgSymbolKeys> = T & {\n [K in TAttr]: PgSymbols[K];\n};\n\nexport interface PgAttrField {\n key: string;\n type: TSchema;\n data: any;\n nested?: any[];\n one?: boolean;\n}\n","import { stat } from \"node:fs/promises\";\nimport {\n $inject,\n Alepha,\n AlephaError,\n type Static,\n type TObject,\n} from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport type { SQLWrapper } from \"drizzle-orm\";\nimport {\n alias,\n type PgDatabase,\n type PgTableWithColumns,\n} from \"drizzle-orm/pg-core\";\nimport { DbError } from \"../../errors/DbError.ts\";\nimport type {\n EntityPrimitive,\n SchemaToTableConfig,\n} from \"../../primitives/$entity.ts\";\nimport type { SequencePrimitive } from \"../../primitives/$sequence.ts\";\nimport type { ModelBuilder } from \"../../services/ModelBuilder.ts\";\nimport type { DrizzleKitProvider } from \"../DrizzleKitProvider.ts\";\n\nexport type SQLLike = SQLWrapper | string;\n\nexport abstract class DatabaseProvider {\n protected readonly alepha = $inject(Alepha);\n protected readonly log = $logger();\n protected abstract readonly builder: ModelBuilder;\n protected abstract readonly kit: DrizzleKitProvider;\n public abstract readonly db: PgDatabase<any>;\n public abstract readonly dialect: \"postgresql\" | \"sqlite\";\n public abstract readonly url: string;\n\n public readonly enums = new Map<string, unknown>();\n public readonly tables = new Map<string, unknown>();\n public readonly sequences = new Map<string, unknown>();\n\n public get name() {\n return \"default\";\n }\n\n public get schema() {\n return \"public\";\n }\n\n public table<T extends TObject>(\n entity: EntityPrimitive<T>,\n ): PgTableWithColumns<SchemaToTableConfig<T>> {\n const table = this.tables.get(entity.name);\n if (!table) {\n throw new AlephaError(`Table '${entity.name}' is not registered`);\n }\n\n const hasAlias = (entity as any).$alias;\n\n if (hasAlias) {\n return alias(\n table as PgTableWithColumns<SchemaToTableConfig<T>>,\n hasAlias,\n ) as PgTableWithColumns<SchemaToTableConfig<T>>;\n }\n\n return table as PgTableWithColumns<SchemaToTableConfig<T>>;\n }\n\n public registerEntity(entity: EntityPrimitive) {\n this.builder.buildTable(entity, this);\n }\n\n public registerSequence(sequence: SequencePrimitive) {\n this.builder.buildSequence(sequence, this);\n }\n\n public abstract execute(\n statement: SQLLike,\n ): Promise<Record<string, unknown>[]>;\n\n public async run<T extends TObject>(\n statement: SQLLike,\n schema: T,\n ): Promise<Array<Static<T>>> {\n const result = await this.execute(statement);\n return result.map((row) => this.alepha.codec.decode(schema, row));\n }\n\n /**\n * Get migrations folder path - can be overridden\n */\n protected getMigrationsFolder(): string {\n return `migrations/${this.name}`;\n }\n\n /**\n * Base migration orchestration - handles environment logic\n */\n protected async migrateDatabase(): Promise<void> {\n const migrationsFolder = this.getMigrationsFolder();\n\n // Handle different environments\n if (this.alepha.isProduction()) {\n await this.runProductionMigration(migrationsFolder);\n } else if (this.alepha.isTest()) {\n await this.runTestMigration();\n } else {\n await this.runDevelopmentMigration(migrationsFolder);\n }\n }\n\n /**\n * Production: run migrations from folder\n */\n protected async runProductionMigration(\n migrationsFolder: string,\n ): Promise<void> {\n // Check folder exists\n const exists = await stat(migrationsFolder).catch(() => false);\n\n if (!exists) {\n this.log.warn(\"Migration SKIPPED - no migrations found\");\n return;\n }\n\n this.log.debug(`Migrate from '${migrationsFolder}' directory ...`);\n\n // Delegate to provider-specific implementation\n await this.executeMigrations(migrationsFolder);\n\n this.log.info(\"Migration OK\");\n }\n\n /**\n * Test: always synchronize\n */\n protected async runTestMigration(): Promise<void> {\n await this.synchronizeSchema();\n }\n\n /**\n * Development: default to synchronize (can be overridden)\n */\n protected async runDevelopmentMigration(\n migrationsFolder: string,\n ): Promise<void> {\n // try migrations silently first\n try {\n // exclude in-memory databases (there is nothing to migrate!)\n if (!this.url.includes(\":memory:\")) {\n await this.executeMigrations(migrationsFolder);\n }\n } catch {\n // Ignore errors\n }\n\n // then synchronize\n await this.synchronizeSchema();\n }\n\n /**\n * Common synchronization with error handling\n */\n protected async synchronizeSchema(): Promise<void> {\n try {\n await this.kit.synchronize(this);\n } catch (error) {\n throw new DbError(\n `Failed to synchronize ${this.dialect} database schema`,\n error as Error,\n );\n }\n }\n\n /**\n * Provider-specific migration execution\n * MUST be implemented by each provider\n */\n protected abstract executeMigrations(migrationsFolder: string): Promise<void>;\n}\n","import { type TObject, t, Value } from \"alepha\";\nimport { getTableName, type SQL, sql } from \"drizzle-orm\";\nimport type { PgSelectBase, PgTableWithColumns } from \"drizzle-orm/pg-core\";\nimport { isSQLWrapper } from \"drizzle-orm/sql/sql\";\nimport type { PgRelationMap } from \"../interfaces/PgQuery.ts\";\nimport type { EntityPrimitive } from \"../primitives/$entity.ts\";\nimport type { DatabaseProvider } from \"../providers/drivers/DatabaseProvider.ts\";\nimport type { PgJoin } from \"./QueryManager.ts\";\n\nexport class PgRelationManager {\n /**\n * Recursively build joins for the query builder based on the relations map\n */\n public buildJoins(\n provider: DatabaseProvider,\n builder: PgSelectBase<any, any, any>,\n joins: Array<PgJoin>,\n withRelations: PgRelationMap<TObject>,\n table: PgTableWithColumns<any>,\n parentKey?: string,\n ) {\n for (const [key, join] of Object.entries(withRelations)) {\n const from = provider.table(join.join as EntityPrimitive);\n const on = isSQLWrapper(join.on)\n ? (join.on as SQL)\n : sql`${table[join.on[0] as string]} = ${from[join.on[1].name]}`;\n\n if (join.type === \"right\") {\n builder.rightJoin(from, on);\n } else if (join.type === \"inner\") {\n builder.innerJoin(from, on);\n } else {\n builder.leftJoin(from, on);\n }\n\n joins.push({\n key,\n table: getTableName(from),\n schema: join.join.schema,\n col: (name: string) => from[name],\n parent: parentKey,\n });\n\n if (join.with) {\n this.buildJoins(\n provider,\n builder,\n joins,\n join.with,\n from,\n parentKey ? `${parentKey}.${key}` : key,\n );\n }\n }\n }\n\n /**\n * Map a row with its joined relations based on the joins definition\n */\n public mapRowWithJoins(\n record: Record<string, unknown>,\n row: Record<string, unknown>,\n schema: TObject,\n joins: PgJoin[],\n parentKey?: string,\n ) {\n for (const join of joins) {\n if (join.parent === parentKey) {\n const joinedData = row[join.table];\n // Set to undefined if all values in the joined table are null (left join with no match)\n if (this.isAllNull(joinedData)) {\n record[join.key] = undefined;\n } else {\n record[join.key] = joinedData;\n // Only process nested joins if the parent join has data\n this.mapRowWithJoins(\n record[join.key] as Record<string, unknown>,\n row,\n schema, // Don't need to pass modified schema, just for recursion\n joins,\n parentKey ? `${parentKey}.${join.key}` : join.key,\n );\n }\n }\n }\n return record;\n }\n\n /**\n * Check if all values in an object are null (indicates a left join with no match)\n */\n private isAllNull(obj: unknown): boolean {\n if (obj === null || obj === undefined) return true;\n if (typeof obj !== \"object\") return false;\n return Object.values(obj).every((val) => val === null);\n }\n\n /**\n * Build a schema that includes all join properties recursively\n */\n public buildSchemaWithJoins(\n baseSchema: TObject,\n joins: PgJoin[],\n parentPath?: string,\n ): TObject {\n const schema = Value.Clone(baseSchema) as TObject;\n\n // Group joins by parent\n const joinsAtThisLevel = joins.filter((j) => j.parent === parentPath);\n\n for (const join of joinsAtThisLevel) {\n // Build the path for this join\n const joinPath = parentPath ? `${parentPath}.${join.key}` : join.key;\n\n // Find child joins\n const childJoins = joins.filter((j) => j.parent === joinPath);\n\n // If there are child joins, recursively build the schema\n let joinSchema = join.schema;\n if (childJoins.length > 0) {\n joinSchema = this.buildSchemaWithJoins(join.schema, joins, joinPath);\n }\n\n // Make the join optional (left joins may return null)\n schema.properties[join.key] = t.optional(joinSchema);\n }\n\n return schema;\n }\n}\n","import type { TObject } from \"alepha\";\nimport { type SQL, sql } from \"drizzle-orm\";\nimport type { PgColumn } from \"drizzle-orm/pg-core\";\nimport type { FilterOperators } from \"../interfaces/FilterOperators.ts\";\nimport type { PgQueryWhere } from \"../interfaces/PgQueryWhere.ts\";\n\n/**\n * Manages JSONB query generation for nested object and array queries in PostgreSQL.\n * This class handles complex nested queries using PostgreSQL's JSONB operators.\n */\nexport class PgJsonQueryManager {\n /**\n * Check if a query contains nested JSONB queries.\n * A nested query is when the value is an object with operator keys.\n */\n public hasNestedQuery(where: PgQueryWhere<TObject>): boolean {\n for (const [key, value] of Object.entries(where)) {\n // Skip logical operators\n if (key === \"and\" || key === \"or\" || key === \"not\") {\n continue;\n }\n\n // Check if value is an object with nested properties\n if (value && typeof value === \"object\" && !Array.isArray(value)) {\n // Check if it has operator keys or nested object keys\n const keys = Object.keys(value);\n const hasOperators = keys.some((k) =>\n [\n \"eq\",\n \"ne\",\n \"gt\",\n \"gte\",\n \"lt\",\n \"lte\",\n \"like\",\n \"ilike\",\n \"isNull\",\n \"isNotNull\",\n \"inArray\",\n \"notInArray\",\n ].includes(k),\n );\n\n // If it doesn't have operators, it might be a nested query\n if (!hasOperators && keys.length > 0) {\n return true;\n }\n }\n }\n return false;\n }\n\n /**\n * Build a JSONB query condition for nested object queries.\n * Supports deep nesting like: { profile: { contact: { email: { eq: \"test@example.com\" } } } }\n *\n * @param column The JSONB column\n * @param path The path to the nested property (e.g., ['profile', 'contact', 'email'])\n * @param operator The filter operator (e.g., { eq: \"test@example.com\" })\n * @param dialect Database dialect (postgresql or sqlite)\n * @param columnSchema Optional schema of the JSON column for type inference\n * @returns SQL condition\n */\n public buildJsonbCondition(\n column: PgColumn,\n path: string[],\n operator: FilterOperators<any>,\n dialect: \"postgresql\" | \"sqlite\",\n columnSchema?: any,\n ): SQL | undefined {\n if (path.length === 0) {\n return undefined;\n }\n\n // Check if operator is an array operator that needs JSONB (not text extraction)\n const isArrayOperator =\n operator.arrayContains !== undefined ||\n operator.arrayContained !== undefined ||\n operator.arrayOverlaps !== undefined;\n\n let jsonValue: SQL;\n\n if (dialect === \"sqlite\") {\n // SQLite: json_extract(column, '$.path.to.field')\n const pathStr = `$.${path.join(\".\")}`;\n jsonValue = sql`json_extract(${column}, ${pathStr})`;\n } else {\n // PostgreSQL: Build the JSON path\n let jsonPath = sql`${column}`;\n\n // Navigate through all path elements except the last\n for (let i = 0; i < path.length - 1; i++) {\n jsonPath = sql`${jsonPath}->${path[i]}`;\n }\n\n // For the last element:\n // - Use -> to keep as JSONB for array operators\n // - Use ->> to extract as text for other operators\n const lastPath = path[path.length - 1];\n if (isArrayOperator) {\n jsonValue = sql`${jsonPath}->${lastPath}`;\n } else {\n jsonValue = sql`${jsonPath}->>${lastPath}`;\n }\n }\n\n // Get field type for smart casting\n const fieldType = columnSchema\n ? this.getFieldType(columnSchema, path)\n : undefined;\n\n // Apply the operator\n return this.applyOperatorToJsonValue(\n jsonValue,\n operator,\n dialect,\n fieldType,\n );\n }\n\n /**\n * Build JSONB array query conditions.\n * Supports queries like: { addresses: { city: { eq: \"Wonderland\" } } }\n * which translates to: EXISTS (SELECT 1 FROM jsonb_array_elements(addresses) elem WHERE elem->>'city' = 'Wonderland')\n *\n * @param dialect Database dialect (postgresql or sqlite)\n * Note: SQLite array queries are not yet supported\n */\n public buildJsonbArrayCondition(\n column: PgColumn,\n path: string[],\n arrayPath: string,\n operator: FilterOperators<any>,\n dialect: \"postgresql\" | \"sqlite\",\n ): SQL | undefined {\n if (dialect === \"sqlite\") {\n throw new Error(\n \"Array queries in JSON columns are not yet supported for SQLite. \" +\n \"Please use PostgreSQL for complex JSON array queries, or restructure your data.\",\n );\n }\n\n if (path.length === 0) {\n return undefined;\n }\n\n // Build the base JSONB path to the array\n let jsonPath = sql`${column}`;\n if (arrayPath) {\n jsonPath = sql`${jsonPath}->${arrayPath}`;\n }\n\n // Build the condition for array elements\n const lastPath = path[0];\n const elemCondition = sql`elem->>${lastPath}`;\n const condition = this.applyOperatorToJsonValue(\n elemCondition,\n operator,\n dialect,\n );\n\n if (!condition) {\n return undefined;\n }\n\n // Wrap in EXISTS with jsonb_array_elements\n return sql`EXISTS (SELECT 1 FROM jsonb_array_elements(${jsonPath}) AS elem WHERE ${condition})`;\n }\n\n /**\n * Apply a filter operator to a JSONB value.\n * @param dialect Database dialect for appropriate casting syntax\n * @param fieldType Optional field type from schema for smart casting\n */\n private applyOperatorToJsonValue(\n jsonValue: SQL,\n operator: FilterOperators<any>,\n dialect: \"postgresql\" | \"sqlite\",\n fieldType?: string,\n ): SQL | undefined {\n // Helper to cast for numeric comparisons based on dialect and field type\n const castForNumeric = (value: SQL): SQL => {\n if (dialect === \"sqlite\") {\n // Use INTEGER for int types, REAL for number types\n if (fieldType === \"integer\" || fieldType === \"int\") {\n return sql`CAST(${value} AS INTEGER)`;\n }\n // Default to REAL for numeric comparisons\n return sql`CAST(${value} AS REAL)`;\n }\n // PostgreSQL\n return sql`(${value})::numeric`;\n };\n\n if (typeof operator !== \"object\") {\n // Direct value comparison\n return sql`${jsonValue} = ${operator}`;\n }\n\n const conditions: SQL[] = [];\n\n if (operator.eq !== undefined) {\n conditions.push(sql`${jsonValue} = ${operator.eq}`);\n }\n\n if (operator.ne !== undefined) {\n conditions.push(sql`${jsonValue} != ${operator.ne}`);\n }\n\n if (operator.gt !== undefined) {\n // Cast to numeric for comparison\n conditions.push(sql`${castForNumeric(jsonValue)} > ${operator.gt}`);\n }\n\n if (operator.gte !== undefined) {\n conditions.push(sql`${castForNumeric(jsonValue)} >= ${operator.gte}`);\n }\n\n if (operator.lt !== undefined) {\n conditions.push(sql`${castForNumeric(jsonValue)} < ${operator.lt}`);\n }\n\n if (operator.lte !== undefined) {\n conditions.push(sql`${castForNumeric(jsonValue)} <= ${operator.lte}`);\n }\n\n if (operator.like !== undefined) {\n conditions.push(sql`${jsonValue} LIKE ${operator.like}`);\n }\n\n if (operator.ilike !== undefined) {\n // SQLite: LIKE is case-insensitive by default, so use LIKE\n // PostgreSQL: Use ILIKE\n if (dialect === \"sqlite\") {\n conditions.push(sql`${jsonValue} LIKE ${operator.ilike}`);\n } else {\n conditions.push(sql`${jsonValue} ILIKE ${operator.ilike}`);\n }\n }\n\n if (operator.notLike !== undefined) {\n conditions.push(sql`${jsonValue} NOT LIKE ${operator.notLike}`);\n }\n\n if (operator.notIlike !== undefined) {\n // SQLite: LIKE is case-insensitive by default, so use NOT LIKE\n // PostgreSQL: Use NOT ILIKE\n if (dialect === \"sqlite\") {\n conditions.push(sql`${jsonValue} NOT LIKE ${operator.notIlike}`);\n } else {\n conditions.push(sql`${jsonValue} NOT ILIKE ${operator.notIlike}`);\n }\n }\n\n if (operator.isNull !== undefined) {\n conditions.push(sql`${jsonValue} IS NULL`);\n }\n\n if (operator.isNotNull !== undefined) {\n conditions.push(sql`${jsonValue} IS NOT NULL`);\n }\n\n if (operator.inArray !== undefined && Array.isArray(operator.inArray)) {\n conditions.push(\n sql`${jsonValue} IN (${sql.join(\n operator.inArray.map((v) => sql`${v}`),\n sql`, `,\n )})`,\n );\n }\n\n if (\n operator.notInArray !== undefined &&\n Array.isArray(operator.notInArray)\n ) {\n conditions.push(\n sql`${jsonValue} NOT IN (${sql.join(\n operator.notInArray.map((v) => sql`${v}`),\n sql`, `,\n )})`,\n );\n }\n\n // Handle array operators for JSONB arrays\n // When these operators are used, jsonValue will be a JSONB value (not text extracted)\n if (operator.arrayContains !== undefined) {\n if (dialect === \"postgresql\") {\n // PostgreSQL @> operator: checks if left JSONB contains right JSONB\n // JSON.stringify ensures the value is properly escaped as a JSON string\n const jsonArray = JSON.stringify(\n Array.isArray(operator.arrayContains)\n ? operator.arrayContains\n : [operator.arrayContains],\n );\n // The value is safely parameterized via sql template, preventing SQL injection\n conditions.push(sql`${jsonValue} @> ${jsonArray}::jsonb`);\n }\n }\n\n if (operator.arrayContained !== undefined) {\n if (dialect === \"postgresql\") {\n // PostgreSQL <@ operator: checks if left JSONB is contained in right JSONB\n const jsonArray = JSON.stringify(\n Array.isArray(operator.arrayContained)\n ? operator.arrayContained\n : [operator.arrayContained],\n );\n conditions.push(sql`${jsonValue} <@ ${jsonArray}::jsonb`);\n }\n }\n\n if (operator.arrayOverlaps !== undefined) {\n if (dialect === \"postgresql\") {\n // PostgreSQL ?| operator: checks if any of the array elements exist as top-level keys\n // Note: For JSONB arrays, we need to use a different approach\n // Convert the JSONB array to text array for the ?| operator\n const values = Array.isArray(operator.arrayOverlaps)\n ? operator.arrayOverlaps\n : [operator.arrayOverlaps];\n\n // Build an OR condition to check if any value exists in the array\n // This is safer than using ?| with dynamic values\n const overlapConditions = values.map((val) => {\n const jsonVal = JSON.stringify(val);\n return sql`${jsonValue} @> ${jsonVal}::jsonb`;\n });\n\n if (overlapConditions.length > 0) {\n conditions.push(sql`(${sql.join(overlapConditions, sql` OR `)})`);\n }\n }\n }\n\n if (conditions.length === 0) {\n return undefined;\n }\n\n if (conditions.length === 1) {\n return conditions[0];\n }\n\n // Multiple conditions - AND them together\n return sql.join(conditions, sql` AND `);\n }\n\n /**\n * Parse a nested query object and extract the path and operator.\n * For example: { profile: { contact: { email: { eq: \"test@example.com\" } } } }\n * Returns: { path: ['profile', 'contact', 'email'], operator: { eq: \"test@example.com\" } }\n */\n public parseNestedQuery(\n nestedQuery: any,\n currentPath: string[] = [],\n ): Array<{ path: string[]; operator: FilterOperators<any> }> {\n const results: Array<{ path: string[]; operator: FilterOperators<any> }> =\n [];\n\n for (const [key, value] of Object.entries(nestedQuery)) {\n if (value && typeof value === \"object\" && !Array.isArray(value)) {\n // Check if this is an operator object\n const keys = Object.keys(value);\n const hasOperators = keys.some((k) =>\n [\n \"eq\",\n \"ne\",\n \"gt\",\n \"gte\",\n \"lt\",\n \"lte\",\n \"like\",\n \"ilike\",\n \"notLike\",\n \"notIlike\",\n \"isNull\",\n \"isNotNull\",\n \"inArray\",\n \"notInArray\",\n \"arrayContains\",\n \"arrayContained\",\n \"arrayOverlaps\",\n ].includes(k),\n );\n\n if (hasOperators) {\n // This is an operator, add to results\n results.push({\n path: [...currentPath, key],\n operator: value as FilterOperators<any>,\n });\n } else {\n // This is a nested object, recurse\n const nestedResults = this.parseNestedQuery(value, [\n ...currentPath,\n key,\n ]);\n results.push(...nestedResults);\n }\n }\n }\n\n return results;\n }\n\n /**\n * Determine if a property is a JSONB column based on the schema.\n * A column is JSONB if it's defined as an object or array in the TypeBox schema.\n */\n public isJsonbColumn(schema: TObject, columnName: string): boolean {\n const property = schema.properties[columnName];\n if (!property) {\n return false;\n }\n\n // Check if it's an object or array type\n return (\n (property as any).type === \"object\" || (property as any).type === \"array\"\n );\n }\n\n /**\n * Check if an array property contains primitive types (string, number, boolean, etc.)\n * rather than objects. Primitive arrays should use native Drizzle operators.\n * @returns true if the array contains primitives, false if it contains objects\n */\n public isPrimitiveArray(schema: TObject, columnName: string): boolean {\n const property = schema.properties[columnName];\n if (!property || (property as any).type !== \"array\") {\n return false;\n }\n\n // Check the items type\n const items = (property as any).items;\n if (!items) {\n return false;\n }\n\n // If items is an object type, it's not a primitive array\n // Primitive types are: string, number, integer, boolean, null\n const itemType = items.type;\n return (\n itemType === \"string\" ||\n itemType === \"number\" ||\n itemType === \"integer\" ||\n itemType === \"boolean\" ||\n itemType === \"null\"\n );\n }\n\n /**\n * Get the type of a field by navigating through a schema path.\n * Used for smart type casting in SQL queries.\n *\n * @param columnSchema The schema of the JSON column (e.g., t.object({ age: t.integer() }))\n * @param path The path to navigate (e.g., ['contact', 'email'])\n * @returns The type string (e.g., 'integer', 'number', 'string') or undefined if not found\n */\n private getFieldType(columnSchema: any, path: string[]): string | undefined {\n let current = columnSchema;\n\n for (const segment of path) {\n // Navigate into object properties\n if (current.type === \"object\" && current.properties) {\n current = current.properties[segment];\n if (!current) {\n return undefined;\n }\n } else {\n // Path segment doesn't exist or current is not an object\n return undefined;\n }\n }\n\n return current.type;\n }\n\n /**\n * Check if a nested path points to an array property.\n */\n public isArrayProperty(schema: TObject, path: string[]): boolean {\n if (path.length === 0) {\n return false;\n }\n\n let currentSchema: any = schema.properties[path[0]];\n if (!currentSchema) {\n return false;\n }\n\n // If first element is an array, return true\n if (currentSchema.type === \"array\") {\n return true;\n }\n\n // Navigate through nested objects\n for (let i = 1; i < path.length; i++) {\n if (currentSchema.type === \"object\" && currentSchema.properties) {\n currentSchema = currentSchema.properties[path[i]];\n if (!currentSchema) {\n return false;\n }\n if (currentSchema.type === \"array\") {\n return true;\n }\n } else {\n return false;\n }\n }\n\n return false;\n }\n}\n","import {\n $inject,\n Alepha,\n AlephaError,\n createPagination,\n type TObject,\n} from \"alepha\";\nimport {\n and,\n arrayContained,\n arrayContains,\n arrayOverlaps,\n between,\n eq,\n gt,\n gte,\n ilike,\n inArray,\n isNotNull,\n isNull,\n isSQLWrapper,\n like,\n lt,\n lte,\n ne,\n not,\n notBetween,\n notIlike,\n notInArray,\n notLike,\n or,\n type SQL,\n sql,\n} from \"drizzle-orm\";\nimport type { PgColumn } from \"drizzle-orm/pg-core\";\nimport type { FilterOperators } from \"../interfaces/FilterOperators.ts\";\nimport type {\n PgQueryWhere,\n PgQueryWhereOrSQL,\n} from \"../interfaces/PgQueryWhere.ts\";\nimport { PgJsonQueryManager } from \"./PgJsonQueryManager.ts\";\n\nexport class QueryManager {\n protected readonly jsonQueryManager = $inject(PgJsonQueryManager);\n protected readonly alepha = $inject(Alepha);\n\n /**\n * Convert a query object to a SQL query.\n */\n public toSQL(\n query: PgQueryWhereOrSQL<TObject>,\n options: {\n schema: TObject;\n col: (key: string) => PgColumn;\n joins?: PgJoin[];\n dialect: \"postgresql\" | \"sqlite\";\n },\n ): SQL | undefined {\n const { schema, col, joins } = options;\n const conditions: SQL[] = [];\n\n if (isSQLWrapper(query)) {\n conditions.push(query as SQL);\n } else {\n const keys = Object.keys(query) as Array<\n keyof PgQueryWhere<TObject> & string\n >;\n\n for (const key of keys) {\n const operator = query[key] as SQL;\n\n // Handle joins - check if this key matches a join at the current level\n if (\n typeof query[key] === \"object\" &&\n query[key] != null &&\n !Array.isArray(query[key]) &&\n joins?.length\n ) {\n // Find the join that matches this key (at the current level, without parent filtering)\n const matchingJoins = joins.filter((j) => j.key === key);\n if (matchingJoins.length > 0) {\n // Use the first matching join (they should all have the same schema)\n const join = matchingJoins[0];\n\n // Build the full path to this join\n const joinPath = join.parent ? `${join.parent}.${key}` : key;\n\n // Find child joins: those whose parent starts with this join's path\n const childJoins = joins.filter((j) => {\n if (!j.parent) return false;\n // Child's parent should be exactly our path, or start with our path + \".\"\n return (\n j.parent === joinPath || j.parent.startsWith(`${joinPath}.`)\n );\n });\n\n // For recursion, we need to restructure child joins\n // Remove the current path prefix from parent keys\n const recursiveJoins = childJoins.map((j) => {\n const newParent =\n j.parent === joinPath\n ? undefined\n : j.parent!.substring(joinPath.length + 1);\n return {\n ...j,\n parent: newParent,\n };\n });\n\n const sql = this.toSQL(query[key], {\n schema: join.schema,\n col: join.col,\n joins: recursiveJoins.length > 0 ? recursiveJoins : undefined,\n dialect: options.dialect,\n });\n if (sql) {\n conditions.push(sql);\n }\n continue;\n }\n }\n\n if (Array.isArray(operator)) {\n const operations: SQL[] = operator\n .map((it) => {\n if (isSQLWrapper(it)) {\n return it as SQL;\n }\n return this.toSQL(it as PgQueryWhere<TObject>, {\n schema,\n col,\n joins, // Pass joins through recursively\n dialect: options.dialect,\n });\n })\n .filter((it) => it != null);\n\n if (key === \"and\") {\n return and(...operations);\n }\n\n if (key === \"or\") {\n return or(...operations);\n }\n }\n\n if (key === \"not\") {\n const where = this.toSQL(operator as PgQueryWhereOrSQL<TObject>, {\n schema,\n col,\n joins, // Pass joins through recursively\n dialect: options.dialect,\n });\n if (where) {\n return not(where);\n }\n }\n\n if (operator) {\n // Check if this is a JSONB column with nested query\n // BUT skip primitive arrays - they should use native Drizzle operators\n if (\n this.jsonQueryManager.isJsonbColumn(schema, key) &&\n !this.jsonQueryManager.isPrimitiveArray(schema, key) &&\n typeof operator === \"object\" &&\n !Array.isArray(operator) &&\n this.jsonQueryManager.hasNestedQuery({ [key]: operator })\n ) {\n // Handle JSONB nested queries for objects and arrays of objects\n const column = col(key);\n const jsonbSql = this.buildJsonbQuery(\n column,\n operator,\n schema,\n key,\n options.dialect,\n );\n if (jsonbSql) {\n conditions.push(jsonbSql);\n }\n } else {\n // Regular column query (including primitive arrays)\n const column = col(key);\n const sql = this.mapOperatorToSql(\n operator,\n column,\n schema,\n key,\n options.dialect,\n );\n if (sql) {\n conditions.push(sql);\n }\n }\n }\n }\n }\n\n if (conditions.length === 1) {\n return conditions[0];\n }\n\n return and(...conditions);\n }\n\n /**\n * Build a JSONB query for nested object/array queries.\n */\n protected buildJsonbQuery(\n column: PgColumn,\n nestedQuery: any,\n schema: TObject,\n columnName: string,\n dialect: \"postgresql\" | \"sqlite\",\n ): SQL | undefined {\n // Parse the nested query to extract paths and operators\n const queries = this.jsonQueryManager.parseNestedQuery(nestedQuery);\n\n if (queries.length === 0) {\n return undefined;\n }\n\n // Get the column schema for type inference\n const columnSchema = schema.properties[columnName];\n\n // Build conditions for each parsed query\n const conditions: SQL[] = [];\n\n for (const { path, operator } of queries) {\n // Check if the operator is an array operator (arrayContains, arrayContained, arrayOverlaps)\n const isArrayOperator =\n operator.arrayContains !== undefined ||\n operator.arrayContained !== undefined ||\n operator.arrayOverlaps !== undefined;\n\n // Check if this is an array property\n const isArrayProp = this.jsonQueryManager.isArrayProperty(schema, [\n columnName,\n ...path,\n ]);\n\n if (isArrayProp && isArrayOperator) {\n // Array operators on JSONB arrays should use buildJsonbCondition\n // This handles cases like: { metadata: { permissions: { arrayContains: [...] } } }\n const condition = this.jsonQueryManager.buildJsonbCondition(\n column,\n path,\n operator,\n dialect,\n columnSchema,\n );\n if (condition) {\n conditions.push(condition);\n }\n } else if (isArrayProp && !isArrayOperator) {\n // Non-array operators on array properties use buildJsonbArrayCondition\n // This handles cases like: { addresses: { city: { eq: \"Wonderland\" } } }\n const condition = this.jsonQueryManager.buildJsonbArrayCondition(\n column,\n path,\n \"\",\n operator,\n dialect,\n );\n if (condition) {\n conditions.push(condition);\n }\n } else {\n // Handle object queries\n const condition = this.jsonQueryManager.buildJsonbCondition(\n column,\n path,\n operator,\n dialect,\n columnSchema,\n );\n if (condition) {\n conditions.push(condition);\n }\n }\n }\n\n if (conditions.length === 0) {\n return undefined;\n }\n\n if (conditions.length === 1) {\n return conditions[0];\n }\n\n // Multiple conditions - AND them together\n return and(...conditions);\n }\n\n /**\n * Check if an object has any filter operator properties.\n */\n protected hasFilterOperatorProperties(obj: any): boolean {\n if (!obj || typeof obj !== \"object\") return false;\n\n const filterOperatorKeys = [\n \"eq\",\n \"ne\",\n \"gt\",\n \"gte\",\n \"lt\",\n \"lte\",\n \"inArray\",\n \"notInArray\",\n \"isNull\",\n \"isNotNull\",\n \"like\",\n \"notLike\",\n \"ilike\",\n \"notIlike\",\n \"contains\",\n \"startsWith\",\n \"endsWith\",\n \"between\",\n \"notBetween\",\n \"arrayContains\",\n \"arrayContained\",\n \"arrayOverlaps\",\n ];\n\n return filterOperatorKeys.some((key) => key in obj);\n }\n\n /**\n * Map a filter operator to a SQL query.\n */\n public mapOperatorToSql(\n operator: FilterOperators<any> | any,\n column: PgColumn,\n columnSchema?: TObject,\n columnName?: string,\n dialect: \"postgresql\" | \"sqlite\" = \"postgresql\",\n ): SQL | undefined {\n // Helper function to encode a value for the specific column\n const encodeValue = (value: any): any => {\n if (value == null) {\n return value;\n }\n\n // If we have schema information, encode the value properly\n if (columnSchema && columnName) {\n try {\n const fieldSchema = columnSchema.properties[columnName];\n if (fieldSchema) {\n // Encode the value using the drizzle codec\n // This converts application values (like Dayjs) to database values (like ISO strings)\n return this.alepha.codec.encode(fieldSchema, value, {\n encoder: \"drizzle\",\n });\n }\n } catch (error) {\n // If encoding fails, fall back to the original value\n // This ensures backward compatibility\n }\n }\n\n return value;\n };\n\n // Helper function to encode array values\n const encodeArray = (values: any[]): any[] => {\n return values.map((v) => encodeValue(v));\n };\n\n // If operator is not an object, OR it's an object but doesn't have any filter operator properties,\n // treat it as a direct value (e.g., string, number, Date, Dayjs, etc.)\n if (\n typeof operator !== \"object\" ||\n operator == null ||\n !this.hasFilterOperatorProperties(operator)\n ) {\n return eq(column, encodeValue(operator));\n }\n\n const conditions: SQL[] = [];\n\n if (operator?.eq != null) {\n conditions.push(eq(column, encodeValue(operator.eq)));\n }\n\n if (operator?.ne != null) {\n conditions.push(ne(column, encodeValue(operator.ne)));\n }\n\n if (operator?.gt != null) {\n conditions.push(gt(column, encodeValue(operator.gt)));\n }\n\n if (operator?.gte != null) {\n conditions.push(gte(column, encodeValue(operator.gte)));\n }\n\n if (operator?.lt != null) {\n conditions.push(lt(column, encodeValue(operator.lt)));\n }\n\n if (operator?.lte != null) {\n conditions.push(lte(column, encodeValue(operator.lte)));\n }\n\n if (operator?.inArray != null) {\n if (!Array.isArray(operator.inArray) || operator.inArray.length === 0) {\n throw new AlephaError(\"inArray operator requires at least one value\");\n }\n conditions.push(inArray(column, encodeArray(operator.inArray)));\n }\n\n if (operator?.notInArray != null) {\n if (\n !Array.isArray(operator.notInArray) ||\n operator.notInArray.length === 0\n ) {\n throw new AlephaError(\n \"notInArray operator requires at least one value\",\n );\n }\n conditions.push(notInArray(column, encodeArray(operator.notInArray)));\n }\n\n if (operator?.isNull != null) {\n conditions.push(isNull(column));\n }\n\n if (operator?.isNotNull != null) {\n conditions.push(isNotNull(column));\n }\n\n if (operator?.like != null) {\n conditions.push(like(column, encodeValue(operator.like)));\n }\n\n if (operator?.notLike != null) {\n conditions.push(notLike(column, encodeValue(operator.notLike)));\n }\n\n if (operator?.ilike != null) {\n conditions.push(ilike(column, encodeValue(operator.ilike)));\n }\n\n if (operator?.notIlike != null) {\n conditions.push(notIlike(column, encodeValue(operator.notIlike)));\n }\n\n if (operator?.contains != null) {\n // Escape LIKE special characters to prevent wildcard injection\n const escapedValue = String(operator.contains)\n .replace(/\\\\/g, \"\\\\\\\\\") // Escape backslash first\n .replace(/%/g, \"\\\\%\") // Escape %\n .replace(/_/g, \"\\\\_\"); // Escape _\n\n if (dialect === \"sqlite\") {\n // SQLite doesn't have ilike, use LOWER() for case-insensitive matching\n conditions.push(\n sql`LOWER(${column}) LIKE LOWER(${encodeValue(`%${escapedValue}%`)})`,\n );\n } else {\n conditions.push(ilike(column, encodeValue(`%${escapedValue}%`)));\n }\n }\n\n if (operator?.startsWith != null) {\n // Escape LIKE special characters to prevent wildcard injection\n const escapedValue = String(operator.startsWith)\n .replace(/\\\\/g, \"\\\\\\\\\") // Escape backslash first\n .replace(/%/g, \"\\\\%\") // Escape %\n .replace(/_/g, \"\\\\_\"); // Escape _\n\n if (dialect === \"sqlite\") {\n // SQLite doesn't have ilike, use LOWER() for case-insensitive matching\n conditions.push(\n sql`LOWER(${column}) LIKE LOWER(${encodeValue(`${escapedValue}%`)})`,\n );\n } else {\n conditions.push(ilike(column, encodeValue(`${escapedValue}%`)));\n }\n }\n\n if (operator?.endsWith != null) {\n // Escape LIKE special characters to prevent wildcard injection\n const escapedValue = String(operator.endsWith)\n .replace(/\\\\/g, \"\\\\\\\\\") // Escape backslash first\n .replace(/%/g, \"\\\\%\") // Escape %\n .replace(/_/g, \"\\\\_\"); // Escape _\n\n if (dialect === \"sqlite\") {\n // SQLite doesn't have ilike, use LOWER() for case-insensitive matching\n conditions.push(\n sql`LOWER(${column}) LIKE LOWER(${encodeValue(`%${escapedValue}`)})`,\n );\n } else {\n conditions.push(ilike(column, encodeValue(`%${escapedValue}`)));\n }\n }\n\n if (operator?.between != null) {\n if (!Array.isArray(operator.between) || operator.between.length !== 2) {\n throw new Error(\n \"between operator requires exactly 2 values [min, max]\",\n );\n }\n conditions.push(\n between(\n column,\n encodeValue(operator.between[0]),\n encodeValue(operator.between[1]),\n ),\n );\n }\n\n if (operator?.notBetween != null) {\n if (\n !Array.isArray(operator.notBetween) ||\n operator.notBetween.length !== 2\n ) {\n throw new Error(\n \"notBetween operator requires exactly 2 values [min, max]\",\n );\n }\n conditions.push(\n notBetween(\n column,\n encodeValue(operator.notBetween[0]),\n encodeValue(operator.notBetween[1]),\n ),\n );\n }\n\n if (operator?.arrayContains != null) {\n conditions.push(\n arrayContains(column, encodeValue(operator.arrayContains)),\n );\n }\n\n if (operator?.arrayContained != null) {\n conditions.push(\n arrayContained(column, encodeValue(operator.arrayContained)),\n );\n }\n\n if (operator?.arrayOverlaps != null) {\n conditions.push(\n arrayOverlaps(column, encodeValue(operator.arrayOverlaps)),\n );\n }\n\n if (conditions.length === 0) {\n return undefined;\n }\n\n if (conditions.length === 1) {\n return conditions[0];\n }\n\n return and(...conditions);\n }\n\n /**\n * Parse pagination sort string to orderBy format.\n * Format: \"firstName,-lastName\" -> [{ column: \"firstName\", direction: \"asc\" }, { column: \"lastName\", direction: \"desc\" }]\n * - Columns separated by comma\n * - Prefix with '-' for DESC direction\n *\n * @param sort Pagination sort string\n * @returns OrderBy array or single object\n */\n public parsePaginationSort(\n sort: string,\n ):\n | Array<{ column: string; direction: \"asc\" | \"desc\" }>\n | { column: string; direction: \"asc\" | \"desc\" } {\n const fields = sort.split(\",\").map((field) => field.trim());\n\n const orderByClauses = fields.map((field) => {\n if (field.startsWith(\"-\")) {\n return {\n column: field.substring(1),\n direction: \"desc\" as const,\n };\n }\n return {\n column: field,\n direction: \"asc\" as const,\n };\n });\n\n // Return single object if only one field, array if multiple\n return orderByClauses.length === 1 ? orderByClauses[0] : orderByClauses;\n }\n\n /**\n * Normalize orderBy parameter to array format.\n * Supports 3 modes:\n * 1. String: \"name\" -> [{ column: \"name\", direction: \"asc\" }]\n * 2. Object: { column: \"name\", direction: \"desc\" } -> [{ column: \"name\", direction: \"desc\" }]\n * 3. Array: [{ column: \"name\" }, { column: \"age\", direction: \"desc\" }] -> normalized array\n *\n * @param orderBy The orderBy parameter\n * @returns Normalized array of order by clauses\n */\n public normalizeOrderBy(\n orderBy: any,\n ): Array<{ column: string; direction: \"asc\" | \"desc\" }> {\n // Mode 1: String -> single column, ASC by default\n if (typeof orderBy === \"string\") {\n return [{ column: orderBy, direction: \"asc\" }];\n }\n\n // Mode 2: Single object -> convert to array\n if (!Array.isArray(orderBy) && typeof orderBy === \"object\") {\n return [\n {\n column: orderBy.column,\n direction: orderBy.direction ?? \"asc\",\n },\n ];\n }\n\n // Mode 3: Array -> normalize each item with default direction\n if (Array.isArray(orderBy)) {\n return orderBy.map((item) => ({\n column: item.column,\n direction: item.direction ?? \"asc\",\n }));\n }\n\n return [];\n }\n\n /**\n * Create a pagination object.\n *\n * @deprecated Use `createPagination` from alepha instead.\n * This method now delegates to the framework-level helper.\n *\n * @param entities The entities to paginate.\n * @param limit The limit of the pagination.\n * @param offset The offset of the pagination.\n * @param sort Optional sort metadata to include in response.\n */\n public createPagination<T>(\n entities: T[],\n limit = 10,\n offset = 0,\n sort?: Array<{ column: string; direction: \"asc\" | \"desc\" }>,\n ) {\n return createPagination(entities, limit, offset, sort);\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface PgJoin {\n table: string;\n schema: TObject;\n key: string;\n col: (key: string) => PgColumn;\n parent?: string;\n}\n","import {\n $inject,\n Alepha,\n AlephaError,\n type Page,\n type PageQuery,\n type Static,\n type StaticEncode,\n type TObject,\n type TSchema,\n t,\n} from \"alepha\";\nimport { type DateTime, DateTimeProvider } from \"alepha/datetime\";\nimport { asc, desc, isSQLWrapper, type SQL } from \"drizzle-orm\";\nimport type {\n LockConfig,\n LockStrength,\n PgColumn,\n PgDatabase,\n PgInsertValue,\n PgTable,\n PgTableWithColumns,\n PgTransaction,\n PgUpdateSetSource,\n} from \"drizzle-orm/pg-core\";\nimport type { PgTransactionConfig } from \"drizzle-orm/pg-core/session\";\nimport {\n PG_DELETED_AT,\n PG_PRIMARY_KEY,\n PG_UPDATED_AT,\n PG_VERSION,\n} from \"../constants/PG_SYMBOLS.ts\";\nimport { DbConflictError } from \"../errors/DbConflictError.ts\";\nimport { DbEntityNotFoundError } from \"../errors/DbEntityNotFoundError.ts\";\nimport { DbError } from \"../errors/DbError.ts\";\nimport { DbVersionMismatchError } from \"../errors/DbVersionMismatchError.ts\";\nimport { getAttrFields, type PgAttrField } from \"../helpers/pgAttr.ts\";\nimport type {\n PgQuery,\n PgQueryRelations,\n PgRelationMap,\n PgStatic,\n} from \"../interfaces/PgQuery.ts\";\nimport type {\n PgQueryWhere,\n PgQueryWhereOrSQL,\n} from \"../interfaces/PgQueryWhere.ts\";\nimport type {\n EntityPrimitive,\n SchemaToTableConfig,\n} from \"../primitives/$entity.ts\";\nimport {\n DatabaseProvider,\n type SQLLike,\n} from \"../providers/drivers/DatabaseProvider.ts\";\nimport type { TObjectInsert } from \"../schemas/insertSchema.ts\";\nimport type { TObjectUpdate } from \"../schemas/updateSchema.ts\";\nimport { PgRelationManager } from \"./PgRelationManager.ts\";\nimport { type PgJoin, QueryManager } from \"./QueryManager.ts\";\n\nexport abstract class Repository<T extends TObject> {\n public readonly entity: EntityPrimitive<T>;\n public readonly provider: DatabaseProvider;\n\n protected readonly relationManager = $inject(PgRelationManager);\n protected readonly queryManager = $inject(QueryManager);\n protected readonly dateTimeProvider = $inject(DateTimeProvider);\n protected readonly alepha = $inject(Alepha);\n\n constructor(entity: EntityPrimitive<T>, provider = DatabaseProvider) {\n this.entity = entity;\n this.provider = this.alepha.inject(provider);\n this.provider.registerEntity(entity as EntityPrimitive);\n }\n\n /**\n * Represents the primary key of the table.\n * - Key is the name of the primary key column.\n * - Type is the type (TypeBox) of the primary key column.\n *\n * ID is mandatory. If the table does not have a primary key, it will throw an error.\n */\n public get id(): {\n type: TSchema;\n key: keyof T[\"properties\"];\n col: PgColumn;\n } {\n return this.getPrimaryKey(this.entity.schema);\n }\n\n /**\n * Get Drizzle table object.\n */\n public get table(): PgTableWithColumns<SchemaToTableConfig<T>> {\n return this.provider.table(this.entity);\n }\n\n /**\n * Get SQL table name. (from Drizzle table object)\n */\n public get tableName(): string {\n return this.entity.name;\n }\n\n /**\n * Getter for the database connection from the database provider.\n */\n protected get db(): PgDatabase<any> {\n return this.provider.db;\n }\n\n /**\n * Execute a SQL query.\n *\n * This method allows executing raw SQL queries against the database.\n * This is by far the easiest way to run custom queries that are not covered by the repository's built-in methods!\n *\n * You must use the `sql` tagged template function from Drizzle ORM to create the query. https://orm.drizzle.team/docs/sql\n *\n * @example\n * ```ts\n * class App {\n * repository = $repository({ ... });\n * async getAdults() {\n * const users = repository.table; // Drizzle table object\n * await repository.query(sql`SELECT * FROM ${users} WHERE ${users.age} > ${18}`);\n * // or better\n * await repository.query((users) => sql`SELECT * FROM ${users} WHERE ${users.age} > ${18}`);\n * }\n * }\n * ```\n */\n public async query<R extends TObject = T>(\n query:\n | SQLLike\n | ((\n table: PgTableWithColumns<SchemaToTableConfig<T>>,\n db: PgDatabase<any>,\n ) => SQLLike),\n schema?: R,\n ): Promise<Static<R>[]> {\n const raw =\n typeof query === \"function\" ? query(this.table, this.db) : query;\n\n if (typeof raw === \"string\" && raw.includes(\"[object Object]\")) {\n throw new AlephaError(\n \"Invalid SQL query. Did you forget to call the 'sql' function?\",\n );\n }\n\n const rows = await this.provider.execute(raw);\n\n return rows.map((it) => {\n return this.clean(\n this.mapRawFieldsToEntity(it),\n schema ?? this.entity.schema,\n ) as Static<R>;\n });\n }\n\n /**\n * Map raw database fields to entity fields. (handles column name differences)\n */\n protected mapRawFieldsToEntity(row: Record<string, unknown>) {\n const entity: any = {};\n\n for (const key of Object.keys(row)) {\n entity[key] = row[key];\n for (const colKey of Object.keys(this.table)) {\n if (this.table[colKey].name === key) {\n entity[colKey] = row[key];\n break;\n }\n }\n }\n\n return entity;\n }\n\n /**\n * Get a Drizzle column from the table by his name.\n */\n protected col(name: keyof StaticEncode<T>): PgColumn {\n const column = (this.table as any)[name];\n if (!column) {\n throw new AlephaError(\n `Invalid access. Column ${String(name)} not found in table ${this.tableName}`,\n );\n }\n\n return column;\n }\n\n /**\n * Run a transaction.\n */\n public async transaction<T>(\n transaction: (\n tx: PgTransaction<any, Record<string, any>, any>,\n ) => Promise<T>,\n config?: PgTransactionConfig,\n ): Promise<T> {\n return await this.db.transaction(transaction, config);\n }\n\n // -------------------------------------------------------------------------------------------------------------------\n\n /**\n * Start a SELECT query on the table.\n */\n protected rawSelect(opts: StatementOptions = {}) {\n return (opts.tx ?? this.db).select().from(this.table as PgTable);\n }\n\n /**\n * Start a SELECT DISTINCT query on the table.\n */\n protected rawSelectDistinct(\n opts: StatementOptions = {},\n columns: (keyof Static<T>)[] = [],\n ) {\n const db = opts.tx ?? this.db;\n const table = this.table as PgTable;\n\n const fields: Record<string, any> = {};\n for (const column of columns) {\n if (typeof column === \"string\") {\n fields[column] = this.col(column);\n }\n }\n\n return db.selectDistinct(fields).from(table);\n }\n\n /**\n * Start an INSERT query on the table.\n */\n protected rawInsert(opts: StatementOptions = {}) {\n return (opts.tx ?? this.db).insert(this.table);\n }\n\n /**\n * Start an UPDATE query on the table.\n */\n protected rawUpdate(opts: StatementOptions = {}) {\n return (opts.tx ?? this.db).update(this.table);\n }\n\n /**\n * Start a DELETE query on the table.\n */\n protected rawDelete(opts: StatementOptions = {}) {\n return (opts.tx ?? this.db).delete(this.table);\n }\n\n // -------------------------------------------------------------------------------------------------------------------\n\n /**\n * Create a Drizzle `select` query based on a JSON query object.\n *\n * > This method is the base for `find`, `findOne`, `findById`, and `paginate`.\n */\n public async findMany<R extends PgRelationMap<T>>(\n query: PgQueryRelations<T, R> = {},\n opts: StatementOptions = {},\n ): Promise<PgStatic<T, R>[]> {\n await this.alepha.events.emit(\"repository:read:before\", {\n tableName: this.tableName,\n query,\n });\n\n const columns = query.columns ?? query.distinct;\n const builder = query.distinct\n ? this.rawSelectDistinct(opts, query.distinct)\n : this.rawSelect(opts);\n\n const joins: Array<PgJoin> = [];\n if (query.with) {\n this.relationManager.buildJoins(\n this.provider,\n builder,\n joins,\n query.with,\n this.table,\n );\n }\n\n const where = this.withDeletedAt(\n (query.where ?? {}) as PgQueryWhere<T>,\n opts,\n );\n\n builder.where(() => this.toSQL(where, joins));\n\n if (query.offset) {\n builder.offset(query.offset);\n\n // SQLite requires LIMIT when OFFSET is used\n if (this.provider.dialect === \"sqlite\" && !query.limit) {\n query.limit = 1000;\n }\n }\n\n if (query.limit) {\n builder.limit(query.limit);\n }\n\n if (query.orderBy) {\n const orderByClauses = this.queryManager.normalizeOrderBy(query.orderBy);\n builder.orderBy(\n ...orderByClauses.map((clause) =>\n clause.direction === \"desc\"\n ? desc(this.col(clause.column as string))\n : asc(this.col(clause.column as string)),\n ),\n );\n }\n\n if (query.groupBy) {\n builder.groupBy(...query.groupBy.map((key) => this.col(key as string)));\n }\n\n if (opts.for) {\n if (typeof opts.for === \"string\") {\n builder.for(opts.for);\n } else if (opts.for) {\n builder.for(opts.for.strength, opts.for.config);\n }\n }\n\n try {\n let rows = await builder.execute();\n\n let schema: TObject = this.entity.schema;\n if (columns) {\n schema = t.pick(schema, columns);\n }\n\n if (joins.length) {\n rows = rows.map((row: any) => {\n // Clone schema for each row to avoid mutation\n const rowSchema = { ...schema, properties: { ...schema.properties } };\n return this.relationManager.mapRowWithJoins(\n row[this.tableName],\n row,\n rowSchema,\n joins,\n );\n });\n }\n\n rows = rows.map((row) => {\n // For joined queries, build a schema that includes all nested joins\n if (joins.length) {\n const joinedSchema = this.relationManager.buildSchemaWithJoins(\n schema,\n joins,\n );\n // Clean the row with the full joined schema (including nested relations)\n return this.cleanWithJoins(row, joinedSchema, joins);\n }\n return this.clean(row, schema);\n });\n\n await this.alepha.events.emit(\"repository:read:after\", {\n tableName: this.tableName,\n query,\n entities: rows,\n });\n\n return rows as PgStatic<T, R>[];\n } catch (error) {\n throw new DbError(\"Query select has failed\", error as Error);\n }\n }\n\n /**\n * Find a single entity.\n */\n public async findOne<R extends PgRelationMap<T>>(\n query: Pick<PgQueryRelations<T, R>, \"with\" | \"where\">,\n opts: StatementOptions = {},\n ): Promise<PgStatic<T, R>> {\n const [entity] = await this.findMany({ limit: 1, ...query }, opts);\n\n if (!entity) {\n // TODO: enhance error message when finding by ID\n throw new DbEntityNotFoundError(this.tableName);\n }\n\n return entity as PgStatic<T, R>;\n }\n\n /**\n * Find entities with pagination.\n *\n * It uses the same parameters as `find()`, but adds pagination metadata to the response.\n *\n * > Pagination CAN also do a count query to get the total number of elements.\n */\n public async paginate<R extends PgRelationMap<T>>(\n pagination: PageQuery = {},\n query: PgQueryRelations<T, R> = {},\n opts: StatementOptions & { count?: boolean } = {},\n ): Promise<Page<PgStatic<T, R>>> {\n const limit = query.limit ?? pagination.size ?? 10;\n const page = pagination.page ?? 0;\n const offset = query.offset ?? page * limit;\n\n let orderBy = query.orderBy;\n if (!query.orderBy && pagination.sort) {\n orderBy = this.queryManager.parsePaginationSort(pagination.sort) as any;\n }\n\n const now = Date.now();\n const timers = {\n query: now,\n count: now,\n };\n\n const tasks: Promise<any>[] = [];\n\n tasks.push(\n this.findMany(\n {\n offset,\n limit: limit + 1,\n orderBy,\n ...query,\n },\n opts,\n ).then((it) => {\n timers.query = Date.now() - timers.query;\n return it;\n }),\n );\n\n if (opts.count) {\n const where = isSQLWrapper(query.where)\n ? query.where\n : query.where\n ? this.toSQL(query.where)\n : undefined;\n\n tasks.push(\n this.db.$count(this.table, where as SQL).then((it) => {\n timers.count = Date.now() - timers.count;\n return it;\n }),\n );\n }\n\n const [entities, countResult] = await Promise.all(tasks);\n\n // Normalize orderBy to get sort metadata\n let sortMetadata:\n | Array<{ column: string; direction: \"asc\" | \"desc\" }>\n | undefined;\n if (orderBy) {\n sortMetadata = this.queryManager.normalizeOrderBy(orderBy);\n }\n\n const response = this.queryManager.createPagination<T>(\n entities,\n limit,\n offset,\n sortMetadata,\n );\n\n response.page.totalElements = countResult;\n if (countResult != null) {\n response.page.totalPages = Math.ceil(countResult / limit);\n }\n\n return response as Page<PgStatic<T, R>>;\n }\n\n /**\n * Find an entity by ID.\n *\n * This is a convenience method for `findOne` with a where clause on the primary key.\n * If you need more complex queries, use `findOne` instead.\n */\n public async findById(\n id: string | number,\n opts: StatementOptions = {},\n ): Promise<Static<T>> {\n return await this.findOne(\n {\n where: this.getWhereId(id),\n },\n opts,\n );\n }\n\n /**\n * Helper to create a type-safe query object.\n */\n public createQuery(): PgQuery<T> {\n return {};\n }\n\n /**\n * Helper to create a type-safe where clause.\n */\n public createQueryWhere(): PgQueryWhere<T> {\n return {};\n }\n\n // -------------------------------------------------------------------------------------------------------------------\n\n /**\n * Create an entity.\n *\n * @param data The entity to create.\n * @param opts The options for creating the entity.\n * @returns The ID of the created entity.\n */\n public async create(\n data: Static<TObjectInsert<T>>,\n opts: StatementOptions = {},\n ): Promise<Static<T>> {\n await this.alepha.events.emit(\"repository:create:before\", {\n tableName: this.tableName,\n data,\n });\n\n try {\n const entity = await this.rawInsert(opts)\n .values(this.cast(data ?? {}, true))\n .returning(this.table)\n .then(([it]) => this.clean(it, this.entity.schema));\n\n await this.alepha.events.emit(\"repository:create:after\", {\n tableName: this.tableName,\n data,\n entity,\n });\n\n return entity;\n } catch (error) {\n throw this.handleError(error, \"Insert query has failed\");\n }\n }\n\n /**\n * Create many entities.\n *\n * Inserts are batched in chunks of 1000 to avoid hitting database limits.\n *\n * @param values The entities to create.\n * @param opts The statement options.\n * @returns The created entities.\n */\n public async createMany(\n values: Array<Static<TObjectInsert<T>>>,\n opts: StatementOptions & { batchSize?: number } = {},\n ): Promise<Static<T>[]> {\n if (values.length === 0) {\n return [];\n }\n\n await this.alepha.events.emit(\"repository:create:before\", {\n tableName: this.tableName,\n data: values,\n });\n\n const batchSize = opts.batchSize ?? 1000;\n const allEntities: Static<T>[] = [];\n\n try {\n for (let i = 0; i < values.length; i += batchSize) {\n const batch = values.slice(i, i + batchSize);\n const entities = await this.rawInsert(opts)\n .values(batch.map((data) => this.cast(data, true)))\n .returning(this.table)\n .then((rows) => rows.map((it) => this.clean(it, this.entity.schema)));\n allEntities.push(...entities);\n }\n\n await this.alepha.events.emit(\"repository:create:after\", {\n tableName: this.tableName,\n data: values,\n entity: allEntities,\n });\n\n return allEntities;\n } catch (error) {\n throw this.handleError(error, \"Insert query has failed\");\n }\n }\n\n // -------------------------------------------------------------------------------------------------------------------\n\n /**\n * Find an entity and update it.\n */\n public async updateOne(\n where: PgQueryWhereOrSQL<T>,\n data: Partial<Static<TObjectUpdate<T>>>,\n opts: StatementOptions = {},\n ): Promise<Static<T>> {\n await this.alepha.events.emit(\"repository:update:before\", {\n tableName: this.tableName,\n where,\n data,\n });\n\n let row = data as any;\n\n const updatedAtField = getAttrFields(\n this.entity.schema,\n PG_UPDATED_AT,\n )?.[0];\n\n if (updatedAtField) {\n row[updatedAtField.key] = this.dateTimeProvider\n .of(opts.now)\n .toISOString();\n }\n\n where = this.withDeletedAt(where, opts);\n row = this.cast(row, false) as any;\n\n // do not update the ID field\n delete row[this.id.key];\n\n const response = await this.rawUpdate(opts)\n .set(row)\n .where(this.toSQL(where))\n .returning(this.table)\n .catch((error) => {\n throw this.handleError(error, \"Update query has failed\");\n });\n\n if (!response[0]) {\n throw new DbEntityNotFoundError(this.tableName);\n }\n\n try {\n const entity = this.clean(response[0], this.entity.schema);\n\n await this.alepha.events.emit(\"repository:update:after\", {\n tableName: this.tableName,\n where,\n data,\n entities: [entity],\n });\n\n return entity;\n } catch (error) {\n throw this.handleError(error, \"Update query has failed\");\n }\n }\n\n /**\n * Save a given entity.\n *\n * @example\n * ```ts\n * const entity = await repository.findById(1);\n * entity.name = \"New Name\"; // update a field\n * delete entity.description; // delete a field\n * await repository.save(entity);\n * ```\n *\n * Difference with `updateById/updateOne`:\n *\n * - requires the entity to be fetched first (whole object is expected)\n * - check pg.version() if present -> optimistic locking\n * - validate entity against schema\n * - undefined values will be set to null, not ignored!\n *\n * @see {@link DbVersionMismatchError}\n */\n public async save(\n entity: Static<T>,\n opts: StatementOptions = {},\n ): Promise<void> {\n const row = entity as any;\n\n const id = row[this.id.key];\n if (id == null) {\n throw new AlephaError(\n \"Cannot save entity without ID - missing primary key in value\",\n );\n }\n\n // in save mode, we do not ignore undefined values, but set them to null\n for (const key of Object.keys(this.entity.schema.properties)) {\n if (row[key] === undefined) {\n row[key] = null;\n }\n }\n\n let where: any = this.createQueryWhere();\n\n where.id = { eq: id };\n\n const versionField = getAttrFields(this.entity.schema, PG_VERSION)?.[0];\n if (versionField && typeof row[versionField.key] === \"number\") {\n where = {\n and: [\n where,\n {\n [versionField.key]: {\n eq: row[versionField.key],\n },\n },\n ],\n } as PgQueryWhere<T>;\n\n row[versionField.key] += 1;\n }\n\n try {\n const newValue = await this.updateOne(where, row, opts);\n for (const key of Object.keys(this.entity.schema.properties)) {\n row[key] = undefined;\n }\n Object.assign(row, newValue);\n } catch (error) {\n if (error instanceof DbEntityNotFoundError && versionField) {\n // Verify entity still exists to differentiate between not-found vs version mismatch\n try {\n // If findById succeeds, entity exists and this was a version mismatch\n await this.findById(id);\n throw new DbVersionMismatchError(this.tableName, id);\n } catch (lookupError) {\n // If it's still not found, propagate the original not found error\n if (lookupError instanceof DbEntityNotFoundError) {\n throw error; // Original error\n }\n // If it's a version mismatch error, propagate it\n if (lookupError instanceof DbVersionMismatchError) {\n throw lookupError;\n }\n // Other errors (network, timeout, etc.) should be re-thrown\n throw lookupError;\n }\n }\n throw error;\n }\n }\n\n /**\n * Find an entity by ID and update it.\n */\n public async updateById(\n id: string | number,\n data: Partial<Static<TObjectUpdate<T>>>,\n opts: StatementOptions = {},\n ): Promise<Static<T>> {\n return await this.updateOne(this.getWhereId(id), data, opts);\n }\n\n /**\n * Find many entities and update all of them.\n */\n public async updateMany(\n where: PgQueryWhereOrSQL<T>,\n data: Partial<Static<TObjectUpdate<T>>>,\n opts: StatementOptions = {},\n ): Promise<Array<number | string>> {\n await this.alepha.events.emit(\"repository:update:before\", {\n tableName: this.tableName,\n where,\n data,\n });\n\n const updatedAtField = getAttrFields(\n this.entity.schema,\n PG_UPDATED_AT,\n )?.[0];\n\n if (updatedAtField) {\n (data as any)[updatedAtField.key] = this.dateTimeProvider\n .of(opts.now)\n .toISOString();\n }\n\n where = this.withDeletedAt(where, opts);\n data = this.cast(data, false) as any;\n try {\n const entities = await this.rawUpdate(opts)\n .set(\n data as PgUpdateSetSource<PgTableWithColumns<SchemaToTableConfig<T>>>,\n )\n .where(this.toSQL(where))\n .returning();\n\n await this.alepha.events.emit(\"repository:update:after\", {\n tableName: this.tableName,\n where,\n data,\n entities,\n });\n\n return entities.map((it: any) => it[this.id.key]);\n } catch (error) {\n throw this.handleError(error, \"Update query has failed\");\n }\n }\n\n /**\n * Find many and delete all of them.\n * @returns Array of deleted entity IDs\n */\n public async deleteMany(\n where: PgQueryWhereOrSQL<T> = {},\n opts: StatementOptions = {},\n ): Promise<Array<number | string>> {\n const deletedAt = this.deletedAt();\n if (deletedAt && !opts.force) {\n return await this.updateMany(\n where,\n {\n [deletedAt.key]: opts.now ?? this.dateTimeProvider.nowISOString(),\n } as any,\n opts,\n );\n }\n\n await this.alepha.events.emit(\"repository:delete:before\", {\n tableName: this.tableName,\n where,\n });\n\n try {\n const result = await this.rawDelete(opts)\n .where(this.toSQL(where))\n .returning({ id: (this.table as any)[this.id.key] });\n const ids = result.map((row) => row.id);\n\n await this.alepha.events.emit(\"repository:delete:after\", {\n tableName: this.tableName,\n where,\n ids,\n });\n\n return ids;\n } catch (error) {\n throw new DbError(\"Delete query has failed\", error as Error);\n }\n }\n\n /**\n * Delete all entities.\n * @returns Array of deleted entity IDs\n */\n public clear(opts: StatementOptions = {}): Promise<Array<number | string>> {\n return this.deleteMany({}, opts);\n }\n\n /**\n * Delete the given entity.\n *\n * You must fetch the entity first in order to delete it.\n * @returns Array containing the deleted entity ID\n */\n public async destroy(\n entity: Static<T>,\n opts: StatementOptions = {},\n ): Promise<Array<number | string>> {\n const id = (entity as any)[this.id.key];\n if (id == null) {\n throw new AlephaError(\"Cannot destroy entity without ID\");\n }\n\n const deletedAt = this.deletedAt();\n if (deletedAt && !opts.force) {\n opts.now ??= this.dateTimeProvider.nowISOString();\n (entity as any)[deletedAt.key] = opts.now;\n }\n\n return await this.deleteById(id, opts);\n }\n\n /**\n * Find an entity and delete it.\n * @returns Array of deleted entity IDs (should contain at most one ID)\n */\n public async deleteOne(\n where: PgQueryWhereOrSQL<T> = {},\n opts: StatementOptions = {},\n ): Promise<Array<number | string>> {\n return await this.deleteMany(where, opts);\n }\n\n /**\n * Find an entity by ID and delete it.\n * @returns Array containing the deleted entity ID\n * @throws DbEntityNotFoundError if the entity is not found\n */\n public async deleteById(\n id: string | number,\n opts: StatementOptions = {},\n ): Promise<Array<number | string>> {\n const result = await this.deleteMany(this.getWhereId(id), opts);\n if (result.length === 0) {\n throw new DbEntityNotFoundError(\n `Entity with ID ${id} not found in ${this.tableName}`,\n );\n }\n return result;\n }\n\n /**\n * Count entities.\n */\n public async count(\n where: PgQueryWhereOrSQL<T> = {},\n opts: StatementOptions = {},\n ): Promise<number> {\n where = this.withDeletedAt(where, opts);\n return (opts.tx ?? this.db).$count(this.table, this.toSQL(where));\n }\n\n // -------------------------------------------------------------------------------------------------------------------\n\n protected conflictMessagePattern =\n \"duplicate key value violates unique constraint\";\n\n protected handleError(error: unknown, message: string): DbError {\n if (!(error instanceof Error)) {\n return new DbError(message);\n }\n\n if (\n (error.cause as Error)?.message.includes(this.conflictMessagePattern) ||\n error.message.includes(this.conflictMessagePattern)\n ) {\n return new DbConflictError(message, error);\n }\n\n return new DbError(message, error);\n }\n\n protected withDeletedAt(\n where: PgQueryWhereOrSQL<T>,\n opts: {\n force?: boolean;\n } = {},\n ): PgQueryWhereOrSQL<T> {\n if (opts.force) {\n return where;\n }\n\n const deletedAt = this.deletedAt();\n if (!deletedAt) {\n return where;\n }\n\n return {\n and: [\n where,\n {\n [deletedAt.key]: {\n isNull: true,\n },\n } as any,\n ],\n } as PgQueryWhereOrSQL<T>;\n }\n\n protected deletedAt(): PgAttrField | undefined {\n const deletedAtFields = getAttrFields(this.entity.schema, PG_DELETED_AT);\n if (deletedAtFields.length > 0) {\n return deletedAtFields[0];\n }\n return undefined;\n }\n\n /**\n * Convert something to valid Pg Insert Value.\n */\n protected cast(\n data: any,\n insert: boolean,\n ): PgInsertValue<PgTableWithColumns<SchemaToTableConfig<T>>> {\n const schema = insert\n ? this.entity.insertSchema // insert\n : (t.partial(this.entity.updateSchema) as TObject); // update\n\n return this.alepha.codec.encode(schema, data) as PgInsertValue<\n PgTableWithColumns<SchemaToTableConfig<T>>\n >;\n }\n\n /**\n * Transform a row from the database into a clean entity.\n */\n protected clean<T extends TObject>(\n row: Record<string, unknown>,\n schema: T,\n ): Static<T> {\n for (const key of Object.keys(schema.properties)) {\n const value = schema.properties[key];\n\n // convert PG date-time and date to ISO strings\n if (typeof row[key] === \"string\") {\n if (t.schema.isDateTime(value)) {\n row[key] = this.dateTimeProvider.of(row[key]).toISOString();\n } else if (t.schema.isDate(value)) {\n row[key] = this.dateTimeProvider\n .of(`${row[key]}T00:00:00Z`)\n .toISOString()\n .split(\"T\")[0];\n }\n }\n\n // convert BigInt to string\n if (typeof row[key] === \"bigint\" && t.schema.isBigInt(value)) {\n row[key] = row[key].toString();\n }\n }\n\n return this.alepha.codec.decode(schema, row) as Static<T>;\n }\n\n // -------------------------------------------------------------------------------------------------------------------\n // INTERNAL METHODS\n\n /**\n * Clean a row with joins recursively\n */\n protected cleanWithJoins<T extends TObject>(\n row: Record<string, unknown>,\n schema: T,\n joins: PgJoin[],\n parentPath?: string,\n ): Static<T> {\n // Get joins at this level\n const joinsAtThisLevel = joins.filter((j) => j.parent === parentPath);\n\n // Create a copy of the row for cleaning, removing joined data temporarily\n const cleanRow: Record<string, unknown> = { ...row };\n const joinedData: Record<string, unknown> = {};\n\n for (const join of joinsAtThisLevel) {\n joinedData[join.key] = cleanRow[join.key];\n delete cleanRow[join.key];\n }\n\n // Clean the base entity without joined properties\n const entity = this.clean(cleanRow, schema);\n\n // Then recursively clean joined entities\n for (const join of joinsAtThisLevel) {\n const joinedValue = joinedData[join.key];\n // Only process if the joined value exists\n if (joinedValue != null) {\n // Build path for this join\n const joinPath = parentPath ? `${parentPath}.${join.key}` : join.key;\n // Find child joins\n const childJoins = joins.filter((j) => j.parent === joinPath);\n // Recursively clean if there are child joins\n if (childJoins.length > 0) {\n (entity as any)[join.key] = this.cleanWithJoins(\n joinedValue as Record<string, unknown>,\n join.schema,\n joins,\n joinPath,\n );\n } else {\n // No child joins, just clean this join\n (entity as any)[join.key] = this.clean(\n joinedValue as Record<string, unknown>,\n join.schema,\n );\n }\n } else {\n // Set to undefined if no data\n (entity as any)[join.key] = undefined;\n }\n }\n\n return entity as Static<T>;\n }\n\n /**\n * Convert a where clause to SQL.\n */\n protected toSQL(\n where: PgQueryWhereOrSQL<T>,\n joins?: PgJoin[],\n ): SQL | undefined {\n return this.queryManager.toSQL(where as PgQueryWhereOrSQL<T>, {\n schema: this.entity.schema,\n col: (name) => {\n return this.col(name);\n },\n joins,\n dialect: this.provider.dialect,\n });\n }\n\n /**\n * Get the where clause for an ID.\n *\n * @param id The ID to get the where clause for.\n * @returns The where clause for the ID.\n */\n protected getWhereId(id: string | number): PgQueryWhere<T> {\n return {\n [this.id.key]: {\n eq: t.schema.isString(this.id.type) ? String(id) : Number(id),\n },\n } as PgQueryWhere<T>;\n }\n\n /**\n * Find a primary key in the schema.\n */\n protected getPrimaryKey(schema: TObject) {\n const primaryKeys = getAttrFields(schema, PG_PRIMARY_KEY);\n if (primaryKeys.length === 0) {\n throw new AlephaError(\"Primary key not found in schema\");\n }\n\n if (primaryKeys.length > 1) {\n throw new AlephaError(\n `Multiple primary keys (${primaryKeys.length}) are not supported`,\n );\n }\n\n return {\n key: primaryKeys[0].key,\n col: this.col(primaryKeys[0].key),\n type: primaryKeys[0].type,\n };\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * The options for a statement.\n */\nexport interface StatementOptions {\n /**\n * Transaction to use.\n */\n tx?: PgTransaction<any, Record<string, any>>;\n\n /**\n * Lock strength.\n */\n for?: LockStrength | { config: LockConfig; strength: LockStrength };\n\n /**\n * If true, ignore soft delete.\n */\n force?: boolean;\n\n /**\n * Force the current time.\n */\n now?: DateTime | string;\n}\n","import { $inject, Alepha, type Service, type TObject } from \"alepha\";\nimport type { EntityPrimitive } from \"../primitives/$entity.ts\";\nimport { Repository } from \"../services/Repository.ts\";\nimport type { DatabaseProvider } from \"./drivers/DatabaseProvider.ts\";\n\nexport class RepositoryProvider {\n protected readonly alepha = $inject(Alepha);\n protected readonly registry = new Map<\n EntityPrimitive<any>,\n Service<Repository<any>>\n >();\n\n public getRepositories(provider?: DatabaseProvider) {\n const repositories = this.alepha.services(Repository);\n\n if (provider) {\n return repositories.filter((it) => it.provider === provider);\n }\n\n return repositories;\n }\n\n public getRepository<T extends TObject>(\n entity: EntityPrimitive<T>,\n ): Repository<T> {\n const RepositoryClass = this.createClassRepository(entity);\n return this.alepha.inject(RepositoryClass);\n }\n\n public createClassRepository<T extends TObject>(\n entity: EntityPrimitive<T>,\n ): Service<Repository<T>> {\n let name = entity.name.charAt(0).toUpperCase() + entity.name.slice(1);\n if (name.endsWith(\"s\")) {\n name = name.slice(0, -1);\n }\n name = `${name}Repository`;\n\n if (this.registry.has(entity)) {\n return this.registry.get(entity) as Service<Repository<T>>;\n }\n\n class GenericRepository extends Repository<T> {\n constructor() {\n super(entity);\n }\n }\n\n // for class name to entity.name + \"Repository\"\n Object.defineProperty(GenericRepository, \"name\", { value: name });\n\n this.registry.set(entity, GenericRepository as Service<Repository<T>>);\n\n return GenericRepository;\n }\n}\n","import { $context, $inject, type TObject } from \"alepha\";\nimport { RepositoryProvider } from \"../providers/RepositoryProvider.ts\";\nimport type { Repository } from \"../services/Repository.ts\";\nimport type { EntityPrimitive } from \"./$entity.ts\";\n\n/**\n * Get the repository for the given entity.\n */\nexport const $repository = <T extends TObject>(\n entity: EntityPrimitive<T>,\n): Repository<T> => {\n const { alepha } = $context();\n const repositoryProvider = alepha.inject(RepositoryProvider);\n return $inject(repositoryProvider.createClassRepository(entity));\n};\n","import { createPrimitive, KIND, Primitive } from \"alepha\";\nimport { sql } from \"drizzle-orm\";\nimport type { PgSequenceOptions } from \"drizzle-orm/pg-core\";\nimport { DatabaseProvider } from \"../providers/drivers/DatabaseProvider.ts\";\n\n/**\n * Creates a PostgreSQL sequence primitive for generating unique numeric values.\n */\nexport const $sequence = (\n options: SequencePrimitiveOptions = {},\n): SequencePrimitive => {\n return createPrimitive(SequencePrimitive, options);\n};\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface SequencePrimitiveOptions extends PgSequenceOptions {\n /**\n * The name of the sequence. If not provided, the property key will be used.\n */\n name?: string;\n\n provider?: DatabaseProvider;\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport class SequencePrimitive extends Primitive<SequencePrimitiveOptions> {\n public readonly provider = this.$provider();\n\n public onInit() {\n this.provider.registerSequence(this);\n }\n\n public get name(): string {\n return this.options.name ?? this.config.propertyKey;\n }\n\n public async next(): Promise<number> {\n return this.provider\n .execute(\n sql`SELECT nextval('${sql.raw(this.provider.schema)}.\"${sql.raw(this.name)}\"')`,\n )\n .then((rows) => Number(rows[0]?.nextval));\n }\n\n public async current(): Promise<number> {\n return this.provider\n .execute(\n sql`SELECT last_value FROM ${sql.raw(this.provider.schema)}.\"${sql.raw(this.name)}\"`,\n )\n .then((rows) => Number(rows[0]?.last_value));\n }\n\n protected $provider() {\n return this.options.provider ?? this.alepha.inject(DatabaseProvider);\n }\n}\n\n$sequence[KIND] = SequencePrimitive;\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { createRequire } from \"node:module\";\nimport { $inject, Alepha, AlephaError, type Static, t } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport type * as DrizzleKit from \"drizzle-kit/api\";\nimport { sql } from \"drizzle-orm\";\nimport type { DatabaseProvider } from \"./drivers/DatabaseProvider.ts\";\n\nexport class DrizzleKitProvider {\n protected readonly log = $logger();\n protected readonly alepha = $inject(Alepha);\n\n /**\n * Synchronize database with current schema definitions.\n *\n * In development mode, it will generate and execute migrations based on the current state.\n * In testing mode, it will generate migrations from scratch without applying them.\n *\n * Does nothing in production mode, you must handle migrations manually.\n */\n public async synchronize(provider: DatabaseProvider): Promise<void> {\n if (this.alepha.isProduction()) {\n this.log.warn(\"Synchronization skipped in production mode.\");\n return;\n }\n\n if (provider.schema !== \"public\") {\n await this.createSchemaIfNotExists(provider, provider.schema);\n }\n\n const now = Date.now();\n\n if (this.alepha.isTest()) {\n // -------------------------------------------------------------------------------------------------------------\n // testing area, generate migrations from scratch - no need to push schema\n const { statements } = await this.generateMigration(provider);\n await this.executeStatements(statements, provider);\n } else {\n // -------------------------------------------------------------------------------------------------------------\n // development area, generate migrations based on the current state\n const entry = await this.loadDevMigrations(provider);\n const { statements, snapshot } = await this.generateMigration(\n provider,\n entry?.snapshot ? JSON.parse(entry.snapshot) : undefined,\n );\n await this.executeStatements(statements, provider, true);\n await this.saveDevMigrations(provider, snapshot, entry);\n }\n\n this.log.info(\n `Db '${provider.name}' synchronization OK [${Date.now() - now}ms]`,\n );\n }\n\n /**\n * Mostly used for testing purposes. You can generate SQL migration statements without executing them.\n */\n public async generateMigration(\n provider: DatabaseProvider,\n prevSnapshot?: any,\n ): Promise<{\n statements: string[];\n models: Record<string, unknown>;\n snapshot?: any;\n }> {\n // import Drizzle Kit API\n const kit = this.importDrizzleKit();\n\n // load all models related to the given database connection provider\n const models = this.getModels(provider);\n\n // generate and return migrations if there are models\n if (Object.keys(models).length > 0) {\n if (provider.dialect === \"sqlite\") {\n const prev = prevSnapshot ?? (await kit.generateSQLiteDrizzleJson({}));\n const curr = await kit.generateSQLiteDrizzleJson(models);\n return {\n models,\n statements: await kit.generateSQLiteMigration(prev, curr),\n snapshot: curr,\n };\n }\n\n const prev = prevSnapshot ?? (await kit.generateDrizzleJson({}));\n const curr = await kit.generateDrizzleJson(models);\n return {\n models,\n statements: await kit.generateMigration(prev, curr),\n snapshot: curr,\n };\n }\n\n return {\n models,\n statements: [],\n snapshot: {},\n };\n }\n\n // -------------------------------------------------------------------------------------------------------------------\n\n /**\n * Load all tables, enums, sequences, etc. from the provider's repositories.\n */\n public getModels(provider: DatabaseProvider): Record<string, unknown> {\n const models: Record<string, unknown> = {};\n for (const [key, value] of provider.tables.entries()) {\n if (models[key]) {\n throw new AlephaError(\n `Model name conflict: '${key}' is already defined.`,\n );\n }\n models[key] = value;\n }\n for (const [key, value] of provider.enums.entries()) {\n if (models[key]) {\n throw new AlephaError(\n `Model name conflict: '${key}' is already defined.`,\n );\n }\n models[key] = value;\n }\n for (const [key, value] of provider.sequences.entries()) {\n if (models[key]) {\n throw new AlephaError(\n `Model name conflict: '${key}' is already defined.`,\n );\n }\n models[key] = value;\n }\n return models;\n }\n\n // -------------------------------------------------------------------------------------------------------------------\n\n /**\n * Load the migration snapshot from the database.\n */\n protected async loadDevMigrations(\n provider: DatabaseProvider,\n ): Promise<DevMigrations | undefined> {\n const name =\n `${this.alepha.env.APP_NAME ?? \"APP\"}-${provider.constructor.name}`.toLowerCase();\n\n if (provider.url.includes(\":memory:\")) {\n this.log.trace(\n `In-memory database detected for '${name}', skipping migration snapshot load.`,\n );\n return;\n }\n\n if (provider.dialect === \"sqlite\") {\n try {\n const text = await readFile(\n `node_modules/.alepha/sqlite-${name}.json`,\n \"utf-8\",\n );\n return this.alepha.codec.decode(devMigrationsSchema, text);\n } catch (e) {\n this.log.trace(`No existing migration snapshot for '${name}'`, e);\n }\n return;\n }\n\n await provider.execute(sql`CREATE SCHEMA IF NOT EXISTS \"drizzle\";`);\n await provider.execute(sql`\n\t\t\t\t\tCREATE TABLE IF NOT EXISTS \"drizzle\".\"__drizzle_dev_migrations\" (\n\t\t\t\t\t\t\"id\" SERIAL PRIMARY KEY,\n\t\t\t\t\t\t\"name\" TEXT NOT NULL,\n\t\t\t\t\t\t\"created_at\" TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n\t\t\t\t\t\t\"snapshot\" TEXT NOT NULL\n\t\t\t\t\t);\n\t\t\t\t`);\n\n const rows = await provider.run(\n sql`SELECT * FROM \"drizzle\".\"__drizzle_dev_migrations\" WHERE \"name\" = ${name} LIMIT 1`,\n devMigrationsSchema,\n );\n\n if (rows.length === 0) {\n this.log.trace(`No existing migration snapshot for '${name}'`);\n return;\n }\n\n return this.alepha.codec.decode(devMigrationsSchema, rows[0]);\n }\n\n protected async saveDevMigrations(\n provider: DatabaseProvider,\n curr: Record<string, any>,\n devMigrations?: DevMigrations,\n ) {\n if (provider.url.includes(\":memory:\")) {\n this.log.trace(\n `In-memory database detected for '${provider.constructor.name}', skipping migration snapshot save.`,\n );\n return;\n }\n\n const name =\n `${this.alepha.env.APP_NAME ?? \"APP\"}-${provider.constructor.name}`.toLowerCase();\n if (provider.dialect === \"sqlite\") {\n const filePath = `node_modules/.alepha/sqlite-${name}.json`;\n await mkdir(\"node_modules/.alepha\", { recursive: true }).catch(\n () => null,\n );\n await writeFile(\n filePath,\n JSON.stringify(\n {\n id: devMigrations?.id ?? 1,\n name,\n created_at: new Date(),\n snapshot: JSON.stringify(curr),\n },\n null,\n 2,\n ),\n );\n this.log.debug(`Saved migration snapshot to '${filePath}'`);\n return;\n }\n\n if (!devMigrations) {\n await provider.execute(\n sql`INSERT INTO \"drizzle\".\"__drizzle_dev_migrations\" (\"name\", \"snapshot\") VALUES (${name}, ${JSON.stringify(curr)})`,\n );\n } else {\n const newSnapshot = JSON.stringify(curr);\n if (devMigrations.snapshot !== newSnapshot) {\n await provider.execute(\n sql`UPDATE \"drizzle\".\"__drizzle_dev_migrations\" SET \"snapshot\" = ${newSnapshot} WHERE \"id\" = ${devMigrations.id}`,\n );\n }\n }\n }\n\n protected async executeStatements(\n statements: string[],\n provider: DatabaseProvider,\n catchErrors = false,\n ) {\n let nErrors = 0;\n for (const statement of statements) {\n // skip drop schema statements to avoid accidental data loss\n if (statement.startsWith(\"DROP SCHEMA\")) {\n continue;\n }\n\n try {\n await provider.execute(sql.raw(statement));\n } catch (error) {\n const errorMessage = `Error executing statement: ${statement}`;\n if (catchErrors) {\n nErrors++;\n this.log.warn(errorMessage, { context: [error] });\n } else {\n throw error;\n }\n }\n }\n if (nErrors > 0) {\n this.log.warn(\n `Executed ${statements.length} statements with ${nErrors} errors.`,\n );\n }\n }\n\n // -------------------------------------------------------------------------------------------------------------------\n\n protected async createSchemaIfNotExists(\n provider: DatabaseProvider,\n schemaName: string,\n ) {\n // Validate schema name to prevent SQL injection\n if (!/^[a-z0-9_]+$/i.test(schemaName)) {\n throw new Error(\n `Invalid schema name: ${schemaName}. Must only contain alphanumeric characters and underscores.`,\n );\n }\n\n const sqlSchema = sql.raw(schemaName);\n\n if (schemaName.startsWith(\"test_\")) {\n this.log.info(`Drop test schema '${schemaName}' ...`, schemaName);\n await provider.execute(sql`DROP SCHEMA IF EXISTS ${sqlSchema} CASCADE`);\n }\n\n // create schema if not exists\n this.log.debug(`Ensuring schema '${schemaName}' exists`);\n await provider.execute(sql`CREATE SCHEMA IF NOT EXISTS ${sqlSchema}`);\n }\n\n // -------------------------------------------------------------------------------------------------------------------\n\n /**\n * Try to load the official Drizzle Kit API.\n * If not available, fallback to the local kit import.\n */\n public importDrizzleKit(): typeof DrizzleKit {\n try {\n return createRequire(import.meta.url)(\"drizzle-kit/api\");\n } catch (_) {\n throw new Error(\n \"Drizzle Kit is not installed. Please install it with `npm install -D drizzle-kit`.\",\n );\n }\n }\n}\n\nconst devMigrationsSchema = t.object({\n id: t.number(),\n name: t.text(),\n snapshot: t.string(),\n created_at: t.string(),\n});\n\ntype DevMigrations = Static<typeof devMigrationsSchema>;\n","import { DbError } from \"./DbError.ts\";\n\nexport class DbMigrationError extends DbError {\n readonly name = \"DbMigrationError\";\n\n constructor(cause?: unknown) {\n super(\"Failed to migrate database\", cause);\n }\n}\n","import { customType } from \"drizzle-orm/pg-core\";\n\n/**\n * Postgres bytea type.\n */\nexport const byte = customType<{\n data: Buffer;\n}>({\n dataType: () => \"bytea\",\n});\n","import type { SQL } from \"drizzle-orm\";\nimport type { EntityPrimitive } from \"../primitives/$entity.ts\";\nimport type { SequencePrimitive } from \"../primitives/$sequence.ts\";\n\n/**\n * Database-specific table configuration functions\n */\nexport interface TableConfigBuilders<TConfig> {\n index: (name: string) => {\n on: (...columns: any[]) => TConfig;\n };\n uniqueIndex: (name: string) => {\n on: (...columns: any[]) => TConfig;\n };\n unique: (name: string) => {\n on: (...columns: any[]) => TConfig;\n };\n check: (name: string, sql: SQL) => TConfig;\n foreignKey: (config: {\n name: string;\n columns: any[];\n foreignColumns: any[];\n }) => TConfig;\n}\n\n/**\n * Abstract base class for transforming Alepha Primitives (Entity, Sequence, etc...)\n * into drizzle models (tables, enums, sequences, etc...).\n */\nexport abstract class ModelBuilder {\n /**\n * Build a table from an entity primitive.\n */\n abstract buildTable(\n entity: EntityPrimitive,\n options: {\n tables: Map<string, unknown>;\n enums: Map<string, unknown>;\n schema: string;\n },\n ): void;\n\n /**\n * Build a sequence from a sequence primitive.\n */\n abstract buildSequence(\n sequence: SequencePrimitive,\n options: {\n sequences: Map<string, unknown>;\n schema: string;\n },\n ): void;\n\n /**\n * Convert camelCase to snake_case for column names.\n */\n protected toColumnName(str: string): string {\n return (\n str[0].toLowerCase() +\n str.slice(1).replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`)\n );\n }\n\n /**\n * Build the table configuration function for any database.\n * This includes indexes, foreign keys, constraints, and custom config.\n *\n * @param entity - The entity primitive\n * @param builders - Database-specific builder functions\n * @param tableResolver - Function to resolve entity references to table columns\n * @param customConfigHandler - Optional handler for custom config\n */\n protected buildTableConfig<TConfig, TSelf>(\n entity: EntityPrimitive,\n builders: TableConfigBuilders<TConfig>,\n tableResolver?: (entityName: string) => any,\n customConfigHandler?: (config: any, self: TSelf) => TConfig[],\n ): ((self: TSelf) => TConfig[]) | undefined {\n // If no extra config is needed, return undefined\n if (\n !entity.options.indexes &&\n !entity.options.foreignKeys &&\n !entity.options.constraints &&\n !entity.options.config\n ) {\n return undefined;\n }\n\n return (self: TSelf) => {\n const configs: TConfig[] = [];\n\n // Build indexes\n if (entity.options.indexes) {\n for (const indexDef of entity.options.indexes) {\n if (typeof indexDef === \"string\") {\n const columnName = this.toColumnName(indexDef);\n const indexName = `${entity.name}_${columnName}_idx`;\n\n // Use original camelCase property name for lookup\n if ((self as any)[indexDef]) {\n configs.push(\n builders.index(indexName).on((self as any)[indexDef]),\n );\n }\n } else if (typeof indexDef === \"object\" && indexDef !== null) {\n if (\"column\" in indexDef) {\n const columnName = this.toColumnName(indexDef.column as string);\n const indexName =\n indexDef.name || `${entity.name}_${columnName}_idx`;\n\n // Use original camelCase property name for lookup\n if ((self as any)[indexDef.column]) {\n if (indexDef.unique) {\n configs.push(\n builders\n .uniqueIndex(indexName)\n .on((self as any)[indexDef.column]),\n );\n } else {\n configs.push(\n builders\n .index(indexName)\n .on((self as any)[indexDef.column]),\n );\n }\n }\n } else if (\"columns\" in indexDef) {\n const columnNames = indexDef.columns.map((col: any) =>\n this.toColumnName(col as string),\n );\n const indexName =\n indexDef.name || `${entity.name}_${columnNames.join(\"_\")}_idx`;\n\n // Use original camelCase property names for lookup\n const cols = indexDef.columns\n .map((col: any) => (self as any)[col])\n .filter(Boolean);\n\n if (cols.length === indexDef.columns.length) {\n if (indexDef.unique) {\n configs.push(builders.uniqueIndex(indexName).on(...cols));\n } else {\n configs.push(builders.index(indexName).on(...cols));\n }\n }\n }\n }\n }\n }\n\n // Build foreign keys\n if (entity.options.foreignKeys) {\n for (const fkDef of entity.options.foreignKeys) {\n const columnNames = fkDef.columns.map((col) =>\n this.toColumnName(col as string),\n );\n\n // Use original camelCase property names for lookup\n const cols = fkDef.columns\n .map((col) => (self as any)[col])\n .filter(Boolean);\n\n if (cols.length === fkDef.columns.length) {\n const fkName =\n fkDef.name || `${entity.name}_${columnNames.join(\"_\")}_fk`;\n\n // Resolve foreign column references\n const foreignColumns = fkDef.foreignColumns.map((colRef) => {\n const entityCol = colRef();\n if (!entityCol || !entityCol.entity || !entityCol.name) {\n throw new Error(\n `Invalid foreign column reference in ${entity.name}`,\n );\n }\n\n // If we have a table resolver, use it to get the actual table column\n if (tableResolver) {\n const foreignTable = tableResolver(entityCol.entity.name);\n if (!foreignTable) {\n throw new Error(\n `Foreign table ${entityCol.entity.name} not found for ${entity.name}`,\n );\n }\n // Use original camelCase property name for lookup in foreign table\n return foreignTable[entityCol.name];\n }\n\n // Fallback: return the entity column reference (will be resolved later)\n return entityCol;\n });\n\n configs.push(\n builders.foreignKey({\n name: fkName,\n columns: cols,\n foreignColumns,\n }),\n );\n }\n }\n }\n\n // Build constraints\n if (entity.options.constraints) {\n for (const constraintDef of entity.options.constraints) {\n const columnNames = constraintDef.columns.map((col) =>\n this.toColumnName(col as string),\n );\n\n // Use original camelCase property names for lookup\n const cols = constraintDef.columns\n .map((col) => (self as any)[col])\n .filter(Boolean);\n\n if (cols.length === constraintDef.columns.length) {\n if (constraintDef.unique) {\n const constraintName =\n constraintDef.name ||\n `${entity.name}_${columnNames.join(\"_\")}_unique`;\n\n configs.push(builders.unique(constraintName).on(...cols));\n }\n\n if (constraintDef.check) {\n const constraintName =\n constraintDef.name ||\n `${entity.name}_${columnNames.join(\"_\")}_check`;\n\n configs.push(builders.check(constraintName, constraintDef.check));\n }\n }\n }\n }\n\n // Add custom config if provided\n if (entity.options.config && customConfigHandler) {\n configs.push(...customConfigHandler(entity.options.config, self));\n } else if (entity.options.config) {\n // Default behavior: call the config function directly\n const customConfigs = entity.options.config(self as any);\n if (Array.isArray(customConfigs)) {\n configs.push(...(customConfigs as any));\n }\n }\n\n return configs;\n };\n }\n}\n","import { AlephaError, type TObject, type TSchema, t } from \"alepha\";\nimport type { BuildExtraConfigColumns } from \"drizzle-orm\";\nimport * as pg from \"drizzle-orm/pg-core\";\nimport {\n check,\n foreignKey,\n index,\n type PgEnum,\n type PgSchema,\n type PgTableExtraConfigValue,\n type PgTableWithColumns,\n pgEnum,\n pgSchema,\n pgTable,\n unique,\n uniqueIndex,\n} from \"drizzle-orm/pg-core\";\nimport {\n PG_CREATED_AT,\n PG_ENUM,\n PG_IDENTITY,\n PG_PRIMARY_KEY,\n PG_REF,\n PG_SERIAL,\n PG_UPDATED_AT,\n type PgEnumOptions,\n type PgIdentityOptions,\n type PgRefOptions,\n} from \"../constants/PG_SYMBOLS.ts\";\nimport type { EntityPrimitive, FromSchema } from \"../primitives/$entity.ts\";\nimport type { SequencePrimitive } from \"../primitives/$sequence.ts\";\nimport { byte } from \"../types/byte.ts\";\nimport { schema } from \"../types/schema.ts\";\nimport { ModelBuilder } from \"./ModelBuilder.ts\";\n\nexport class PostgresModelBuilder extends ModelBuilder {\n protected schemas = new Map<string, PgSchema>();\n\n protected getPgSchema(name: string) {\n if (!this.schemas.has(name) && name !== \"public\") {\n this.schemas.set(name, pgSchema(name));\n }\n\n const nsp =\n name !== \"public\"\n ? this.schemas.get(name)\n : ({\n enum: pgEnum,\n table: pgTable,\n } as any);\n\n if (!nsp) {\n throw new AlephaError(`Postgres schema ${name} not found`);\n }\n\n return nsp;\n }\n\n public buildTable(\n entity: EntityPrimitive<any>,\n options: {\n tables: Map<string, unknown>;\n enums: Map<string, unknown>;\n schema: string;\n },\n ) {\n const tableName = entity.name;\n if (options.tables.has(tableName)) {\n return;\n }\n\n const nsp = this.getPgSchema(options.schema);\n\n const columns = this.schemaToPgColumns(\n tableName,\n entity.schema,\n nsp,\n options.enums,\n options.tables,\n );\n\n // Build the config function that includes indexes, foreign keys, constraints, and custom config\n const configFn = this.getTableConfig(entity, options.tables);\n\n const table = nsp.table(tableName, columns, configFn);\n\n options.tables.set(tableName, table);\n }\n\n public buildSequence(\n sequence: SequencePrimitive,\n options: {\n sequences: Map<string, unknown>;\n schema: string;\n },\n ) {\n const sequenceName = sequence.name;\n if (options.sequences.has(sequenceName)) {\n return;\n }\n\n const nsp = this.getPgSchema(options.schema);\n\n options.sequences.set(\n sequenceName,\n nsp.sequence(sequenceName, sequence.options),\n );\n }\n\n // -------------------------------------------------------------------------------------------------------------------\n\n /**\n * Get PostgreSQL-specific config builder for the table.\n */\n protected getTableConfig(\n entity: EntityPrimitive,\n tables: Map<string, unknown>,\n ):\n | ((\n self: BuildExtraConfigColumns<string, any, \"pg\">,\n ) => PgTableExtraConfigValue[])\n | undefined {\n // PostgreSQL-specific builders\n const pgBuilders = {\n index,\n uniqueIndex,\n unique,\n check,\n foreignKey,\n };\n\n // Table resolver function\n const tableResolver = (entityName: string) => {\n return tables.get(entityName) as any;\n };\n\n return this.buildTableConfig<\n PgTableExtraConfigValue,\n BuildExtraConfigColumns<string, any, \"pg\">\n >(entity, pgBuilders as any, tableResolver);\n }\n\n schemaToPgColumns = <T extends TObject>(\n tableName: string,\n schema: T,\n nsp: PgSchema,\n enums: Map<string, unknown>,\n tables: Map<string, unknown>,\n ): FromSchema<T> => {\n return Object.entries(schema.properties).reduce<Partial<FromSchema<T>>>(\n (columns, [key, value]) => {\n let col = this.mapFieldToColumn(tableName, key, value, nsp, enums);\n\n if (\"default\" in value && value.default != null) {\n col = col.default(value.default as any);\n }\n\n if (PG_PRIMARY_KEY in value) {\n col = col.primaryKey();\n }\n\n if (PG_REF in value) {\n const config = value[PG_REF] as PgRefOptions;\n col = col.references(() => {\n const ref = config.ref();\n const table = tables.get(\n ref.entity.name,\n ) as PgTableWithColumns<any>;\n\n if (!table) {\n throw new AlephaError(\n `Referenced table ${ref.entity.name} not found for ${tableName}.${key}`,\n );\n }\n\n const target = table[ref.name];\n if (!target) {\n throw new AlephaError(\n `Referenced column ${ref.name} not found in table ${ref.entity.name} for ${tableName}.${key}`,\n );\n }\n\n return target;\n }, config.actions);\n }\n\n if (schema.required?.includes(key)) {\n col = col.notNull();\n }\n\n return {\n ...columns,\n [key]: col,\n };\n },\n {},\n ) as FromSchema<T>;\n };\n\n mapFieldToColumn = (\n tableName: string,\n fieldName: string,\n value: TSchema,\n nsp: PgSchema,\n enums: Map<string, any>,\n ) => {\n const key = this.toColumnName(fieldName);\n\n if (\n // is nullish ?\n \"anyOf\" in value &&\n Array.isArray(value.anyOf) &&\n value.anyOf.length === 2 &&\n value.anyOf.some((it: TSchema) => t.schema.isNull(it))\n ) {\n // then, remove nullish\n value = value.anyOf.find((it: TSchema) => !t.schema.isNull(it))!;\n }\n\n if (t.schema.isInteger(value)) {\n if (PG_SERIAL in value) {\n return pg.serial(key);\n }\n\n if (PG_IDENTITY in value) {\n const options = value[PG_IDENTITY] as PgIdentityOptions;\n if (options.mode === \"byDefault\") {\n return pg.integer().generatedByDefaultAsIdentity(options);\n }\n return pg.integer().generatedAlwaysAsIdentity(options);\n }\n\n return pg.integer(key);\n }\n\n if (t.schema.isBigInt(value)) {\n if (PG_IDENTITY in value) {\n const options = value[PG_IDENTITY] as PgIdentityOptions;\n if (options.mode === \"byDefault\") {\n return pg\n .bigint({ mode: \"bigint\" })\n .generatedByDefaultAsIdentity(options);\n }\n return pg.bigint({ mode: \"bigint\" }).generatedAlwaysAsIdentity(options);\n }\n }\n\n if (t.schema.isNumber(value)) {\n if (PG_IDENTITY in value) {\n const options = value[PG_IDENTITY] as PgIdentityOptions;\n if (options.mode === \"byDefault\") {\n return pg\n .bigint({ mode: \"number\" })\n .generatedByDefaultAsIdentity(options);\n }\n return pg.bigint({ mode: \"number\" }).generatedAlwaysAsIdentity(options);\n }\n\n if (value.format === \"int64\") {\n return pg.bigint(key, { mode: \"number\" });\n }\n\n return pg.numeric(key);\n }\n\n if (t.schema.isString(value)) {\n return this.mapStringToColumn(key, value);\n }\n\n if (t.schema.isBoolean(value)) {\n return pg.boolean(key);\n }\n\n if (t.schema.isObject(value)) {\n return schema(key, value);\n }\n\n if (t.schema.isRecord(value)) {\n return schema(key, value);\n }\n\n const isTypeEnum = (value: any): value is { enum: any[] } =>\n t.schema.isUnsafe(value) &&\n \"type\" in value &&\n value.type === \"string\" &&\n \"enum\" in value &&\n Array.isArray(value.enum);\n\n if (t.schema.isArray(value)) {\n if (t.schema.isObject(value.items)) {\n return schema(key, value);\n }\n if (t.schema.isRecord(value.items)) {\n return schema(key, value);\n }\n if (t.schema.isString(value.items)) {\n return pg.text(key).array();\n }\n if (t.schema.isInteger(value.items)) {\n return pg.integer(key).array();\n }\n if (t.schema.isNumber(value.items)) {\n return pg.numeric(key).array();\n }\n if (t.schema.isBoolean(value.items)) {\n return pg.boolean(key).array();\n }\n if (isTypeEnum(value.items)) {\n return pg.text(key).array();\n }\n }\n\n // Enum handling\n if (isTypeEnum(value)) {\n if (!value.enum.every((it) => typeof it === \"string\")) {\n throw new AlephaError(\n `Enum for ${fieldName} must be an array of strings, got ${JSON.stringify(\n value.enum,\n )}`,\n );\n }\n\n // SQL Enum\n if (PG_ENUM in value && value[PG_ENUM]) {\n const options = value[PG_ENUM] as PgEnumOptions;\n const enumName = options.name ?? `${tableName}_${key}_enum`;\n\n if (enums.has(enumName)) {\n const values = (\n enums.get(enumName) as PgEnum<[string]>\n ).enumValues.join(\",\");\n const newValues = value.enum.join(\",\");\n if (values !== newValues) {\n throw new AlephaError(\n `Enum name conflict for ${enumName}: [${values}] vs [${newValues}]`,\n );\n }\n }\n\n enums.set(enumName, nsp.enum(enumName, value.enum as [string]));\n\n return enums.get(enumName)(key);\n }\n\n // else, map to TEXT\n return this.mapStringToColumn(key, value);\n }\n\n throw new AlephaError(\n `Unsupported schema type for ${fieldName} as ${JSON.stringify(value)}`,\n );\n };\n\n /**\n * Map a string to a PG column.\n *\n * @param key The key of the field.\n * @param value The value of the field.\n */\n mapStringToColumn = (key: string, value: TSchema) => {\n if (\"format\" in value) {\n if (value.format === \"uuid\") {\n if (PG_PRIMARY_KEY in value) {\n return pg.uuid(key).defaultRandom();\n }\n\n return pg.uuid(key);\n }\n\n if (value.format === \"byte\") {\n return byte(key);\n }\n\n if (value.format === \"date-time\") {\n if (PG_CREATED_AT in value) {\n return pg\n .timestamp(key, { mode: \"string\", withTimezone: true })\n .defaultNow();\n }\n if (PG_UPDATED_AT in value) {\n return pg\n .timestamp(key, { mode: \"string\", withTimezone: true })\n .defaultNow();\n }\n return pg.timestamp(key, { mode: \"string\", withTimezone: true });\n }\n\n if (value.format === \"date\") {\n return pg.date(key, { mode: \"string\" });\n }\n }\n\n return pg.text(key);\n };\n}\n","import { $env, $hook, $inject, AlephaError, type Static, t } from \"alepha\";\nimport { $lock } from \"alepha/lock\";\nimport { $logger } from \"alepha/logger\";\nimport { sql } from \"drizzle-orm\";\nimport type { PostgresJsDatabase } from \"drizzle-orm/postgres-js\";\nimport { drizzle } from \"drizzle-orm/postgres-js\";\nimport { migrate } from \"drizzle-orm/postgres-js/migrator\";\nimport postgres from \"postgres\";\nimport { DbError } from \"../../errors/DbError.ts\";\nimport { DbMigrationError } from \"../../errors/DbMigrationError.ts\";\nimport { PostgresModelBuilder } from \"../../services/PostgresModelBuilder.ts\";\nimport { DrizzleKitProvider } from \"../DrizzleKitProvider.ts\";\nimport { DatabaseProvider, type SQLLike } from \"./DatabaseProvider.ts\";\n\ndeclare module \"alepha\" {\n interface Env extends Partial<Static<typeof envSchema>> {}\n}\n\nconst envSchema = t.object({\n /**\n * Main configuration for database connection.\n * Accept a string in the format of a Postgres connection URL.\n * Example: postgres://user:password@localhost:5432/database\n * or\n * Example: postgres://user:password@localhost:5432/database?sslmode=require\n */\n DATABASE_URL: t.optional(t.text()),\n\n /**\n * In addition to the DATABASE_URL, you can specify the postgres schema name.\n *\n * It will monkey patch drizzle tables.\n */\n POSTGRES_SCHEMA: t.optional(t.text()),\n});\n\nexport class NodePostgresProvider extends DatabaseProvider {\n static readonly SSL_MODES = [\n \"require\",\n \"allow\",\n \"prefer\",\n \"verify-full\",\n ] as const;\n\n protected readonly log = $logger();\n protected readonly env = $env(envSchema);\n protected readonly kit = $inject(DrizzleKitProvider);\n protected readonly builder = $inject(PostgresModelBuilder);\n protected client?: postgres.Sql;\n protected pg?: PostgresJsDatabase;\n\n public readonly dialect = \"postgresql\";\n\n public get name() {\n return \"postgres\";\n }\n\n /**\n * In testing mode, the schema name will be generated and deleted after the test.\n */\n protected schemaForTesting = this.alepha.isTest()\n ? this.env.POSTGRES_SCHEMA?.startsWith(\"test_\")\n ? this.env.POSTGRES_SCHEMA\n : this.generateTestSchemaName()\n : undefined;\n\n public override get url() {\n if (!this.env.DATABASE_URL) {\n throw new AlephaError(\"DATABASE_URL is not defined in the environment\");\n }\n\n return this.env.DATABASE_URL;\n }\n\n /**\n * Execute a SQL statement.\n */\n public override execute(\n statement: SQLLike,\n ): Promise<Array<Record<string, unknown>>> {\n try {\n return this.db.execute(statement);\n } catch (error) {\n throw new DbError(\"Error executing statement\", error);\n }\n }\n\n /**\n * Get Postgres schema used by this provider.\n */\n public override get schema(): string {\n if (this.schemaForTesting) {\n return this.schemaForTesting;\n }\n\n if (this.env.POSTGRES_SCHEMA) {\n return this.env.POSTGRES_SCHEMA;\n }\n\n return \"public\";\n }\n\n /**\n * Get the Drizzle Postgres database instance.\n */\n public override get db(): PostgresJsDatabase {\n if (!this.pg) {\n throw new AlephaError(\"Database not initialized\");\n }\n\n return this.pg;\n }\n\n protected override async executeMigrations(\n migrationsFolder: string,\n ): Promise<void> {\n await migrate(this.db, { migrationsFolder });\n }\n\n // -------------------------------------------------------------------------------------------------------------------\n\n protected readonly onStart = $hook({\n on: \"start\",\n handler: async () => {\n await this.connect();\n\n // never migrate in serverless mode (vercel, netlify, ...)\n if (!this.alepha.isServerless()) {\n try {\n await this.migrate.run();\n } catch (error) {\n throw new DbMigrationError(error);\n }\n }\n },\n });\n\n protected readonly onStop = $hook({\n on: \"stop\",\n handler: async () => {\n // cleanup test schema\n if (\n this.alepha.isTest() &&\n this.schemaForTesting &&\n this.schemaForTesting.startsWith(\"test_\")\n ) {\n // Additional validation: schema name must only contain safe characters\n if (!/^test_[a-z0-9_]+$/i.test(this.schemaForTesting)) {\n throw new AlephaError(\n `Invalid test schema name: ${this.schemaForTesting}. Must match pattern: test_[a-z0-9_]+`,\n );\n }\n\n this.log.warn(`Deleting test schema '${this.schemaForTesting}' ...`);\n // Use sql.raw without quotes (Drizzle handles identifier escaping)\n await this.execute(\n sql`DROP SCHEMA IF EXISTS ${sql.raw(this.schemaForTesting)} CASCADE`,\n );\n this.log.info(`Test schema '${this.schemaForTesting}' deleted`);\n }\n\n // close the connection\n await this.close();\n },\n });\n\n public async connect(): Promise<void> {\n this.log.debug(\"Connect ..\");\n\n const client = postgres(this.getClientOptions());\n await client`SELECT 1`; // test connection\n\n this.client = client;\n this.pg = drizzle(client, {\n logger: {\n // forward logs\n logQuery: (query: string, params: unknown[]) => {\n this.log.trace(query, { params });\n },\n },\n });\n\n this.log.info(\"Connection OK\");\n }\n\n public async close(): Promise<void> {\n if (this.client) {\n this.log.debug(\"Close...\");\n\n await this.client.end();\n\n this.client = undefined;\n this.pg = undefined;\n\n this.log.info(\"Connection closed\");\n }\n }\n\n protected migrate = $lock({\n handler: async () => {\n await this.migrateDatabase();\n },\n });\n\n /**\n * Map the DATABASE_URL to postgres client options.\n */\n protected getClientOptions(): postgres.Options<any> {\n const url = new URL(this.url);\n\n return {\n host: url.hostname,\n user: decodeURIComponent(url.username),\n database: decodeURIComponent(url.pathname.replace(\"/\", \"\")),\n password: decodeURIComponent(url.password),\n port: Number(url.port || 5432),\n ssl: this.ssl(url),\n onnotice: () => {\n // let drizzle handle logs\n },\n };\n }\n\n protected ssl(\n url: URL,\n ): \"require\" | \"allow\" | \"prefer\" | \"verify-full\" | undefined {\n const mode = url.searchParams.get(\"sslmode\");\n for (const it of NodePostgresProvider.SSL_MODES) {\n if (mode === it) {\n return it;\n }\n }\n }\n\n // -------------------------------------------------------------------------------------------------------------------\n\n /**\n * For testing purposes, generate a unique schema name.\n * The schema name will be generated based on the current date and time.\n * It will be in the format of `test_YYYYMMDD_HHMMSS_randomSuffix`.\n */\n protected generateTestSchemaName(): string {\n const pad = (n: number) => n.toString().padStart(2, \"0\");\n\n const now = new Date();\n const year = now.getUTCFullYear();\n const month = pad(now.getUTCMonth() + 1);\n const day = pad(now.getUTCDate());\n const hours = pad(now.getUTCHours());\n const minutes = pad(now.getUTCMinutes());\n const seconds = pad(now.getUTCSeconds());\n\n const timestamp = `${year}${month}${day}_${hours}${minutes}${seconds}`;\n\n const randomSuffix = Math.random().toString(36).slice(2, 6); // 4 alphanumeric chars\n\n return `test_${timestamp}_${randomSuffix}`;\n }\n}\n","import { randomUUID } from \"node:crypto\";\nimport {\n AlephaError,\n type Static,\n type TObject,\n type TSchema,\n type TString,\n t,\n} from \"alepha\";\nimport { type BuildColumns, sql } from \"drizzle-orm\";\nimport * as pg from \"drizzle-orm/sqlite-core\";\nimport {\n check,\n foreignKey,\n index,\n type SQLiteColumnBuilderBase,\n type SQLiteTableWithColumns,\n sqliteTable,\n unique,\n uniqueIndex,\n} from \"drizzle-orm/sqlite-core\";\nimport {\n PG_CREATED_AT,\n PG_IDENTITY,\n PG_PRIMARY_KEY,\n PG_REF,\n PG_SERIAL,\n PG_UPDATED_AT,\n type PgRefOptions,\n} from \"../constants/PG_SYMBOLS.ts\";\nimport type { EntityPrimitive } from \"../primitives/$entity.ts\";\nimport type { SequencePrimitive } from \"../primitives/$sequence.ts\";\nimport { ModelBuilder } from \"./ModelBuilder.ts\";\n\nexport class SqliteModelBuilder extends ModelBuilder {\n public buildTable(\n entity: EntityPrimitive<any>,\n options: {\n tables: Map<string, unknown>;\n enums: Map<string, unknown>;\n schema: string;\n },\n ) {\n const tableName = entity.name;\n if (options.tables.has(tableName)) {\n return;\n }\n\n const columns = this.schemaToSqliteColumns(\n tableName,\n entity.schema,\n options.enums,\n options.tables,\n );\n\n // Build the config function for SQLite\n const configFn = this.getTableConfig(entity, options.tables);\n\n const table = sqliteTable(tableName, columns, configFn);\n\n options.tables.set(tableName, table);\n }\n\n public buildSequence(\n sequence: SequencePrimitive,\n options: {\n sequences: Map<string, unknown>;\n schema: string;\n },\n ) {\n throw new AlephaError(\"SQLite does not support sequences\");\n }\n\n /**\n * Get SQLite-specific config builder for the table.\n */\n protected getTableConfig(\n entity: EntityPrimitive,\n tables: Map<string, unknown>,\n ): ((self: BuildColumns<string, any, \"sqlite\">) => any) | undefined {\n // SQLite-specific builders\n const sqliteBuilders = {\n index,\n uniqueIndex,\n unique,\n check,\n foreignKey,\n };\n\n // Table resolver function\n const tableResolver = (entityName: string) => {\n return tables.get(entityName) as any;\n };\n\n return this.buildTableConfig<any, BuildColumns<string, any, \"sqlite\">>(\n entity,\n sqliteBuilders,\n tableResolver,\n (config, self) => {\n // SQLite custom config handler\n const customConfigs = (config as any)(self);\n return Array.isArray(customConfigs) ? customConfigs : [];\n },\n );\n }\n\n // -------------------------------------------------------------------------------------------------------------------\n\n schemaToSqliteColumns = <T extends TObject>(\n tableName: string,\n schema: T,\n enums: Map<string, unknown>,\n tables: Map<string, unknown>,\n ): SchemaToSqliteBuilder<T> => {\n return Object.entries(schema.properties).reduce<\n Partial<SchemaToSqliteBuilder<T>>\n >((columns, [key, value]) => {\n let col = this.mapFieldToSqliteColumn(tableName, key, value, enums);\n\n if (\"default\" in value && value.default != null) {\n col = col.default(value.default as any);\n }\n\n if (PG_PRIMARY_KEY in value) {\n col = col.primaryKey();\n }\n\n if (PG_REF in value) {\n const config = value[PG_REF] as PgRefOptions;\n col = col.references(() => {\n const ref = config.ref();\n const table = tables.get(\n ref.entity.name,\n ) as SQLiteTableWithColumns<any>;\n\n if (!table) {\n throw new AlephaError(\n `Referenced table ${ref.entity.name} not found for ${tableName}.${key}`,\n );\n }\n\n const target = table[ref.name];\n if (!target) {\n throw new AlephaError(\n `Referenced column ${ref.name} not found in table ${ref.entity.name} for ${tableName}.${key}`,\n );\n }\n\n return target;\n }, config.actions);\n }\n\n if (schema.required?.includes(key)) {\n col = col.notNull();\n }\n\n return {\n ...columns,\n [key]: col,\n };\n }, {}) as SchemaToSqliteBuilder<T>;\n };\n\n mapFieldToSqliteColumn = (\n tableName: string,\n fieldName: string,\n value: TSchema,\n enums: Map<string, any>,\n ) => {\n const key = this.toColumnName(fieldName);\n\n if (\n // is nullish ?\n \"anyOf\" in value &&\n Array.isArray(value.anyOf) &&\n value.anyOf.length === 2 &&\n value.anyOf.some((it: TSchema) => t.schema.isNull(it))\n ) {\n // then, remove nullish\n value = value.anyOf.find((it: TSchema) => !t.schema.isNull(it))!;\n }\n\n if (t.schema.isInteger(value)) {\n if (PG_SERIAL in value || PG_IDENTITY in value) {\n return pg\n .integer(key, { mode: \"number\" })\n .primaryKey({ autoIncrement: true });\n }\n\n return pg.integer(key);\n }\n\n if (t.schema.isBigInt(value)) {\n if (PG_PRIMARY_KEY in value || PG_IDENTITY in value) {\n return pg\n .integer(key, { mode: \"number\" })\n .primaryKey({ autoIncrement: true });\n }\n\n return pg.integer(key, { mode: \"number\" });\n }\n\n if (t.schema.isNumber(value)) {\n if (PG_IDENTITY in value) {\n return pg\n .integer(key, { mode: \"number\" })\n .primaryKey({ autoIncrement: true });\n }\n\n return pg.numeric(key);\n }\n\n if (t.schema.isString(value)) {\n return this.mapStringToSqliteColumn(key, value);\n }\n\n if (t.schema.isBoolean(value)) {\n return this.sqliteBool(key, value);\n }\n\n if (t.schema.isObject(value)) {\n return this.sqliteJson(key, value);\n }\n\n if (t.schema.isRecord(value)) {\n return this.sqliteJson(key, value);\n }\n\n if (t.schema.isAny(value)) {\n return this.sqliteJson(key, value);\n }\n\n if (t.schema.isArray(value)) {\n if (t.schema.isObject(value.items)) {\n return this.sqliteJson(key, value);\n }\n if (t.schema.isRecord(value.items)) {\n return this.sqliteJson(key, value);\n }\n if (t.schema.isAny(value.items)) {\n return this.sqliteJson(key, value);\n }\n if (t.schema.isString(value.items)) {\n return this.sqliteJson(key, value);\n }\n if (t.schema.isInteger(value.items)) {\n return this.sqliteJson(key, value);\n }\n if (t.schema.isNumber(value.items)) {\n return this.sqliteJson(key, value);\n }\n if (t.schema.isBoolean(value.items)) {\n return this.sqliteJson(key, value);\n }\n }\n\n if (\n t.schema.isUnsafe(value) &&\n \"type\" in value &&\n value.type === \"string\"\n ) {\n return this.mapStringToSqliteColumn(key, value as any);\n }\n\n throw new Error(\n `Unsupported schema for field '${tableName}.${fieldName}' (schema: ${JSON.stringify(value)})`,\n );\n };\n\n mapStringToSqliteColumn = (key: string, value: TString) => {\n if (value.format === \"uuid\") {\n if (PG_PRIMARY_KEY in value) {\n return pg\n .text(key)\n .primaryKey()\n .$defaultFn(() => randomUUID());\n }\n\n return pg.text(key);\n }\n\n if (value.format === \"byte\") {\n return this.sqliteJson(key, value);\n }\n\n if (value.format === \"date-time\") {\n if (PG_CREATED_AT in value) {\n return this.sqliteDateTime(key, {}).default(\n sql`(unixepoch('subsec') * 1000)`,\n );\n }\n if (PG_UPDATED_AT in value) {\n return this.sqliteDateTime(key, {}).default(\n sql`(unixepoch('subsec') * 1000)`,\n );\n }\n return this.sqliteDateTime(key, {});\n }\n\n if (value.format === \"date\") {\n return this.sqliteDate(key, {});\n }\n\n return pg.text(key);\n };\n\n sqliteJson = <TDocument extends TSchema>(name: string, document: TDocument) =>\n pg\n .customType<{\n data: Static<TDocument>;\n driverData: string;\n config: { document: TDocument };\n configRequired: true;\n }>({\n dataType: () => \"text\",\n toDriver: (value) => JSON.stringify(value),\n fromDriver: (value: TDocument | string) => {\n return value && typeof value === \"string\" ? JSON.parse(value) : value;\n },\n })(name, { document })\n .$type<Static<TDocument>>();\n\n sqliteDateTime = pg.customType<{\n data: string;\n driverData: number;\n configRequired: true;\n }>({\n dataType: () => \"integer\",\n toDriver: (value) => new Date(value).getTime(),\n fromDriver: (value) => {\n return new Date(value).toISOString();\n },\n });\n\n sqliteBool = pg.customType<{\n data: boolean;\n driverData: number;\n configRequired: true;\n }>({\n dataType: () => \"integer\",\n toDriver: (value) => (value ? 1 : 0),\n fromDriver: (value) => value === 1,\n });\n\n sqliteDate = pg.customType<{\n data: string;\n driverData: number;\n configRequired: true;\n }>({\n dataType: () => \"integer\",\n toDriver: (value) => new Date(value).getTime(),\n fromDriver: (value) => {\n return new Date(value).toISOString().split(\"T\")[0];\n },\n });\n}\n\nexport type SchemaToSqliteBuilder<T extends TObject> = {\n [key in keyof T[\"properties\"]]: SQLiteColumnBuilderBase;\n};\n","import { mkdir } from \"node:fs/promises\";\nimport type { DatabaseSync } from \"node:sqlite\";\nimport {\n $atom,\n $env,\n $hook,\n $inject,\n $use,\n AlephaError,\n type Static,\n t,\n} from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport type { PgDatabase } from \"drizzle-orm/pg-core\";\nimport { drizzle, type SqliteRemoteDatabase } from \"drizzle-orm/sqlite-proxy\";\nimport { migrate } from \"drizzle-orm/sqlite-proxy/migrator\";\nimport { SqliteModelBuilder } from \"../../services/SqliteModelBuilder.ts\";\nimport { DrizzleKitProvider } from \"../DrizzleKitProvider.ts\";\nimport { DatabaseProvider, type SQLLike } from \"./DatabaseProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nconst envSchema = t.object({\n DATABASE_URL: t.optional(t.text()),\n});\n\n/**\n * Configuration options for the Node.js SQLite database provider.\n */\nexport const nodeSqliteOptions = $atom({\n name: \"alepha.postgres.node-sqlite.options\",\n schema: t.object({\n path: t.optional(\n t.string({\n description:\n \"Filepath or :memory:. If empty, provider will use DATABASE_URL from env.\",\n }),\n ),\n }),\n default: {},\n});\n\nexport type NodeSqliteProviderOptions = Static<typeof nodeSqliteOptions.schema>;\n\ndeclare module \"alepha\" {\n interface State {\n [nodeSqliteOptions.key]: NodeSqliteProviderOptions;\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Add a fake support for SQLite in Node.js based on Postgres interfaces.\n *\n * This is NOT a real SQLite provider, it's a workaround to use SQLite with Drizzle ORM.\n * This is NOT recommended for production use.\n */\nexport class NodeSqliteProvider extends DatabaseProvider {\n protected readonly kit = $inject(DrizzleKitProvider);\n protected readonly log = $logger();\n protected readonly env = $env(envSchema);\n protected readonly builder = $inject(SqliteModelBuilder);\n protected readonly options = $use(nodeSqliteOptions);\n\n protected sqlite!: DatabaseSync;\n\n public get name() {\n return \"sqlite\";\n }\n\n public override readonly dialect = \"sqlite\";\n\n public override get url(): string {\n const path = this.options.path ?? this.env.DATABASE_URL;\n if (path) {\n if (path.startsWith(\"postgres://\")) {\n throw new AlephaError(\n \"Postgres URL is not supported for SQLite provider.\",\n );\n }\n return path;\n }\n\n if (this.alepha.isTest() || this.alepha.isServerless()) {\n return \":memory:\";\n } else {\n return \"node_modules/.alepha/sqlite.db\";\n }\n }\n\n public override async execute(\n query: SQLLike,\n ): Promise<Array<Record<string, unknown>>> {\n const all = (this.db as unknown as SqliteRemoteDatabase).all(query);\n const { sql, params, method } = all.getQuery();\n this.log.trace(`${sql}`, params);\n\n const statement = this.sqlite.prepare(sql);\n if (method === \"run\") {\n statement.run(...(params as any[]));\n return [];\n }\n\n if (method === \"get\") {\n const data = statement.get(...(params as any[]));\n return data ? [{ ...data }] : [];\n }\n\n return statement.all(...(params as any[]));\n }\n\n public readonly db = drizzle(async (sql, params, method) => {\n const statement = this.sqlite.prepare(sql);\n this.log.trace(`${sql}`, { params });\n\n if (method === \"get\") {\n const data = statement.get(...params);\n return { rows: data ? [{ ...data }] : [] };\n }\n\n if (method === \"run\") {\n statement.run(...params);\n return { rows: [] };\n }\n\n if (method === \"all\") {\n const rows = statement.all(...params);\n return {\n rows: rows.map((row) => Object.values(row)),\n };\n }\n\n if (method === \"values\") {\n const rows = statement.all(...params);\n return {\n rows: rows.map((row) => Object.values(row)),\n };\n }\n\n throw new AlephaError(`Unsupported method: ${method}`);\n }) as unknown as PgDatabase<any>;\n\n protected readonly onStart = $hook({\n on: \"start\",\n handler: async () => {\n const { DatabaseSync } = await import(\"node:sqlite\");\n const filepath = this.url.replace(\"sqlite://\", \"\");\n if (filepath !== \":memory:\" && filepath !== \"\") {\n const dirname = filepath.split(\"/\").slice(0, -1).join(\"/\");\n if (dirname) {\n await mkdir(dirname, { recursive: true }).catch(() => null);\n }\n }\n\n this.sqlite = new DatabaseSync(filepath);\n\n await this.migrateDatabase();\n\n this.log.info(`Using SQLite database at ${filepath}`);\n },\n });\n\n protected async executeMigrations(migrationsFolder: string): Promise<void> {\n await migrate(\n this.db as unknown as SqliteRemoteDatabase,\n async (migrationQueries: string[]) => {\n this.log.debug(\"Executing migration queries\", { migrationQueries });\n for (const query of migrationQueries) {\n this.sqlite.prepare(query).run();\n }\n },\n { migrationsFolder },\n );\n }\n}\n","import { mkdir } from \"node:fs/promises\";\nimport { createRequire } from \"node:module\";\nimport type { PGlite } from \"@electric-sql/pglite\";\nimport { $env, $hook, $inject, AlephaError, t } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport type { PgliteDatabase } from \"drizzle-orm/pglite\";\nimport { migrate } from \"drizzle-orm/pglite/migrator\";\nimport { PostgresModelBuilder } from \"../../services/PostgresModelBuilder.ts\";\nimport { DrizzleKitProvider } from \"../DrizzleKitProvider.ts\";\nimport { DatabaseProvider, type SQLLike } from \"./DatabaseProvider.ts\";\n\nconst envSchema = t.object({\n /**\n * Same as NodePostgresProvider connection string.\n * But, will accept only `file:` protocol for the database path.\n *\n * DATABASE_URL=memory://\n * DATABASE_URL=./db\n * DATABASE_URL=file://absolute/path/to/db\n */\n DATABASE_URL: t.optional(t.text()),\n});\n\nexport interface PgLiteModule {\n PGlite: typeof PGlite;\n}\n\nexport class PglitePostgresProvider extends DatabaseProvider {\n public static importPglite(): PgLiteModule | undefined {\n try {\n return createRequire(import.meta.url)(\"@electric-sql/pglite\");\n } catch {\n // ignored\n }\n }\n\n protected readonly env = $env(envSchema);\n protected readonly log = $logger();\n protected readonly kit = $inject(DrizzleKitProvider);\n protected readonly builder = $inject(PostgresModelBuilder);\n\n protected client?: PGlite;\n protected pglite?: PgliteDatabase;\n\n public get name() {\n return \"pglite\";\n }\n\n public override readonly dialect = \"postgresql\";\n\n public override get url(): string {\n let path = this.env.DATABASE_URL;\n\n if (!path) {\n if (this.alepha.isTest()) {\n path = \":memory:\"; // use in-memory database for tests by default\n } else {\n path = \"node_modules/.db\"; // default path for dev\n }\n } else {\n if (path.includes(\":memory:\")) {\n // like postgres://:memory: or pglite://:memory:\n path = \":memory:\";\n } else if (path.startsWith(\"file://\")) {\n path = path.replace(\"file://\", \"\");\n }\n }\n\n return path;\n }\n\n public override get db(): PgliteDatabase {\n if (!this.pglite) {\n throw new AlephaError(\"Database not initialized\");\n }\n\n return this.pglite;\n }\n\n public override async execute(\n statement: SQLLike,\n ): Promise<Array<Record<string, unknown>>> {\n const { rows } = await this.db.execute(statement);\n return rows;\n }\n\n protected readonly onStart = $hook({\n on: \"start\",\n handler: async () => {\n if (Object.keys(this.kit.getModels(this)).length === 0) {\n return;\n }\n\n const module = PglitePostgresProvider.importPglite();\n if (!module) {\n throw new AlephaError(\n \"@electric-sql/pglite is not installed. Please install it to use the pglite driver.\",\n );\n }\n\n const { drizzle } = createRequire(import.meta.url)(\"drizzle-orm/pglite\");\n const path = this.url;\n\n if (path !== \":memory:\") {\n await mkdir(path, { recursive: true }).catch(() => null);\n this.client = new module.PGlite(path);\n } else {\n this.client = new module.PGlite();\n }\n\n this.pglite = drizzle({\n client: this.client,\n });\n\n await this.migrateDatabase();\n\n this.log.info(`Using PGlite database at ${path}`);\n },\n });\n\n protected readonly onStop = $hook({\n on: \"stop\",\n handler: async () => {\n if (this.client) {\n this.log.debug(\"Closing PGlite connection...\");\n await this.client.close();\n this.client = undefined;\n this.pglite = undefined;\n this.log.info(\"PGlite connection closed\");\n }\n },\n });\n\n protected async executeMigrations(migrationsFolder: string): Promise<void> {\n await migrate(this.db, { migrationsFolder });\n }\n}\n","import { AlephaError, type TObject } from \"alepha\";\nimport type { PgQueryWhere } from \"../interfaces/PgQueryWhere.ts\";\n\n/**\n * Parse a string query into a PgQueryWhere object.\n *\n * Supported syntax:\n * - Simple equality: \"name=John\"\n * - Wildcard patterns: \"name=John*\" (startsWith), \"name=*John\" (endsWith), \"name=*John*\" (contains)\n * - Operators: \"age>18\", \"age>=18\", \"age<65\", \"age<=65\", \"status!=active\"\n * - NULL checks: \"deletedAt=null\", \"email!=null\"\n * - IN arrays: \"status=[pending,active]\"\n * - AND conditions: \"name=John&age>18\"\n * - OR conditions: \"name=John|email=john@example.com\"\n * - Nested AND/OR: \"(name=John|name=Jane)&age>18\"\n * - JSONB nested: \"profile.city=Paris\"\n *\n * @example\n * ```ts\n * // Simple equality\n * parseQueryString(\"name=John\")\n * // => { name: { eq: \"John\" } }\n *\n * // Wildcard patterns\n * parseQueryString(\"name=John*\") // startsWith\n * // => { name: { startsWith: \"John\" } }\n * parseQueryString(\"name=*Smith\") // endsWith\n * // => { name: { endsWith: \"Smith\" } }\n * parseQueryString(\"name=*oh*\") // contains\n * // => { name: { contains: \"oh\" } }\n *\n * // Multiple conditions\n * parseQueryString(\"name=John&age>18\")\n * // => { and: [{ name: { eq: \"John\" } }, { age: { gt: 18 } }] }\n *\n * // OR conditions\n * parseQueryString(\"status=active|status=pending\")\n * // => { or: [{ status: { eq: \"active\" } }, { status: { eq: \"pending\" } }] }\n *\n * // Complex nested\n * parseQueryString(\"(name=John|name=Jane)&age>18&status!=archived\")\n * // => { and: [\n * // { or: [{ name: { eq: \"John\" } }, { name: { eq: \"Jane\" } }] },\n * // { age: { gt: 18 } },\n * // { status: { ne: \"archived\" } }\n * // ] }\n *\n * // JSONB nested query\n * parseQueryString(\"profile.city=Paris&profile.age>25\")\n * // => { profile: { city: { eq: \"Paris\" }, age: { gt: 25 } } }\n * ```\n */\nexport function parseQueryString<T extends TObject>(\n query: string,\n): PgQueryWhere<T> {\n if (!query || query.trim() === \"\") {\n return {};\n }\n\n const parser = new QueryStringParser(query);\n return parser.parse() as PgQueryWhere<T>;\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nclass QueryStringParser {\n private pos = 0;\n private readonly query: string;\n\n constructor(query: string) {\n this.query = query.trim();\n }\n\n parse(): PgQueryWhere<any> {\n return this.parseExpression();\n }\n\n private parseExpression(): PgQueryWhere<any> {\n return this.parseOr();\n }\n\n private parseOr(): any {\n const left = this.parseAnd();\n\n // Check for OR operator (|)\n if (this.peek() === \"|\") {\n const conditions = [left];\n\n while (this.peek() === \"|\") {\n this.consume(\"|\");\n conditions.push(this.parseAnd());\n }\n\n return { or: conditions };\n }\n\n return left;\n }\n\n private parseAnd(): any {\n const left = this.parsePrimary();\n\n // Check for AND operator (&)\n if (this.peek() === \"&\") {\n const conditions = [left];\n\n while (this.peek() === \"&\") {\n this.consume(\"&\");\n conditions.push(this.parsePrimary());\n }\n\n return { and: conditions };\n }\n\n return left;\n }\n\n private parsePrimary(): any {\n this.skipWhitespace();\n\n // Handle parentheses\n if (this.peek() === \"(\") {\n this.consume(\"(\");\n const expr = this.parseExpression();\n this.consume(\")\");\n return expr;\n }\n\n // Parse field condition\n return this.parseCondition();\n }\n\n private parseCondition(): any {\n const field = this.parseFieldPath();\n this.skipWhitespace();\n\n // Get operator\n const operator = this.parseOperator();\n this.skipWhitespace();\n\n // Get value\n const value = this.parseValue();\n\n if (value === \"\") {\n throw new AlephaError(`Expected value for field '${field.join(\".\")}'`);\n }\n\n // Build the condition object\n return this.buildCondition(field, operator, value);\n }\n\n private parseFieldPath(): string[] {\n const path: string[] = [];\n let current = \"\";\n\n while (this.pos < this.query.length) {\n const ch = this.query[this.pos];\n\n if (ch === \".\" && current) {\n path.push(current);\n current = \"\";\n this.pos++;\n continue;\n }\n\n if (ch === \"=\" || ch === \"!\" || ch === \">\" || ch === \"<\" || ch === \" \") {\n break;\n }\n\n current += ch;\n this.pos++;\n }\n\n if (current) {\n path.push(current);\n }\n\n return path;\n }\n\n private parseOperator(): string {\n this.skipWhitespace();\n\n const remaining = this.query.slice(this.pos);\n\n // Two-character operators\n if (remaining.startsWith(\">=\")) {\n this.pos += 2;\n return \">=\";\n }\n if (remaining.startsWith(\"<=\")) {\n this.pos += 2;\n return \"<=\";\n }\n if (remaining.startsWith(\"!=\")) {\n this.pos += 2;\n return \"!=\";\n }\n\n // Single-character operators\n const ch = this.query[this.pos];\n if (ch === \"=\" || ch === \">\" || ch === \"<\") {\n this.pos++;\n return ch;\n }\n\n throw new Error(`Expected operator at position ${this.pos}`);\n }\n\n private parseValue(): any {\n this.skipWhitespace();\n\n // Handle null\n if (this.query.slice(this.pos, this.pos + 4).toLowerCase() === \"null\") {\n this.pos += 4;\n return null;\n }\n\n // Handle arrays [value1,value2,...]\n if (this.query[this.pos] === \"[\") {\n return this.parseArray();\n }\n\n // Handle quoted strings\n if (this.query[this.pos] === '\"' || this.query[this.pos] === \"'\") {\n return this.parseQuotedString();\n }\n\n // Parse unquoted value (until &, |, or ))\n let value = \"\";\n while (this.pos < this.query.length) {\n const ch = this.query[this.pos];\n if (ch === \"&\" || ch === \"|\" || ch === \")\") {\n break;\n }\n value += ch;\n this.pos++;\n }\n\n return this.coerceValue(value.trim());\n }\n\n private parseArray(): any[] {\n this.consume(\"[\");\n const values: any[] = [];\n\n while (this.pos < this.query.length && this.query[this.pos] !== \"]\") {\n this.skipWhitespace();\n\n // Handle quoted values\n if (this.query[this.pos] === '\"' || this.query[this.pos] === \"'\") {\n values.push(this.parseQuotedString());\n } else {\n // Parse until comma or ]\n let value = \"\";\n while (\n this.pos < this.query.length &&\n this.query[this.pos] !== \",\" &&\n this.query[this.pos] !== \"]\"\n ) {\n value += this.query[this.pos];\n this.pos++;\n }\n values.push(this.coerceValue(value.trim()));\n }\n\n this.skipWhitespace();\n if (this.query[this.pos] === \",\") {\n this.pos++;\n }\n }\n\n this.consume(\"]\");\n return values;\n }\n\n private parseQuotedString(): string {\n const quote = this.query[this.pos];\n this.pos++; // Skip opening quote\n\n let value = \"\";\n let escaped = false;\n\n while (this.pos < this.query.length) {\n const ch = this.query[this.pos];\n\n if (escaped) {\n value += ch;\n escaped = false;\n this.pos++;\n continue;\n }\n\n if (ch === \"\\\\\") {\n escaped = true;\n this.pos++;\n continue;\n }\n\n if (ch === quote) {\n this.pos++; // Skip closing quote\n break;\n }\n\n value += ch;\n this.pos++;\n }\n\n return value;\n }\n\n private coerceValue(value: string): any {\n // Try to parse as number\n if (/^-?\\d+$/.test(value)) {\n return parseInt(value, 10);\n }\n\n if (/^-?\\d+\\.\\d+$/.test(value)) {\n return parseFloat(value);\n }\n\n // Try to parse as boolean\n if (value.toLowerCase() === \"true\") {\n return true;\n }\n if (value.toLowerCase() === \"false\") {\n return false;\n }\n\n return value;\n }\n\n private buildCondition(path: string[], operator: string, value: any): any {\n // Map operator to filter operator\n let filterOp: any;\n\n if (operator === \"=\") {\n if (value === null) {\n filterOp = { isNull: true };\n } else if (Array.isArray(value)) {\n // Arrays should be treated as inArray regardless of content\n filterOp = { inArray: value };\n } else if (typeof value === \"string\" && value.includes(\"*\")) {\n // Handle wildcard patterns\n const startsWithAsterisk = value.startsWith(\"*\");\n const endsWithAsterisk = value.endsWith(\"*\");\n const cleanValue = value.replace(/^\\*|\\*$/g, \"\"); // Remove leading/trailing asterisks\n\n if (startsWithAsterisk && endsWithAsterisk) {\n // *text* -> contains\n filterOp = { contains: cleanValue };\n } else if (startsWithAsterisk) {\n // *text -> endsWith\n filterOp = { endsWith: cleanValue };\n } else if (endsWithAsterisk) {\n // text* -> startsWith\n filterOp = { startsWith: cleanValue };\n } else {\n // Has asterisk in the middle, treat as literal\n filterOp = { eq: value };\n }\n } else {\n filterOp = { eq: value };\n }\n } else if (operator === \"!=\") {\n if (value === null) {\n filterOp = { isNotNull: true };\n } else {\n filterOp = { ne: value };\n }\n } else if (operator === \">\") {\n filterOp = { gt: value };\n } else if (operator === \">=\") {\n filterOp = { gte: value };\n } else if (operator === \"<\") {\n filterOp = { lt: value };\n } else if (operator === \"<=\") {\n filterOp = { lte: value };\n } else {\n throw new Error(`Unsupported operator: ${operator}`);\n }\n\n // Build nested object for path\n if (path.length === 1) {\n return { [path[0]]: filterOp };\n }\n\n // Handle nested paths (JSONB)\n let result: any = filterOp;\n for (let i = path.length - 1; i >= 0; i--) {\n result = { [path[i]]: result };\n }\n\n return result;\n }\n\n private peek(): string {\n this.skipWhitespace();\n return this.query[this.pos] || \"\";\n }\n\n private consume(expected: string): void {\n this.skipWhitespace();\n if (this.query[this.pos] !== expected) {\n throw new Error(\n `Expected '${expected}' at position ${this.pos}, got '${this.query[this.pos]}'`,\n );\n }\n this.pos++;\n }\n\n private skipWhitespace(): void {\n while (this.pos < this.query.length && /\\s/.test(this.query[this.pos])) {\n this.pos++;\n }\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Helper function to build query strings programmatically\n *\n * @example\n * ```ts\n * buildQueryString({\n * and: [\n * { name: \"eq:John\" },\n * { age: \"gt:18\" }\n * ]\n * })\n * // => \"name=John&age>18\"\n * ```\n */\nexport function buildQueryString(where: any): string {\n if (!where || typeof where !== \"object\") {\n return \"\";\n }\n\n // Handle logical operators\n if (\"and\" in where && Array.isArray(where.and)) {\n return where.and.map((w: any) => buildQueryString(w)).join(\"&\");\n }\n\n if (\"or\" in where && Array.isArray(where.or)) {\n const parts = where.or.map((w: any) => buildQueryString(w));\n return parts.length > 1 ? `(${parts.join(\"|\")})` : parts[0];\n }\n\n if (\"not\" in where) {\n // Not operator is harder to represent in string form\n // For now, we'll skip it or you could add a syntax like \"!field=value\"\n return \"\";\n }\n\n // Handle field conditions\n const parts: string[] = [];\n\n for (const [field, condition] of Object.entries(where)) {\n if (typeof condition !== \"object\" || condition === null) {\n parts.push(`${field}=${condition}`);\n continue;\n }\n\n if (\"eq\" in condition) {\n parts.push(`${field}=${condition.eq}`);\n } else if (\"ne\" in condition) {\n parts.push(`${field}!=${condition.ne}`);\n } else if (\"gt\" in condition) {\n parts.push(`${field}>${condition.gt}`);\n } else if (\"gte\" in condition) {\n parts.push(`${field}>=${condition.gte}`);\n } else if (\"lt\" in condition) {\n parts.push(`${field}<${condition.lt}`);\n } else if (\"lte\" in condition) {\n parts.push(`${field}<=${condition.lte}`);\n } else if (\"contains\" in condition) {\n parts.push(`${field}=*${condition.contains}*`);\n } else if (\"startsWith\" in condition) {\n parts.push(`${field}=${condition.startsWith}*`);\n } else if (\"endsWith\" in condition) {\n parts.push(`${field}=*${condition.endsWith}`);\n } else if (\"isNull\" in condition && condition.isNull) {\n parts.push(`${field}=null`);\n } else if (\"isNotNull\" in condition && condition.isNotNull) {\n parts.push(`${field}!=null`);\n } else if (\"inArray\" in condition && Array.isArray(condition.inArray)) {\n const values = condition.inArray.map((v: any) =>\n typeof v === \"string\" ? `\"${v}\"` : v,\n );\n parts.push(`${field}=[${values.join(\",\")}]`);\n } else {\n // Nested object (JSONB)\n const nested = buildQueryString(condition);\n if (nested) {\n parts.push(`${field}.${nested}`);\n }\n }\n }\n\n return parts.join(\"&\");\n}\n","import { $context } from \"alepha\";\nimport { $retry } from \"alepha/retry\";\nimport type { PgTransaction } from \"drizzle-orm/pg-core\";\nimport type { PgTransactionConfig } from \"drizzle-orm/pg-core/session\";\nimport { DbVersionMismatchError } from \"../errors/DbVersionMismatchError.ts\";\nimport { DatabaseProvider } from \"../providers/drivers/DatabaseProvider.ts\";\n\n/**\n * Creates a transaction primitive for database operations requiring atomicity and consistency.\n *\n * This primitive provides a convenient way to wrap database operations in PostgreSQL\n * transactions, ensuring ACID properties and automatic retry logic for version conflicts.\n * It integrates seamlessly with the repository pattern and provides built-in handling\n * for optimistic locking scenarios with automatic retry on version mismatches.\n *\n * **Important Notes**:\n * - All operations within the transaction handler are atomic\n * - Automatic retry on `PgVersionMismatchError` for optimistic locking\n * - Pass `{ tx }` option to all repository operations within the transaction\n * - Transactions are automatically rolled back on any unhandled error\n * - Use appropriate isolation levels based on your consistency requirements\n */\nexport const $transaction = <T extends any[], R>(\n opts: TransactionPrimitiveOptions<T, R>,\n) => {\n const { alepha } = $context();\n const provider = alepha.inject(DatabaseProvider);\n\n return $retry({\n when: (err) => err instanceof DbVersionMismatchError,\n handler: (...args: T) =>\n provider.db.transaction(\n async (tx) => opts.handler(tx, ...args),\n opts.config,\n ),\n });\n};\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface TransactionPrimitiveOptions<T extends any[], R> {\n /**\n * Transaction handler function that contains all database operations to be executed atomically.\n *\n * This function:\n * - Receives a transaction object as the first parameter\n * - Should pass the transaction to all repository operations via `{ tx }` option\n * - All operations within are automatically rolled back if any error occurs\n * - Has access to the full Alepha dependency injection container\n * - Will be automatically retried if a `PgVersionMismatchError` occurs\n *\n * **Transaction Guidelines**:\n * - Keep transactions as short as possible to minimize lock contention\n * - Always pass the `tx` parameter to repository operations\n * - Handle expected business errors gracefully\n * - Log important operations for debugging and audit trails\n * - Consider the impact of long-running transactions on performance\n *\n * **Error Handling**:\n * - Throwing any error will automatically roll back the transaction\n * - `PgVersionMismatchError` triggers automatic retry logic\n * - Other database errors will be propagated after rollback\n * - Use try-catch within the handler for business-specific error handling\n *\n * @param tx - The PostgreSQL transaction object to use for all database operations\n * @param ...args - Additional arguments passed to the transaction function\n * @returns Promise resolving to the transaction result\n *\n * @example\n * ```ts\n * handler: async (tx, orderId: string, newStatus: string) => {\n * // Get the current order (with transaction)\n * const order = await this.orders.findById(orderId, { tx });\n *\n * // Validate business rules\n * if (!this.isValidStatusTransition(order.status, newStatus)) {\n * throw new Error(`Invalid status transition: ${order.status} -> ${newStatus}`);\n * }\n *\n * // Update order status (with transaction)\n * const updatedOrder = await this.orders.updateById(\n * orderId,\n * { status: newStatus },\n * { tx }\n * );\n *\n * // Create audit log (with transaction)\n * await this.auditLogs.create({\n * id: generateUUID(),\n * entityId: orderId,\n * action: 'status_change',\n * oldValue: order.status,\n * newValue: newStatus,\n * timestamp: new Date().toISOString()\n * }, { tx });\n *\n * return updatedOrder;\n * }\n * ```\n */\n handler: (tx: PgTransaction<any, any, any>, ...args: T) => Promise<R>;\n\n /**\n * PostgreSQL transaction configuration options.\n *\n * This allows you to customize transaction behavior including:\n * - **Isolation Level**: Controls visibility of concurrent transaction changes\n * - **Access Mode**: Whether the transaction is read-only or read-write\n * - **Deferrable**: For serializable transactions, allows deferring to avoid conflicts\n *\n * **Isolation Levels**:\n * - **read_uncommitted**: Lowest isolation, allows dirty reads (rarely used)\n * - **read_committed**: Default level, prevents dirty reads\n * - **repeatable_read**: Prevents dirty and non-repeatable reads\n * - **serializable**: Highest isolation, full ACID compliance\n *\n * **Access Modes**:\n * - **read_write**: Default, allows both read and write operations\n * - **read_only**: Only allows read operations, can provide performance benefits\n *\n * **When to Use Different Isolation Levels**:\n * - **read_committed**: Most common operations, good balance of consistency and performance\n * - **repeatable_read**: When you need consistent reads throughout the transaction\n * - **serializable**: Critical financial operations, when absolute consistency is required\n *\n * @example\n * ```ts\n * config: {\n * isolationLevel: 'serializable', // Highest consistency for financial operations\n * accessMode: 'read_write'\n * }\n * ```\n *\n * @example\n * ```ts\n * config: {\n * isolationLevel: 'read_committed', // Default level for most operations\n * accessMode: 'read_only' // Performance optimization for read-only operations\n * }\n * ```\n */\n config?: PgTransactionConfig;\n}\n\nexport type TransactionContext = PgTransaction<any, any, any>;\n","import {\n AlephaError,\n pageSchema,\n type Static,\n type TBigInt,\n type TInteger,\n type TNumber,\n type TNumberOptions,\n type TObject,\n type TObjectOptions,\n type TPage,\n type TSchema,\n type TString,\n type TStringOptions,\n type TUnsafe,\n t,\n} from \"alepha\";\nimport type { UpdateDeleteAction } from \"drizzle-orm/pg-core/foreign-keys\";\nimport {\n PG_CREATED_AT,\n PG_DEFAULT,\n PG_DELETED_AT,\n PG_ENUM,\n PG_IDENTITY,\n PG_PRIMARY_KEY,\n PG_REF,\n PG_UPDATED_AT,\n PG_VERSION,\n type PgDefault,\n type PgEnumOptions,\n type PgIdentityOptions,\n type PgPrimaryKey,\n type PgRef,\n} from \"../constants/PG_SYMBOLS.ts\";\nimport type { PgAttr } from \"../helpers/pgAttr.ts\";\nimport { pgAttr } from \"../helpers/pgAttr.ts\";\n\nexport class PostgresTypeProvider {\n public readonly attr = pgAttr;\n\n /**\n * Creates a primary key with an identity column.\n */\n public readonly identityPrimaryKey = (\n identity?: PgIdentityOptions,\n options?: TNumberOptions,\n ) =>\n pgAttr(\n pgAttr(pgAttr(t.integer(options), PG_PRIMARY_KEY), PG_IDENTITY, identity),\n PG_DEFAULT,\n );\n\n /**\n * Creates a primary key with a big identity column. (default)\n */\n public readonly bigIdentityPrimaryKey = (\n identity?: PgIdentityOptions,\n options?: TNumberOptions,\n ) =>\n pgAttr(\n pgAttr(pgAttr(t.int64(options), PG_PRIMARY_KEY), PG_IDENTITY, identity),\n PG_DEFAULT,\n );\n\n /**\n * Creates a primary key with a UUID column.\n */\n public readonly uuidPrimaryKey = () =>\n pgAttr(pgAttr(t.uuid(), PG_PRIMARY_KEY), PG_DEFAULT);\n\n /**\n * Creates a primary key for a given type. Supports:\n * - `t.integer()` -> PG INT (default)\n * - `t.bigint()` -> PG BIGINT\n * - `t.uuid()` -> PG UUID\n */\n public primaryKey(): PgAttr<PgAttr<TInteger, PgPrimaryKey>, PgDefault>;\n public primaryKey(\n type: TString,\n options?: TStringOptions,\n ): PgAttr<PgAttr<TString, PgPrimaryKey>, PgDefault>;\n public primaryKey(\n type: TInteger,\n options?: TNumberOptions,\n identity?: PgIdentityOptions,\n ): PgAttr<PgAttr<TInteger, PgPrimaryKey>, PgDefault>;\n public primaryKey(\n type: TNumber,\n options?: TNumberOptions,\n identity?: PgIdentityOptions,\n ): PgAttr<PgAttr<TNumber, PgPrimaryKey>, PgDefault>;\n public primaryKey(\n type: TBigInt,\n options?: TNumberOptions,\n identity?: PgIdentityOptions,\n ): PgAttr<PgAttr<TBigInt, PgPrimaryKey>, PgDefault>;\n public primaryKey(\n type?: TSchema,\n options?: TNumberOptions | TStringOptions,\n identity?: PgIdentityOptions,\n ): PgAttr<PgAttr<TSchema, PgPrimaryKey>, PgDefault> {\n if (!type || t.schema.isInteger(type)) {\n return pgAttr(\n pgAttr(\n pgAttr(t.integer(options), PG_PRIMARY_KEY),\n PG_IDENTITY,\n identity,\n ),\n PG_DEFAULT,\n );\n }\n\n if (t.schema.isString(type) && type.format === \"uuid\") {\n return pgAttr(pgAttr(t.uuid(), PG_PRIMARY_KEY), PG_DEFAULT);\n }\n\n if (t.schema.isNumber(type) && type.format === \"int64\") {\n return pgAttr(\n pgAttr(\n pgAttr(t.number(options), PG_PRIMARY_KEY),\n PG_IDENTITY,\n identity,\n ),\n PG_DEFAULT,\n );\n }\n\n if (t.schema.isBigInt(type)) {\n return pgAttr(\n pgAttr(\n pgAttr(t.bigint(options), PG_PRIMARY_KEY),\n PG_IDENTITY,\n identity,\n ),\n PG_DEFAULT,\n );\n }\n\n throw new AlephaError(`Unsupported type for primary key: ${type}`);\n }\n\n /**\n * Wrap a schema with \"default\" attribute.\n * This is used to set a default value for a column in the database.\n */\n public readonly default = <T extends TSchema>(\n type: T,\n value?: Static<T>,\n ): PgAttr<T, PgDefault> => {\n if (value != null) {\n Object.assign(type, { default: value });\n }\n\n return this.attr(type, PG_DEFAULT);\n };\n\n /**\n * Creates a column 'version'.\n *\n * This is used to track the version of a row in the database.\n *\n * You can use it for optimistic concurrency control (OCC) with {@link RepositoryPrimitive#save}.\n *\n * @see {@link RepositoryPrimitive#save}\n * @see {@link PgVersionMismatchError}\n */\n public readonly version = (options: TNumberOptions = {}) =>\n this.default(pgAttr(t.integer(options), PG_VERSION), 0);\n\n /**\n * Creates a column Created At. So just a datetime column with a default value of the current timestamp.\n */\n public readonly createdAt = (options?: TStringOptions) =>\n pgAttr(pgAttr(t.datetime(options), PG_CREATED_AT), PG_DEFAULT);\n\n /**\n * Creates a column Updated At. Like createdAt, but it is updated on every update of the row.\n */\n public readonly updatedAt = (options?: TStringOptions) =>\n pgAttr(pgAttr(t.datetime(options), PG_UPDATED_AT), PG_DEFAULT);\n\n /**\n * Creates a column Deleted At for soft delete functionality.\n * This is used to mark rows as deleted without actually removing them from the database.\n * The column is nullable - NULL means not deleted, timestamp means deleted.\n */\n public readonly deletedAt = (options?: TStringOptions) =>\n pgAttr(t.optional(t.datetime(options)), PG_DELETED_AT);\n\n /**\n * Creates a Postgres ENUM type.\n *\n * > By default, `t.enum()` is mapped to a TEXT column in Postgres.\n * > Using this method, you can create a real ENUM type in the database.\n *\n * @example\n * ```ts\n * const statusEnum = pg.enum([\"pending\", \"active\", \"archived\"], { name: \"status_enum\" });\n * ```\n */\n public readonly enum = <T extends string[]>(\n values: [...T],\n pgEnumOptions?: PgEnumOptions,\n typeOptions?: TStringOptions,\n ): PgAttr<TUnsafe<T[number]>, typeof PG_ENUM> => {\n return pgAttr(\n t.enum(values, {\n description: pgEnumOptions?.description,\n ...typeOptions,\n }),\n PG_ENUM,\n pgEnumOptions,\n );\n };\n\n /**\n * Creates a reference to another table or schema. Basically a foreign key.\n */\n public readonly ref = <T extends TSchema>(\n type: T,\n ref: () => any,\n actions?: {\n onUpdate?: UpdateDeleteAction;\n onDelete?: UpdateDeleteAction;\n },\n ): PgAttr<T, PgRef> => {\n // If actions are not provided, set default onDelete based on type\n const finalActions = actions ?? {\n onDelete: t.schema.isOptional(type) ? \"set null\" : \"cascade\",\n };\n\n return this.attr(type, PG_REF, {\n ref,\n actions: finalActions,\n });\n };\n\n // -------------------------------------------------------------------------------------------------------------------\n\n /**\n * Creates a page schema for a given object schema.\n * It's used by {@link RepositoryPrimitive#paginate} method.\n */\n public readonly page = <T extends TObject>(\n resource: T,\n options?: TObjectOptions,\n ): TPage<T> => {\n return pageSchema(resource, options);\n };\n}\n\nexport const pg = new PostgresTypeProvider();\n","import { t } from \"alepha\";\nimport {\n PG_DEFAULT,\n PG_PRIMARY_KEY,\n PG_SERIAL,\n} from \"../constants/PG_SYMBOLS.ts\";\nimport { pgAttr } from \"../helpers/pgAttr.ts\";\n\n/**\n * @deprecated Use `pg.primaryKey()` instead.\n */\nexport const legacyIdSchema = pgAttr(\n pgAttr(pgAttr(t.integer(), PG_PRIMARY_KEY), PG_SERIAL),\n PG_DEFAULT,\n);\n","import { $module, type Alepha, t } from \"alepha\";\nimport { AlephaDateTime } from \"alepha/datetime\";\nimport * as drizzle from \"drizzle-orm\";\nimport { $entity } from \"./primitives/$entity.ts\";\nimport { $repository } from \"./primitives/$repository.ts\";\nimport { $sequence } from \"./primitives/$sequence.ts\";\nimport { DrizzleKitProvider } from \"./providers/DrizzleKitProvider.ts\";\nimport { DatabaseProvider } from \"./providers/drivers/DatabaseProvider.ts\";\nimport { NodePostgresProvider } from \"./providers/drivers/NodePostgresProvider.ts\";\nimport { NodeSqliteProvider } from \"./providers/drivers/NodeSqliteProvider.ts\";\nimport { PglitePostgresProvider } from \"./providers/drivers/PglitePostgresProvider.ts\";\nimport { RepositoryProvider } from \"./providers/RepositoryProvider.ts\";\nimport { PgJsonQueryManager } from \"./services/PgJsonQueryManager.ts\";\nimport { PgRelationManager } from \"./services/PgRelationManager.ts\";\nimport { PostgresModelBuilder } from \"./services/PostgresModelBuilder.ts\";\nimport { QueryManager } from \"./services/QueryManager.ts\";\nimport { Repository } from \"./services/Repository.ts\";\nimport { SqliteModelBuilder } from \"./services/SqliteModelBuilder.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\ndeclare module \"alepha\" {\n interface Hooks {\n /**\n * Fires before creating an entity in the repository.\n */\n \"repository:create:before\": {\n tableName: string;\n data: any;\n };\n /**\n * Fires after creating an entity in the repository.\n */\n \"repository:create:after\": {\n tableName: string;\n data: any;\n entity: any;\n };\n /**\n * Fires before updating entities in the repository.\n */\n \"repository:update:before\": {\n tableName: string;\n where: any;\n data: any;\n };\n /**\n * Fires after updating entities in the repository.\n */\n \"repository:update:after\": {\n tableName: string;\n where: any;\n data: any;\n entities: any[];\n };\n /**\n * Fires before deleting entities from the repository.\n */\n \"repository:delete:before\": {\n tableName: string;\n where: any;\n };\n /**\n * Fires after deleting entities from the repository.\n */\n \"repository:delete:after\": {\n tableName: string;\n where: any;\n ids: Array<string | number>;\n };\n /**\n * Fires before reading entities from the repository.\n */\n \"repository:read:before\": {\n tableName: string;\n query: any;\n };\n /**\n * Fires after reading entities from the repository.\n */\n \"repository:read:after\": {\n tableName: string;\n query: any;\n entities: any[];\n };\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport { drizzle };\nexport {\n type Page,\n type PageQuery,\n pageQuerySchema,\n pageSchema,\n} from \"alepha\";\nexport { sql } from \"drizzle-orm\";\nexport * from \"drizzle-orm/pg-core\";\nexport * from \"./constants/PG_SYMBOLS.ts\";\nexport * from \"./errors/DbConflictError.ts\";\nexport * from \"./errors/DbEntityNotFoundError.ts\";\nexport * from \"./errors/DbError.ts\";\nexport * from \"./errors/DbMigrationError.ts\";\nexport * from \"./errors/DbVersionMismatchError.ts\";\nexport * from \"./helpers/parseQueryString.ts\";\nexport * from \"./helpers/pgAttr.ts\";\nexport * from \"./interfaces/FilterOperators.ts\";\nexport * from \"./interfaces/PgQuery.ts\";\nexport * from \"./interfaces/PgQueryWhere.ts\";\nexport * from \"./primitives/$entity.ts\";\nexport * from \"./primitives/$repository.ts\";\nexport * from \"./primitives/$sequence.ts\";\nexport * from \"./primitives/$transaction.ts\";\nexport * from \"./providers/DrizzleKitProvider.ts\";\nexport * from \"./providers/drivers/DatabaseProvider.ts\";\nexport * from \"./providers/drivers/NodePostgresProvider.ts\";\nexport * from \"./providers/drivers/NodeSqliteProvider.ts\";\nexport * from \"./providers/PostgresTypeProvider.ts\";\nexport * from \"./providers/RepositoryProvider.ts\";\nexport * from \"./schemas/insertSchema.ts\";\nexport * from \"./schemas/legacyIdSchema.ts\";\nexport * from \"./schemas/updateSchema.ts\";\nexport * from \"./services/Repository.ts\";\nexport * from \"./types/schema.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Postgres client based on Drizzle ORM, Alepha type-safe friendly.\n *\n * ```ts\n * const users = $entity({\n * name: \"users\",\n * schema: t.object({\n * id: pg.primaryKey(),\n * name: t.text(),\n * email: t.text(),\n * }),\n * });\n *\n * class Db {\n * users = $repository(users);\n * }\n *\n * const db = alepha.inject(Db);\n * const user = await db.users.one({ name: { eq: \"John Doe\" } });\n * ```\n *\n * This is not a full ORM, but rather a set of tools to work with Postgres databases in a type-safe way.\n *\n * It provides:\n * - A type-safe way to define entities and repositories. (via `$entity` and `$repository`)\n * - Custom query builders and filters.\n * - Built-in special columns like `createdAt`, `updatedAt`, `deletedAt`, `version`.\n * - Automatic JSONB support.\n * - Automatic synchronization of entities with the database schema (for testing and development).\n * - Fallback to raw SQL via Drizzle ORM `sql` function.\n *\n * Migrations are supported via Drizzle ORM, you need to use the `drizzle-kit` CLI tool to generate and run migrations.\n *\n * @see {@link $entity}\n * @see {@link $sequence}\n * @see {@link $repository}\n * @see {@link $transaction}\n * @module alepha.postgres\n */\nexport const AlephaPostgres = $module({\n name: \"alepha.postgres\",\n primitives: [$sequence, $entity],\n services: [\n AlephaDateTime,\n DatabaseProvider,\n NodePostgresProvider,\n PglitePostgresProvider,\n NodeSqliteProvider,\n SqliteModelBuilder,\n PostgresModelBuilder,\n DrizzleKitProvider,\n RepositoryProvider,\n Repository,\n PgRelationManager,\n PgJsonQueryManager,\n QueryManager,\n ],\n register: (alepha: Alepha) => {\n const env = alepha.parseEnv(\n t.object({\n DATABASE_URL: t.optional(t.text()),\n }),\n );\n\n alepha.with(DrizzleKitProvider);\n alepha.with(RepositoryProvider);\n\n const url = env.DATABASE_URL;\n const hasPGlite = !!PglitePostgresProvider.importPglite();\n const isPostgres = url?.startsWith(\"postgres:\");\n const isSqlite = url?.startsWith(\"sqlite:\");\n const isMemory = url?.includes(\":memory:\");\n const isFile = !!url && !isPostgres && !isMemory;\n\n if (hasPGlite && (isMemory || isFile || !url) && !isSqlite) {\n alepha.with({\n optional: true,\n provide: DatabaseProvider,\n use: PglitePostgresProvider,\n });\n return;\n }\n\n if (isPostgres) {\n alepha.with({\n optional: true,\n provide: DatabaseProvider,\n use: NodePostgresProvider,\n });\n return;\n }\n\n alepha.with({\n optional: true,\n provide: DatabaseProvider,\n use: NodeSqliteProvider,\n });\n },\n});\n"],"mappings":"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"}
|