Skip to main content

alibi_entity_codegen/
accessors.rs

1use super::*;
2/// `impl AuthUser`: absent plugin fields return their defaults.
3#[expect(
4    clippy::too_many_lines,
5    reason = "Keep the generated AuthUser implementation together as one quoted trait contract"
6)]
7#[must_use]
8pub fn auth_user_impl(
9    ident: &Ident,
10    fields: &FieldsNamed,
11    entity_fields: &[EntityField],
12    secondary: bool,
13    core_root: &TokenStream,
14) -> TokenStream {
15    let has = |name: &str| has_field(fields, name);
16    let optional = |name: &str| optional_field(fields, name);
17    let secondary_codec = if secondary {
18        secondary_codec(fields, core_root)
19    } else {
20        quote! {}
21    };
22    let additional_output = additional_output(EntityRole::User, entity_fields, core_root);
23    let text_getter = |name: &str| {
24        let field = Ident::new(name, Span::call_site());
25        if optional(name) {
26            quote! { fn #field(&self) -> Option<&str> { self.#field.as_deref() } }
27        } else {
28            quote! { fn #field(&self) -> Option<&str> { Some(self.#field.as_str()) } }
29        }
30    };
31    let email_impl = text_getter("email");
32    let name_impl = text_getter("name");
33    let username_impl = if has("username") {
34        quote! { fn username(&self) -> Option<&str> { self.username.as_deref() } }
35    } else {
36        quote! { fn username(&self) -> Option<&str> { None } }
37    };
38    let display_username_impl = if has("display_username") {
39        quote! { fn display_username(&self) -> Option<&str> { self.display_username.as_deref() } }
40    } else {
41        quote! { fn display_username(&self) -> Option<&str> { None } }
42    };
43    let two_factor_impl = if has("two_factor_enabled") {
44        if optional("two_factor_enabled") {
45            quote! {
46                fn two_factor_enabled(&self) -> bool { self.two_factor_enabled.unwrap_or(false) }
47                fn two_factor_enabled_value(&self) -> Option<bool> { self.two_factor_enabled }
48            }
49        } else {
50            quote! { fn two_factor_enabled(&self) -> bool { self.two_factor_enabled } }
51        }
52    } else {
53        quote! {
54            fn two_factor_enabled(&self) -> bool { false }
55            fn two_factor_enabled_value(&self) -> Option<bool> { None }
56        }
57    };
58    let role_impl = if has("role") {
59        quote! { fn role(&self) -> Option<&str> { self.role.as_deref() } }
60    } else {
61        quote! { fn role(&self) -> Option<&str> { None } }
62    };
63    let banned_impl = if has("banned") {
64        if optional("banned") {
65            quote! {
66                fn banned(&self) -> bool { self.banned.unwrap_or(false) }
67                fn banned_value(&self) -> Option<bool> { self.banned }
68            }
69        } else {
70            quote! { fn banned(&self) -> bool { self.banned } }
71        }
72    } else {
73        quote! {
74            fn banned(&self) -> bool { false }
75            fn banned_value(&self) -> Option<bool> { None }
76        }
77    };
78    let ban_reason_impl = if has("ban_reason") {
79        quote! { fn ban_reason(&self) -> Option<&str> { self.ban_reason.as_deref() } }
80    } else {
81        quote! { fn ban_reason(&self) -> Option<&str> { None } }
82    };
83    let ban_expires_impl = if has("ban_expires") {
84        quote! { fn ban_expires(&self) -> Option<::chrono::DateTime<::chrono::Utc>> { #core_root::entity::AuthTimestamp::into_utc(self.ban_expires) } }
85    } else {
86        quote! { fn ban_expires(&self) -> Option<::chrono::DateTime<::chrono::Utc>> { None } }
87    };
88    let metadata_impl = if has("metadata") {
89        quote! { fn metadata(&self) -> &::serde_json::Value { &self.metadata } }
90    } else {
91        quote! { fn metadata(&self) -> &::serde_json::Value {
92            static EMPTY: ::std::sync::LazyLock<::serde_json::Value> =
93                ::std::sync::LazyLock::new(|| ::serde_json::json!({}));
94            &EMPTY
95        } }
96    };
97    let mut optional_user_getters = Vec::new();
98    for name in ["is_anonymous", "phone_number_verified"] {
99        if has(name) {
100            let field = Ident::new(name, Span::call_site());
101            optional_user_getters.push(quote! { fn #field(&self) -> Option<bool> { self.#field } });
102        }
103    }
104    for name in ["phone_number", "last_login_method"] {
105        if has(name) {
106            let field = Ident::new(name, Span::call_site());
107            optional_user_getters
108                .push(quote! { fn #field(&self) -> Option<&str> { self.#field.as_deref() } });
109        }
110    }
111    quote! {
112        impl #core_root::entity::AuthUser for #ident {
113            #secondary_codec
114            #additional_output
115            fn id(&self) -> ::std::borrow::Cow<'_, str> { ::std::borrow::Cow::Borrowed(&self.id) }
116            #email_impl
117            #name_impl
118            fn email_verified(&self) -> bool { self.email_verified }
119            fn image(&self) -> Option<&str> { self.image.as_deref() }
120            fn created_at(&self) -> ::chrono::DateTime<::chrono::Utc> { #core_root::entity::AuthTimestamp::into_utc(self.created_at) }
121            fn updated_at(&self) -> ::chrono::DateTime<::chrono::Utc> { #core_root::entity::AuthTimestamp::into_utc(self.updated_at) }
122            #username_impl
123            #display_username_impl
124            #two_factor_impl
125            #role_impl
126            #banned_impl
127            #ban_reason_impl
128            #ban_expires_impl
129            #metadata_impl
130            #(#optional_user_getters)*
131        }
132    }
133}
134
135/// `impl AuthSession`: absent plugin fields return their defaults.
136#[must_use]
137pub fn auth_session_impl(
138    ident: &Ident,
139    fields: &FieldsNamed,
140    entity_fields: &[EntityField],
141    secondary: bool,
142    core_root: &TokenStream,
143) -> TokenStream {
144    let has = |name: &str| has_field(fields, name);
145    let secondary_codec = if secondary {
146        secondary_codec(fields, core_root)
147    } else {
148        quote! {}
149    };
150    let additional_output = additional_output(EntityRole::Session, entity_fields, core_root);
151    let impersonated_by_impl = if has("impersonated_by") {
152        quote! { fn impersonated_by(&self) -> Option<&str> { self.impersonated_by.as_deref() } }
153    } else {
154        quote! { fn impersonated_by(&self) -> Option<&str> { None } }
155    };
156    let active_org_impl = if has("active_organization_id") {
157        quote! { fn active_organization_id(&self) -> Option<&str> { self.active_organization_id.as_deref() } }
158    } else {
159        quote! { fn active_organization_id(&self) -> Option<&str> { None } }
160    };
161    let active_team_impl = if has("active_team_id") {
162        quote! { fn active_team_id(&self) -> Option<&str> { self.active_team_id.as_deref() } }
163    } else {
164        quote! {}
165    };
166    quote! {
167        impl #core_root::entity::AuthSession for #ident {
168            #secondary_codec
169            #additional_output
170            fn id(&self) -> ::std::borrow::Cow<'_, str> { ::std::borrow::Cow::Borrowed(&self.id) }
171            fn expires_at(&self) -> ::chrono::DateTime<::chrono::Utc> { #core_root::entity::AuthTimestamp::into_utc(self.expires_at) }
172            fn token(&self) -> &str { &self.token }
173            fn created_at(&self) -> ::chrono::DateTime<::chrono::Utc> { #core_root::entity::AuthTimestamp::into_utc(self.created_at) }
174            fn updated_at(&self) -> ::chrono::DateTime<::chrono::Utc> { #core_root::entity::AuthTimestamp::into_utc(self.updated_at) }
175            fn ip_address(&self) -> Option<&str> { self.ip_address.as_deref() }
176            fn user_agent(&self) -> Option<&str> { self.user_agent.as_deref() }
177            fn user_id(&self) -> ::std::borrow::Cow<'_, str> { ::std::borrow::Cow::Borrowed(&self.user_id) }
178            #impersonated_by_impl
179            #active_org_impl
180            #active_team_impl
181            fn active(&self) -> bool { self.active }
182        }
183    }
184}
185
186/// `impl AuthAccount`: account fields are all core fields.
187#[must_use]
188pub fn auth_account_impl(
189    ident: &Ident,
190    entity_fields: &[EntityField],
191    core_root: &TokenStream,
192) -> TokenStream {
193    let additional_output = additional_output(EntityRole::Account, entity_fields, core_root);
194    quote! {
195        impl #core_root::entity::AuthAccount for #ident {
196            #additional_output
197            fn id(&self) -> ::std::borrow::Cow<'_, str> { ::std::borrow::Cow::Borrowed(&self.id) }
198            fn account_id(&self) -> &str { &self.account_id }
199            fn provider_id(&self) -> &str { &self.provider_id }
200            fn user_id(&self) -> ::std::borrow::Cow<'_, str> { ::std::borrow::Cow::Borrowed(&self.user_id) }
201            fn access_token(&self) -> Option<&str> { self.access_token.as_deref() }
202            fn refresh_token(&self) -> Option<&str> { self.refresh_token.as_deref() }
203            fn id_token(&self) -> Option<&str> { self.id_token.as_deref() }
204            fn access_token_expires_at(&self) -> Option<::chrono::DateTime<::chrono::Utc>> { #core_root::entity::AuthTimestamp::into_utc(self.access_token_expires_at) }
205            fn refresh_token_expires_at(&self) -> Option<::chrono::DateTime<::chrono::Utc>> { #core_root::entity::AuthTimestamp::into_utc(self.refresh_token_expires_at) }
206            fn scope(&self) -> Option<&str> { self.scope.as_deref() }
207            fn password(&self) -> Option<&str> { self.password.as_deref() }
208            fn created_at(&self) -> ::chrono::DateTime<::chrono::Utc> { #core_root::entity::AuthTimestamp::into_utc(self.created_at) }
209            fn updated_at(&self) -> ::chrono::DateTime<::chrono::Utc> { #core_root::entity::AuthTimestamp::into_utc(self.updated_at) }
210        }
211    }
212}
213
214/// `impl AuthVerification`: verification fields are all core fields.
215#[must_use]
216pub fn auth_verification_impl(ident: &Ident, core_root: &TokenStream) -> TokenStream {
217    quote! {
218        impl #core_root::entity::AuthVerification for #ident {
219            fn id(&self) -> ::std::borrow::Cow<'_, str> { ::std::borrow::Cow::Borrowed(&self.id) }
220            fn identifier(&self) -> &str { &self.identifier }
221            fn value(&self) -> &str { &self.value }
222            fn expires_at(&self) -> ::chrono::DateTime<::chrono::Utc> { #core_root::entity::AuthTimestamp::into_utc(self.expires_at) }
223            fn created_at(&self) -> ::chrono::DateTime<::chrono::Utc> { #core_root::entity::AuthTimestamp::into_utc(self.created_at) }
224            fn updated_at(&self) -> ::chrono::DateTime<::chrono::Utc> { #core_root::entity::AuthTimestamp::into_utc(self.updated_at) }
225        }
226    }
227}