1use crate::evaluator::DatabaseEvaluator;
4use crate::owner_ref::OwnershipConfig;
5use crate::privacy::PolicyEvaluator;
6use crate::ttl::SchemaTtlPolicy;
7use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone, Serialize, Deserialize, Default)]
11pub struct SchemaPolicyRule {
12 pub name: String,
13 #[serde(skip_serializing_if = "Option::is_none")]
14 pub description: Option<String>,
15 #[serde(skip, default)]
16 pub evaluator: Option<&'static dyn PolicyEvaluator>,
17}
18
19#[derive(Debug, Clone, Serialize, Deserialize, Default)]
21pub struct SchemaPolicyRules {
22 #[serde(default, skip_serializing_if = "Vec::is_empty")]
23 pub always_allow: Vec<SchemaPolicyRule>,
24 #[serde(default, skip_serializing_if = "Vec::is_empty")]
25 pub allow: Vec<SchemaPolicyRule>,
26 #[serde(default, skip_serializing_if = "Vec::is_empty")]
27 pub block: Vec<SchemaPolicyRule>,
28 #[serde(default, skip_serializing_if = "Vec::is_empty")]
29 pub always_block: Vec<SchemaPolicyRule>,
30}
31
32#[derive(Debug, Clone, Serialize, Deserialize, Default)]
34pub struct SchemaPolicies {
35 #[serde(skip_serializing_if = "Option::is_none")]
36 pub read: Option<SchemaPolicyRules>,
37 #[serde(skip_serializing_if = "Option::is_none")]
38 pub create: Option<SchemaPolicyRules>,
39 #[serde(skip_serializing_if = "Option::is_none")]
40 pub update: Option<SchemaPolicyRules>,
41 #[serde(skip_serializing_if = "Option::is_none")]
42 pub delete: Option<SchemaPolicyRules>,
43}
44
45#[derive(Debug, Clone, Serialize, Deserialize)]
47pub struct SchemaPrivacy {
48 pub read: String,
49 pub write: String,
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize)]
54pub struct ForeignKeyRef {
55 pub ref_table: String,
56 pub field: String,
57}
58
59#[derive(Debug, Clone, Serialize, Deserialize)]
61pub struct SchemaField {
62 pub name: String,
63 pub field_type: String,
64 pub primary: bool,
65 pub nullable: bool,
66 pub indexed: bool,
67 #[serde(default, skip_serializing_if = "is_false")]
68 pub unique: bool,
69 #[serde(skip_serializing_if = "Option::is_none")]
70 pub default: Option<String>,
71 #[serde(skip_serializing_if = "Option::is_none")]
72 pub fk: Option<ForeignKeyRef>,
73 #[serde(default, skip_serializing_if = "Vec::is_empty")]
74 pub validations: Vec<String>,
75 #[serde(skip_serializing_if = "Option::is_none")]
76 pub policies: Option<SchemaPolicies>,
77 #[serde(default, skip_serializing_if = "is_false")]
78 pub encrypted: bool,
79 #[serde(default, skip_serializing_if = "Vec::is_empty")]
80 pub enum_variants: Vec<String>,
81 #[serde(default, skip_serializing_if = "Option::is_none")]
82 pub enum_type: Option<String>,
83 #[serde(default, skip_serializing_if = "Option::is_none")]
85 pub model_path: Option<String>,
86}
87
88#[derive(Debug, Clone, Serialize, Deserialize)]
90pub struct SchemaEdge {
91 pub from_field: String,
92 pub to_table: String,
93 pub label: String,
94}
95
96#[derive(Debug, Clone, Serialize, Deserialize)]
98pub struct SchemaConnection {
99 pub name: String,
100 pub from_table: String,
101 pub from_field: String,
102 pub to_table: String,
103 pub cardinality: String,
104 pub required: bool,
105 pub on_delete: String,
106 pub label: String,
107 #[serde(skip_serializing_if = "Option::is_none")]
108 pub model_path: Option<String>,
109 #[serde(skip_serializing_if = "Option::is_none")]
110 pub reverse_field: Option<String>,
111 #[serde(skip_serializing_if = "Option::is_none")]
112 pub edge_table: Option<String>,
113 #[serde(skip_serializing_if = "Option::is_none")]
114 pub target_trait: Option<String>,
115}
116
117impl From<SchemaEdge> for SchemaConnection {
118 fn from(edge: SchemaEdge) -> Self {
119 let label = edge.label.clone();
120 Self {
121 name: edge.from_field.clone(),
122 from_table: String::new(),
123 from_field: edge.from_field,
124 to_table: edge.to_table,
125 cardinality: "HasOne".to_string(),
126 required: true,
127 on_delete: "Cascade".to_string(),
128 label,
129 model_path: None,
130 reverse_field: None,
131 edge_table: None,
132 target_trait: None,
133 }
134 }
135}
136
137#[derive(Debug, Clone, Serialize, Deserialize)]
139pub struct SchemaMeta {
140 pub retention: String,
141 pub row_count: u64,
142 pub owner: String,
143 #[serde(skip_serializing_if = "Option::is_none")]
144 pub description: Option<String>,
145}
146
147#[derive(Debug, Clone, Serialize)]
149pub struct Schema {
150 pub name: String,
151 pub version: String,
152 pub databases: Vec<String>,
153 #[serde(skip)]
154 pub database_evaluator: &'static dyn DatabaseEvaluator,
155 pub privacy: SchemaPrivacy,
156 #[serde(skip_serializing_if = "Option::is_none")]
157 pub policies: Option<SchemaPolicies>,
158 pub fields: Vec<SchemaField>,
159 #[serde(default, skip_serializing_if = "Vec::is_empty")]
160 pub edges: Vec<SchemaEdge>,
161 #[serde(default, skip_serializing_if = "Vec::is_empty")]
162 pub connections: Vec<SchemaConnection>,
163 #[serde(default, skip_serializing_if = "Vec::is_empty")]
164 pub side_effects: Vec<String>,
165 #[serde(default, skip_serializing_if = "Vec::is_empty")]
166 pub iters: Vec<String>,
167 #[serde(default, skip_serializing_if = "Vec::is_empty")]
168 pub composite_key: Vec<String>,
169 #[serde(default, skip_serializing_if = "Vec::is_empty")]
170 pub traits: Vec<String>,
171 #[serde(skip_serializing_if = "Option::is_none")]
172 pub ttl: Option<SchemaTtlPolicy>,
173 #[serde(skip_serializing_if = "Option::is_none")]
174 pub ownership: Option<OwnershipConfig>,
175 pub meta: SchemaMeta,
176}
177
178#[allow(
179 clippy::trivially_copy_pass_by_ref,
180 reason = "serde's `skip_serializing_if` callback signature passes field values by reference"
181)]
182fn is_false(value: &bool) -> bool {
183 !*value
184}