1use indexmap::IndexMap;
2
3use crate::dict::Compound;
4use crate::span::Span;
5
6#[cfg(feature = "serde")]
7use serde::Serialize;
8
9#[cfg_attr(
13 feature = "serde",
14 derive(Serialize),
15 serde(tag = "kind", rename_all = "camelCase")
16)]
17#[derive(Debug, Clone)]
18pub enum Origin {
19 Own,
21 Mixin {
22 name: String,
23 #[cfg_attr(feature = "serde", serde(skip))]
24 def_span: Span,
25 },
26 Blueprint {
27 name: String,
28 #[cfg_attr(feature = "serde", serde(skip))]
29 def_span: Span,
30 #[cfg_attr(feature = "serde", serde(skip))]
31 apply_span: Span,
32 },
33 Generated { by: String },
35}
36
37#[cfg_attr(feature = "serde", derive(Serialize), serde(rename_all = "camelCase"))]
38#[derive(Debug, Clone, PartialEq, Eq)]
39pub enum Val {
40 Literal(String),
41 Eval(String),
42}
43
44#[cfg_attr(feature = "serde", derive(Serialize), serde(rename_all = "camelCase"))]
45#[derive(Debug, Clone)]
46pub struct Column {
47 pub name: String,
48 #[cfg_attr(feature = "serde", serde(rename = "type"))]
49 pub ty: String,
50 pub null: bool,
51 pub default: Option<Val>,
52 pub on_update: Option<Val>,
53 pub comment: Option<String>,
54 pub origin: Origin,
55 #[cfg_attr(feature = "serde", serde(skip))]
56 pub span: Span,
57}
58
59#[cfg_attr(feature = "serde", derive(Serialize), serde(rename_all = "camelCase"))]
60#[derive(Debug, Clone)]
61pub struct Index {
62 pub name: String,
63 pub columns: Vec<String>,
64 pub unique: bool,
65 #[cfg_attr(feature = "serde", serde(skip))]
66 pub span: Span,
67}
68
69#[cfg_attr(feature = "serde", derive(Serialize), serde(rename_all = "camelCase"))]
70#[derive(Debug, Clone)]
71pub struct ForeignKey {
72 pub alias: String,
74 pub columns: Vec<String>,
75 pub ref_table: String,
76 pub ref_columns: Vec<String>,
77 pub on_delete: String,
78 pub on_update: String,
79 #[cfg_attr(feature = "serde", serde(skip))]
80 pub span: Span,
81}
82
83#[cfg_attr(feature = "serde", derive(Serialize), serde(rename_all = "camelCase"))]
85#[derive(Debug, Clone)]
86pub struct Reverse {
87 pub alias: String,
88 pub from_table: String,
90 pub via: Vec<String>,
92 pub unique: bool,
94 #[cfg_attr(feature = "serde", serde(skip))]
95 pub span: Span,
96}
97
98#[cfg_attr(feature = "serde", derive(Serialize), serde(rename_all = "camelCase"))]
99#[derive(Debug, Clone)]
100pub struct Table {
101 pub name: String,
103 #[cfg_attr(feature = "serde", serde(skip))]
105 pub noun: Option<Compound>,
106 pub singular: Option<String>,
108 pub plural: Option<String>,
110 pub comment: Option<String>,
111 pub columns: IndexMap<String, Column>,
112 pub pk: Vec<String>,
113 pub indexes: Vec<Index>,
114 pub foreign_keys: Vec<ForeignKey>,
115 pub reverses: Vec<Reverse>,
116 pub origin: Origin,
117 #[cfg_attr(feature = "serde", serde(skip))]
118 pub span: Span,
119}
120
121#[cfg_attr(feature = "serde", derive(Serialize), serde(rename_all = "camelCase"))]
122#[derive(Debug, Clone, Default)]
123pub struct Schema {
124 pub tables: Vec<Table>,
125}
126
127impl Schema {
128 pub fn table(&self, name: &str) -> Option<&Table> {
129 self.tables.iter().find(|t| t.name == name)
130 }
131
132 pub fn table_by_noun(&self, name: &str) -> Option<&Table> {
134 self.tables
135 .iter()
136 .find(|t| t.noun.as_ref().and_then(Compound::as_single_noun) == Some(name))
137 }
138}