Skip to content
This repository was archived by the owner on Mar 1, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 23 additions & 9 deletions packages/language/src/validators/datasource-validator.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { ValidationAcceptor } from 'langium';
import { SUPPORTED_PROVIDERS } from '../constants';
import { DataSource, isConfigArrayExpr, isInvocationExpr, isLiteralExpr } from '../generated/ast';
import { DataSource, isConfigArrayExpr, isDataModel, isEnum, isInvocationExpr, isLiteralExpr } from '../generated/ast';
import { getStringLiteral } from '../utils';
import { validateDuplicatedDeclarations, type AstValidator } from './common';

Expand Down Expand Up @@ -70,14 +70,28 @@ export default class DataSourceValidator implements AstValidator<DataSource> {
accept('error', '"schemas" must be an array of string literals', {
node: schemasField,
});
} else if (
// validate `defaultSchema` is included in `schemas`
defaultSchemaValue &&
!schemasValue.items.some((e) => getStringLiteral(e) === defaultSchemaValue)
) {
accept('error', `"${defaultSchemaValue}" must be included in the "schemas" array`, {
node: schemasField,
});
} else {
const schemasArray = schemasValue.items.map((e) => getStringLiteral(e)!);

if (defaultSchemaValue) {
// validate `defaultSchema` is included in `schemas`
if (!schemasArray.includes(defaultSchemaValue)) {
accept('error', `"${defaultSchemaValue}" must be included in the "schemas" array`, {
node: schemasField,
});
}
} else {
// if no explicit default schema is specified, and there are models or enums without '@@schema',
Comment thread
ymc9 marked this conversation as resolved.
// "public" is implicitly used, so it must be included in the "schemas" array
const hasImplicitPublicSchema = ds.$container.declarations.some(
(d) => (isDataModel(d) || isEnum(d)) && !d.attributes.some((a) => a.decl.$refText === '@@schema'),
);
if (hasImplicitPublicSchema && !schemasArray.includes('public')) {
accept('error', `"public" must be included in the "schemas" array`, {
node: schemasField,
});
}
}
}
}
}
Expand Down
69 changes: 69 additions & 0 deletions tests/e2e/orm/client-api/pg-custom-schema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,75 @@ model Foo {
).rejects.toThrow('"mySchema" must be included in the "schemas" array');
});

it('requires implicit public schema to be included in schemas', async () => {
await expect(
createTestClient(
`
datasource db {
provider = 'postgresql'
schemas = ['mySchema']
url = '$DB_URL'
}

enum Role {
ADMIN
USER
}

model Foo {
id Int @id
name String
role Role
@@schema('mySchema')
}

model Bar {
id Int @id
name String
}
`,
),
).rejects.toThrow('"public" must be included in the "schemas" array');
});
Comment thread
ymc9 marked this conversation as resolved.
Comment thread
ymc9 marked this conversation as resolved.

it('does not require public schema when all models and enums have explicit schema', async () => {
const db = await createTestClient(
`
datasource db {
provider = 'postgresql'
schemas = ['mySchema']
url = '$DB_URL'
}

enum Role {
ADMIN
USER
@@schema('mySchema')
}

model Foo {
id Int @id
name String
role Role
@@schema('mySchema')
}

model Bar {
id Int @id
name String
@@schema('mySchema')
}
`,
{
provider: 'postgresql',
usePrismaPush: true,
},
);

await expect(db.foo.create({ data: { id: 1, name: 'test', role: 'ADMIN' } })).toResolveTruthy();
await expect(db.bar.create({ data: { id: 1, name: 'test' } })).toResolveTruthy();
});

it('allows specifying schema only on a few models', async () => {
let fooQueriesVerified = false;
let barQueriesVerified = false;
Expand Down