diff --git a/packages/2-sql/2-authoring/contract-psl/test/interpreter.diagnostics.test.ts b/packages/2-sql/2-authoring/contract-psl/test/interpreter.diagnostics.test.ts index c9ae75c773..2b4273e546 100644 --- a/packages/2-sql/2-authoring/contract-psl/test/interpreter.diagnostics.test.ts +++ b/packages/2-sql/2-authoring/contract-psl/test/interpreter.diagnostics.test.ts @@ -22,6 +22,24 @@ const testSpan: PslSpan = { end: { line: 1, column: 7, offset: 6 }, }; +function expectDiagnosticForSchema( + schema: string, + diagnostic: { readonly code: string; readonly message: string }, +): void { + const document = parsePslDocument({ schema, sourceId: 'schema.prisma' }); + const result = interpretPslDocumentToSqlContract({ + ...baseInput, + document, + controlMutationDefaults: builtinControlMutationDefaults, + }); + + expect(result.ok).toBe(false); + if (result.ok) return; + expect(result.failure.diagnostics).toEqual( + expect.arrayContaining([expect.objectContaining(diagnostic)]), + ); +} + describe('interpretPslDocumentToSqlContract diagnostics', () => { it('returns diagnostics when target context is missing', () => { const document = parsePslDocument({ @@ -193,6 +211,56 @@ model User { ); }); + it('returns diagnostics for duplicate field and model primary keys', () => { + expectDiagnosticForSchema( + `model Membership { + id Int @id + orgId String + userId String + + @@id([orgId, userId]) +} +`, + { + code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT', + message: 'Model "Membership" cannot declare both field-level @id and model-level @@id', + }, + ); + }); + + it('returns diagnostics for nullable composite primary key fields', () => { + expectDiagnosticForSchema( + `model Membership { + orgId String + userId String? + + @@id([orgId, userId]) +} +`, + { + code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT', + message: + 'Model "Membership" @@id cannot include optional field "userId"; primary key columns must be NOT NULL', + }, + ); + }); + + it('returns diagnostics for unknown composite primary key fields', () => { + expectDiagnosticForSchema( + `model Membership { + orgId String + userId String + + @@id([orgId, missingId]) +} +`, + { + code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT', + message: 'Model "Membership" @@id references unknown field "Membership.missingId"', + }, + ); + }); + it('returns diagnostics for model attributes with unrecognized extension namespace', () => { const document = parsePslDocument({ schema: `model Team { diff --git a/packages/2-sql/2-authoring/contract-psl/test/interpreter.test.ts b/packages/2-sql/2-authoring/contract-psl/test/interpreter.test.ts index 0f3397dc4d..45d9369aeb 100644 --- a/packages/2-sql/2-authoring/contract-psl/test/interpreter.test.ts +++ b/packages/2-sql/2-authoring/contract-psl/test/interpreter.test.ts @@ -526,4 +526,34 @@ model OrderItem { }); }); }); + + it('maps model-level composite primary keys to storage columns', () => { + const document = parsePslDocument({ + schema: `model Membership { + orgId String @map("org_id") + userId String @map("user_id") + + @@id([orgId, userId], map: "membership_pkey") + @@map("membership") +} +`, + sourceId: 'schema.prisma', + }); + + const result = interpretPslDocumentToSqlContract({ + document, + controlMutationDefaults: builtinControlMutationDefaults, + }); + + expect(result.ok).toBe(true); + if (!result.ok) return; + + expect(result.value.storage).toMatchObject({ + tables: { + membership: { + primaryKey: { columns: ['org_id', 'user_id'], name: 'membership_pkey' }, + }, + }, + }); + }); });