data_modelling_sdk/model/
saver.rs1use crate::storage::{StorageBackend, StorageError};
6use anyhow::Result;
7use serde_yaml;
8use tracing::info;
9use uuid::Uuid;
10
11pub struct ModelSaver<B: StorageBackend> {
13 storage: B,
14}
15
16impl<B: StorageBackend> ModelSaver<B> {
17 pub fn new(storage: B) -> Self {
19 Self { storage }
20 }
21
22 pub async fn save_table(
27 &self,
28 workspace_path: &str,
29 table: &TableData,
30 ) -> Result<(), StorageError> {
31 let tables_dir = format!("{}/tables", workspace_path);
32
33 if !self.storage.dir_exists(&tables_dir).await? {
35 self.storage.create_dir(&tables_dir).await?;
36 }
37
38 let file_path = if let Some(ref yaml_path) = table.yaml_file_path {
40 format!(
41 "{}/{}",
42 workspace_path,
43 yaml_path.strip_prefix('/').unwrap_or(yaml_path)
44 )
45 } else {
46 let sanitized_name = sanitize_filename(&table.name);
48 format!("{}/tables/{}.yaml", workspace_path, sanitized_name)
49 };
50
51 let yaml_content = serde_yaml::to_string(&table.yaml_value).map_err(|e| {
53 StorageError::SerializationError(format!("Failed to serialize table: {}", e))
54 })?;
55
56 self.storage
58 .write_file(&file_path, yaml_content.as_bytes())
59 .await?;
60
61 info!("Saved table '{}' to {}", table.name, file_path);
62 Ok(())
63 }
64
65 pub async fn save_relationships(
69 &self,
70 workspace_path: &str,
71 relationships: &[RelationshipData],
72 ) -> Result<(), StorageError> {
73 let file_path = format!("{}/relationships.yaml", workspace_path);
74
75 let mut yaml_map = serde_yaml::Mapping::new();
77 let mut rels_array = serde_yaml::Sequence::new();
78 for rel in relationships {
79 rels_array.push(rel.yaml_value.clone());
80 }
81 yaml_map.insert(
82 serde_yaml::Value::String("relationships".to_string()),
83 serde_yaml::Value::Sequence(rels_array),
84 );
85 let yaml_value = serde_yaml::Value::Mapping(yaml_map);
86
87 let yaml_content = serde_yaml::to_string(&yaml_value).map_err(|e| {
88 StorageError::SerializationError(format!("Failed to write YAML: {}", e))
89 })?;
90
91 self.storage
93 .write_file(&file_path, yaml_content.as_bytes())
94 .await?;
95
96 info!(
97 "Saved {} relationships to {}",
98 relationships.len(),
99 file_path
100 );
101 Ok(())
102 }
103}
104
105#[derive(Debug, Clone)]
107pub struct TableData {
108 pub id: Uuid,
109 pub name: String,
110 pub yaml_file_path: Option<String>,
111 pub yaml_value: serde_yaml::Value,
112}
113
114#[derive(Debug, Clone)]
116pub struct RelationshipData {
117 pub id: Uuid,
118 pub source_table_id: Uuid,
119 pub target_table_id: Uuid,
120 pub yaml_value: serde_yaml::Value,
121}
122
123fn sanitize_filename(name: &str) -> String {
125 name.chars()
126 .map(|c| match c {
127 '/' | '\\' | ':' | '*' | '?' | '"' | '<' | '>' | '|' => '_',
128 _ => c,
129 })
130 .collect()
131}