1use crate::span::Span;
28use std::fmt;
29
30#[derive(Debug, Clone, PartialEq)]
32pub struct Schema {
33 pub declarations: Vec<Declaration>,
35 pub span: Span,
37}
38
39impl Schema {
40 pub fn new(declarations: Vec<Declaration>, span: Span) -> Self {
42 Self { declarations, span }
43 }
44
45 pub fn models(&self) -> impl Iterator<Item = &ModelDecl> {
47 self.declarations.iter().filter_map(|d| match d {
48 Declaration::Model(m) => Some(m),
49 _ => None,
50 })
51 }
52
53 pub fn enums(&self) -> impl Iterator<Item = &EnumDecl> {
55 self.declarations.iter().filter_map(|d| match d {
56 Declaration::Enum(e) => Some(e),
57 _ => None,
58 })
59 }
60
61 pub fn types(&self) -> impl Iterator<Item = &TypeDecl> {
63 self.declarations.iter().filter_map(|d| match d {
64 Declaration::Type(t) => Some(t),
65 _ => None,
66 })
67 }
68
69 pub fn datasource(&self) -> Option<&DatasourceDecl> {
71 self.declarations.iter().find_map(|d| match d {
72 Declaration::Datasource(ds) => Some(ds),
73 _ => None,
74 })
75 }
76
77 pub fn generator(&self) -> Option<&GeneratorDecl> {
79 self.declarations.iter().find_map(|d| match d {
80 Declaration::Generator(g) => Some(g),
81 _ => None,
82 })
83 }
84}
85
86#[derive(Debug, Clone, PartialEq)]
88pub enum Declaration {
89 Datasource(DatasourceDecl),
91 Generator(GeneratorDecl),
93 Model(ModelDecl),
95 Enum(EnumDecl),
97 Type(TypeDecl),
99}
100
101impl Declaration {
102 pub fn span(&self) -> Span {
104 match self {
105 Declaration::Datasource(d) => d.span,
106 Declaration::Generator(g) => g.span,
107 Declaration::Model(m) => m.span,
108 Declaration::Enum(e) => e.span,
109 Declaration::Type(t) => t.span,
110 }
111 }
112
113 pub fn name(&self) -> &str {
115 match self {
116 Declaration::Datasource(d) => &d.name.value,
117 Declaration::Generator(g) => &g.name.value,
118 Declaration::Model(m) => &m.name.value,
119 Declaration::Enum(e) => &e.name.value,
120 Declaration::Type(t) => &t.name.value,
121 }
122 }
123}
124
125#[derive(Debug, Clone, PartialEq)]
136pub struct DatasourceDecl {
137 pub name: Ident,
139 pub fields: Vec<ConfigField>,
141 pub span: Span,
143}
144
145impl DatasourceDecl {
146 pub fn find_field(&self, name: &str) -> Option<&ConfigField> {
148 self.fields.iter().find(|f| f.name.value == name)
149 }
150
151 pub fn provider(&self) -> Option<&str> {
153 self.find_field("provider").and_then(|f| match &f.value {
154 Expr::Literal(Literal::String(s, _)) => Some(s.as_str()),
155 _ => None,
156 })
157 }
158}
159
160#[derive(Debug, Clone, PartialEq)]
171pub struct GeneratorDecl {
172 pub name: Ident,
174 pub fields: Vec<ConfigField>,
176 pub span: Span,
178}
179
180impl GeneratorDecl {
181 pub fn find_field(&self, name: &str) -> Option<&ConfigField> {
183 self.fields.iter().find(|f| f.name.value == name)
184 }
185}
186
187#[derive(Debug, Clone, PartialEq)]
189pub struct ConfigField {
190 pub name: Ident,
192 pub value: Expr,
194 pub span: Span,
196}
197
198#[derive(Debug, Clone, PartialEq)]
210pub struct ModelDecl {
211 pub name: Ident,
213 pub fields: Vec<FieldDecl>,
215 pub attributes: Vec<ModelAttribute>,
217 pub span: Span,
219}
220
221impl ModelDecl {
222 pub fn find_field(&self, name: &str) -> Option<&FieldDecl> {
224 self.fields.iter().find(|f| f.name.value == name)
225 }
226
227 pub fn table_name(&self) -> &str {
229 self.attributes
230 .iter()
231 .find_map(|attr| match attr {
232 ModelAttribute::Map(name) => Some(name.as_str()),
233 _ => None,
234 })
235 .unwrap_or(&self.name.value)
236 }
237
238 pub fn has_composite_key(&self) -> bool {
240 self.attributes
241 .iter()
242 .any(|attr| matches!(attr, ModelAttribute::Id(_)))
243 }
244
245 pub fn relation_fields(&self) -> impl Iterator<Item = &FieldDecl> {
248 self.fields.iter().filter(|f| {
249 f.has_relation_attribute() || matches!(f.field_type, FieldType::UserType(_))
250 })
251 }
252}
253
254#[derive(Debug, Clone, PartialEq)]
256pub struct FieldDecl {
257 pub name: Ident,
259 pub field_type: FieldType,
261 pub modifier: FieldModifier,
263 pub attributes: Vec<FieldAttribute>,
265 pub span: Span,
267}
268
269impl FieldDecl {
270 pub fn is_optional(&self) -> bool {
272 matches!(self.modifier, FieldModifier::Optional)
273 }
274
275 pub fn is_not_null(&self) -> bool {
277 matches!(self.modifier, FieldModifier::NotNull)
278 }
279
280 pub fn is_array(&self) -> bool {
282 matches!(self.modifier, FieldModifier::Array)
283 }
284
285 pub fn find_attribute(&self, kind: &str) -> Option<&FieldAttribute> {
287 self.attributes.iter().find(|attr| {
288 matches!(
289 (kind, attr),
290 ("id", FieldAttribute::Id)
291 | ("unique", FieldAttribute::Unique)
292 | ("default", FieldAttribute::Default(_, _))
293 | ("map", FieldAttribute::Map(_))
294 | ("relation", FieldAttribute::Relation { .. })
295 | ("check", FieldAttribute::Check { .. })
296 )
297 })
298 }
299
300 pub fn has_relation_attribute(&self) -> bool {
302 self.attributes
303 .iter()
304 .any(|attr| matches!(attr, FieldAttribute::Relation { .. }))
305 }
306
307 pub fn column_name(&self) -> &str {
309 self.attributes
310 .iter()
311 .find_map(|attr| match attr {
312 FieldAttribute::Map(name) => Some(name.as_str()),
313 _ => None,
314 })
315 .unwrap_or(&self.name.value)
316 }
317}
318
319#[derive(Debug, Clone, Copy, PartialEq, Eq)]
321pub enum FieldModifier {
322 None,
324 Optional,
326 NotNull,
328 Array,
330}
331
332#[derive(Debug, Clone, PartialEq)]
334pub enum FieldType {
335 String,
337 Boolean,
339 Int,
341 BigInt,
343 Float,
345 Decimal {
347 precision: u32,
349 scale: u32,
351 },
352 DateTime,
354 Bytes,
356 Json,
358 Uuid,
360 Jsonb,
362 Xml,
364 Char {
366 length: u32,
368 },
369 VarChar {
371 length: u32,
373 },
374 UserType(String),
376}
377
378impl fmt::Display for FieldType {
379 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
380 match self {
381 FieldType::String => write!(f, "String"),
382 FieldType::Boolean => write!(f, "Boolean"),
383 FieldType::Int => write!(f, "Int"),
384 FieldType::BigInt => write!(f, "BigInt"),
385 FieldType::Float => write!(f, "Float"),
386 FieldType::Decimal { precision, scale } => {
387 write!(f, "Decimal({}, {})", precision, scale)
388 }
389 FieldType::DateTime => write!(f, "DateTime"),
390 FieldType::Bytes => write!(f, "Bytes"),
391 FieldType::Json => write!(f, "Json"),
392 FieldType::Uuid => write!(f, "Uuid"),
393 FieldType::Jsonb => write!(f, "Jsonb"),
394 FieldType::Xml => write!(f, "Xml"),
395 FieldType::Char { length } => write!(f, "Char({})", length),
396 FieldType::VarChar { length } => write!(f, "VarChar({})", length),
397 FieldType::UserType(name) => write!(f, "{}", name),
398 }
399 }
400}
401
402#[derive(Debug, Clone, Copy, PartialEq, Eq)]
404pub enum StorageStrategy {
405 Native,
407 Json,
409}
410
411#[derive(Debug, Clone, Copy, PartialEq, Eq)]
413pub enum ComputedKind {
414 Stored,
416 Virtual,
418}
419
420#[derive(Debug, Clone, PartialEq)]
422pub enum FieldAttribute {
423 Id,
425 Unique,
427 Default(Expr, Span),
430 Map(String),
432 Store {
434 strategy: StorageStrategy,
436 span: Span,
438 },
439 Relation {
441 name: Option<String>,
443 fields: Option<Vec<Ident>>,
445 references: Option<Vec<Ident>>,
447 on_delete: Option<ReferentialAction>,
449 on_update: Option<ReferentialAction>,
451 span: Span,
453 },
454 UpdatedAt {
456 span: Span,
458 },
459 Computed {
461 expr: crate::sql_expr::SqlExpr,
463 kind: ComputedKind,
465 span: Span,
467 },
468 Check {
470 expr: crate::bool_expr::BoolExpr,
472 span: Span,
474 },
475}
476
477#[derive(Debug, Clone, Copy, PartialEq, Eq)]
479pub enum ReferentialAction {
480 Cascade,
482 Restrict,
484 NoAction,
486 SetNull,
488 SetDefault,
490}
491
492impl fmt::Display for ReferentialAction {
493 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
494 match self {
495 ReferentialAction::Cascade => write!(f, "Cascade"),
496 ReferentialAction::Restrict => write!(f, "Restrict"),
497 ReferentialAction::NoAction => write!(f, "NoAction"),
498 ReferentialAction::SetNull => write!(f, "SetNull"),
499 ReferentialAction::SetDefault => write!(f, "SetDefault"),
500 }
501 }
502}
503
504#[derive(Debug, Clone, PartialEq)]
506pub enum ModelAttribute {
507 Map(String),
509 Id(Vec<Ident>),
511 Unique(Vec<Ident>),
513 Index {
515 fields: Vec<Ident>,
517 index_type: Option<Ident>,
519 name: Option<String>,
521 map: Option<String>,
523 },
524 Check {
526 expr: crate::bool_expr::BoolExpr,
528 span: Span,
530 },
531}
532
533#[derive(Debug, Clone, PartialEq)]
544pub struct EnumDecl {
545 pub name: Ident,
547 pub variants: Vec<EnumVariant>,
549 pub span: Span,
551}
552
553#[derive(Debug, Clone, PartialEq)]
569pub struct TypeDecl {
570 pub name: Ident,
572 pub fields: Vec<FieldDecl>,
574 pub span: Span,
576}
577
578impl TypeDecl {
579 pub fn find_field(&self, name: &str) -> Option<&FieldDecl> {
581 self.fields.iter().find(|f| f.name.value == name)
582 }
583}
584
585#[derive(Debug, Clone, PartialEq)]
587pub struct EnumVariant {
588 pub name: Ident,
590 pub span: Span,
592}
593
594#[derive(Debug, Clone, PartialEq, Eq, Hash)]
596pub struct Ident {
597 pub value: String,
599 pub span: Span,
601}
602
603impl Ident {
604 pub fn new(value: String, span: Span) -> Self {
606 Self { value, span }
607 }
608}
609
610impl fmt::Display for Ident {
611 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
612 write!(f, "{}", self.value)
613 }
614}
615
616#[derive(Debug, Clone, PartialEq)]
618pub enum Expr {
619 Literal(Literal),
621 FunctionCall {
623 name: Ident,
625 args: Vec<Expr>,
627 span: Span,
629 },
630 Array {
632 elements: Vec<Expr>,
634 span: Span,
636 },
637 NamedArg {
639 name: Ident,
641 value: Box<Expr>,
643 span: Span,
645 },
646 Ident(Ident),
648}
649
650impl Expr {
651 pub fn span(&self) -> Span {
653 match self {
654 Expr::Literal(lit) => lit.span(),
655 Expr::FunctionCall { span, .. } => *span,
656 Expr::Array { span, .. } => *span,
657 Expr::NamedArg { span, .. } => *span,
658 Expr::Ident(ident) => ident.span,
659 }
660 }
661}
662
663#[derive(Debug, Clone, PartialEq)]
665pub enum Literal {
666 String(String, Span),
668 Number(String, Span),
670 Boolean(bool, Span),
672}
673
674impl Literal {
675 pub fn span(&self) -> Span {
677 match self {
678 Literal::String(_, span) => *span,
679 Literal::Number(_, span) => *span,
680 Literal::Boolean(_, span) => *span,
681 }
682 }
683}
684
685#[cfg(test)]
686mod tests {
687 use super::*;
688
689 #[test]
690 fn test_field_modifier() {
691 assert_eq!(FieldModifier::None, FieldModifier::None);
692 assert_ne!(FieldModifier::Optional, FieldModifier::Array);
693 }
694
695 #[test]
696 fn test_field_type_display() {
697 assert_eq!(FieldType::String.to_string(), "String");
698 assert_eq!(FieldType::Int.to_string(), "Int");
699 assert_eq!(
700 FieldType::Decimal {
701 precision: 10,
702 scale: 2
703 }
704 .to_string(),
705 "Decimal(10, 2)"
706 );
707 }
708
709 #[test]
710 fn test_ident() {
711 let ident = Ident::new("test".to_string(), Span::new(0, 4));
712 assert_eq!(ident.value, "test");
713 assert_eq!(ident.to_string(), "test");
714 }
715
716 #[test]
717 fn test_referential_action_display() {
718 assert_eq!(ReferentialAction::Cascade.to_string(), "Cascade");
719 assert_eq!(ReferentialAction::SetNull.to_string(), "SetNull");
720 }
721
722 #[test]
723 fn test_model_table_name() {
724 let model = ModelDecl {
725 name: Ident::new("User".to_string(), Span::new(0, 4)),
726 fields: vec![],
727 attributes: vec![ModelAttribute::Map("users".to_string())],
728 span: Span::new(0, 10),
729 };
730 assert_eq!(model.table_name(), "users");
731 }
732
733 #[test]
734 fn test_model_table_name_default() {
735 let model = ModelDecl {
736 name: Ident::new("User".to_string(), Span::new(0, 4)),
737 fields: vec![],
738 attributes: vec![],
739 span: Span::new(0, 10),
740 };
741 assert_eq!(model.table_name(), "User");
742 }
743
744 #[test]
745 fn test_field_column_name() {
746 let field = FieldDecl {
747 name: Ident::new("userId".to_string(), Span::new(0, 6)),
748 field_type: FieldType::Int,
749 modifier: FieldModifier::None,
750 attributes: vec![FieldAttribute::Map("user_id".to_string())],
751 span: Span::new(0, 20),
752 };
753 assert_eq!(field.column_name(), "user_id");
754 }
755
756 #[test]
757 fn test_schema_helpers() {
758 let schema = Schema {
759 declarations: vec![
760 Declaration::Model(ModelDecl {
761 name: Ident::new("User".to_string(), Span::new(0, 4)),
762 fields: vec![],
763 attributes: vec![],
764 span: Span::new(0, 10),
765 }),
766 Declaration::Enum(EnumDecl {
767 name: Ident::new("Role".to_string(), Span::new(0, 4)),
768 variants: vec![],
769 span: Span::new(0, 10),
770 }),
771 ],
772 span: Span::new(0, 100),
773 };
774
775 assert_eq!(schema.models().count(), 1);
776 assert_eq!(schema.enums().count(), 1);
777 assert!(schema.datasource().is_none());
778 }
779}