icydb_build/
lib.rs

1pub mod db;
2pub mod metrics;
3pub mod query;
4
5use icydb_schema::{
6    build::get_schema,
7    node::{Canister, Entity, Schema, Store},
8};
9use proc_macro2::TokenStream;
10use quote::quote;
11use std::sync::Arc;
12
13// generate
14#[must_use]
15/// Generate canister actor code for the given schema path.
16pub fn generate(canister_path: &str) -> String {
17    // load schema and get the specified canister
18    let schema = get_schema().expect("schema must be valid before codegen");
19
20    // filter by name
21    let canister = schema.cast_node::<Canister>(canister_path).unwrap();
22
23    // create the ActorBuilder and generate the code
24    let code = ActorBuilder::new(Arc::new(schema.clone()), canister.clone());
25    let tokens = code.generate();
26
27    tokens.to_string()
28}
29
30///
31/// ActorBuilder
32///
33
34pub struct ActorBuilder {
35    pub schema: Arc<Schema>,
36    pub canister: Canister,
37}
38
39impl ActorBuilder {
40    // new
41    #[must_use]
42    /// Create an actor builder for a specific canister.
43    pub const fn new(schema: Arc<Schema>, canister: Canister) -> Self {
44        Self { schema, canister }
45    }
46
47    // generate
48    #[must_use]
49    /// Generate the full actor module (db/metrics/query glue).
50    pub fn generate(self) -> TokenStream {
51        let mut tokens = quote!();
52
53        // shared between all canisters
54        tokens.extend(db::generate(&self));
55        tokens.extend(metrics::generate(&self));
56        tokens.extend(query::generate(&self));
57
58        quote! {
59            #tokens
60        }
61    }
62
63    // get_stores
64    #[must_use]
65    /// All stores belonging to the current canister, keyed by path.
66    pub fn get_stores(&self) -> Vec<(String, Store)> {
67        let canister_path = self.canister.def.path();
68
69        self.schema
70            .filter_nodes::<Store>(|node| node.canister == canister_path)
71            .map(|(path, store)| (path.to_string(), store.clone()))
72            .collect()
73    }
74
75    // get_entities
76    // helper function to get all the entities for the current canister
77    #[must_use]
78    /// All entities attached to the current canister, keyed by path.
79    pub fn get_entities(&self) -> Vec<(String, Entity)> {
80        let canister_path = self.canister.def.path();
81        let mut entities = Vec::new();
82
83        for (store_path, _) in self
84            .schema
85            .filter_nodes::<Store>(|node| node.canister == canister_path)
86        {
87            for (entity_path, entity) in self
88                .schema
89                .filter_nodes::<Entity>(|node| node.store == store_path)
90            {
91                entities.push((entity_path.to_string(), entity.clone()));
92            }
93        }
94
95        entities
96    }
97}