// Prax Schema Definition Language Grammar
// =========================================
// A Pest grammar for parsing .prax schema files
// Main entry point
schema = {
SOI ~
(documentation | datasource_def | generator_def | model_def | enum_def | type_def | view_def | server_group_def | policy_def | raw_sql_def | NEWLINE)* ~
EOI
}
// ============================================================================
// DATASOURCE DEFINITION
// ============================================================================
// Datasource block: datasource db { provider = "postgresql" extensions = [vector, pg_trgm] }
datasource_def = {
"datasource" ~ identifier ~ "{" ~ NEWLINE* ~
(datasource_property ~ NEWLINE*)* ~
"}"
}
// Datasource property: key = value
datasource_property = {
identifier ~ "=" ~ datasource_value
}
// Datasource value types
datasource_value = {
env_function |
extension_array |
string_literal |
identifier
}
// Environment function: env("DATABASE_URL")
env_function = {
"env" ~ "(" ~ string_literal ~ ")"
}
// Extension array: [vector, pg_trgm, postgis]
extension_array = {
"[" ~ (extension_item ~ ("," ~ extension_item)*)? ~ "]"
}
// Extension item: can be identifier or function call for schema/version
extension_item = {
identifier ~ extension_args? |
identifier
}
// Extension arguments: (schema: "public", version: "0.5.0")
extension_args = {
"(" ~ (extension_arg ~ ("," ~ extension_arg)*)? ~ ")"
}
// Extension argument: schema: "public"
extension_arg = {
identifier ~ ":" ~ string_literal
}
// ============================================================================
// GENERATOR DEFINITION (for code generation configuration)
// ============================================================================
generator_def = {
"generator" ~ identifier ~ "{" ~ NEWLINE* ~
(datasource_property ~ NEWLINE*)* ~
"}"
}
// ============================================================================
// WHITESPACE AND COMMENTS
// ============================================================================
WHITESPACE = _{ " " | "\t" }
NEWLINE = _{ "\r\n" | "\n" | "\r" }
COMMENT = _{ "//" ~ (!NEWLINE ~ ANY)* }
// Documentation comments (triple slash)
documentation = { (doc_line ~ NEWLINE?)+ }
doc_line = @{ "///" ~ (!NEWLINE ~ ANY)* }
// ============================================================================
// LITERALS
// ============================================================================
// String literal (double quotes)
string_literal = @{ "\"" ~ string_content ~ "\"" }
string_content = @{ (!"\"" ~ ANY)* }
// Multi-line string (triple quotes)
multiline_string = @{ "\"\"\"" ~ multiline_content ~ "\"\"\"" }
multiline_content = @{ (!"\"\"\"" ~ ANY)* }
// Number literals
number_literal = @{ "-"? ~ ASCII_DIGIT+ ~ ("." ~ ASCII_DIGIT+)? }
// Boolean literals
boolean_literal = @{ "true" | "false" }
// ============================================================================
// IDENTIFIERS AND TYPES
// ============================================================================
// Basic identifier (PascalCase or snake_case)
identifier = @{ ASCII_ALPHA ~ (ASCII_ALPHANUMERIC | "_")* }
// Type name (same as identifier but semantic)
type_name = @{ ASCII_ALPHA ~ (ASCII_ALPHANUMERIC | "_")* }
// Field type with optional modifiers
field_type = {
type_name ~ list_marker? ~ optional_marker? |
type_name ~ optional_marker? ~ list_marker?
}
optional_marker = { "?" }
list_marker = { "[]" }
// ============================================================================
// ATTRIBUTES
// ============================================================================
// Field-level attribute: @name or @name(args)
field_attribute = {
"@" ~ attribute_name ~ attribute_args?
}
// Model-level attribute: @@name or @@name(args)
model_attribute = {
"@@" ~ attribute_name ~ attribute_args?
}
// Attribute name (can include dots for namespacing like @db.VarChar)
attribute_name = @{ identifier ~ ("." ~ identifier)? }
// Attribute arguments
attribute_args = {
"(" ~ (attribute_arg ~ ("," ~ attribute_arg)*)? ~ ")"
}
// Single attribute argument (named or positional)
attribute_arg = {
identifier ~ ":" ~ attribute_value |
attribute_value
}
// Attribute value types
attribute_value = {
function_call |
field_ref_list |
array_literal |
string_literal |
number_literal |
boolean_literal |
identifier
}
// Function call: now(), uuid(), etc.
function_call = {
identifier ~ "(" ~ (attribute_value ~ ("," ~ attribute_value)*)? ~ ")"
}
// Field reference list: [field1, field2]
field_ref_list = {
"[" ~ identifier ~ ("," ~ identifier)* ~ "]"
}
// Array literal: [value1, value2]
array_literal = {
"[" ~ (attribute_value ~ ("," ~ attribute_value)*)? ~ "]"
}
// ============================================================================
// MODEL DEFINITION
// ============================================================================
model_def = {
"model" ~ identifier ~ "{" ~ NEWLINE* ~
(model_body_item ~ NEWLINE*)* ~
"}"
}
model_body_item = {
field_def |
model_attribute
}
// Field definition: name Type @attr1 @attr2
field_def = {
identifier ~ field_type ~ field_attribute*
}
// ============================================================================
// ENUM DEFINITION
// ============================================================================
enum_def = {
"enum" ~ identifier ~ "{" ~ NEWLINE* ~
(enum_body_item ~ NEWLINE*)* ~
"}"
}
enum_body_item = {
enum_variant |
model_attribute
}
// Enum variant: Name or Name @map("value")
enum_variant = {
identifier ~ field_attribute*
}
// ============================================================================
// COMPOSITE TYPE DEFINITION
// ============================================================================
type_def = {
"type" ~ identifier ~ "{" ~ NEWLINE* ~
(field_def ~ NEWLINE*)* ~
"}"
}
// ============================================================================
// VIEW DEFINITION
// ============================================================================
view_def = {
"view" ~ identifier ~ "{" ~ NEWLINE* ~
(model_body_item ~ NEWLINE*)* ~
"}"
}
// ============================================================================
// SERVER GROUP DEFINITION
// ============================================================================
// Server group for multi-server configurations (replicas, shards, regions)
server_group_def = {
"serverGroup" ~ identifier ~ "{" ~ NEWLINE* ~
(server_group_item ~ NEWLINE*)* ~
"}"
}
server_group_item = {
server_def |
model_attribute
}
// Individual server definition within a group
server_def = {
"server" ~ identifier ~ "{" ~ NEWLINE* ~
(server_property ~ NEWLINE*)* ~
"}"
}
// Server property: key = value
server_property = {
identifier ~ "=" ~ attribute_value
}
// ============================================================================
// RAW SQL DEFINITION
// ============================================================================
raw_sql_def = {
"@@sql" ~ "(" ~ string_literal ~ "," ~ multiline_string ~ ")"
}
// ============================================================================
// POLICY DEFINITION (PostgreSQL Row-Level Security)
// ============================================================================
// Policy block: policy PolicyName on ModelName { ... }
policy_def = {
"policy" ~ identifier ~ "on" ~ identifier ~ "{" ~ NEWLINE* ~
(policy_item ~ NEWLINE*)* ~
"}"
}
// Policy item: one of the policy properties
policy_item = {
policy_for |
policy_to |
policy_as |
policy_using |
policy_check |
policy_mssql_schema |
policy_mssql_block
}
// FOR clause: for SELECT | for [SELECT, UPDATE, DELETE]
policy_for = {
"for" ~ (policy_command_list | policy_command)
}
// Single command: SELECT, INSERT, UPDATE, DELETE, ALL
policy_command = @{
"ALL" | "All" | "all" |
"SELECT" | "Select" | "select" |
"INSERT" | "Insert" | "insert" |
"UPDATE" | "Update" | "update" |
"DELETE" | "Delete" | "delete"
}
// Command list: [SELECT, UPDATE, DELETE]
policy_command_list = {
"[" ~ policy_command ~ ("," ~ policy_command)* ~ "]"
}
// TO clause: to authenticated | to [authenticated, admin]
policy_to = {
"to" ~ (policy_role_list | identifier)
}
// Role list: [authenticated, admin]
policy_role_list = {
"[" ~ identifier ~ ("," ~ identifier)* ~ "]"
}
// AS clause: as PERMISSIVE | as RESTRICTIVE
policy_as = {
"as" ~ policy_type
}
// Policy type: PERMISSIVE or RESTRICTIVE
policy_type = @{
"PERMISSIVE" | "Permissive" | "permissive" |
"RESTRICTIVE" | "Restrictive" | "restrictive"
}
// USING clause: using "expression"
policy_using = {
"using" ~ (multiline_string | string_literal)
}
// CHECK clause: check "expression"
policy_check = {
"check" ~ (multiline_string | string_literal)
}
// MSSQL schema clause: mssqlSchema "Security"
policy_mssql_schema = {
"mssqlSchema" ~ string_literal
}
// MSSQL block operations clause: mssqlBlock [AFTER_INSERT, BEFORE_DELETE]
policy_mssql_block = {
"mssqlBlock" ~ (mssql_block_op_list | mssql_block_op)
}
// Single MSSQL block operation
mssql_block_op = @{
"AFTER_INSERT" | "AfterInsert" | "after_insert" |
"AFTER_UPDATE" | "AfterUpdate" | "after_update" |
"BEFORE_UPDATE" | "BeforeUpdate" | "before_update" |
"BEFORE_DELETE" | "BeforeDelete" | "before_delete"
}
// MSSQL block operation list: [AFTER_INSERT, BEFORE_DELETE]
mssql_block_op_list = {
"[" ~ mssql_block_op ~ ("," ~ mssql_block_op)* ~ "]"
}