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, 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(crate) struct ActorBuilder {
35    pub(crate) schema: Arc<Schema>,
36    pub(crate) 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
57        quote! {
58            #tokens
59        }
60    }
61
62    // get_stores
63    #[must_use]
64    /// All stores belonging to the current canister, keyed by path.
65    pub fn get_stores(&self) -> Vec<(String, Store)> {
66        let canister_path = self.canister.def.path();
67
68        self.schema
69            .filter_nodes::<Store>(|node| node.canister == canister_path)
70            .map(|(path, store)| (path.to_string(), store.clone()))
71            .collect()
72    }
73
74    // get_entities
75    // helper function to get all the entities for the current canister
76    #[must_use]
77    /// All entities attached to the current canister, keyed by path.
78    pub fn get_entities(&self) -> Vec<(String, Entity)> {
79        let canister_path = self.canister.def.path();
80        let mut entities = Vec::new();
81
82        for (store_path, _) in self
83            .schema
84            .filter_nodes::<Store>(|node| node.canister == canister_path)
85        {
86            for (entity_path, entity) in self
87                .schema
88                .filter_nodes::<Entity>(|node| node.store == store_path)
89            {
90                entities.push((entity_path.to_string(), entity.clone()));
91            }
92        }
93
94        entities
95    }
96}