alepha 0.20.1 → 0.20.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -1
- package/assets/swagger-ui/swagger-ui-bundle.js +1 -1
- package/assets/swagger-ui/swagger-ui.css +1 -1
- package/dist/api/audits/index.browser.js +49 -0
- package/dist/api/audits/index.browser.js.map +1 -1
- package/dist/api/audits/index.d.ts.map +1 -1
- package/dist/api/audits/index.js +49 -0
- package/dist/api/audits/index.js.map +1 -1
- package/dist/api/files/index.d.ts.map +1 -1
- package/dist/api/files/index.js +2 -1
- package/dist/api/files/index.js.map +1 -1
- package/dist/api/jobs/index.browser.js +64 -148
- package/dist/api/jobs/index.browser.js.map +1 -1
- package/dist/api/jobs/index.d.ts +339 -600
- package/dist/api/jobs/index.d.ts.map +1 -1
- package/dist/api/jobs/index.js +605 -1012
- package/dist/api/jobs/index.js.map +1 -1
- package/dist/api/keys/index.js.map +1 -1
- package/dist/api/notifications/index.d.ts +79 -27
- package/dist/api/notifications/index.d.ts.map +1 -1
- package/dist/api/notifications/index.js +90 -23
- package/dist/api/notifications/index.js.map +1 -1
- package/dist/api/organizations/index.d.ts.map +1 -1
- package/dist/api/parameters/index.browser.js +37 -0
- package/dist/api/parameters/index.browser.js.map +1 -1
- package/dist/api/parameters/index.d.ts +4 -65
- package/dist/api/parameters/index.d.ts.map +1 -1
- package/dist/api/parameters/index.js +37 -0
- package/dist/api/parameters/index.js.map +1 -1
- package/dist/api/payments/index.d.ts +2 -1
- package/dist/api/payments/index.d.ts.map +1 -1
- package/dist/api/payments/index.js +4 -2
- package/dist/api/payments/index.js.map +1 -1
- package/dist/api/users/index.d.ts +225 -5199
- package/dist/api/users/index.d.ts.map +1 -1
- package/dist/api/users/index.js +15 -11
- package/dist/api/users/index.js.map +1 -1
- package/dist/api/verifications/index.d.ts.map +1 -1
- package/dist/api/verifications/index.js +4 -2
- package/dist/api/verifications/index.js.map +1 -1
- package/dist/bucket/index.js +5 -1
- package/dist/bucket/index.js.map +1 -1
- package/dist/bucket/index.workerd.js +5 -1
- package/dist/bucket/index.workerd.js.map +1 -1
- package/dist/cache/core/index.js.map +1 -1
- package/dist/cache/core/index.workerd.js.map +1 -1
- package/dist/captcha/index.js.map +1 -1
- package/dist/cli/core/index.d.ts +225 -11681
- package/dist/cli/core/index.d.ts.map +1 -1
- package/dist/cli/core/index.js +732 -257
- package/dist/cli/core/index.js.map +1 -1
- package/dist/cli/devtools/index.js +7 -1
- package/dist/cli/devtools/index.js.map +1 -1
- package/dist/cli/platform/index.d.ts +65 -63
- package/dist/cli/platform/index.d.ts.map +1 -1
- package/dist/cli/platform/index.js +140 -27
- package/dist/cli/platform/index.js.map +1 -1
- package/dist/cli/vendor/index.js +15 -0
- package/dist/cli/vendor/index.js.map +1 -1
- package/dist/command/index.d.ts +1 -1
- package/dist/command/index.js +1 -1
- package/dist/command/index.js.map +1 -1
- package/dist/core/index.browser.js +6 -0
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +8 -8
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +6 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js +6 -0
- package/dist/core/index.native.js.map +1 -1
- package/dist/core/index.workerd.js +6 -0
- package/dist/core/index.workerd.js.map +1 -1
- package/dist/crypto/index.js.map +1 -1
- package/dist/datetime/index.js.map +1 -1
- package/dist/email/core/index.js.map +1 -1
- package/dist/email/smtp/index.js +2 -10522
- package/dist/email/smtp/index.js.map +1 -1
- package/dist/fake/index.d.ts +4 -8085
- package/dist/fake/index.d.ts.map +1 -1
- package/dist/fake/index.js +3 -33554
- package/dist/fake/index.js.map +1 -1
- package/dist/lock/core/index.js.map +1 -1
- package/dist/lock/redis/index.js.map +1 -1
- package/dist/logger/index.js +32 -1
- package/dist/logger/index.js.map +1 -1
- package/dist/mcp/index.js +5 -1
- package/dist/mcp/index.js.map +1 -1
- package/dist/orm/core/index.browser.js +1 -361
- package/dist/orm/core/index.browser.js.map +1 -1
- package/dist/orm/core/index.bun.js +14 -406
- package/dist/orm/core/index.bun.js.map +1 -1
- package/dist/orm/core/index.d.ts +96 -5117
- package/dist/orm/core/index.d.ts.map +1 -1
- package/dist/orm/core/index.js +23 -419
- package/dist/orm/core/index.js.map +1 -1
- package/dist/orm/postgres/index.bun.js +17 -20
- package/dist/orm/postgres/index.bun.js.map +1 -1
- package/dist/orm/postgres/index.d.ts +2 -613
- package/dist/orm/postgres/index.d.ts.map +1 -1
- package/dist/orm/postgres/index.js +17 -20
- package/dist/orm/postgres/index.js.map +1 -1
- package/dist/react/core/index.js.map +1 -1
- package/dist/react/form/index.d.ts +60 -1
- package/dist/react/form/index.d.ts.map +1 -1
- package/dist/react/form/index.js +86 -1
- package/dist/react/form/index.js.map +1 -1
- package/dist/react/head/index.browser.js +16 -1
- package/dist/react/head/index.browser.js.map +1 -1
- package/dist/react/head/index.d.ts +6 -0
- package/dist/react/head/index.d.ts.map +1 -1
- package/dist/react/head/index.js +16 -1
- package/dist/react/head/index.js.map +1 -1
- package/dist/react/i18n/index.js.map +1 -1
- package/dist/react/intro/index.js +22 -17
- package/dist/react/intro/index.js.map +1 -1
- package/dist/react/router/index.browser.js +78 -12
- package/dist/react/router/index.browser.js.map +1 -1
- package/dist/react/router/index.d.ts +57 -13
- package/dist/react/router/index.d.ts.map +1 -1
- package/dist/react/router/index.js +102 -14
- package/dist/react/router/index.js.map +1 -1
- package/dist/react/testing/index.d.ts +1 -411
- package/dist/react/testing/index.d.ts.map +1 -1
- package/dist/react/testing/index.js +13 -12293
- package/dist/react/testing/index.js.map +1 -1
- package/dist/react/ui/index.d.ts +124 -0
- package/dist/react/ui/index.d.ts.map +1 -0
- package/dist/react/ui/index.js +209 -0
- package/dist/react/ui/index.js.map +1 -0
- package/dist/react/websocket/index.js.map +1 -1
- package/dist/redis/index.js.map +1 -1
- package/dist/router/index.d.ts +13 -13
- package/dist/router/index.d.ts.map +1 -1
- package/dist/router/index.js +45 -32
- package/dist/router/index.js.map +1 -1
- package/dist/scheduler/index.d.ts +1 -83
- package/dist/scheduler/index.d.ts.map +1 -1
- package/dist/scheduler/index.js +2 -391
- package/dist/scheduler/index.js.map +1 -1
- package/dist/scheduler/index.workerd.js +2 -391
- package/dist/scheduler/index.workerd.js.map +1 -1
- package/dist/security/index.browser.js.map +1 -1
- package/dist/security/index.d.ts +2 -325
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/index.js +3 -1362
- package/dist/security/index.js.map +1 -1
- package/dist/server/auth/index.d.ts +1 -1054
- package/dist/server/auth/index.d.ts.map +1 -1
- package/dist/server/auth/index.js +16 -1224
- package/dist/server/auth/index.js.map +1 -1
- package/dist/server/cookies/index.js.map +1 -1
- package/dist/server/core/index.browser.js.map +1 -1
- package/dist/server/core/index.d.ts +1 -4
- package/dist/server/core/index.d.ts.map +1 -1
- package/dist/server/core/index.js +19 -4
- package/dist/server/core/index.js.map +1 -1
- package/dist/server/links/index.browser.js.map +1 -1
- package/dist/server/links/index.js.map +1 -1
- package/dist/server/metrics/index.d.ts +1 -514
- package/dist/server/metrics/index.d.ts.map +1 -1
- package/dist/server/metrics/index.js +4 -4356
- package/dist/server/metrics/index.js.map +1 -1
- package/dist/server/rate-limit/index.js.map +1 -1
- package/dist/server/static/index.js.map +1 -1
- package/dist/server/swagger/index.js +1 -1
- package/dist/server/swagger/index.js.map +1 -1
- package/dist/sms/index.js.map +1 -1
- package/dist/system/index.browser.js.map +1 -1
- package/dist/system/index.d.ts.map +1 -1
- package/dist/system/index.js +1 -0
- package/dist/system/index.js.map +1 -1
- package/dist/system/index.workerd.js.map +1 -1
- package/dist/topic/core/index.js +1 -1
- package/dist/topic/core/index.js.map +1 -1
- package/dist/websocket/index.browser.js +21 -0
- package/dist/websocket/index.browser.js.map +1 -1
- package/dist/websocket/index.js +21 -0
- package/dist/websocket/index.js.map +1 -1
- package/package.json +23 -37
- package/src/api/files/__tests__/FileController.spec.ts +1 -1
- package/src/api/files/jobs/FileJobs.ts +2 -1
- package/src/api/jobs/__tests__/$job.spec.ts +320 -2867
- package/src/api/jobs/controllers/AdminJobController.ts +29 -138
- package/src/api/jobs/entities/jobExecutionEntity.ts +27 -19
- package/src/api/jobs/index.browser.ts +5 -7
- package/src/api/jobs/index.ts +23 -51
- package/src/api/jobs/primitives/$job.ts +66 -58
- package/src/api/jobs/providers/JobProvider.ts +561 -566
- package/src/api/jobs/providers/JobQueueProvider.ts +18 -19
- package/src/api/jobs/schemas/jobConfigAtom.ts +20 -23
- package/src/api/jobs/schemas/jobExecutionQuerySchema.ts +3 -27
- package/src/api/jobs/schemas/jobExecutionResourceSchema.ts +5 -7
- package/src/api/jobs/schemas/jobRegistrationSchema.ts +7 -4
- package/src/api/jobs/schemas/triggerJobSchema.ts +0 -1
- package/src/api/jobs/services/JobService.ts +90 -483
- package/src/api/notifications/controllers/AdminNotificationController.ts +19 -12
- package/src/api/notifications/index.ts +7 -4
- package/src/api/notifications/jobs/NotificationJobs.ts +83 -12
- package/src/api/payments/services/PaymentService.ts +4 -2
- package/src/api/users/__tests__/UserJobs.spec.ts +10 -49
- package/src/api/users/audits/UserAudits.ts +3 -1
- package/src/api/users/buckets/UserBuckets.ts +2 -1
- package/src/api/users/index.ts +1 -4
- package/src/api/users/jobs/UserJobs.ts +5 -4
- package/src/api/users/schemas/userQuerySchema.ts +0 -1
- package/src/api/users/services/UserService.ts +1 -5
- package/src/api/verifications/__tests__/CodeVerification.spec.ts +14 -0
- package/src/api/verifications/__tests__/LinkVerification.spec.ts +14 -0
- package/src/api/verifications/jobs/VerificationJobs.ts +2 -1
- package/src/api/verifications/services/VerificationService.ts +1 -0
- package/src/cli/core/__tests__/init.spec.ts +209 -1
- package/src/cli/core/commands/init.ts +9 -9
- package/src/cli/core/services/PackageManagerUtils.ts +22 -12
- package/src/cli/core/services/ProjectScaffolder.ts +300 -70
- package/src/cli/core/tasks/BuildDockerTask.ts +9 -10
- package/src/cli/core/tasks/BuildServerTask.ts +8 -0
- package/src/cli/core/templates/agentMd.ts +2 -8
- package/src/cli/core/templates/apiIndexTs.ts +22 -14
- package/src/cli/core/templates/componentsJsonTs.ts +39 -0
- package/src/cli/core/templates/mainCss.ts +2 -36
- package/src/cli/core/templates/saasAdminLayoutTsx.ts +77 -0
- package/src/cli/core/templates/saasAdminPagesTsx.ts +26 -0
- package/src/cli/core/templates/saasAuthLayoutTsx.ts +20 -0
- package/src/cli/core/templates/saasAuthPagesTsx.ts +62 -0
- package/src/cli/core/templates/saasRealmProviderTs.ts +46 -0
- package/src/cli/core/templates/vitestConfigTs.ts +17 -0
- package/src/cli/core/templates/webAppRouterTs.ts +102 -82
- package/src/cli/core/templates/webIndexTs.ts +23 -1
- package/src/cli/platform/__tests__/CloudflareAdapter.spec.ts +22 -71
- package/src/cli/platform/__tests__/SecretsCommand.spec.ts +2 -0
- package/src/cli/platform/adapters/CloudflareAdapter.ts +12 -11
- package/src/cli/platform/atoms/platformOptions.ts +9 -0
- package/src/cli/platform/schemas/cloudflare.ts +3 -2
- package/src/cli/platform/services/CloudflareApi.ts +164 -25
- package/src/cli/platform/services/WranglerApi.ts +0 -17
- package/src/command/providers/CliProvider.ts +1 -1
- package/src/core/Alepha.ts +9 -0
- package/src/core/interfaces/Service.ts +3 -1
- package/src/core/providers/TypeProvider.ts +1 -1
- package/src/logger/services/Logger.ts +1 -1
- package/src/mcp/__tests__/$resource.spec.ts +1 -1
- package/src/mcp/__tests__/$tool.spec.ts +1 -1
- package/src/mcp/__tests__/McpServerProvider.spec.ts +1 -1
- package/src/orm/__tests__/$repository-tests.ts +1 -0
- package/src/orm/__tests__/orm-next-tests.ts +2 -67
- package/src/orm/__tests__/orm-next.spec.ts +0 -21
- package/src/orm/core/index.shared.ts +0 -2
- package/src/orm/core/index.ts +1 -2
- package/src/orm/core/primitives/$repository.ts +3 -6
- package/src/orm/core/providers/drivers/DatabaseProvider.ts +0 -5
- package/src/orm/core/providers/drivers/NodeSqliteProvider.ts +11 -13
- package/src/orm/core/services/ModelBuilder.ts +1 -13
- package/src/orm/core/services/Repository.ts +1 -42
- package/src/orm/core/services/SqliteModelBuilder.ts +2 -33
- package/src/orm/postgres/services/PostgresModelBuilder.ts +10 -45
- package/src/react/form/index.ts +2 -0
- package/src/react/form/services/parseField.ts +163 -0
- package/src/react/form/services/prettyName.ts +19 -0
- package/src/react/head/providers/BrowserHeadProvider.ts +31 -10
- package/src/react/intro/components/GettingStartedAuthSlide.tsx +11 -4
- package/src/react/router/__tests__/ReactBrowserProvider.browser.spec.ts +213 -2
- package/src/react/router/primitives/$page.ts +35 -12
- package/src/react/router/providers/ReactBrowserProvider.ts +73 -0
- package/src/react/router/providers/ReactBrowserRouterProvider.ts +1 -1
- package/src/react/router/providers/ReactPreloadProvider.ts +1 -1
- package/src/react/router/providers/ReactServerProvider.ts +1 -0
- package/src/react/ui/atoms/uiAtom.ts +28 -0
- package/src/react/ui/components/ColorScheme.tsx +36 -0
- package/src/react/ui/hooks/useColorMode.ts +49 -0
- package/src/react/ui/hooks/useSidebarState.ts +26 -0
- package/src/react/ui/hooks/useTheme.ts +22 -0
- package/src/react/ui/index.ts +35 -0
- package/src/react/ui/services/UiPersistence.ts +41 -0
- package/src/router/TemplatedPathParser.ts +50 -51
- package/src/router/__tests__/RouterProvider.spec.ts +62 -0
- package/src/router/__tests__/TemplatedPathParser.spec.ts +18 -0
- package/src/router/providers/RouterProvider.ts +10 -5
- package/src/scheduler/providers/CronProvider.ts +1 -1
- package/src/security/primitives/$basicAuth.ts +1 -1
- package/src/server/auth/providers/ServerAuthProvider.ts +5 -1
- package/src/server/core/interfaces/ServerRequest.ts +1 -0
- package/src/server/core/providers/ServerProvider.ts +1 -1
- package/src/server/core/providers/ServerRouterProvider.ts +2 -2
- package/src/server/core/services/HttpClient.ts +1 -1
- package/src/server/swagger/providers/ServerSwaggerProvider.ts +1 -1
- package/src/system/providers/NodeShellProvider.ts +1 -0
- package/src/topic/core/providers/TopicProvider.ts +1 -1
- package/dist/api/invitations/index.d.ts +0 -790
- package/dist/api/invitations/index.d.ts.map +0 -1
- package/dist/api/invitations/index.js +0 -662
- package/dist/api/invitations/index.js.map +0 -1
- package/dist/api/issues/index.d.ts +0 -810
- package/dist/api/issues/index.d.ts.map +0 -1
- package/dist/api/issues/index.js +0 -444
- package/dist/api/issues/index.js.map +0 -1
- package/dist/api/subscriptions/index.d.ts +0 -1692
- package/dist/api/subscriptions/index.d.ts.map +0 -1
- package/dist/api/subscriptions/index.js +0 -1867
- package/dist/api/subscriptions/index.js.map +0 -1
- package/dist/api/workflows/index.browser.js +0 -246
- package/dist/api/workflows/index.browser.js.map +0 -1
- package/dist/api/workflows/index.d.ts +0 -1618
- package/dist/api/workflows/index.d.ts.map +0 -1
- package/dist/api/workflows/index.js +0 -1495
- package/dist/api/workflows/index.js.map +0 -1
- package/dist/react/testing/chunk-DBEY4PJZ.js +0 -16
- package/src/api/invitations/__tests__/InvitationService.spec.ts +0 -439
- package/src/api/invitations/controllers/AdminInvitationController.ts +0 -86
- package/src/api/invitations/controllers/InvitationController.ts +0 -84
- package/src/api/invitations/entities/invitations.ts +0 -33
- package/src/api/invitations/index.ts +0 -58
- package/src/api/invitations/jobs/InvitationJobs.ts +0 -37
- package/src/api/invitations/providers/InvitationProvider.ts +0 -45
- package/src/api/invitations/schemas/createInvitationSchema.ts +0 -12
- package/src/api/invitations/schemas/invitationConfigAtom.ts +0 -20
- package/src/api/invitations/schemas/invitationQuerySchema.ts +0 -15
- package/src/api/invitations/schemas/invitationResourceSchema.ts +0 -6
- package/src/api/invitations/schemas/invitationWithResourceInfoSchema.ts +0 -22
- package/src/api/invitations/schemas/myInvitationsQuerySchema.ts +0 -10
- package/src/api/invitations/services/InvitationService.ts +0 -556
- package/src/api/issues/__tests__/IssueService.spec.ts +0 -263
- package/src/api/issues/controllers/AdminIssueController.ts +0 -149
- package/src/api/issues/controllers/IssueController.ts +0 -44
- package/src/api/issues/entities/issues.ts +0 -49
- package/src/api/issues/index.ts +0 -50
- package/src/api/issues/schemas/createIssueSchema.ts +0 -13
- package/src/api/issues/schemas/issueConfigAtom.ts +0 -13
- package/src/api/issues/schemas/issueQuerySchema.ts +0 -18
- package/src/api/issues/schemas/issueResourceSchema.ts +0 -6
- package/src/api/issues/schemas/myIssueQuerySchema.ts +0 -10
- package/src/api/issues/schemas/updateIssueSchema.ts +0 -13
- package/src/api/issues/services/IssueService.ts +0 -264
- package/src/api/jobs/__tests__/$job-middleware.spec.ts +0 -126
- package/src/api/jobs/__tests__/JobService.spec.ts +0 -31
- package/src/api/jobs/entities/jobExecutionLogEntity.ts +0 -13
- package/src/api/jobs/schemas/jobActivitySchema.ts +0 -15
- package/src/api/jobs/schemas/jobCronInfoSchema.ts +0 -22
- package/src/api/jobs/schemas/jobExecutionDetailResourceSchema.ts +0 -20
- package/src/api/jobs/schemas/jobFailureSchema.ts +0 -9
- package/src/api/jobs/schemas/jobQueueDepthSchema.ts +0 -14
- package/src/api/jobs/schemas/jobStatsSchema.ts +0 -14
- package/src/api/jobs/services/JobService-tests.ts +0 -157
- package/src/api/subscriptions/__tests__/BillingService.spec.ts +0 -218
- package/src/api/subscriptions/__tests__/SubscriptionService.spec.ts +0 -278
- package/src/api/subscriptions/controllers/AdminSubscriptionController.ts +0 -212
- package/src/api/subscriptions/controllers/SubscriptionController.ts +0 -189
- package/src/api/subscriptions/entities/subscriptionEvents.ts +0 -54
- package/src/api/subscriptions/entities/subscriptions.ts +0 -68
- package/src/api/subscriptions/index.ts +0 -133
- package/src/api/subscriptions/jobs/SubscriptionJobs.ts +0 -382
- package/src/api/subscriptions/middleware/$requireLimit.ts +0 -50
- package/src/api/subscriptions/middleware/$requirePlan.ts +0 -49
- package/src/api/subscriptions/notifications/SubscriptionNotifications.ts +0 -110
- package/src/api/subscriptions/schemas/cancelSubscriptionSchema.ts +0 -8
- package/src/api/subscriptions/schemas/changePlanSchema.ts +0 -9
- package/src/api/subscriptions/schemas/createSubscriptionSchema.ts +0 -11
- package/src/api/subscriptions/schemas/entitlementsSchema.ts +0 -21
- package/src/api/subscriptions/schemas/mrrSchema.ts +0 -13
- package/src/api/subscriptions/schemas/planDefinitionSchema.ts +0 -71
- package/src/api/subscriptions/schemas/planResourceSchema.ts +0 -25
- package/src/api/subscriptions/schemas/subscriptionEventResourceSchema.ts +0 -8
- package/src/api/subscriptions/schemas/subscriptionQuerySchema.ts +0 -19
- package/src/api/subscriptions/schemas/subscriptionResourceSchema.ts +0 -6
- package/src/api/subscriptions/schemas/subscriptionSettingsSchema.ts +0 -32
- package/src/api/subscriptions/schemas/subscriptionStatsSchema.ts +0 -23
- package/src/api/subscriptions/services/BillingService.ts +0 -437
- package/src/api/subscriptions/services/SubscriptionConfig.ts +0 -56
- package/src/api/subscriptions/services/SubscriptionService.ts +0 -867
- package/src/api/subscriptions/services/UsageService.ts +0 -118
- package/src/api/workflows/__tests__/$workflow.spec.ts +0 -616
- package/src/api/workflows/controllers/AdminWorkflowController.ts +0 -191
- package/src/api/workflows/entities/workflowExecutions.ts +0 -74
- package/src/api/workflows/entities/workflowStepExecutions.ts +0 -74
- package/src/api/workflows/entities/workflowStepLogs.ts +0 -13
- package/src/api/workflows/index.browser.ts +0 -22
- package/src/api/workflows/index.ts +0 -115
- package/src/api/workflows/jobs/WorkflowJobs.ts +0 -77
- package/src/api/workflows/primitives/$workflow.ts +0 -202
- package/src/api/workflows/providers/WorkflowProvider.ts +0 -1284
- package/src/api/workflows/schemas/workflowActivitySchema.ts +0 -15
- package/src/api/workflows/schemas/workflowConfigAtom.ts +0 -51
- package/src/api/workflows/schemas/workflowExecutionDetailSchema.ts +0 -18
- package/src/api/workflows/schemas/workflowExecutionQuerySchema.ts +0 -26
- package/src/api/workflows/schemas/workflowExecutionResourceSchema.ts +0 -30
- package/src/api/workflows/schemas/workflowRegistrationSchema.ts +0 -26
- package/src/api/workflows/schemas/workflowStatsSchema.ts +0 -16
- package/src/api/workflows/schemas/workflowStepExecutionResourceSchema.ts +0 -15
- package/src/api/workflows/services/WorkflowService.ts +0 -382
- package/src/cli/core/templates/apiAppSecurityTs.ts +0 -43
- package/src/cli/core/templates/webAdminDashboardTsx.ts +0 -17
- package/src/orm/core/__tests__/parseQueryString.spec.ts +0 -196
- package/src/orm/core/helpers/parseQueryString.ts +0 -502
- package/src/orm/core/primitives/$view.ts +0 -88
|
@@ -1,196 +0,0 @@
|
|
|
1
|
-
import { describe, test } from "vitest";
|
|
2
|
-
import { buildQueryString, parseQueryString } from "../index.ts";
|
|
3
|
-
|
|
4
|
-
describe("parseQueryString with wildcard patterns", () => {
|
|
5
|
-
test("should parse wildcard patterns with = operator", ({ expect }) => {
|
|
6
|
-
// Test startsWith pattern
|
|
7
|
-
const result1 = parseQueryString("name=John*");
|
|
8
|
-
expect(result1).toEqual({ name: { startsWith: "John" } });
|
|
9
|
-
|
|
10
|
-
// Test endsWith pattern
|
|
11
|
-
const result2 = parseQueryString("name=*Smith");
|
|
12
|
-
expect(result2).toEqual({ name: { endsWith: "Smith" } });
|
|
13
|
-
|
|
14
|
-
// Test contains pattern
|
|
15
|
-
const result3 = parseQueryString("name=*oh*");
|
|
16
|
-
expect(result3).toEqual({ name: { contains: "oh" } });
|
|
17
|
-
|
|
18
|
-
// Test literal asterisk in the middle (not at beginning or end)
|
|
19
|
-
const result4 = parseQueryString("name=Jo*hn");
|
|
20
|
-
expect(result4).toEqual({ name: { eq: "Jo*hn" } });
|
|
21
|
-
|
|
22
|
-
// Test literal equals (no wildcards)
|
|
23
|
-
const result5 = parseQueryString("name=John");
|
|
24
|
-
expect(result5).toEqual({ name: { eq: "John" } });
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
test("should handle wildcard patterns in complex queries", ({ expect }) => {
|
|
28
|
-
// Multiple conditions with wildcards
|
|
29
|
-
const result1 = parseQueryString("name=*John&email=*@example.com");
|
|
30
|
-
expect(result1).toEqual({
|
|
31
|
-
and: [
|
|
32
|
-
{ name: { endsWith: "John" } },
|
|
33
|
-
{ email: { endsWith: "@example.com" } },
|
|
34
|
-
],
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
// OR conditions with wildcards
|
|
38
|
-
const result2 = parseQueryString("name=John*|name=*Smith");
|
|
39
|
-
expect(result2).toEqual({
|
|
40
|
-
or: [{ name: { startsWith: "John" } }, { name: { endsWith: "Smith" } }],
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
// Nested conditions with wildcards
|
|
44
|
-
const result3 = parseQueryString("(name=*John*|email=admin*)&age>18");
|
|
45
|
-
expect(result3).toEqual({
|
|
46
|
-
and: [
|
|
47
|
-
{
|
|
48
|
-
or: [
|
|
49
|
-
{ name: { contains: "John" } },
|
|
50
|
-
{ email: { startsWith: "admin" } },
|
|
51
|
-
],
|
|
52
|
-
},
|
|
53
|
-
{ age: { gt: 18 } },
|
|
54
|
-
],
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
test("should handle wildcard patterns in quoted strings", ({ expect }) => {
|
|
59
|
-
// Quoted string with wildcards should be treated as wildcards
|
|
60
|
-
const result1 = parseQueryString('name="*John*"');
|
|
61
|
-
expect(result1).toEqual({ name: { contains: "John" } });
|
|
62
|
-
|
|
63
|
-
// Quoted string with asterisk in middle
|
|
64
|
-
const result2 = parseQueryString('name="Jo*hn"');
|
|
65
|
-
expect(result2).toEqual({ name: { eq: "Jo*hn" } });
|
|
66
|
-
|
|
67
|
-
// Single quotes
|
|
68
|
-
const result3 = parseQueryString("name='*Smith'");
|
|
69
|
-
expect(result3).toEqual({ name: { endsWith: "Smith" } });
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
test("should handle wildcard patterns with special characters", ({
|
|
73
|
-
expect,
|
|
74
|
-
}) => {
|
|
75
|
-
// Wildcard with spaces
|
|
76
|
-
const result1 = parseQueryString("name=*John Smith*");
|
|
77
|
-
expect(result1).toEqual({ name: { contains: "John Smith" } });
|
|
78
|
-
|
|
79
|
-
// Wildcard with special characters
|
|
80
|
-
const result2 = parseQueryString("email=*@example.com");
|
|
81
|
-
expect(result2).toEqual({ email: { endsWith: "@example.com" } });
|
|
82
|
-
|
|
83
|
-
// Wildcard with numbers
|
|
84
|
-
const result3 = parseQueryString("code=ABC*123");
|
|
85
|
-
expect(result3).toEqual({ code: { eq: "ABC*123" } }); // Asterisk in middle is literal
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
test("should handle wildcard patterns in arrays", ({ expect }) => {
|
|
89
|
-
// Array values don't support wildcards (treated as literal)
|
|
90
|
-
const result = parseQueryString("status=[active*,*pending,*idle*]");
|
|
91
|
-
expect(result).toEqual({
|
|
92
|
-
status: { inArray: ["active*", "*pending", "*idle*"] },
|
|
93
|
-
});
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
test("should handle wildcard patterns with != operator", ({ expect }) => {
|
|
97
|
-
// != operator doesn't support wildcards, treats as literal
|
|
98
|
-
const result1 = parseQueryString("name!=*John");
|
|
99
|
-
expect(result1).toEqual({ name: { ne: "*John" } });
|
|
100
|
-
|
|
101
|
-
const result2 = parseQueryString("name!=John*");
|
|
102
|
-
expect(result2).toEqual({ name: { ne: "John*" } });
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
test("should handle empty wildcard patterns", ({ expect }) => {
|
|
106
|
-
// Just asterisks - a single asterisk at the end means "starts with nothing" = everything
|
|
107
|
-
const result1 = parseQueryString("name=*");
|
|
108
|
-
expect(result1).toEqual({ name: { contains: "" } }); // Since * alone has both start and end asterisk
|
|
109
|
-
|
|
110
|
-
const result2 = parseQueryString("name=**");
|
|
111
|
-
expect(result2).toEqual({ name: { contains: "" } });
|
|
112
|
-
|
|
113
|
-
const result3 = parseQueryString("name=***");
|
|
114
|
-
expect(result3).toEqual({ name: { contains: "*" } });
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
test("should handle JSONB nested queries with wildcards", ({ expect }) => {
|
|
118
|
-
const result = parseQueryString("profile.city=*Paris*&profile.name=John*");
|
|
119
|
-
expect(result).toEqual({
|
|
120
|
-
and: [
|
|
121
|
-
{ profile: { city: { contains: "Paris" } } },
|
|
122
|
-
{ profile: { name: { startsWith: "John" } } },
|
|
123
|
-
],
|
|
124
|
-
});
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
test("should not apply wildcards to non-string operators", ({ expect }) => {
|
|
128
|
-
// Numeric comparison operators don't use wildcards
|
|
129
|
-
const result1 = parseQueryString("age>18");
|
|
130
|
-
expect(result1).toEqual({ age: { gt: 18 } });
|
|
131
|
-
|
|
132
|
-
// NULL checks don't use wildcards
|
|
133
|
-
const result2 = parseQueryString("name=null");
|
|
134
|
-
expect(result2).toEqual({ name: { isNull: true } });
|
|
135
|
-
|
|
136
|
-
const result3 = parseQueryString("name!=null");
|
|
137
|
-
expect(result3).toEqual({ name: { isNotNull: true } });
|
|
138
|
-
});
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
describe("buildQueryString with wildcard patterns", () => {
|
|
142
|
-
test("should build query strings from wildcard conditions", ({ expect }) => {
|
|
143
|
-
// startsWith
|
|
144
|
-
const query1 = buildQueryString({ name: { startsWith: "John" } });
|
|
145
|
-
expect(query1).toBe("name=John*");
|
|
146
|
-
|
|
147
|
-
// endsWith
|
|
148
|
-
const query2 = buildQueryString({ name: { endsWith: "Smith" } });
|
|
149
|
-
expect(query2).toBe("name=*Smith");
|
|
150
|
-
|
|
151
|
-
// contains
|
|
152
|
-
const query3 = buildQueryString({ name: { contains: "oh" } });
|
|
153
|
-
expect(query3).toBe("name=*oh*");
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
test("should build complex query strings with wildcards", ({ expect }) => {
|
|
157
|
-
const query = buildQueryString({
|
|
158
|
-
and: [
|
|
159
|
-
{ name: { startsWith: "John" } },
|
|
160
|
-
{ email: { endsWith: "@example.com" } },
|
|
161
|
-
{ bio: { contains: "developer" } },
|
|
162
|
-
],
|
|
163
|
-
});
|
|
164
|
-
expect(query).toBe("name=John*&email=*@example.com&bio=*developer*");
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
test("should handle OR conditions with wildcards", ({ expect }) => {
|
|
168
|
-
const query = buildQueryString({
|
|
169
|
-
or: [
|
|
170
|
-
{ name: { startsWith: "Admin" } },
|
|
171
|
-
{ role: { contains: "manager" } },
|
|
172
|
-
],
|
|
173
|
-
});
|
|
174
|
-
expect(query).toBe("(name=Admin*|role=*manager*)");
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
test("round-trip conversion should preserve wildcard semantics", ({
|
|
178
|
-
expect,
|
|
179
|
-
}) => {
|
|
180
|
-
const testCases = [
|
|
181
|
-
"name=John*",
|
|
182
|
-
"name=*Smith",
|
|
183
|
-
"name=*John*",
|
|
184
|
-
"email=admin*&role=*manager*",
|
|
185
|
-
"(name=*John*|name=*Jane*)&active=true",
|
|
186
|
-
"profile.city=*Paris*",
|
|
187
|
-
];
|
|
188
|
-
|
|
189
|
-
for (const original of testCases) {
|
|
190
|
-
const parsed = parseQueryString(original);
|
|
191
|
-
const rebuilt = buildQueryString(parsed);
|
|
192
|
-
const reparsed = parseQueryString(rebuilt);
|
|
193
|
-
expect(reparsed).toEqual(parsed);
|
|
194
|
-
}
|
|
195
|
-
});
|
|
196
|
-
});
|
|
@@ -1,502 +0,0 @@
|
|
|
1
|
-
import { AlephaError, type TObject } from "alepha";
|
|
2
|
-
import type { PgQueryWhere } from "../interfaces/PgQueryWhere.ts";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Parse a string query into a PgQueryWhere object.
|
|
6
|
-
*
|
|
7
|
-
* Supported syntax:
|
|
8
|
-
* - Simple equality: "name=John"
|
|
9
|
-
* - Wildcard patterns: "name=John*" (startsWith), "name=*John" (endsWith), "name=*John*" (contains)
|
|
10
|
-
* - Operators: "age>18", "age>=18", "age<65", "age<=65", "status!=active"
|
|
11
|
-
* - NULL checks: "deletedAt=null", "email!=null"
|
|
12
|
-
* - IN arrays: "status=[pending,active]"
|
|
13
|
-
* - AND conditions: "name=John&age>18"
|
|
14
|
-
* - OR conditions: "name=John|email=john@example.com"
|
|
15
|
-
* - Nested AND/OR: "(name=John|name=Jane)&age>18"
|
|
16
|
-
* - JSONB nested: "profile.city=Paris"
|
|
17
|
-
*
|
|
18
|
-
* @example
|
|
19
|
-
* ```ts
|
|
20
|
-
* // Simple equality
|
|
21
|
-
* parseQueryString("name=John")
|
|
22
|
-
* // => { name: { eq: "John" } }
|
|
23
|
-
*
|
|
24
|
-
* // Wildcard patterns
|
|
25
|
-
* parseQueryString("name=John*") // startsWith
|
|
26
|
-
* // => { name: { startsWith: "John" } }
|
|
27
|
-
* parseQueryString("name=*Smith") // endsWith
|
|
28
|
-
* // => { name: { endsWith: "Smith" } }
|
|
29
|
-
* parseQueryString("name=*oh*") // contains
|
|
30
|
-
* // => { name: { contains: "oh" } }
|
|
31
|
-
*
|
|
32
|
-
* // Multiple conditions
|
|
33
|
-
* parseQueryString("name=John&age>18")
|
|
34
|
-
* // => { and: [{ name: { eq: "John" } }, { age: { gt: 18 } }] }
|
|
35
|
-
*
|
|
36
|
-
* // OR conditions
|
|
37
|
-
* parseQueryString("status=active|status=pending")
|
|
38
|
-
* // => { or: [{ status: { eq: "active" } }, { status: { eq: "pending" } }] }
|
|
39
|
-
*
|
|
40
|
-
* // Complex nested
|
|
41
|
-
* parseQueryString("(name=John|name=Jane)&age>18&status!=archived")
|
|
42
|
-
* // => { and: [
|
|
43
|
-
* // { or: [{ name: { eq: "John" } }, { name: { eq: "Jane" } }] },
|
|
44
|
-
* // { age: { gt: 18 } },
|
|
45
|
-
* // { status: { ne: "archived" } }
|
|
46
|
-
* // ] }
|
|
47
|
-
*
|
|
48
|
-
* // JSONB nested query
|
|
49
|
-
* parseQueryString("profile.city=Paris&profile.age>25")
|
|
50
|
-
* // => { profile: { city: { eq: "Paris" }, age: { gt: 25 } } }
|
|
51
|
-
* ```
|
|
52
|
-
*/
|
|
53
|
-
export function parseQueryString<T extends TObject>(
|
|
54
|
-
query: string,
|
|
55
|
-
): PgQueryWhere<T> {
|
|
56
|
-
if (!query || query.trim() === "") {
|
|
57
|
-
return {};
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const parser = new QueryStringParser(query);
|
|
61
|
-
return parser.parse() as PgQueryWhere<T>;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// ---------------------------------------------------------------------------------------------------------------------
|
|
65
|
-
|
|
66
|
-
class QueryStringParser {
|
|
67
|
-
protected pos = 0;
|
|
68
|
-
protected readonly query: string;
|
|
69
|
-
|
|
70
|
-
constructor(query: string) {
|
|
71
|
-
this.query = query.trim();
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
parse(): PgQueryWhere<any> {
|
|
75
|
-
return this.parseExpression();
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
protected parseExpression(): PgQueryWhere<any> {
|
|
79
|
-
return this.parseOr();
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
protected parseOr(): any {
|
|
83
|
-
const left = this.parseAnd();
|
|
84
|
-
|
|
85
|
-
// Check for OR operator (|)
|
|
86
|
-
if (this.peek() === "|") {
|
|
87
|
-
const conditions = [left];
|
|
88
|
-
|
|
89
|
-
while (this.peek() === "|") {
|
|
90
|
-
this.consume("|");
|
|
91
|
-
conditions.push(this.parseAnd());
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
return { or: conditions };
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return left;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
protected parseAnd(): any {
|
|
101
|
-
const left = this.parsePrimary();
|
|
102
|
-
|
|
103
|
-
// Check for AND operator (&)
|
|
104
|
-
if (this.peek() === "&") {
|
|
105
|
-
const conditions = [left];
|
|
106
|
-
|
|
107
|
-
while (this.peek() === "&") {
|
|
108
|
-
this.consume("&");
|
|
109
|
-
conditions.push(this.parsePrimary());
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return { and: conditions };
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
return left;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
protected parsePrimary(): any {
|
|
119
|
-
this.skipWhitespace();
|
|
120
|
-
|
|
121
|
-
// Handle parentheses
|
|
122
|
-
if (this.peek() === "(") {
|
|
123
|
-
this.consume("(");
|
|
124
|
-
const expr = this.parseExpression();
|
|
125
|
-
this.consume(")");
|
|
126
|
-
return expr;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Parse field condition
|
|
130
|
-
return this.parseCondition();
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
protected parseCondition(): any {
|
|
134
|
-
const field = this.parseFieldPath();
|
|
135
|
-
this.skipWhitespace();
|
|
136
|
-
|
|
137
|
-
// Get operator
|
|
138
|
-
const operator = this.parseOperator();
|
|
139
|
-
this.skipWhitespace();
|
|
140
|
-
|
|
141
|
-
// Get value
|
|
142
|
-
const value = this.parseValue();
|
|
143
|
-
|
|
144
|
-
if (value === "") {
|
|
145
|
-
throw new AlephaError(`Expected value for field '${field.join(".")}'`);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// Build the condition object
|
|
149
|
-
return this.buildCondition(field, operator, value);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
protected parseFieldPath(): string[] {
|
|
153
|
-
const path: string[] = [];
|
|
154
|
-
let current = "";
|
|
155
|
-
|
|
156
|
-
while (this.pos < this.query.length) {
|
|
157
|
-
const ch = this.query[this.pos];
|
|
158
|
-
|
|
159
|
-
if (ch === "." && current) {
|
|
160
|
-
path.push(current);
|
|
161
|
-
current = "";
|
|
162
|
-
this.pos++;
|
|
163
|
-
continue;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
if (ch === "=" || ch === "!" || ch === ">" || ch === "<" || ch === " ") {
|
|
167
|
-
break;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
current += ch;
|
|
171
|
-
this.pos++;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
if (current) {
|
|
175
|
-
path.push(current);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
return path;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
protected parseOperator(): string {
|
|
182
|
-
this.skipWhitespace();
|
|
183
|
-
|
|
184
|
-
const remaining = this.query.slice(this.pos);
|
|
185
|
-
|
|
186
|
-
// Two-character operators
|
|
187
|
-
if (remaining.startsWith(">=")) {
|
|
188
|
-
this.pos += 2;
|
|
189
|
-
return ">=";
|
|
190
|
-
}
|
|
191
|
-
if (remaining.startsWith("<=")) {
|
|
192
|
-
this.pos += 2;
|
|
193
|
-
return "<=";
|
|
194
|
-
}
|
|
195
|
-
if (remaining.startsWith("!=")) {
|
|
196
|
-
this.pos += 2;
|
|
197
|
-
return "!=";
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// Single-character operators
|
|
201
|
-
const ch = this.query[this.pos];
|
|
202
|
-
if (ch === "=" || ch === ">" || ch === "<") {
|
|
203
|
-
this.pos++;
|
|
204
|
-
return ch;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
throw new AlephaError(`Expected operator at position ${this.pos}`);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
protected parseValue(): any {
|
|
211
|
-
this.skipWhitespace();
|
|
212
|
-
|
|
213
|
-
// Handle null
|
|
214
|
-
if (this.query.slice(this.pos, this.pos + 4).toLowerCase() === "null") {
|
|
215
|
-
this.pos += 4;
|
|
216
|
-
return null;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// Handle arrays [value1,value2,...]
|
|
220
|
-
if (this.query[this.pos] === "[") {
|
|
221
|
-
return this.parseArray();
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
// Handle quoted strings
|
|
225
|
-
if (this.query[this.pos] === '"' || this.query[this.pos] === "'") {
|
|
226
|
-
return this.parseQuotedString();
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// Parse unquoted value (until &, |, or ))
|
|
230
|
-
let value = "";
|
|
231
|
-
while (this.pos < this.query.length) {
|
|
232
|
-
const ch = this.query[this.pos];
|
|
233
|
-
if (ch === "&" || ch === "|" || ch === ")") {
|
|
234
|
-
break;
|
|
235
|
-
}
|
|
236
|
-
value += ch;
|
|
237
|
-
this.pos++;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
return this.coerceValue(value.trim());
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
protected parseArray(): any[] {
|
|
244
|
-
this.consume("[");
|
|
245
|
-
const values: any[] = [];
|
|
246
|
-
|
|
247
|
-
while (this.pos < this.query.length && this.query[this.pos] !== "]") {
|
|
248
|
-
this.skipWhitespace();
|
|
249
|
-
|
|
250
|
-
// Handle quoted values
|
|
251
|
-
if (this.query[this.pos] === '"' || this.query[this.pos] === "'") {
|
|
252
|
-
values.push(this.parseQuotedString());
|
|
253
|
-
} else {
|
|
254
|
-
// Parse until comma or ]
|
|
255
|
-
let value = "";
|
|
256
|
-
while (
|
|
257
|
-
this.pos < this.query.length &&
|
|
258
|
-
this.query[this.pos] !== "," &&
|
|
259
|
-
this.query[this.pos] !== "]"
|
|
260
|
-
) {
|
|
261
|
-
value += this.query[this.pos];
|
|
262
|
-
this.pos++;
|
|
263
|
-
}
|
|
264
|
-
values.push(this.coerceValue(value.trim()));
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
this.skipWhitespace();
|
|
268
|
-
if (this.query[this.pos] === ",") {
|
|
269
|
-
this.pos++;
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
this.consume("]");
|
|
274
|
-
return values;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
protected parseQuotedString(): string {
|
|
278
|
-
const quote = this.query[this.pos];
|
|
279
|
-
this.pos++; // Skip opening quote
|
|
280
|
-
|
|
281
|
-
let value = "";
|
|
282
|
-
let escaped = false;
|
|
283
|
-
|
|
284
|
-
while (this.pos < this.query.length) {
|
|
285
|
-
const ch = this.query[this.pos];
|
|
286
|
-
|
|
287
|
-
if (escaped) {
|
|
288
|
-
value += ch;
|
|
289
|
-
escaped = false;
|
|
290
|
-
this.pos++;
|
|
291
|
-
continue;
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
if (ch === "\\") {
|
|
295
|
-
escaped = true;
|
|
296
|
-
this.pos++;
|
|
297
|
-
continue;
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
if (ch === quote) {
|
|
301
|
-
this.pos++; // Skip closing quote
|
|
302
|
-
break;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
value += ch;
|
|
306
|
-
this.pos++;
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
return value;
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
protected coerceValue(value: string): any {
|
|
313
|
-
// Try to parse as number
|
|
314
|
-
if (/^-?\d+$/.test(value)) {
|
|
315
|
-
return parseInt(value, 10);
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
if (/^-?\d+\.\d+$/.test(value)) {
|
|
319
|
-
return parseFloat(value);
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
// Try to parse as boolean
|
|
323
|
-
if (value.toLowerCase() === "true") {
|
|
324
|
-
return true;
|
|
325
|
-
}
|
|
326
|
-
if (value.toLowerCase() === "false") {
|
|
327
|
-
return false;
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
return value;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
protected buildCondition(path: string[], operator: string, value: any): any {
|
|
334
|
-
// Map operator to filter operator
|
|
335
|
-
let filterOp: any;
|
|
336
|
-
|
|
337
|
-
if (operator === "=") {
|
|
338
|
-
if (value === null) {
|
|
339
|
-
filterOp = { isNull: true };
|
|
340
|
-
} else if (Array.isArray(value)) {
|
|
341
|
-
// Arrays should be treated as inArray regardless of content
|
|
342
|
-
filterOp = { inArray: value };
|
|
343
|
-
} else if (typeof value === "string" && value.includes("*")) {
|
|
344
|
-
// Handle wildcard patterns
|
|
345
|
-
const startsWithAsterisk = value.startsWith("*");
|
|
346
|
-
const endsWithAsterisk = value.endsWith("*");
|
|
347
|
-
const cleanValue = value.replace(/^\*|\*$/g, ""); // Remove leading/trailing asterisks
|
|
348
|
-
|
|
349
|
-
if (startsWithAsterisk && endsWithAsterisk) {
|
|
350
|
-
// *text* -> contains
|
|
351
|
-
filterOp = { contains: cleanValue };
|
|
352
|
-
} else if (startsWithAsterisk) {
|
|
353
|
-
// *text -> endsWith
|
|
354
|
-
filterOp = { endsWith: cleanValue };
|
|
355
|
-
} else if (endsWithAsterisk) {
|
|
356
|
-
// text* -> startsWith
|
|
357
|
-
filterOp = { startsWith: cleanValue };
|
|
358
|
-
} else {
|
|
359
|
-
// Has asterisk in the middle, treat as literal
|
|
360
|
-
filterOp = { eq: value };
|
|
361
|
-
}
|
|
362
|
-
} else {
|
|
363
|
-
filterOp = { eq: value };
|
|
364
|
-
}
|
|
365
|
-
} else if (operator === "!=") {
|
|
366
|
-
if (value === null) {
|
|
367
|
-
filterOp = { isNotNull: true };
|
|
368
|
-
} else {
|
|
369
|
-
filterOp = { ne: value };
|
|
370
|
-
}
|
|
371
|
-
} else if (operator === ">") {
|
|
372
|
-
filterOp = { gt: value };
|
|
373
|
-
} else if (operator === ">=") {
|
|
374
|
-
filterOp = { gte: value };
|
|
375
|
-
} else if (operator === "<") {
|
|
376
|
-
filterOp = { lt: value };
|
|
377
|
-
} else if (operator === "<=") {
|
|
378
|
-
filterOp = { lte: value };
|
|
379
|
-
} else {
|
|
380
|
-
throw new AlephaError(`Unsupported operator: ${operator}`);
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
// Build nested object for path
|
|
384
|
-
if (path.length === 1) {
|
|
385
|
-
return { [path[0]]: filterOp };
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
// Handle nested paths (JSONB)
|
|
389
|
-
let result: any = filterOp;
|
|
390
|
-
for (let i = path.length - 1; i >= 0; i--) {
|
|
391
|
-
result = { [path[i]]: result };
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
return result;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
protected peek(): string {
|
|
398
|
-
this.skipWhitespace();
|
|
399
|
-
return this.query[this.pos] || "";
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
protected consume(expected: string): void {
|
|
403
|
-
this.skipWhitespace();
|
|
404
|
-
if (this.query[this.pos] !== expected) {
|
|
405
|
-
throw new AlephaError(
|
|
406
|
-
`Expected '${expected}' at position ${this.pos}, got '${this.query[this.pos]}'`,
|
|
407
|
-
);
|
|
408
|
-
}
|
|
409
|
-
this.pos++;
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
protected skipWhitespace(): void {
|
|
413
|
-
while (this.pos < this.query.length && /\s/.test(this.query[this.pos])) {
|
|
414
|
-
this.pos++;
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
// ---------------------------------------------------------------------------------------------------------------------
|
|
420
|
-
|
|
421
|
-
/**
|
|
422
|
-
* Helper function to build query strings programmatically
|
|
423
|
-
*
|
|
424
|
-
* @example
|
|
425
|
-
* ```ts
|
|
426
|
-
* buildQueryString({
|
|
427
|
-
* and: [
|
|
428
|
-
* { name: "eq:John" },
|
|
429
|
-
* { age: "gt:18" }
|
|
430
|
-
* ]
|
|
431
|
-
* })
|
|
432
|
-
* // => "name=John&age>18"
|
|
433
|
-
* ```
|
|
434
|
-
*/
|
|
435
|
-
export function buildQueryString(where: any): string {
|
|
436
|
-
if (!where || typeof where !== "object") {
|
|
437
|
-
return "";
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
// Handle logical operators
|
|
441
|
-
if ("and" in where && Array.isArray(where.and)) {
|
|
442
|
-
return where.and.map((w: any) => buildQueryString(w)).join("&");
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
if ("or" in where && Array.isArray(where.or)) {
|
|
446
|
-
const parts = where.or.map((w: any) => buildQueryString(w));
|
|
447
|
-
return parts.length > 1 ? `(${parts.join("|")})` : parts[0];
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
if ("not" in where) {
|
|
451
|
-
// Not operator is harder to represent in string form
|
|
452
|
-
// For now, we'll skip it or you could add a syntax like "!field=value"
|
|
453
|
-
return "";
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
// Handle field conditions
|
|
457
|
-
const parts: string[] = [];
|
|
458
|
-
|
|
459
|
-
for (const [field, condition] of Object.entries(where)) {
|
|
460
|
-
if (typeof condition !== "object" || condition === null) {
|
|
461
|
-
parts.push(`${field}=${condition}`);
|
|
462
|
-
continue;
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
if ("eq" in condition) {
|
|
466
|
-
parts.push(`${field}=${condition.eq}`);
|
|
467
|
-
} else if ("ne" in condition) {
|
|
468
|
-
parts.push(`${field}!=${condition.ne}`);
|
|
469
|
-
} else if ("gt" in condition) {
|
|
470
|
-
parts.push(`${field}>${condition.gt}`);
|
|
471
|
-
} else if ("gte" in condition) {
|
|
472
|
-
parts.push(`${field}>=${condition.gte}`);
|
|
473
|
-
} else if ("lt" in condition) {
|
|
474
|
-
parts.push(`${field}<${condition.lt}`);
|
|
475
|
-
} else if ("lte" in condition) {
|
|
476
|
-
parts.push(`${field}<=${condition.lte}`);
|
|
477
|
-
} else if ("contains" in condition) {
|
|
478
|
-
parts.push(`${field}=*${condition.contains}*`);
|
|
479
|
-
} else if ("startsWith" in condition) {
|
|
480
|
-
parts.push(`${field}=${condition.startsWith}*`);
|
|
481
|
-
} else if ("endsWith" in condition) {
|
|
482
|
-
parts.push(`${field}=*${condition.endsWith}`);
|
|
483
|
-
} else if ("isNull" in condition && condition.isNull) {
|
|
484
|
-
parts.push(`${field}=null`);
|
|
485
|
-
} else if ("isNotNull" in condition && condition.isNotNull) {
|
|
486
|
-
parts.push(`${field}!=null`);
|
|
487
|
-
} else if ("inArray" in condition && Array.isArray(condition.inArray)) {
|
|
488
|
-
const values = condition.inArray.map((v: any) =>
|
|
489
|
-
typeof v === "string" ? `"${v}"` : v,
|
|
490
|
-
);
|
|
491
|
-
parts.push(`${field}=[${values.join(",")}]`);
|
|
492
|
-
} else {
|
|
493
|
-
// Nested object (JSONB)
|
|
494
|
-
const nested = buildQueryString(condition);
|
|
495
|
-
if (nested) {
|
|
496
|
-
parts.push(`${field}.${nested}`);
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
return parts.join("&");
|
|
502
|
-
}
|