prax_schema/
lib.rs

1//! # prax-schema
2//!
3//! Schema parser and AST for the Prax ORM.
4//!
5//! This crate provides:
6//! - Schema Definition Language (SDL) parser for `.prax` files
7//! - Configuration parser for `prax.toml` files
8//! - Abstract Syntax Tree (AST) types for schema representation
9//! - Schema validation and semantic analysis
10//!
11//! ## Quick Start
12//!
13//! Parse a schema string:
14//!
15//! ```rust
16//! use prax_schema::parse_schema;
17//!
18//! let schema = parse_schema(r#"
19//! model User {
20//!     id    Int    @id @auto
21//!     email String @unique
22//!     name  String?
23//! }
24//! "#).unwrap();
25//!
26//! assert!(schema.get_model("User").is_some());
27//! ```
28//!
29//! ## Parsing Models
30//!
31//! Models define database tables with typed fields:
32//!
33//! ```rust
34//! use prax_schema::parse_schema;
35//!
36//! let schema = parse_schema(r#"
37//! model Post {
38//!     id        Int      @id @auto
39//!     title     String
40//!     content   String?
41//!     published Boolean  @default(false)
42//!     viewCount Int      @default(0)
43//! }
44//! "#).unwrap();
45//!
46//! let post = schema.get_model("Post").unwrap();
47//! assert_eq!(post.fields.len(), 5);
48//!
49//! // Check field properties
50//! let title = post.fields.get("title").unwrap();
51//! assert!(!title.is_optional());
52//!
53//! let content = post.fields.get("content").unwrap();
54//! assert!(content.is_optional());
55//! ```
56//!
57//! ## Parsing Enums
58//!
59//! Enums define custom value types:
60//!
61//! ```rust
62//! use prax_schema::parse_schema;
63//!
64//! let schema = parse_schema(r#"
65//! enum Role {
66//!     User
67//!     Admin
68//!     Moderator
69//! }
70//!
71//! model User {
72//!     id   Int  @id @auto
73//!     role Role @default(User)
74//! }
75//! "#).unwrap();
76//!
77//! let role_enum = schema.get_enum("Role").unwrap();
78//! assert_eq!(role_enum.variants.len(), 3);
79//! ```
80//!
81//! ## Parsing Relations
82//!
83//! Relations define relationships between models:
84//!
85//! ```rust
86//! use prax_schema::parse_schema;
87//!
88//! let schema = parse_schema(r#"
89//! model User {
90//!     id    Int    @id @auto
91//!     posts Post[]
92//! }
93//!
94//! model Post {
95//!     id       Int  @id @auto
96//!     authorId Int
97//!     author   User @relation(fields: [authorId], references: [id])
98//! }
99//! "#).unwrap();
100//!
101//! let post = schema.get_model("Post").unwrap();
102//! let author_field = post.fields.get("author").unwrap();
103//! assert!(author_field.is_relation());
104//! ```
105//!
106//! ## Parsing Views
107//!
108//! Views represent SQL views:
109//!
110//! ```rust
111//! use prax_schema::parse_schema;
112//!
113//! let schema = parse_schema(r#"
114//! model User {
115//!     id     Int    @id @auto
116//!     active Boolean
117//! }
118//!
119//! view ActiveUsers {
120//!     id Int @unique
121//!
122//!     @@map("active_users_view")
123//! }
124//! "#).unwrap();
125//!
126//! assert!(schema.get_view("ActiveUsers").is_some());
127//! ```
128//!
129//! ## Parsing Server Groups
130//!
131//! Server groups define multi-server configurations:
132//!
133//! ```rust
134//! use prax_schema::parse_schema;
135//!
136//! let schema = parse_schema(r#"
137//! serverGroup MainCluster {
138//!     server primary {
139//!         url  = "postgres://primary/db"
140//!         role = "primary"
141//!     }
142//!
143//!     server replica1 {
144//!         url    = "postgres://replica1/db"
145//!         role   = "replica"
146//!         weight = 100
147//!     }
148//!
149//!     @@strategy("ReadReplica")
150//!     @@loadBalance("RoundRobin")
151//! }
152//! "#).unwrap();
153//!
154//! let cluster = schema.get_server_group("MainCluster").unwrap();
155//! assert_eq!(cluster.servers.len(), 2);
156//! ```
157//!
158//! ## Schema Validation
159//!
160//! Validate schemas for correctness:
161//!
162//! ```rust
163//! use prax_schema::validate_schema;
164//!
165//! // Valid schema passes validation
166//! let result = validate_schema(r#"
167//! model User {
168//!     id    Int    @id @auto
169//!     email String @unique
170//! }
171//! "#);
172//! assert!(result.is_ok());
173//!
174//! // Schema with relations validates correctly
175//! let result = validate_schema(r#"
176//! model User {
177//!     id    Int    @id @auto
178//!     posts Post[]
179//! }
180//! model Post {
181//!     id       Int  @id @auto
182//!     authorId Int
183//!     author   User @relation(fields: [authorId], references: [id])
184//! }
185//! "#);
186//! assert!(result.is_ok());
187//! ```
188//!
189//! ## Schema Statistics
190//!
191//! Get statistics about a schema:
192//!
193//! ```rust
194//! use prax_schema::parse_schema;
195//!
196//! let schema = parse_schema(r#"
197//! model User { id Int @id @auto }
198//! model Post { id Int @id @auto }
199//! enum Role { User Admin }
200//! type Address { street String }
201//! "#).unwrap();
202//!
203//! let stats = schema.stats();
204//! assert_eq!(stats.model_count, 2);
205//! assert_eq!(stats.enum_count, 1);
206//! assert_eq!(stats.type_count, 1);
207//! ```
208//!
209//! ## Configuration Parsing
210//!
211//! Parse `prax.toml` configuration:
212//!
213//! ```rust
214//! use prax_schema::config::PraxConfig;
215//!
216//! let config: PraxConfig = toml::from_str(r#"
217//! [database]
218//! provider = "postgresql"
219//! url = "postgres://localhost/mydb"
220//!
221//! [database.pool]
222//! max_connections = 10
223//!
224//! [generator.client]
225//! output = "./src/generated"
226//! "#).unwrap();
227//!
228//! assert_eq!(config.database.pool.max_connections, 10);
229//! ```
230//!
231//! ## Prelude
232//!
233//! Import commonly used types:
234//!
235//! ```rust
236//! use prax_schema::prelude::*;
237//!
238//! // Now you can use parse_schema, Schema, etc.
239//! let schema = parse_schema("model User { id Int @id }").unwrap();
240//! ```
241
242pub mod ast;
243pub mod cache;
244pub mod config;
245pub mod error;
246pub mod parser;
247pub mod validator;
248
249pub use ast::*;
250pub use cache::{SchemaCache, DocString, CacheStats, LazyFieldAttrs, FieldAttrsCache, ValidationTypePool};
251pub use config::PraxConfig;
252pub use error::{SchemaError, SchemaResult};
253pub use parser::{parse_schema, parse_schema_file};
254pub use validator::{Validator, validate_schema};
255
256/// Prelude module for convenient imports.
257pub mod prelude {
258    pub use crate::ast::*;
259    pub use crate::cache::{SchemaCache, DocString};
260    pub use crate::config::PraxConfig;
261    pub use crate::error::{SchemaError, SchemaResult};
262    pub use crate::parser::{parse_schema, parse_schema_file};
263    pub use crate::validator::{Validator, validate_schema};
264}