Validation Pipeline
The validation pipeline transforms a parsed AST into a semantically validated schema. This is handled by theparser-database and psl-core crates.
Parser Database
TheParserDatabase is the core container for validated schema information:
Purpose and Scope
The parser database is connector-agnostic - it performs generic validations that apply to all databases:- Name resolution and uniqueness
- Type checking
- Relationship validation
- Attribute syntax validation
- Constraint name generation
psl-core.
ParserDatabase never fails. It accumulates diagnostics while building as complete a database as possible, even with errors in the schema.
Validation Phases
Validation proceeds in four phases:1. Name Resolution
First pass: resolve all identifiers to IDs- Models and views
- Enums
- Composite types
- Fields (model fields, composite fields)
- Datasources
- Generators
2. Type Resolution
Second pass: resolve type references- Resolve type identifier to its definition
- Determine if it’s a scalar, relation, enum, or composite
- Handle optional/required/list arity
- Validate type compatibility
3. Attribute Validation
Third pass: validate attributes on models and fields- Required vs. optional arguments
- Argument types
- Attribute compatibility
- Duplicate attributes
4. Global Validations
Fourth pass: cross-cutting validations- Relation completeness and consistency
- Index name collisions
- Unique constraint validation
- Primary key requirements
- Referential actions compatibility
Database Structure
String Interning
Efficient string storage:- Reduced memory usage
- Fast string comparison (compare IDs)
- Canonical representation
Type System
Relations
Walker API
The walker API provides type-safe schema traversal:Walker Types
- Safe access to schema data
- Navigation between related items
- Computed properties
- Database name resolution
Walkers borrow from ParserDatabase, ensuring data consistency. They’re lightweight and can be created on-demand.
Validation Examples
Name Uniqueness
DatamodelError::new_duplicate_top_error("User", ...)
Type Resolution
Relation Validation
Attribute Validation
Constraint Names
The database generates default constraint names:Constraint name generation is connector-specific, handled by the connector trait’s
constraint_violation_scopes() method.Reserved Names
Certain names are reserved and validated:Index Definitions
Indexes are validated and stored:Extension Types
Support for custom types via extensions:Diagnostic Collection
Diagnostics accumulate throughout validation:Error Types
Validation Pipeline Entry Points
Single File
Multi-File
Parse Only (Skip Validation)
Testing
PSL uses declarative validation tests:Tests with no error comment at the end expect a valid schema. Tests with error comments expect those exact errors.
Configuration Parsing
Parse only datasource and generator blocks:Common Validations
Primary Key Validation
- Every model needs an
@idor@@id - Single-field or compound primary keys
- Primary key fields cannot be optional
Unique Constraint Validation
- Single-field
@uniqueor compound@@unique - Unique fields can be optional
- Unique constraints can have names via
map:
Relation Validation
- Both sides of relation must have fields
- Referencing fields must match referenced fields in type and count
- Referential actions must be supported by the connector
Default Value Validation
- Default must match field type
- Functions like
autoincrement(),now(),uuid()validated per connector - Constants validated for type compatibility
Next Steps
Connectors
Learn about database-specific validations
Parser
Understand the AST and parsing phase