1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
5pub struct ResourceSpec {
6 pub kind: String,
7 pub name: String,
8 pub route: String,
9 pub storage: StorageSpec,
10 #[serde(default)]
11 pub indexes: Vec<IndexSpec>,
12 #[serde(default)]
13 pub uniques: Vec<UniqueSpec>,
14 #[serde(default)]
15 pub relations: Vec<RelationSpec>,
16 pub api: ApiSpec,
17 #[serde(default)]
18 pub policy: PolicySpec,
19 #[serde(default)]
20 pub validate: ValidateSpec,
21 #[serde(default)]
22 pub examples: HashMap<String, serde_json::Value>,
23 #[serde(default)]
24 pub events: EventSpec,
25}
26
27#[derive(Debug, Clone, Serialize, Deserialize)]
28pub struct StorageSpec {
29 pub table: String,
30 #[serde(default)]
31 pub soft_delete: bool,
32 #[serde(default = "default_true")]
33 pub timestamps: bool,
34 pub fields: Vec<FieldSpec>,
35}
36
37#[derive(Debug, Clone, Serialize, Deserialize)]
38pub struct FieldSpec {
39 pub name: String,
40 #[serde(rename = "type")]
41 pub field_type: String,
42 #[serde(default)]
43 pub pk: bool,
44 #[serde(default)]
45 pub required: bool,
46 #[serde(default)]
47 pub index: bool,
48 pub default: Option<String>,
49 pub validate: Option<ValidationRule>,
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize)]
53pub struct ValidationRule {
54 pub min: Option<i64>,
55 pub max: Option<i64>,
56 pub pattern: Option<String>,
57}
58
59#[derive(Debug, Clone, Serialize, Deserialize)]
60pub struct IndexSpec {
61 pub name: String,
62 pub fields: Vec<String>,
63}
64
65#[derive(Debug, Clone, Serialize, Deserialize)]
66pub struct UniqueSpec {
67 pub name: String,
68 pub fields: Vec<String>,
69}
70
71#[derive(Debug, Clone, Serialize, Deserialize)]
72pub struct RelationSpec {
73 pub name: String,
74 pub target: String,
75 pub relation_type: String,
76}
77
78#[derive(Debug, Clone, Serialize, Deserialize)]
79pub struct ApiSpec {
80 pub operations: Vec<OperationSpec>,
81}
82
83#[derive(Debug, Clone, Serialize, Deserialize)]
84pub struct OperationSpec {
85 pub op: String,
86 pub method: String,
87 pub path: String,
88 pub paging: Option<String>,
89 pub filter: Option<Vec<String>>,
90 pub search_by: Option<Vec<String>>,
91 pub order_by: Option<Vec<String>>,
92}
93
94#[derive(Debug, Clone, Default, Serialize, Deserialize)]
95pub struct PolicySpec {
96 #[serde(default = "default_public")]
97 pub auth: String,
98 pub rate_limit: Option<String>,
99}
100
101#[derive(Debug, Clone, Default, Serialize, Deserialize)]
102pub struct ValidateSpec {
103 #[serde(default)]
104 pub constraints: Vec<ConstraintSpec>,
105}
106
107#[derive(Debug, Clone, Serialize, Deserialize)]
108pub struct ConstraintSpec {
109 pub rule: String,
110 pub code: String,
111 pub hint: String,
112}
113
114#[derive(Debug, Clone, Default, Serialize, Deserialize)]
115pub struct EventSpec {
116 #[serde(default)]
117 pub emit: Vec<String>,
118}
119
120fn default_true() -> bool {
121 true
122}
123
124fn default_public() -> String {
125 "public".to_string()
126}
127
128impl ResourceSpec {
129 pub fn from_yaml(yaml: &str) -> Result<Self, serde_yaml::Error> {
130 serde_yaml::from_str(yaml)
131 }
132
133 pub fn to_yaml(&self) -> Result<String, serde_yaml::Error> {
134 serde_yaml::to_string(self)
135 }
136
137 pub fn table_name(&self) -> &str {
138 &self.storage.table
139 }
140
141 pub fn primary_key(&self) -> Option<&FieldSpec> {
142 self.storage.fields.iter().find(|f| f.pk)
143 }
144}