elif_core/
spec.rs

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}