core_crypto_macros/entity_derive/
mod.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
mod derive_impl;
mod parse;

use proc_macro2::Ident;

/// Representation of a struct annotated with `#[derive(Entity)]`.
pub(super) struct KeyStoreEntity {
    /// Name of the type to implement the trait on
    struct_name: Ident,
    /// Database table name
    collection_name: String,
    /// The ID column
    id: IdColumn,
    /// All other columns
    columns: Columns,
    /// Whether to fail on inserting conflicting ids instead of using upsert semantics (default: false)
    no_upsert: bool,
}

impl KeyStoreEntity {
    /// Convert Keystore entity to a flattened version that is more verbose but can be used more easily in `quote!()`.
    pub(super) fn flatten(self) -> KeyStoreEntityFlattened {
        let all_columns = self
            .columns
            .0
            .iter()
            .map(|column| column.name.clone())
            .collect::<Vec<_>>();

        let blob_columns = self
            .columns
            .0
            .iter()
            .filter(|column| column.column_type == ColumnType::Bytes)
            .map(|column| column.name.clone())
            .collect::<Vec<_>>();

        let optional_blob_columns = self
            .columns
            .0
            .iter()
            .filter(|column| column.column_type == ColumnType::OptionalBytes)
            .map(|column| column.name.clone())
            .collect::<Vec<_>>();

        let all_column_names = all_columns.iter().map(ToString::to_string).collect();
        let blob_column_names = blob_columns.iter().map(ToString::to_string).collect();
        let optional_blob_column_names = optional_blob_columns.iter().map(ToString::to_string).collect();

        let id = self.id.name;
        let id_name = self.id.column_name.unwrap_or_else(|| id.to_string());
        let id_type = self.id.column_type;

        KeyStoreEntityFlattened {
            struct_name: self.struct_name,
            collection_name: self.collection_name,
            no_upsert: self.no_upsert,
            id,
            id_type,
            id_name,
            id_transformation: self.id.transformation,
            all_columns,
            all_column_names,
            blob_columns,
            blob_column_names,
            optional_blob_columns,
            optional_blob_column_names,
        }
    }
}

/// Less abstract version of [KeyStoreEntity] that has all the fields flattened
/// ready for usage in `quote!()`.
pub(super) struct KeyStoreEntityFlattened {
    struct_name: Ident,
    collection_name: String,
    id: Ident,
    id_name: String,
    id_type: IdColumnType,
    id_transformation: Option<IdTransformation>,
    all_columns: Vec<Ident>,
    all_column_names: Vec<String>,
    blob_columns: Vec<Ident>,
    blob_column_names: Vec<String>,
    optional_blob_columns: Vec<Ident>,
    optional_blob_column_names: Vec<String>,
    no_upsert: bool,
}

#[derive(PartialEq, Eq)]
enum IdColumnType {
    String,
    Bytes,
}

struct IdColumn {
    name: Ident,
    column_type: IdColumnType,
    /// Only present if it differs from the name
    column_name: Option<String>,
    /// If the ID cannot be stored as-is because of indexing limitations
    transformation: Option<IdTransformation>,
}

enum IdTransformation {
    Hex,
    #[expect(dead_code)]
    Sha256,
}

struct Columns(Vec<Column>);

struct Column {
    name: Ident,
    column_type: ColumnType,
}

#[derive(PartialEq, Eq)]
enum ColumnType {
    String,
    Bytes,
    OptionalBytes,
}