Source Model
A Saeril package contains one or more modules. A module may define:
Saeril source files are UTF-8 text. Newlines are significant only where they terminate declarations or improve diagnostics. Braces define declaration bodies.
- Databases.
- Entities.
- Enums.
- Indexes scoped to entities.
- Migration blocks.
Modules
A file begins with a module declaration.
- Exactly one module declaration is allowed per file.
- Module names use dot-separated identifiers.
- The module name participates in emitted VTI type_id values.
Databases
A database block names the database provider, logical database name, and optional extensions.
Supported v0.3 fields:
database postgres "main" { extension "uuid-ossp"}Entities
An entity declares a persisted type.
- Entity names use PascalCase.
- The table clause is required for persisted entities.
- Table names are quoted strings.
- Field names use snake_case.
- Each entity emits a VTI record or row declaration with facts.storage.relational.
- Field order is stable and is preserved in VTI.
entity User table "users" { id: Uuid @primary email: String @unique @max(320) display_name: String? @max(120) status: UserStatus @default(active)}Field Declarations
? marks nullable type syntax. String? maps to VTI nullable of scalar String. T[] marks an array column. Struct { ... } declares an inline composite value.
Marks a field as part of the primary key.
Adds a uniqueness constraint for the field.
- At least one primary key field is required per persisted entity.
- Multiple @primary fields form a composite primary key in declaration order.
- Primary fields are required and cannot be nullable.
- N must be a positive integer.
- @max is valid only on String.
- The value maps to VTI scalar String.max_length.
- Defaults must type-check against the field type.
- Provider functions such as now() must be supported by the selected database provider.
id: Uuid @primaryemail: String @unique @max(320)deleted_at: DateTime?account_id: Uuid @ref(Account.id) @on_delete(restrict)total: Decimal(12, 2) @check("total >= 0") @indextags: Text[]metadata: Jsonb?shipping_address: Struct { city: Text zip: String? }display_name: Text @generated("email")Enums
Enum with storage values:
- Enum names use PascalCase.
- Variants use snake_case.
- Variant order is stable and emitted to VTI.
- Removing or renaming a variant is a breaking change.
- Adding a variant may be breaking for exhaustive consumers unless policy allows unknown handling.
enum UserStatus { active suspended archived}Indexes
Indexes may be declared inside an entity.
- SQL index names are emitted as idx_{table}_{NAME}.
- Fields must exist on the entity.
- Field order is preserved.
- where creates a partial index and is emitted to VTI as where.
- Partial predicates must reference fields on the entity and type-check as boolean expressions.
entity User table "users" { id: Uuid @primary email: String @max(320) deleted_at: DateTime? index active_email on (email) where deleted_at == null index deleted_at_desc on (deleted_at desc)}Entity Constraints
Entity constraints are declared inside an entity body.
- check NAME ("PREDICATE") emits a named table-level CHECK.
- unique NAME on (FIELD_LIST) emits a composite unique index named uq_{table}_{NAME}.
- Constraint names must be unique within the entity.
- Unique fields must exist on the entity.
entity Invoice table "invoices" { id: Uuid @primary account_id: Uuid invoice_number: String total: Decimal(12, 2) check positive_total ("total >= 0") unique account_invoice on (account_id, invoice_number)}Seed Data
An entity may include an optional seed block.
Seed rows are emitted as INSERT statements when a table is created. String and enum values are SQL-quoted, numeric values are emitted directly, and true, false, and null map to SQL keywords.
entity Plan table "plans" { id: Uuid @primary code: Text @unique name: Text seed { row { id: "018f", code: "free", name: "Free" } row { id: "0190", code: "pro", name: "Pro" } }}Download
Saeril is in active development and has no public downloads or releases yet.
No public download artifacts are available yet for this language.
Looking for everything in one place? See the downloads index.
