byteorm_lib/rustgen/
mod.rs

1use std::collections::HashMap;
2use std::fs;
3use quote::quote;
4use crate::Schema;
5
6pub mod client;
7pub mod jsonb;
8pub mod model;
9pub mod query;
10pub mod update;
11pub mod upsert;
12pub mod utils;
13
14pub use client::*;
15pub use jsonb::*;
16pub use model::*;
17pub use query::*;
18pub use update::*;
19pub use upsert::*;
20pub use utils::*;
21
22pub fn generate_rust_code(schema: &Schema) -> String {
23    let mut jsonb_defaults = HashMap::new();
24    for model in &schema.models {
25        for field in &model.fields {
26            if let Some(path) = field.get_jsonb_default_path() {
27                match fs::read_to_string(&path) {
28                    Ok(content) => {
29                        jsonb_defaults.insert((model.name.clone(), field.name.clone()), content);
30                    }
31                    Err(e) => {
32                        eprintln!("Warning: Could not read default file '{}': {}", path, e);
33                    }
34                }
35            }
36        }
37    }
38
39    let structs_and_impls = schema.models.iter().map(|model| {
40        generate_model_with_query_builder(model)
41    });
42
43    let client_struct = generate_client_struct(schema, &jsonb_defaults);
44    let jsonb_ext = generate_jsonb_ext();
45
46    let code = quote! {
47        use serde::{Deserialize, Serialize};
48        use chrono::{DateTime, Utc};
49        use tokio_postgres::{Client as PgClient, NoTls, Error};
50        use std::sync::Arc;
51        use once_cell::sync::Lazy;
52        use std::collections::HashMap;
53        pub fn expect_keys<T: Copy>(
54            map: &std::collections::HashMap<String, T>,
55            keys: &[&str]
56        ) -> Result<Vec<T>, &'static str> {
57            keys.iter()
58                .map(|k| map.get(*k).copied().ok_or("missing key"))
59                .collect()
60        }
61
62        fn calculate_json_diff(before: &serde_json::Value, after: &serde_json::Value) -> serde_json::Value {
63            let mut diff = serde_json::Map::new();
64            if let (Some(before_obj), Some(after_obj)) = (before.as_object(), after.as_object()) {
65                for (key, after_val) in after_obj {
66                    if let Some(before_val) = before_obj.get(key) {
67                        if before_val != after_val {
68                            diff.insert(key.clone(), serde_json::json!({ "from": before_val, "to": after_val }));
69                        }
70                    } else {
71                        diff.insert(key.clone(), serde_json::json!({ "added": after_val }));
72                    }
73                }
74                for (key, before_val) in before_obj {
75                    if !after_obj.contains_key(key) {
76                        diff.insert(key.clone(), serde_json::json!({ "removed": before_val }));
77                    }
78                }
79            }
80            serde_json::Value::Object(diff)
81        }
82
83        #jsonb_ext
84        #client_struct
85        #(#structs_and_impls)*
86    };
87
88    let file: syn::File = syn::parse2(code).unwrap();
89    prettyplease::unparse(&file)
90}