icydb_build/
lib.rs

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