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(_))
251 })
252 }
253}
254
255#[derive(Debug, Clone, PartialEq)]
257pub struct FieldDecl {
258 pub name: Ident,
260 pub field_type: FieldType,
262 pub modifier: FieldModifier,
264 pub attributes: Vec<FieldAttribute>,
266 pub span: Span,
268}
269
270impl FieldDecl {
271 pub fn is_optional(&self) -> bool {
273 matches!(self.modifier, FieldModifier::Optional)
274 }
275
276 pub fn is_not_null(&self) -> bool {
278 matches!(self.modifier, FieldModifier::NotNull)
279 }
280
281 pub fn is_array(&self) -> bool {
283 matches!(self.modifier, FieldModifier::Array)
284 }
285
286 pub fn find_attribute(&self, kind: &str) -> Option<&FieldAttribute> {
288 self.attributes.iter().find(|attr| {
289 matches!(
290 (kind, attr),
291 ("id", FieldAttribute::Id)
292 | ("unique", FieldAttribute::Unique)
293 | ("default", FieldAttribute::Default(_, _))
294 | ("map", FieldAttribute::Map(_))
295 | ("relation", FieldAttribute::Relation { .. })
296 | ("check", FieldAttribute::Check { .. })
297 )
298 })
299 }
300
301 pub fn has_relation_attribute(&self) -> bool {
303 self.attributes
304 .iter()
305 .any(|attr| matches!(attr, FieldAttribute::Relation { .. }))
306 }
307
308 pub fn column_name(&self) -> &str {
310 self.attributes
311 .iter()
312 .find_map(|attr| match attr {
313 FieldAttribute::Map(name) => Some(name.as_str()),
314 _ => None,
315 })
316 .unwrap_or(&self.name.value)
317 }
318}
319
320#[derive(Debug, Clone, Copy, PartialEq, Eq)]
322pub enum FieldModifier {
323 None,
325 Optional,
327 NotNull,
329 Array,
331}
332
333#[derive(Debug, Clone, PartialEq)]
335pub enum FieldType {
336 String,
338 Boolean,
340 Int,
342 BigInt,
344 Float,
346 Decimal {
348 precision: u32,
350 scale: u32,
352 },
353 DateTime,
355 Bytes,
357 Json,
359 Uuid,
361 Jsonb,
363 Xml,
365 Char {
367 length: u32,
369 },
370 VarChar {
372 length: u32,
374 },
375 UserType(String),
377}
378
379impl fmt::Display for FieldType {
380 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
381 match self {
382 FieldType::String => write!(f, "String"),
383 FieldType::Boolean => write!(f, "Boolean"),
384 FieldType::Int => write!(f, "Int"),
385 FieldType::BigInt => write!(f, "BigInt"),
386 FieldType::Float => write!(f, "Float"),
387 FieldType::Decimal { precision, scale } => {
388 write!(f, "Decimal({}, {})", precision, scale)
389 }
390 FieldType::DateTime => write!(f, "DateTime"),
391 FieldType::Bytes => write!(f, "Bytes"),
392 FieldType::Json => write!(f, "Json"),
393 FieldType::Uuid => write!(f, "Uuid"),
394 FieldType::Jsonb => write!(f, "Jsonb"),
395 FieldType::Xml => write!(f, "Xml"),
396 FieldType::Char { length } => write!(f, "Char({})", length),
397 FieldType::VarChar { length } => write!(f, "VarChar({})", length),
398 FieldType::UserType(name) => write!(f, "{}", name),
399 }
400 }
401}
402
403#[derive(Debug, Clone, Copy, PartialEq, Eq)]
405pub enum StorageStrategy {
406 Native,
408 Json,
410}
411
412#[derive(Debug, Clone, Copy, PartialEq, Eq)]
414pub enum ComputedKind {
415 Stored,
417 Virtual,
419}
420
421#[derive(Debug, Clone, PartialEq)]
423pub enum FieldAttribute {
424 Id,
426 Unique,
428 Default(Expr, Span),
431 Map(String),
433 Store {
435 strategy: StorageStrategy,
437 span: Span,
439 },
440 Relation {
442 name: Option<String>,
444 fields: Option<Vec<Ident>>,
446 references: Option<Vec<Ident>>,
448 on_delete: Option<ReferentialAction>,
450 on_update: Option<ReferentialAction>,
452 span: Span,
454 },
455 UpdatedAt {
457 span: Span,
459 },
460 Computed {
462 expr: crate::sql_expr::SqlExpr,
464 kind: ComputedKind,
466 span: Span,
468 },
469 Check {
471 expr: crate::bool_expr::BoolExpr,
473 span: Span,
475 },
476}
477
478#[derive(Debug, Clone, Copy, PartialEq, Eq)]
480pub enum ReferentialAction {
481 Cascade,
483 Restrict,
485 NoAction,
487 SetNull,
489 SetDefault,
491}
492
493impl fmt::Display for ReferentialAction {
494 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
495 match self {
496 ReferentialAction::Cascade => write!(f, "Cascade"),
497 ReferentialAction::Restrict => write!(f, "Restrict"),
498 ReferentialAction::NoAction => write!(f, "NoAction"),
499 ReferentialAction::SetNull => write!(f, "SetNull"),
500 ReferentialAction::SetDefault => write!(f, "SetDefault"),
501 }
502 }
503}
504
505#[derive(Debug, Clone, PartialEq)]
507pub enum ModelAttribute {
508 Map(String),
510 Id(Vec<Ident>),
512 Unique(Vec<Ident>),
514 Index {
516 fields: Vec<Ident>,
518 index_type: Option<Ident>,
520 name: Option<String>,
522 map: Option<String>,
524 },
525 Check {
527 expr: crate::bool_expr::BoolExpr,
529 span: Span,
531 },
532}
533
534#[derive(Debug, Clone, PartialEq)]
545pub struct EnumDecl {
546 pub name: Ident,
548 pub variants: Vec<EnumVariant>,
550 pub span: Span,
552}
553
554#[derive(Debug, Clone, PartialEq)]
570pub struct TypeDecl {
571 pub name: Ident,
573 pub fields: Vec<FieldDecl>,
575 pub span: Span,
577}
578
579impl TypeDecl {
580 pub fn find_field(&self, name: &str) -> Option<&FieldDecl> {
582 self.fields.iter().find(|f| f.name.value == name)
583 }
584}
585
586#[derive(Debug, Clone, PartialEq)]
588pub struct EnumVariant {
589 pub name: Ident,
591 pub span: Span,
593}
594
595#[derive(Debug, Clone, PartialEq, Eq, Hash)]
597pub struct Ident {
598 pub value: String,
600 pub span: Span,
602}
603
604impl Ident {
605 pub fn new(value: String, span: Span) -> Self {
607 Self { value, span }
608 }
609}
610
611impl fmt::Display for Ident {
612 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
613 write!(f, "{}", self.value)
614 }
615}
616
617#[derive(Debug, Clone, PartialEq)]
619pub enum Expr {
620 Literal(Literal),
622 FunctionCall {
624 name: Ident,
626 args: Vec<Expr>,
628 span: Span,
630 },
631 Array {
633 elements: Vec<Expr>,
635 span: Span,
637 },
638 NamedArg {
640 name: Ident,
642 value: Box<Expr>,
644 span: Span,
646 },
647 Ident(Ident),
649}
650
651impl Expr {
652 pub fn span(&self) -> Span {
654 match self {
655 Expr::Literal(lit) => lit.span(),
656 Expr::FunctionCall { span, .. } => *span,
657 Expr::Array { span, .. } => *span,
658 Expr::NamedArg { span, .. } => *span,
659 Expr::Ident(ident) => ident.span,
660 }
661 }
662}
663
664#[derive(Debug, Clone, PartialEq)]
666pub enum Literal {
667 String(String, Span),
669 Number(String, Span),
671 Boolean(bool, Span),
673}
674
675impl Literal {
676 pub fn span(&self) -> Span {
678 match self {
679 Literal::String(_, span) => *span,
680 Literal::Number(_, span) => *span,
681 Literal::Boolean(_, span) => *span,
682 }
683 }
684}
685
686#[cfg(test)]
687mod tests {
688 use super::*;
689
690 #[test]
691 fn test_field_modifier() {
692 assert_eq!(FieldModifier::None, FieldModifier::None);
693 assert_ne!(FieldModifier::Optional, FieldModifier::Array);
694 }
695
696 #[test]
697 fn test_field_type_display() {
698 assert_eq!(FieldType::String.to_string(), "String");
699 assert_eq!(FieldType::Int.to_string(), "Int");
700 assert_eq!(
701 FieldType::Decimal {
702 precision: 10,
703 scale: 2
704 }
705 .to_string(),
706 "Decimal(10, 2)"
707 );
708 }
709
710 #[test]
711 fn test_ident() {
712 let ident = Ident::new("test".to_string(), Span::new(0, 4));
713 assert_eq!(ident.value, "test");
714 assert_eq!(ident.to_string(), "test");
715 }
716
717 #[test]
718 fn test_referential_action_display() {
719 assert_eq!(ReferentialAction::Cascade.to_string(), "Cascade");
720 assert_eq!(ReferentialAction::SetNull.to_string(), "SetNull");
721 }
722
723 #[test]
724 fn test_model_table_name() {
725 let model = ModelDecl {
726 name: Ident::new("User".to_string(), Span::new(0, 4)),
727 fields: vec![],
728 attributes: vec![ModelAttribute::Map("users".to_string())],
729 span: Span::new(0, 10),
730 };
731 assert_eq!(model.table_name(), "users");
732 }
733
734 #[test]
735 fn test_model_table_name_default() {
736 let model = ModelDecl {
737 name: Ident::new("User".to_string(), Span::new(0, 4)),
738 fields: vec![],
739 attributes: vec![],
740 span: Span::new(0, 10),
741 };
742 assert_eq!(model.table_name(), "User");
743 }
744
745 #[test]
746 fn test_field_column_name() {
747 let field = FieldDecl {
748 name: Ident::new("userId".to_string(), Span::new(0, 6)),
749 field_type: FieldType::Int,
750 modifier: FieldModifier::None,
751 attributes: vec![FieldAttribute::Map("user_id".to_string())],
752 span: Span::new(0, 20),
753 };
754 assert_eq!(field.column_name(), "user_id");
755 }
756
757 #[test]
758 fn test_schema_helpers() {
759 let schema = Schema {
760 declarations: vec![
761 Declaration::Model(ModelDecl {
762 name: Ident::new("User".to_string(), Span::new(0, 4)),
763 fields: vec![],
764 attributes: vec![],
765 span: Span::new(0, 10),
766 }),
767 Declaration::Enum(EnumDecl {
768 name: Ident::new("Role".to_string(), Span::new(0, 4)),
769 variants: vec![],
770 span: Span::new(0, 10),
771 }),
772 ],
773 span: Span::new(0, 100),
774 };
775
776 assert_eq!(schema.models().count(), 1);
777 assert_eq!(schema.enums().count(), 1);
778 assert!(schema.datasource().is_none());
779 }
780}