diff --git a/src/generator/datasource.test.ts b/src/generator/datasource.test.ts index a1a477e..8b8a999 100644 --- a/src/generator/datasource.test.ts +++ b/src/generator/datasource.test.ts @@ -142,7 +142,7 @@ describe('Datasource Generator', () => { expect(result.content).toContain('country LowCardinality(String)'); }); - it('formats LowCardinality(Nullable) correctly', () => { + it('formats LowCardinality(Nullable) correctly with .lowCardinality().nullable()', () => { const ds = defineDatasource('test_ds', { schema: { country: t.string().lowCardinality().nullable(), @@ -151,6 +151,19 @@ describe('Datasource Generator', () => { const result = generateDatasource(ds); expect(result.content).toContain('country LowCardinality(Nullable(String))'); + expect(result.content).not.toContain('Nullable(LowCardinality'); + }); + + it('formats LowCardinality(Nullable) correctly with .nullable().lowCardinality()', () => { + const ds = defineDatasource('test_ds', { + schema: { + country: t.string().nullable().lowCardinality(), + }, + }); + + const result = generateDatasource(ds); + expect(result.content).toContain('country LowCardinality(Nullable(String))'); + expect(result.content).not.toContain('Nullable(LowCardinality'); }); it('includes default values', () => { diff --git a/src/schema/types.test.ts b/src/schema/types.test.ts index 60bda31..4a49386 100644 --- a/src/schema/types.test.ts +++ b/src/schema/types.test.ts @@ -87,10 +87,18 @@ describe("Type Validators (t.*)", () => { expect(type._tinybirdType).toBe("LowCardinality(Nullable(String))"); }); - it("preserves both modifiers when chained", () => { + it("preserves lowCardinality modifier and omits nullable when combined (nullable is in the type string)", () => { const type = t.string().lowCardinality().nullable(); expect(type._modifiers.lowCardinality).toBe(true); - expect(type._modifiers.nullable).toBe(true); + expect(type._modifiers.nullable).toBeUndefined(); + expect(type._tinybirdType).toBe("LowCardinality(Nullable(String))"); + }); + + it("omits nullable modifier when nullable().lowCardinality() is chained", () => { + const type = t.string().nullable().lowCardinality(); + expect(type._modifiers.lowCardinality).toBe(true); + expect(type._modifiers.nullable).toBeUndefined(); + expect(type._tinybirdType).toBe("LowCardinality(Nullable(String))"); }); }); diff --git a/src/schema/types.ts b/src/schema/types.ts index 5eb05e4..80c89e9 100644 --- a/src/schema/types.ts +++ b/src/schema/types.ts @@ -106,7 +106,6 @@ function createValidator( `LowCardinality(Nullable(${string}))` >(newType as `LowCardinality(Nullable(${string}))`, { ...modifiers, - nullable: true, }) as unknown as TypeValidator< TType | null, `Nullable(${TTinybirdType})`, @@ -129,9 +128,10 @@ function createValidator( // Extract base type from Nullable(X) and wrap as LowCardinality(Nullable(X)) const baseType = tinybirdType.replace(/^Nullable\((.+)\)$/, "$1"); const newType = `LowCardinality(Nullable(${baseType}))`; + const { nullable: _, ...rest } = modifiers; return createValidator( newType as `LowCardinality(Nullable(${string}))`, - { ...modifiers, lowCardinality: true }, + { ...rest, lowCardinality: true }, ) as unknown as TypeValidator< TType, `LowCardinality(${TTinybirdType})`,