UNPKG

alepha

Version:

Easy-to-use modern TypeScript framework for building many kind of applications.

314 lines (252 loc) 9.4 kB
import { Alepha, z } from "alepha"; import { describe, expect, it } from "vitest"; import { $entity, $repository, DrizzleKitProvider, db } from "../core/index.ts"; import { AlephaOrmPostgres } from "../postgres/index.ts"; // Test 1: z.enum with mode: "text" (should map to TEXT column) const textEnumEntity = $entity({ name: "text_enum_test", schema: z.object({ id: db.primaryKey(), status: z.enum(["pending", "active", "archived"]).meta({ mode: "text" }), role: z.enum(["user", "admin", "moderator"]).meta({ mode: "text" }), }), }); // Test 2: z.enum without mode (should create real PG ENUM type) const pgEnumEntity = $entity({ name: "pg_enum_test", schema: z.object({ id: db.primaryKey(), status: z.enum(["draft", "published", "deleted"]), priority: z.enum(["low", "medium", "high"]), }), }); // Test 3: Mixed text and pg enum in the same table const mixedEnumEntity = $entity({ name: "mixed_enum_test", schema: z.object({ id: db.primaryKey(), textStatus: z.enum(["open", "closed"]).meta({ mode: "text" }), pgStatus: z.enum(["new", "in_progress", "done"]), }), }); // Test 4: Shared enum with custom name across two tables const sharedEnumEntity1 = $entity({ name: "shared_enum_test_1", schema: z.object({ id: db.primaryKey(), status: z .enum(["enabled", "disabled"]) .meta({ name: "shared_status_enum" }), }), }); const sharedEnumEntity2 = $entity({ name: "shared_enum_test_2", schema: z.object({ id: db.primaryKey(), status: z .enum(["enabled", "disabled"]) .meta({ name: "shared_status_enum" }), }), }); // Test 5: Conflicting enum - same name but different values (should throw error) const conflictEnumEntity1 = $entity({ name: "conflict_enum_test_1", schema: z.object({ id: db.primaryKey(), status: z.enum(["a", "b", "c"]).meta({ name: "conflict_status_enum" }), }), }); const conflictEnumEntity2 = $entity({ name: "conflict_enum_test_2", schema: z.object({ id: db.primaryKey(), status: z.enum(["a", "b", "d"]).meta({ name: "conflict_status_enum" }), // Different value! }), }); describe("enums - z.enum with mode: 'text' (TEXT column)", () => { it("should create TEXT columns for z.enum fields with mode: 'text'", async () => { const alepha = Alepha.create().with(AlephaOrmPostgres); class App { repository = $repository(textEnumEntity); } const app = alepha.inject(App); const drizzleKit = alepha.inject(DrizzleKitProvider); await alepha.start(); // Check generated SQL const { statements: sql } = await drizzleKit.generateMigration( app.repository.provider, ); expect(sql).toContainEqual(expect.stringContaining("CREATE TABLE")); expect(sql).toContainEqual(expect.stringContaining("text_enum_test")); // mode: "text" should map to TEXT, not a real ENUM type expect(sql.some((s) => s.includes('"status" text'))).toBe(true); expect(sql.some((s) => s.includes('"role" text'))).toBe(true); }); it("should allow inserting and querying with text enum values", async () => { const alepha = Alepha.create().with(AlephaOrmPostgres); class App { repository = $repository(textEnumEntity); } const app = alepha.inject(App); await alepha.start(); const created = await app.repository.create({ status: "pending", role: "user", }); expect(created.status).toBe("pending"); expect(created.role).toBe("user"); expect(created.id).toBeDefined(); const found = await app.repository.findOne({ where: { id: created.id } }); expect(found?.status).toBe("pending"); expect(found?.role).toBe("user"); }); }); describe("enums - z.enum (real PG ENUM type)", () => { it("should create real PostgreSQL ENUM types for z.enum fields", async () => { const alepha = Alepha.create().with(AlephaOrmPostgres); class App { repository = $repository(pgEnumEntity); } const app = alepha.inject(App); const drizzleKit = alepha.inject(DrizzleKitProvider); await alepha.start(); // Check generated SQL const { statements: sql } = await drizzleKit.generateMigration( app.repository.provider, ); expect(sql).toContainEqual(expect.stringContaining("CREATE TABLE")); expect(sql).toContainEqual(expect.stringContaining("pg_enum_test")); // z.enum without mode should create real ENUM types expect( sql.some((s) => s.includes("CREATE TYPE") || s.includes("DO $$ BEGIN")), ).toBe(true); }); it("should allow inserting and querying with pg enum values", async () => { const alepha = Alepha.create().with(AlephaOrmPostgres); class App { repository = $repository(pgEnumEntity); } const app = alepha.inject(App); await alepha.start(); const created = await app.repository.create({ status: "draft", priority: "high", }); expect(created.status).toBe("draft"); expect(created.priority).toBe("high"); expect(created.id).toBeDefined(); const found = await app.repository.findOne({ where: { id: created.id } }); expect(found?.status).toBe("draft"); expect(found?.priority).toBe("high"); }); }); describe("enums - mixed text and pg enum in same table", () => { it("should handle both TEXT and PG ENUM types in the same table", async () => { const alepha = Alepha.create().with(AlephaOrmPostgres); class App { repository = $repository(mixedEnumEntity); } const app = alepha.inject(App); const drizzleKit = alepha.inject(DrizzleKitProvider); await alepha.start(); // Check generated SQL const { statements: sql } = await drizzleKit.generateMigration( app.repository.provider, ); expect(sql).toContainEqual(expect.stringContaining("CREATE TABLE")); expect(sql).toContainEqual(expect.stringContaining("mixed_enum_test")); // textStatus should be TEXT expect( sql.some( (s) => s.includes('"text_status" text') || s.includes('"textStatus" text'), ), ).toBe(true); // pgStatus should create an ENUM type expect( sql.some((s) => s.includes("CREATE TYPE") || s.includes("DO $$ BEGIN")), ).toBe(true); }); it("should allow inserting and querying with mixed enum values", async () => { const alepha = Alepha.create().with(AlephaOrmPostgres); class App { repository = $repository(mixedEnumEntity); } const app = alepha.inject(App); await alepha.start(); const created = await app.repository.create({ textStatus: "open", pgStatus: "new", }); expect(created.textStatus).toBe("open"); expect(created.pgStatus).toBe("new"); expect(created.id).toBeDefined(); const found = await app.repository.findOne({ where: { id: created.id } }); expect(found?.textStatus).toBe("open"); expect(found?.pgStatus).toBe("new"); }); }); describe("enums - shared enum with custom name across tables", () => { it("should reuse the same PG ENUM type across multiple tables", async () => { const alepha = Alepha.create().with(AlephaOrmPostgres); class App { repository1 = $repository(sharedEnumEntity1); repository2 = $repository(sharedEnumEntity2); } const app = alepha.inject(App); const drizzleKit = alepha.inject(DrizzleKitProvider); await alepha.start(); // Check generated SQL const { statements: sql } = await drizzleKit.generateMigration( app.repository1.provider, ); // Count how many times the shared_status_enum is created // It should only be created once, even though it's used in two tables const enumCreations = sql.filter( (s) => s.includes("shared_status_enum") && (s.includes("CREATE TYPE") || s.includes("DO $$ BEGIN")), ); // Should only create the enum type once expect(enumCreations.length).toBeLessThanOrEqual(1); // Both tables should exist expect(sql.some((s) => s.includes("shared_enum_test_1"))).toBe(true); expect(sql.some((s) => s.includes("shared_enum_test_2"))).toBe(true); }); it("should allow both tables to use the shared enum values", async () => { const alepha = Alepha.create().with(AlephaOrmPostgres); class App { repository1 = $repository(sharedEnumEntity1); repository2 = $repository(sharedEnumEntity2); } const app = alepha.inject(App); await alepha.start(); const created1 = await app.repository1.create({ status: "enabled", }); const created2 = await app.repository2.create({ status: "disabled", }); expect(created1.status).toBe("enabled"); expect(created2.status).toBe("disabled"); const found1 = await app.repository1.findOne({ where: { id: created1.id }, }); const found2 = await app.repository2.findOne({ where: { id: created2.id }, }); expect(found1?.status).toBe("enabled"); expect(found2?.status).toBe("disabled"); }); }); describe("enums - conflict detection with different values", () => { it("should throw error when same enum name has different values", async () => { const alepha = Alepha.create().with(AlephaOrmPostgres); expect(() => alepha.with(() => ({ r1: $repository(conflictEnumEntity1), r2: $repository(conflictEnumEntity2), })), ).toThrow(/Enum name conflict/i); }); });