Skip to main content

post_archiver/utils/
macros.rs

1use crate::query::FromQuery;
2
3pub trait AsTable: FromQuery<Based = Self> + Sized {
4    const TABLE_NAME: &'static str;
5}
6
7#[macro_export]
8macro_rules! as_column {
9    ($row: expr, $col: expr) => {
10        $row.get($col)?
11    };
12    (json, $row: expr, $col: expr) => {{
13        let value: String = $row.get($col)?;
14        serde_json::from_str(&value).unwrap()
15    }};
16}
17
18#[macro_export]
19macro_rules! as_table {
20    ($($table:expr => $name:ident { $($field:ident: $col:expr $(=> $mode: ident)?),* $(,)? })+) => {
21        $(impl $crate::utils::macros::AsTable for $name {
22            const TABLE_NAME: &'static str = $table;
23        }
24
25        impl $crate::query::FromQuery for $name {
26            type Based = Self;
27            fn select_sql() -> String {
28                format!("SELECT * FROM {}", <Self as crate::utils::macros::AsTable>::TABLE_NAME)
29            }
30            fn from_row(row: &rusqlite::Row) -> Result<Self, rusqlite::Error> {
31                Ok(Self {
32                    $(
33                        $field: crate::utils::macros::as_column!(
34                            $($mode ,)?
35                            row,
36                            $col
37                        ),
38                    )*
39                })
40            }
41        })+
42    };
43}
44
45/// Helper macro to implement `FromQuery` for a struct with custom column mappings and optional JSON deserialization.
46/// ```
47/// # use post_archiver::{utils::macros::impl_from_query, *};
48///
49/// struct PostPreview {
50///     id: i64,
51///     title: String,
52///     thumb: Option<FileMetaId>,
53///     updated: i64,
54///     comments: Vec<Comment>,
55/// }
56///
57/// impl_from_query! {
58///     PostPreview extends Post {
59///         id: "id",
60///         title: "title",
61///         thumb: "thumb",
62///         updated: "updated",
63///         comments: "comments" => json,
64///     }
65/// }
66/// ```
67#[macro_export]
68macro_rules! impl_from_query {
69    ($name:ident extends $based:ty { $($field:ident: $col:expr $(=> $mode: ident)?),* $(,)? }) => {
70        impl $crate::query::FromQuery for $name {
71            type Based = $based;
72            fn select_sql() -> String {
73                format!("SELECT {} FROM {}", [$($col),*].join(","), <$based as $crate::utils::macros::AsTable>::TABLE_NAME)
74            }
75            fn from_row(row: &rusqlite::Row) -> Result<Self, rusqlite::Error> {
76                Ok(Self {
77                    $(
78                        $field: $crate::utils::macros::as_column!(
79                            $($mode ,)?
80                            row,
81                            $col
82                        ),
83                    )*
84                })
85            }
86        }
87    };
88}
89
90pub use {as_column, as_table, impl_from_query};