alepha 0.19.3 → 0.19.5
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/assets/swagger-ui/swagger-ui-bundle.js +1 -1
- package/dist/api/invitations/index.d.ts +790 -0
- package/dist/api/invitations/index.d.ts.map +1 -0
- package/dist/api/invitations/index.js +665 -0
- package/dist/api/invitations/index.js.map +1 -0
- package/dist/api/issues/index.d.ts +810 -0
- package/dist/api/issues/index.d.ts.map +1 -0
- package/dist/api/issues/index.js +447 -0
- package/dist/api/issues/index.js.map +1 -0
- package/dist/api/jobs/index.browser.js +8 -9
- package/dist/api/jobs/index.browser.js.map +1 -1
- package/dist/api/jobs/index.d.ts +99 -43
- package/dist/api/jobs/index.d.ts.map +1 -1
- package/dist/api/jobs/index.js +257 -40
- package/dist/api/jobs/index.js.map +1 -1
- package/dist/api/notifications/index.browser.js +0 -1
- package/dist/api/notifications/index.browser.js.map +1 -1
- package/dist/api/notifications/index.d.ts +3 -3
- package/dist/api/notifications/index.d.ts.map +1 -1
- package/dist/api/notifications/index.js +0 -1
- package/dist/api/notifications/index.js.map +1 -1
- package/dist/api/parameters/index.browser.js +112 -1
- package/dist/api/parameters/index.browser.js.map +1 -1
- package/dist/api/parameters/index.d.ts +90 -3
- package/dist/api/parameters/index.d.ts.map +1 -1
- package/dist/api/parameters/index.js +79 -12
- package/dist/api/parameters/index.js.map +1 -1
- package/dist/{billing → api/payments}/index.d.ts +67 -49
- package/dist/api/payments/index.d.ts.map +1 -0
- package/dist/{billing → api/payments}/index.js +108 -74
- package/dist/api/payments/index.js.map +1 -0
- package/dist/api/subscriptions/index.d.ts +1692 -0
- package/dist/api/subscriptions/index.d.ts.map +1 -0
- package/dist/api/subscriptions/index.js +1870 -0
- package/dist/api/subscriptions/index.js.map +1 -0
- package/dist/api/users/index.d.ts +24 -2
- package/dist/api/users/index.d.ts.map +1 -1
- package/dist/api/users/index.js +176 -36
- package/dist/api/users/index.js.map +1 -1
- package/dist/api/verifications/index.d.ts +13 -13
- package/dist/api/workflows/index.browser.js +246 -0
- package/dist/api/workflows/index.browser.js.map +1 -0
- package/dist/api/workflows/index.d.ts +1618 -0
- package/dist/api/workflows/index.d.ts.map +1 -0
- package/dist/api/workflows/index.js +1504 -0
- package/dist/api/workflows/index.js.map +1 -0
- package/dist/captcha/index.d.ts +142 -0
- package/dist/captcha/index.d.ts.map +1 -0
- package/dist/captcha/index.js +177 -0
- package/dist/captcha/index.js.map +1 -0
- package/dist/cli/core/index.d.ts +126 -30
- package/dist/cli/core/index.d.ts.map +1 -1
- package/dist/cli/core/index.js +106 -67
- package/dist/cli/core/index.js.map +1 -1
- package/dist/cli/platform/index.d.ts +84 -10
- package/dist/cli/platform/index.d.ts.map +1 -1
- package/dist/cli/platform/index.js +92 -4
- package/dist/cli/platform/index.js.map +1 -1
- package/dist/cli/vendor/index.d.ts +60 -10
- package/dist/cli/vendor/index.d.ts.map +1 -1
- package/dist/cli/vendor/index.js +177 -45
- package/dist/cli/vendor/index.js.map +1 -1
- package/dist/command/index.d.ts.map +1 -1
- package/dist/command/index.js +2 -3
- package/dist/command/index.js.map +1 -1
- package/dist/core/index.browser.js +21 -2
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +33 -2
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +21 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js +21 -2
- package/dist/core/index.native.js.map +1 -1
- package/dist/core/index.workerd.js +21 -2
- package/dist/core/index.workerd.js.map +1 -1
- package/dist/email/smtp/index.js +24 -8
- package/dist/email/smtp/index.js.map +1 -1
- package/dist/orm/core/index.browser.js +0 -18
- package/dist/orm/core/index.browser.js.map +1 -1
- package/dist/orm/core/index.bun.js +6 -23
- package/dist/orm/core/index.bun.js.map +1 -1
- package/dist/orm/core/index.d.ts +1 -13
- package/dist/orm/core/index.d.ts.map +1 -1
- package/dist/orm/core/index.js +6 -23
- package/dist/orm/core/index.js.map +1 -1
- package/dist/orm/postgres/index.bun.js +3 -3
- package/dist/orm/postgres/index.bun.js.map +1 -1
- package/dist/orm/postgres/index.d.ts.map +1 -1
- package/dist/orm/postgres/index.js +3 -3
- package/dist/orm/postgres/index.js.map +1 -1
- package/dist/react/i18n/index.d.ts +1 -0
- package/dist/react/i18n/index.d.ts.map +1 -1
- package/dist/react/i18n/index.js +8 -4
- package/dist/react/i18n/index.js.map +1 -1
- package/dist/react/router/index.browser.js +25 -3
- package/dist/react/router/index.browser.js.map +1 -1
- package/dist/react/router/index.d.ts +16 -1
- package/dist/react/router/index.d.ts.map +1 -1
- package/dist/react/router/index.js +25 -3
- package/dist/react/router/index.js.map +1 -1
- package/dist/security/index.d.ts +28 -0
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/index.js +28 -0
- package/dist/security/index.js.map +1 -1
- package/dist/server/auth/index.d.ts +145 -2
- package/dist/server/auth/index.d.ts.map +1 -1
- package/dist/server/auth/index.js +364 -63
- package/dist/server/auth/index.js.map +1 -1
- package/dist/server/cookies/index.d.ts.map +1 -1
- package/dist/server/cookies/index.js.map +1 -1
- package/dist/websocket/index.d.ts.map +1 -1
- package/dist/websocket/index.js.map +1 -1
- package/package.json +47 -20
- package/src/api/invitations/__tests__/InvitationService.spec.ts +439 -0
- package/src/api/invitations/controllers/AdminInvitationController.ts +86 -0
- package/src/api/invitations/controllers/InvitationController.ts +84 -0
- package/src/api/invitations/entities/invitations.ts +33 -0
- package/src/api/invitations/index.ts +65 -0
- package/src/api/invitations/jobs/InvitationJobs.ts +37 -0
- package/src/api/invitations/providers/InvitationProvider.ts +45 -0
- package/src/api/invitations/schemas/createInvitationSchema.ts +12 -0
- package/src/api/invitations/schemas/invitationConfigAtom.ts +20 -0
- package/src/api/invitations/schemas/invitationQuerySchema.ts +15 -0
- package/src/api/invitations/schemas/invitationResourceSchema.ts +6 -0
- package/src/api/invitations/schemas/invitationWithResourceInfoSchema.ts +22 -0
- package/src/api/invitations/schemas/myInvitationsQuerySchema.ts +10 -0
- package/src/api/invitations/services/InvitationService.ts +556 -0
- package/src/api/issues/__tests__/IssueService.spec.ts +263 -0
- package/src/api/issues/controllers/AdminIssueController.ts +149 -0
- package/src/api/issues/controllers/IssueController.ts +44 -0
- package/src/api/issues/entities/issues.ts +49 -0
- package/src/api/issues/index.ts +53 -0
- package/src/api/issues/schemas/createIssueSchema.ts +13 -0
- package/src/api/issues/schemas/issueConfigAtom.ts +13 -0
- package/src/api/issues/schemas/issueQuerySchema.ts +18 -0
- package/src/api/issues/schemas/issueResourceSchema.ts +6 -0
- package/src/api/issues/schemas/myIssueQuerySchema.ts +10 -0
- package/src/api/issues/schemas/updateIssueSchema.ts +13 -0
- package/src/api/issues/services/IssueService.ts +264 -0
- package/src/api/jobs/__tests__/$job.spec.ts +876 -0
- package/src/api/jobs/controllers/AdminJobController.ts +44 -0
- package/src/api/jobs/entities/jobExecutionEntity.ts +0 -2
- package/src/api/jobs/index.ts +0 -3
- package/src/api/jobs/primitives/$job.ts +22 -11
- package/src/api/jobs/providers/JobProvider.ts +229 -19
- package/src/api/jobs/schemas/jobConfigAtom.ts +4 -0
- package/src/api/jobs/schemas/jobCronInfoSchema.ts +1 -0
- package/src/api/jobs/schemas/jobExecutionQuerySchema.ts +0 -1
- package/src/api/jobs/schemas/jobQueueDepthSchema.ts +1 -0
- package/src/api/jobs/schemas/jobRegistrationSchema.ts +1 -6
- package/src/api/jobs/services/JobService.ts +51 -12
- package/src/api/notifications/schemas/notificationQuerySchema.ts +0 -1
- package/src/api/parameters/__tests__/$parameter.spec.ts +327 -0
- package/src/api/parameters/controllers/AdminParameterController.ts +29 -3
- package/src/api/parameters/index.browser.ts +12 -0
- package/src/api/parameters/primitives/$parameter.ts +20 -3
- package/src/api/parameters/services/ParameterProvider.ts +48 -7
- package/src/{billing → api/payments}/__tests__/PaymentMethodService.spec.ts +32 -6
- package/src/api/payments/__tests__/PaymentService.spec.ts +279 -0
- package/src/{billing/controllers/AdminBillingController.ts → api/payments/controllers/AdminPaymentController.ts} +26 -21
- package/src/{billing/controllers/BillingController.ts → api/payments/controllers/PaymentController.ts} +23 -11
- package/src/{billing → api/payments}/entities/paymentIntents.ts +1 -0
- package/src/{billing/errors/BillingError.ts → api/payments/errors/PaymentError.ts} +1 -1
- package/src/{billing → api/payments}/index.ts +31 -25
- package/src/{billing/providers/MemoryBillingProvider.ts → api/payments/providers/MemoryPaymentProvider.ts} +4 -4
- package/src/{billing/providers/BillingProvider.ts → api/payments/providers/PaymentProvider.ts} +9 -2
- package/src/{billing → api/payments}/services/PaymentMethodService.ts +5 -5
- package/src/{billing/services/BillingService.ts → api/payments/services/PaymentService.ts} +94 -18
- package/src/api/subscriptions/__tests__/BillingService.spec.ts +218 -0
- package/src/api/subscriptions/__tests__/SubscriptionService.spec.ts +278 -0
- package/src/api/subscriptions/controllers/AdminSubscriptionController.ts +212 -0
- package/src/api/subscriptions/controllers/SubscriptionController.ts +189 -0
- package/src/api/subscriptions/entities/subscriptionEvents.ts +54 -0
- package/src/api/subscriptions/entities/subscriptions.ts +68 -0
- package/src/api/subscriptions/index.ts +144 -0
- package/src/api/subscriptions/jobs/SubscriptionJobs.ts +382 -0
- package/src/api/subscriptions/middleware/$requireLimit.ts +50 -0
- package/src/api/subscriptions/middleware/$requirePlan.ts +49 -0
- package/src/api/subscriptions/notifications/SubscriptionNotifications.ts +110 -0
- package/src/api/subscriptions/schemas/cancelSubscriptionSchema.ts +8 -0
- package/src/api/subscriptions/schemas/changePlanSchema.ts +9 -0
- package/src/api/subscriptions/schemas/createSubscriptionSchema.ts +11 -0
- package/src/api/subscriptions/schemas/entitlementsSchema.ts +21 -0
- package/src/api/subscriptions/schemas/mrrSchema.ts +13 -0
- package/src/api/subscriptions/schemas/planDefinitionSchema.ts +71 -0
- package/src/api/subscriptions/schemas/planResourceSchema.ts +25 -0
- package/src/api/subscriptions/schemas/subscriptionEventResourceSchema.ts +8 -0
- package/src/api/subscriptions/schemas/subscriptionQuerySchema.ts +19 -0
- package/src/api/subscriptions/schemas/subscriptionResourceSchema.ts +6 -0
- package/src/api/subscriptions/schemas/subscriptionSettingsSchema.ts +32 -0
- package/src/api/subscriptions/schemas/subscriptionStatsSchema.ts +23 -0
- package/src/api/subscriptions/services/BillingService.ts +437 -0
- package/src/api/subscriptions/services/SubscriptionConfig.ts +56 -0
- package/src/api/subscriptions/services/SubscriptionService.ts +867 -0
- package/src/api/subscriptions/services/UsageService.ts +118 -0
- package/src/api/users/__tests__/AdminUserController.spec.ts +80 -1
- package/src/api/users/__tests__/CredentialService.spec.ts +177 -0
- package/src/api/users/__tests__/EmailVerification.spec.ts +29 -18
- package/src/api/users/__tests__/PasswordReset.spec.ts +3 -0
- package/src/api/users/__tests__/RegistrationService.spec.ts +148 -1
- package/src/api/users/__tests__/SessionService.spec.ts +142 -1
- package/src/api/users/atoms/realmAuthSettingsAtom.ts +10 -1
- package/src/api/users/controllers/UserController.ts +3 -8
- package/src/api/users/notifications/UserNotifications.ts +23 -0
- package/src/api/users/primitives/$realm.ts +24 -0
- package/src/api/users/schemas/loginSchema.ts +1 -1
- package/src/api/users/services/CredentialService.ts +57 -7
- package/src/api/users/services/RegistrationService.ts +50 -11
- package/src/api/users/services/SessionService.ts +64 -9
- package/src/api/users/services/UserService.ts +21 -12
- package/src/api/workflows/__tests__/$workflow.spec.ts +616 -0
- package/src/api/workflows/controllers/AdminWorkflowController.ts +191 -0
- package/src/api/workflows/entities/workflowExecutions.ts +74 -0
- package/src/api/workflows/entities/workflowStepExecutions.ts +74 -0
- package/src/api/workflows/entities/workflowStepLogs.ts +13 -0
- package/src/api/workflows/index.browser.ts +22 -0
- package/src/api/workflows/index.ts +124 -0
- package/src/api/workflows/jobs/WorkflowJobs.ts +77 -0
- package/src/api/workflows/primitives/$workflow.ts +202 -0
- package/src/api/workflows/providers/WorkflowProvider.ts +1284 -0
- package/src/api/workflows/schemas/workflowActivitySchema.ts +15 -0
- package/src/api/workflows/schemas/workflowConfigAtom.ts +51 -0
- package/src/api/workflows/schemas/workflowExecutionDetailSchema.ts +18 -0
- package/src/api/workflows/schemas/workflowExecutionQuerySchema.ts +26 -0
- package/src/api/workflows/schemas/workflowExecutionResourceSchema.ts +30 -0
- package/src/api/workflows/schemas/workflowRegistrationSchema.ts +26 -0
- package/src/api/workflows/schemas/workflowStatsSchema.ts +16 -0
- package/src/api/workflows/schemas/workflowStepExecutionResourceSchema.ts +15 -0
- package/src/api/workflows/services/WorkflowService.ts +382 -0
- package/src/captcha/__tests__/MemoryCaptchaProvider.spec.ts +74 -0
- package/src/captcha/index.ts +33 -0
- package/src/captcha/providers/CaptchaProvider.ts +17 -0
- package/src/captcha/providers/MemoryCaptchaProvider.ts +65 -0
- package/src/captcha/providers/TurnstileCaptchaProvider.ts +125 -0
- package/src/cli/core/atoms/buildOptions.ts +57 -0
- package/src/cli/core/commands/build.ts +2 -0
- package/src/cli/core/providers/ViteDevServerProvider.ts +1 -1
- package/src/cli/core/services/ViteUtils.ts +5 -2
- package/src/cli/core/tasks/BuildClientTask.ts +3 -1
- package/src/cli/core/tasks/BuildCloudflareTask.ts +4 -0
- package/src/cli/core/tasks/BuildPwaTask.ts +81 -0
- package/src/cli/core/templates/webAppRouterTs.ts +5 -58
- package/src/cli/platform/adapters/CloudflareAdapter.ts +24 -0
- package/src/cli/platform/atoms/platformOptions.ts +19 -3
- package/src/cli/platform/hooks/PlatformHook.ts +51 -0
- package/src/cli/platform/index.ts +1 -0
- package/src/cli/platform/services/CloudflareApi.ts +22 -1
- package/src/cli/platform/services/PlatformOrchestrator.ts +67 -2
- package/src/cli/vendor/__tests__/VendorService.spec.ts +322 -178
- package/src/cli/vendor/commands/VendorCommand.ts +41 -38
- package/src/cli/vendor/services/VendorService.ts +234 -31
- package/src/command/__tests__/CliProvider.spec.ts +45 -0
- package/src/command/providers/CliProvider.ts +3 -4
- package/src/core/__tests__/TypeProvider.spec.ts +4 -2
- package/src/core/providers/SchemaValidator.ts +1 -1
- package/src/core/providers/TypeProvider.ts +46 -3
- package/src/orm/__tests__/enums.spec.ts +22 -29
- package/src/orm/__tests__/orm-showcase-tests.ts +430 -0
- package/src/orm/__tests__/orm-showcase.spec.ts +167 -0
- package/src/orm/core/providers/DatabaseTypeProvider.ts +0 -29
- package/src/orm/core/services/Repository.ts +20 -6
- package/src/orm/postgres/services/PostgresModelBuilder.ts +3 -6
- package/src/react/i18n/__tests__/I18nProvider.spec.ts +83 -0
- package/src/react/i18n/providers/I18nProvider.ts +12 -10
- package/src/react/router/__tests__/$page.browser.spec.tsx +157 -0
- package/src/react/router/providers/ReactBrowserProvider.ts +39 -0
- package/src/react/router/providers/ReactBrowserRouterProvider.ts +22 -0
- package/src/security/__tests__/$secure-combinations.spec.ts +945 -0
- package/src/security/primitives/$issuer.ts +3 -1
- package/src/security/primitives/$secure.ts +28 -0
- package/src/server/auth/index.ts +7 -0
- package/src/server/auth/primitives/$auth.ts +37 -3
- package/src/server/auth/primitives/$authApple.ts +114 -4
- package/src/server/auth/primitives/$authFacebook.ts +98 -0
- package/src/server/auth/primitives/$authFranceConnect.ts +105 -0
- package/src/server/auth/primitives/$authGithub.ts +22 -16
- package/src/server/auth/primitives/$authMicrosoft.ts +88 -0
- package/src/server/auth/providers/ServerAuthProvider.ts +197 -72
- package/src/server/cookies/providers/ServerCookiesProvider.ts +3 -0
- package/src/server/core/__tests__/ServerRouterProvider-errorHandler.spec.ts +1 -1
- package/src/websocket/providers/NodeWebSocketServerProvider.ts +3 -1
- package/dist/billing/index.d.ts.map +0 -1
- package/dist/billing/index.js.map +0 -1
- package/src/billing/__tests__/BillingService.spec.ts +0 -136
- /package/src/{billing → api/payments}/entities/paymentMethods.ts +0 -0
- /package/src/{billing → api/payments}/entities/refunds.ts +0 -0
- /package/src/{billing → api/payments}/schemas/intentSchemas.ts +0 -0
- /package/src/{billing → api/payments}/schemas/paymentMethodSchemas.ts +0 -0
- /package/src/{billing → api/payments}/schemas/refundSchemas.ts +0 -0
|
@@ -3,33 +3,33 @@ import { describe, expect, it } from "vitest";
|
|
|
3
3
|
import { $entity, $repository, DrizzleKitProvider, db } from "../core/index.ts";
|
|
4
4
|
import { AlephaOrmPostgres } from "../postgres/index.ts";
|
|
5
5
|
|
|
6
|
-
// Test 1:
|
|
6
|
+
// Test 1: t.enum with mode: "text" (should map to TEXT column)
|
|
7
7
|
const textEnumEntity = $entity({
|
|
8
8
|
name: "text_enum_test",
|
|
9
9
|
schema: t.object({
|
|
10
10
|
id: db.primaryKey(),
|
|
11
|
-
status: t.enum(["pending", "active", "archived"]),
|
|
12
|
-
role: t.enum(["user", "admin", "moderator"]),
|
|
11
|
+
status: t.enum(["pending", "active", "archived"], { mode: "text" }),
|
|
12
|
+
role: t.enum(["user", "admin", "moderator"], { mode: "text" }),
|
|
13
13
|
}),
|
|
14
14
|
});
|
|
15
15
|
|
|
16
|
-
// Test 2:
|
|
16
|
+
// Test 2: t.enum without mode (should create real PG ENUM type)
|
|
17
17
|
const pgEnumEntity = $entity({
|
|
18
18
|
name: "pg_enum_test",
|
|
19
19
|
schema: t.object({
|
|
20
20
|
id: db.primaryKey(),
|
|
21
|
-
status:
|
|
22
|
-
priority:
|
|
21
|
+
status: t.enum(["draft", "published", "deleted"]),
|
|
22
|
+
priority: t.enum(["low", "medium", "high"]),
|
|
23
23
|
}),
|
|
24
24
|
});
|
|
25
25
|
|
|
26
|
-
// Test 3: Mixed
|
|
26
|
+
// Test 3: Mixed text and pg enum in the same table
|
|
27
27
|
const mixedEnumEntity = $entity({
|
|
28
28
|
name: "mixed_enum_test",
|
|
29
29
|
schema: t.object({
|
|
30
30
|
id: db.primaryKey(),
|
|
31
|
-
textStatus: t.enum(["open", "closed"]),
|
|
32
|
-
pgStatus:
|
|
31
|
+
textStatus: t.enum(["open", "closed"], { mode: "text" }),
|
|
32
|
+
pgStatus: t.enum(["new", "in_progress", "done"]),
|
|
33
33
|
}),
|
|
34
34
|
});
|
|
35
35
|
|
|
@@ -38,7 +38,7 @@ const sharedEnumEntity1 = $entity({
|
|
|
38
38
|
name: "shared_enum_test_1",
|
|
39
39
|
schema: t.object({
|
|
40
40
|
id: db.primaryKey(),
|
|
41
|
-
status:
|
|
41
|
+
status: t.enum(["enabled", "disabled"], { name: "shared_status_enum" }),
|
|
42
42
|
}),
|
|
43
43
|
});
|
|
44
44
|
|
|
@@ -46,7 +46,7 @@ const sharedEnumEntity2 = $entity({
|
|
|
46
46
|
name: "shared_enum_test_2",
|
|
47
47
|
schema: t.object({
|
|
48
48
|
id: db.primaryKey(),
|
|
49
|
-
status:
|
|
49
|
+
status: t.enum(["enabled", "disabled"], { name: "shared_status_enum" }),
|
|
50
50
|
}),
|
|
51
51
|
});
|
|
52
52
|
|
|
@@ -55,7 +55,7 @@ const conflictEnumEntity1 = $entity({
|
|
|
55
55
|
name: "conflict_enum_test_1",
|
|
56
56
|
schema: t.object({
|
|
57
57
|
id: db.primaryKey(),
|
|
58
|
-
status:
|
|
58
|
+
status: t.enum(["a", "b", "c"], { name: "conflict_status_enum" }),
|
|
59
59
|
}),
|
|
60
60
|
});
|
|
61
61
|
|
|
@@ -63,12 +63,12 @@ const conflictEnumEntity2 = $entity({
|
|
|
63
63
|
name: "conflict_enum_test_2",
|
|
64
64
|
schema: t.object({
|
|
65
65
|
id: db.primaryKey(),
|
|
66
|
-
status:
|
|
66
|
+
status: t.enum(["a", "b", "d"], { name: "conflict_status_enum" }), // Different value!
|
|
67
67
|
}),
|
|
68
68
|
});
|
|
69
69
|
|
|
70
|
-
describe("enums - t.enum (TEXT column)", () => {
|
|
71
|
-
it("should create TEXT columns for t.enum fields", async () => {
|
|
70
|
+
describe("enums - t.enum with mode: 'text' (TEXT column)", () => {
|
|
71
|
+
it("should create TEXT columns for t.enum fields with mode: 'text'", async () => {
|
|
72
72
|
const alepha = Alepha.create().with(AlephaOrmPostgres);
|
|
73
73
|
|
|
74
74
|
class App {
|
|
@@ -87,12 +87,12 @@ describe("enums - t.enum (TEXT column)", () => {
|
|
|
87
87
|
|
|
88
88
|
expect(sql).toContainEqual(expect.stringContaining("CREATE TABLE"));
|
|
89
89
|
expect(sql).toContainEqual(expect.stringContaining("text_enum_test"));
|
|
90
|
-
//
|
|
90
|
+
// mode: "text" should map to TEXT, not a real ENUM type
|
|
91
91
|
expect(sql.some((s) => s.includes('"status" text'))).toBe(true);
|
|
92
92
|
expect(sql.some((s) => s.includes('"role" text'))).toBe(true);
|
|
93
93
|
});
|
|
94
94
|
|
|
95
|
-
it("should allow inserting and querying with
|
|
95
|
+
it("should allow inserting and querying with text enum values", async () => {
|
|
96
96
|
const alepha = Alepha.create().with(AlephaOrmPostgres);
|
|
97
97
|
|
|
98
98
|
class App {
|
|
@@ -117,8 +117,8 @@ describe("enums - t.enum (TEXT column)", () => {
|
|
|
117
117
|
});
|
|
118
118
|
});
|
|
119
119
|
|
|
120
|
-
describe("enums -
|
|
121
|
-
it("should create real PostgreSQL ENUM types for
|
|
120
|
+
describe("enums - t.enum (real PG ENUM type)", () => {
|
|
121
|
+
it("should create real PostgreSQL ENUM types for t.enum fields", async () => {
|
|
122
122
|
const alepha = Alepha.create().with(AlephaOrmPostgres);
|
|
123
123
|
|
|
124
124
|
class App {
|
|
@@ -137,13 +137,13 @@ describe("enums - db.enum (real PG ENUM type)", () => {
|
|
|
137
137
|
|
|
138
138
|
expect(sql).toContainEqual(expect.stringContaining("CREATE TABLE"));
|
|
139
139
|
expect(sql).toContainEqual(expect.stringContaining("pg_enum_test"));
|
|
140
|
-
//
|
|
140
|
+
// t.enum without mode should create real ENUM types
|
|
141
141
|
expect(
|
|
142
142
|
sql.some((s) => s.includes("CREATE TYPE") || s.includes("DO $$ BEGIN")),
|
|
143
143
|
).toBe(true);
|
|
144
144
|
});
|
|
145
145
|
|
|
146
|
-
it("should allow inserting and querying with
|
|
146
|
+
it("should allow inserting and querying with pg enum values", async () => {
|
|
147
147
|
const alepha = Alepha.create().with(AlephaOrmPostgres);
|
|
148
148
|
|
|
149
149
|
class App {
|
|
@@ -168,7 +168,7 @@ describe("enums - db.enum (real PG ENUM type)", () => {
|
|
|
168
168
|
});
|
|
169
169
|
});
|
|
170
170
|
|
|
171
|
-
describe("enums - mixed
|
|
171
|
+
describe("enums - mixed text and pg enum in same table", () => {
|
|
172
172
|
it("should handle both TEXT and PG ENUM types in the same table", async () => {
|
|
173
173
|
const alepha = Alepha.create().with(AlephaOrmPostgres);
|
|
174
174
|
|
|
@@ -299,13 +299,6 @@ describe("enums - conflict detection with different values", () => {
|
|
|
299
299
|
it("should throw error when same enum name has different values", async () => {
|
|
300
300
|
const alepha = Alepha.create().with(AlephaOrmPostgres);
|
|
301
301
|
|
|
302
|
-
const load = async () => {
|
|
303
|
-
return alepha.with(() => ({
|
|
304
|
-
r1: $repository(conflictEnumEntity1),
|
|
305
|
-
r2: $repository(conflictEnumEntity2),
|
|
306
|
-
}));
|
|
307
|
-
};
|
|
308
|
-
|
|
309
302
|
expect(() =>
|
|
310
303
|
alepha.with(() => ({
|
|
311
304
|
r1: $repository(conflictEnumEntity1),
|
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
import type { Alepha } from "alepha";
|
|
2
|
+
import { t } from "alepha";
|
|
3
|
+
import { expect } from "vitest";
|
|
4
|
+
import { $entity, $repository, db } from "../core/index.ts";
|
|
5
|
+
|
|
6
|
+
// ============================================================================
|
|
7
|
+
// Entity definitions — two entities with a foreign key relationship
|
|
8
|
+
// ============================================================================
|
|
9
|
+
|
|
10
|
+
const teams = $entity({
|
|
11
|
+
name: "teams",
|
|
12
|
+
schema: t.object({
|
|
13
|
+
id: db.primaryKey(),
|
|
14
|
+
name: t.text(),
|
|
15
|
+
country: t.text(),
|
|
16
|
+
}),
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const players = $entity({
|
|
20
|
+
name: "players",
|
|
21
|
+
schema: t.object({
|
|
22
|
+
id: db.primaryKey(),
|
|
23
|
+
teamId: db.ref(t.optional(t.integer()), () => teams.cols.id),
|
|
24
|
+
name: t.text(),
|
|
25
|
+
position: t.text(),
|
|
26
|
+
goals: db.default(t.integer(), 0),
|
|
27
|
+
}),
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
class App {
|
|
31
|
+
teams = $repository(teams);
|
|
32
|
+
players = $repository(players);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// ============================================================================
|
|
36
|
+
// Shared setup
|
|
37
|
+
// ============================================================================
|
|
38
|
+
|
|
39
|
+
async function seed(app: App) {
|
|
40
|
+
const barca = await app.teams.create({
|
|
41
|
+
name: "FC Barcelona",
|
|
42
|
+
country: "Spain",
|
|
43
|
+
});
|
|
44
|
+
const psg = await app.teams.create({
|
|
45
|
+
name: "Paris Saint-Germain",
|
|
46
|
+
country: "France",
|
|
47
|
+
});
|
|
48
|
+
const real = await app.teams.create({
|
|
49
|
+
name: "Real Madrid",
|
|
50
|
+
country: "Spain",
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const messi = await app.players.create({
|
|
54
|
+
teamId: barca.id,
|
|
55
|
+
name: "Messi",
|
|
56
|
+
position: "Forward",
|
|
57
|
+
goals: 672,
|
|
58
|
+
});
|
|
59
|
+
const pedri = await app.players.create({
|
|
60
|
+
teamId: barca.id,
|
|
61
|
+
name: "Pedri",
|
|
62
|
+
position: "Midfielder",
|
|
63
|
+
goals: 18,
|
|
64
|
+
});
|
|
65
|
+
const mbappe = await app.players.create({
|
|
66
|
+
teamId: psg.id,
|
|
67
|
+
name: "Mbappé",
|
|
68
|
+
position: "Forward",
|
|
69
|
+
goals: 256,
|
|
70
|
+
});
|
|
71
|
+
const modric = await app.players.create({
|
|
72
|
+
teamId: real.id,
|
|
73
|
+
name: "Modrić",
|
|
74
|
+
position: "Midfielder",
|
|
75
|
+
goals: 39,
|
|
76
|
+
});
|
|
77
|
+
const freeAgent = await app.players.create({
|
|
78
|
+
name: "Free Agent",
|
|
79
|
+
position: "Goalkeeper",
|
|
80
|
+
goals: 0,
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
teams: { barca, psg, real },
|
|
85
|
+
players: { messi, pedri, mbappe, modric, freeAgent },
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// ============================================================================
|
|
90
|
+
// 1. Basic left join — player with their team
|
|
91
|
+
// ============================================================================
|
|
92
|
+
|
|
93
|
+
export const testLeftJoinPlayerWithTeam = async (alepha: Alepha) => {
|
|
94
|
+
const app = alepha.inject(App);
|
|
95
|
+
await alepha.start();
|
|
96
|
+
const { players: p } = await seed(app);
|
|
97
|
+
|
|
98
|
+
const result = await app.players.getOne({
|
|
99
|
+
where: { id: { eq: p.messi.id } },
|
|
100
|
+
with: {
|
|
101
|
+
team: {
|
|
102
|
+
join: teams,
|
|
103
|
+
on: ["teamId", teams.cols.id],
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
expect(result.name).toBe("Messi");
|
|
109
|
+
expect(result.team).toBeDefined();
|
|
110
|
+
expect(result.team.name).toBe("FC Barcelona");
|
|
111
|
+
expect(result.team.country).toBe("Spain");
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
// ============================================================================
|
|
115
|
+
// 2. Left join returns undefined when FK is null
|
|
116
|
+
// ============================================================================
|
|
117
|
+
|
|
118
|
+
export const testLeftJoinReturnsUndefinedWhenFkNull = async (
|
|
119
|
+
alepha: Alepha,
|
|
120
|
+
) => {
|
|
121
|
+
const app = alepha.inject(App);
|
|
122
|
+
await alepha.start();
|
|
123
|
+
const { players: p } = await seed(app);
|
|
124
|
+
|
|
125
|
+
const result = await app.players.getOne({
|
|
126
|
+
where: { id: { eq: p.freeAgent.id } },
|
|
127
|
+
with: {
|
|
128
|
+
team: {
|
|
129
|
+
join: teams,
|
|
130
|
+
on: ["teamId", teams.cols.id],
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
expect(result.name).toBe("Free Agent");
|
|
136
|
+
expect(result.team).toBeUndefined();
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
// ============================================================================
|
|
140
|
+
// 3. Inner join excludes rows without match
|
|
141
|
+
// ============================================================================
|
|
142
|
+
|
|
143
|
+
export const testInnerJoinExcludesNulls = async (alepha: Alepha) => {
|
|
144
|
+
const app = alepha.inject(App);
|
|
145
|
+
await alepha.start();
|
|
146
|
+
await seed(app);
|
|
147
|
+
|
|
148
|
+
const results = await app.players.findMany({
|
|
149
|
+
with: {
|
|
150
|
+
team: {
|
|
151
|
+
type: "inner",
|
|
152
|
+
join: teams,
|
|
153
|
+
on: ["teamId", teams.cols.id],
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// Free Agent has no team → excluded by inner join
|
|
159
|
+
expect(results.length).toBe(4);
|
|
160
|
+
expect(results.every((r) => r.team !== null && r.team !== undefined)).toBe(
|
|
161
|
+
true,
|
|
162
|
+
);
|
|
163
|
+
expect(results.find((r) => r.name === "Free Agent")).toBeUndefined();
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
// ============================================================================
|
|
167
|
+
// 4. findMany with join + filter on joined table
|
|
168
|
+
// ============================================================================
|
|
169
|
+
|
|
170
|
+
export const testFilterOnJoinedTable = async (alepha: Alepha) => {
|
|
171
|
+
const app = alepha.inject(App);
|
|
172
|
+
await alepha.start();
|
|
173
|
+
await seed(app);
|
|
174
|
+
|
|
175
|
+
const spanishPlayers = await app.players.findMany({
|
|
176
|
+
with: {
|
|
177
|
+
team: {
|
|
178
|
+
join: teams,
|
|
179
|
+
on: ["teamId", teams.cols.id],
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
where: {
|
|
183
|
+
team: {
|
|
184
|
+
country: { eq: "Spain" },
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
expect(spanishPlayers.length).toBe(3); // Messi, Pedri (Barça), Modrić (Real)
|
|
190
|
+
expect(spanishPlayers.every((p) => p.team.country === "Spain")).toBe(true);
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
// ============================================================================
|
|
194
|
+
// 5. Combined filters — base table + joined table
|
|
195
|
+
// ============================================================================
|
|
196
|
+
|
|
197
|
+
export const testCombinedFilters = async (alepha: Alepha) => {
|
|
198
|
+
const app = alepha.inject(App);
|
|
199
|
+
await alepha.start();
|
|
200
|
+
await seed(app);
|
|
201
|
+
|
|
202
|
+
const results = await app.players.findMany({
|
|
203
|
+
with: {
|
|
204
|
+
team: {
|
|
205
|
+
join: teams,
|
|
206
|
+
on: ["teamId", teams.cols.id],
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
where: {
|
|
210
|
+
and: [
|
|
211
|
+
{ position: { eq: "Forward" } },
|
|
212
|
+
{ team: { country: { eq: "Spain" } } },
|
|
213
|
+
],
|
|
214
|
+
},
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
expect(results.length).toBe(1);
|
|
218
|
+
expect(results[0].name).toBe("Messi");
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
// ============================================================================
|
|
222
|
+
// 6. findMany with join + orderBy + limit
|
|
223
|
+
// ============================================================================
|
|
224
|
+
|
|
225
|
+
export const testJoinWithOrderByAndLimit = async (alepha: Alepha) => {
|
|
226
|
+
const app = alepha.inject(App);
|
|
227
|
+
await alepha.start();
|
|
228
|
+
await seed(app);
|
|
229
|
+
|
|
230
|
+
const topScorers = await app.players.findMany({
|
|
231
|
+
with: {
|
|
232
|
+
team: {
|
|
233
|
+
join: teams,
|
|
234
|
+
on: ["teamId", teams.cols.id],
|
|
235
|
+
},
|
|
236
|
+
},
|
|
237
|
+
orderBy: { column: "goals", direction: "desc" },
|
|
238
|
+
limit: 2,
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
expect(topScorers.length).toBe(2);
|
|
242
|
+
expect(topScorers[0].name).toBe("Messi");
|
|
243
|
+
expect(topScorers[1].name).toBe("Mbappé");
|
|
244
|
+
expect(topScorers[0].team).toBeDefined();
|
|
245
|
+
expect(topScorers[1].team).toBeDefined();
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
// ============================================================================
|
|
249
|
+
// 7. Pagination with joins
|
|
250
|
+
// ============================================================================
|
|
251
|
+
|
|
252
|
+
export const testPaginationWithJoins = async (alepha: Alepha) => {
|
|
253
|
+
const app = alepha.inject(App);
|
|
254
|
+
await alepha.start();
|
|
255
|
+
await seed(app);
|
|
256
|
+
|
|
257
|
+
const page = await app.players.paginate(
|
|
258
|
+
{ page: 0, size: 2 },
|
|
259
|
+
{
|
|
260
|
+
with: {
|
|
261
|
+
team: {
|
|
262
|
+
join: teams,
|
|
263
|
+
on: ["teamId", teams.cols.id],
|
|
264
|
+
},
|
|
265
|
+
},
|
|
266
|
+
orderBy: { column: "name", direction: "asc" },
|
|
267
|
+
},
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
expect(page.content.length).toBe(2);
|
|
271
|
+
expect(page.page.isFirst).toBe(true);
|
|
272
|
+
expect(page.page.isLast).toBe(false);
|
|
273
|
+
// Each result should include the joined team
|
|
274
|
+
for (const player of page.content) {
|
|
275
|
+
// Some players may have no team (left join)
|
|
276
|
+
if (player.teamId) {
|
|
277
|
+
expect(player.team).toBeDefined();
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
// ============================================================================
|
|
283
|
+
// 8. OR filter across base + joined table
|
|
284
|
+
// ============================================================================
|
|
285
|
+
|
|
286
|
+
export const testOrFilterAcrossTables = async (alepha: Alepha) => {
|
|
287
|
+
const app = alepha.inject(App);
|
|
288
|
+
await alepha.start();
|
|
289
|
+
await seed(app);
|
|
290
|
+
|
|
291
|
+
const results = await app.players.findMany({
|
|
292
|
+
with: {
|
|
293
|
+
team: {
|
|
294
|
+
join: teams,
|
|
295
|
+
on: ["teamId", teams.cols.id],
|
|
296
|
+
},
|
|
297
|
+
},
|
|
298
|
+
where: {
|
|
299
|
+
or: [{ goals: { gte: 200 } }, { team: { country: { eq: "France" } } }],
|
|
300
|
+
},
|
|
301
|
+
orderBy: { column: "goals", direction: "desc" },
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
// Messi (672), Mbappé (256 + France) — Mbappé matches both conditions
|
|
305
|
+
expect(results.length).toBe(2);
|
|
306
|
+
expect(results.map((r) => r.name)).toEqual(["Messi", "Mbappé"]);
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
// ============================================================================
|
|
310
|
+
// 9. getOne with join throws when not found
|
|
311
|
+
// ============================================================================
|
|
312
|
+
|
|
313
|
+
export const testGetOneWithJoinThrowsWhenNotFound = async (alepha: Alepha) => {
|
|
314
|
+
const app = alepha.inject(App);
|
|
315
|
+
await alepha.start();
|
|
316
|
+
await seed(app);
|
|
317
|
+
|
|
318
|
+
await expect(
|
|
319
|
+
app.players.getOne({
|
|
320
|
+
where: { name: { eq: "Neymar" } },
|
|
321
|
+
with: {
|
|
322
|
+
team: {
|
|
323
|
+
join: teams,
|
|
324
|
+
on: ["teamId", teams.cols.id],
|
|
325
|
+
},
|
|
326
|
+
},
|
|
327
|
+
}),
|
|
328
|
+
).rejects.toThrow();
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
// ============================================================================
|
|
332
|
+
// 10. findOne with join — returns undefined instead of throwing
|
|
333
|
+
// ============================================================================
|
|
334
|
+
|
|
335
|
+
export const testFindOneWithJoinReturnsUndefined = async (alepha: Alepha) => {
|
|
336
|
+
const app = alepha.inject(App);
|
|
337
|
+
await alepha.start();
|
|
338
|
+
await seed(app);
|
|
339
|
+
|
|
340
|
+
const result = await app.players.findOne({
|
|
341
|
+
where: { name: { eq: "Neymar" } },
|
|
342
|
+
with: {
|
|
343
|
+
team: {
|
|
344
|
+
join: teams,
|
|
345
|
+
on: ["teamId", teams.cols.id],
|
|
346
|
+
},
|
|
347
|
+
},
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
expect(result).toBeUndefined();
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
// ============================================================================
|
|
354
|
+
// 11. Empty result set with joins
|
|
355
|
+
// ============================================================================
|
|
356
|
+
|
|
357
|
+
export const testEmptyResultWithJoins = async (alepha: Alepha) => {
|
|
358
|
+
const app = alepha.inject(App);
|
|
359
|
+
await alepha.start();
|
|
360
|
+
await seed(app);
|
|
361
|
+
|
|
362
|
+
const results = await app.players.findMany({
|
|
363
|
+
where: { position: { eq: "Defender" } },
|
|
364
|
+
with: {
|
|
365
|
+
team: {
|
|
366
|
+
join: teams,
|
|
367
|
+
on: ["teamId", teams.cols.id],
|
|
368
|
+
},
|
|
369
|
+
},
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
expect(results.length).toBe(0);
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
// ============================================================================
|
|
376
|
+
// 12. Multiple operators on joined table filter
|
|
377
|
+
// ============================================================================
|
|
378
|
+
|
|
379
|
+
export const testMultipleOperatorsOnJoinedFilter = async (alepha: Alepha) => {
|
|
380
|
+
const app = alepha.inject(App);
|
|
381
|
+
await alepha.start();
|
|
382
|
+
await seed(app);
|
|
383
|
+
|
|
384
|
+
const results = await app.players.findMany({
|
|
385
|
+
with: {
|
|
386
|
+
team: {
|
|
387
|
+
join: teams,
|
|
388
|
+
on: ["teamId", teams.cols.id],
|
|
389
|
+
},
|
|
390
|
+
},
|
|
391
|
+
where: {
|
|
392
|
+
team: {
|
|
393
|
+
name: { contains: "paris" }, // case-insensitive
|
|
394
|
+
},
|
|
395
|
+
},
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
expect(results.length).toBe(1);
|
|
399
|
+
expect(results[0].name).toBe("Mbappé");
|
|
400
|
+
expect(results[0].team.name).toBe("Paris Saint-Germain");
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
// ============================================================================
|
|
404
|
+
// 13. Join with offset (pagination without paginate)
|
|
405
|
+
// ============================================================================
|
|
406
|
+
|
|
407
|
+
export const testJoinWithOffset = async (alepha: Alepha) => {
|
|
408
|
+
const app = alepha.inject(App);
|
|
409
|
+
await alepha.start();
|
|
410
|
+
await seed(app);
|
|
411
|
+
|
|
412
|
+
const results = await app.players.findMany({
|
|
413
|
+
with: {
|
|
414
|
+
team: {
|
|
415
|
+
type: "inner",
|
|
416
|
+
join: teams,
|
|
417
|
+
on: ["teamId", teams.cols.id],
|
|
418
|
+
},
|
|
419
|
+
},
|
|
420
|
+
orderBy: { column: "name", direction: "asc" },
|
|
421
|
+
offset: 1,
|
|
422
|
+
limit: 2,
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
// Inner join excludes Free Agent → sorted: Mbappé, Messi, Modrić, Pedri
|
|
426
|
+
// offset 1 + limit 2 → Messi, Modrić
|
|
427
|
+
expect(results.length).toBe(2);
|
|
428
|
+
expect(results[0].name).toBe("Messi");
|
|
429
|
+
expect(results[1].name).toBe("Modrić");
|
|
430
|
+
};
|