Skip to main content

icydb_build/
lib.rs

1mod db;
2mod macros;
3mod metrics;
4
5use icydb_schema::{
6    build::get_schema,
7    node::{Canister, DataStore, Entity, IndexStore, Schema},
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(crate) struct ActorBuilder {
35    pub(crate) schema: Arc<Schema>,
36    pub(crate) canister: Canister,
37}
38
39impl ActorBuilder {
40    #[must_use]
41    /// Create an actor builder for a specific canister.
42    pub const fn new(schema: Arc<Schema>, canister: Canister) -> Self {
43        Self { schema, canister }
44    }
45
46    #[must_use]
47    /// Generate the full actor module (db/metrics/query glue).
48    pub fn generate(self) -> TokenStream {
49        let mut tokens = quote!();
50
51        // shared between all canisters
52        tokens.extend(db::generate(&self));
53        tokens.extend(metrics::generate(&self));
54
55        quote! {
56            #tokens
57        }
58    }
59
60    /// All stores belonging to the current canister, keyed by path.
61    #[must_use]
62    pub fn get_data_stores(&self) -> Vec<(String, DataStore)> {
63        let canister_path = self.canister.def.path();
64
65        self.schema
66            .filter_nodes::<DataStore>(|node| node.canister == canister_path)
67            .map(|(path, store)| (path.to_string(), store.clone()))
68            .collect()
69    }
70
71    /// All stores belonging to the current canister, keyed by path.
72    #[must_use]
73    pub fn get_index_stores(&self) -> Vec<(String, IndexStore)> {
74        let canister_path = self.canister.def.path();
75
76        self.schema
77            .filter_nodes::<IndexStore>(|node| node.canister == canister_path)
78            .map(|(path, store)| (path.to_string(), store.clone()))
79            .collect()
80    }
81
82    /// All entities attached to the current canister, keyed by path.
83    #[must_use]
84    pub fn get_entities(&self) -> Vec<(String, Entity)> {
85        let canister_path = self.canister.def.path();
86        let mut entities = Vec::new();
87
88        for (store_path, _) in self
89            .schema
90            .filter_nodes::<DataStore>(|node| node.canister == canister_path)
91        {
92            for (entity_path, entity) in self
93                .schema
94                .filter_nodes::<Entity>(|node| node.store == store_path)
95            {
96                entities.push((entity_path.to_string(), entity.clone()));
97            }
98        }
99
100        entities
101    }
102}