Skip to main content

ferriorm_codegen/
client.rs

1//! Generates the `client.rs` module containing the `FerriormClient` struct.
2//!
3//! `FerriormClient` is the user-facing entry point. It wraps a
4//! `ferriorm_runtime::client::DatabaseClient` and exposes a method per model
5//! (e.g., `.user()`, `.post()`) that returns the model's `Actions` struct
6//! for performing CRUD operations.
7
8use ferriorm_core::schema::Schema;
9use ferriorm_core::utils::to_snake_case;
10use proc_macro2::TokenStream;
11use quote::{format_ident, quote};
12
13/// Generate the `client.rs` module with the `FerriormClient` struct.
14#[must_use]
15pub fn generate_client_module(schema: &Schema) -> TokenStream {
16    let model_accessors: Vec<TokenStream> = schema
17        .models
18        .iter()
19        .map(|m| {
20            let method_name = format_ident!("{}", to_snake_case(&m.name));
21            let actions_type = format_ident!("{}Actions", m.name);
22            let module_name = format_ident!("{}", to_snake_case(&m.name));
23
24            quote! {
25                pub fn #method_name(&self) -> super::#module_name::#actions_type<'_> {
26                    super::#module_name::#actions_type::new(&self.inner)
27                }
28            }
29        })
30        .collect();
31
32    quote! {
33        #![allow(unused_imports, dead_code, unused_variables, clippy::all, clippy::pedantic, clippy::nursery)]
34
35        use ferriorm_runtime::prelude::*;
36
37        pub struct FerriormClient {
38            inner: DatabaseClient,
39        }
40
41        impl FerriormClient {
42            /// Connect to the database using the provided URL.
43            pub async fn connect(url: &str) -> Result<Self, FerriormError> {
44                let inner = DatabaseClient::connect(url).await?;
45                Ok(Self { inner })
46            }
47
48            /// Connect to the database using the provided URL and pool configuration.
49            pub async fn connect_with_config(url: &str, config: &PoolConfig) -> Result<Self, FerriormError> {
50                let inner = DatabaseClient::connect_with_config(url, config).await?;
51                Ok(Self { inner })
52            }
53
54            /// Get a reference to the underlying [`DatabaseClient`].
55            ///
56            /// Use this for raw SQL queries via `client().pg_pool()` or
57            /// `client().sqlite_pool()`.
58            pub fn client(&self) -> &DatabaseClient {
59                &self.inner
60            }
61
62            #(#model_accessors)*
63
64            /// Close the database connection.
65            pub async fn disconnect(self) {
66                self.inner.disconnect().await;
67            }
68        }
69    }
70}