rustauth_plugins/siwe/
schema.rs1use indexmap::IndexMap;
2use rustauth_core::db::{DbField, DbFieldType, DbTable, ForeignKey, OnDelete};
3use rustauth_core::plugin::PluginSchemaContribution;
4
5#[derive(Debug, Clone, Default, PartialEq, Eq)]
6pub struct SiweSchemaOptions {
7 table_name: Option<String>,
8 field_names: IndexMap<String, String>,
9}
10
11impl SiweSchemaOptions {
12 pub fn new() -> Self {
13 Self::default()
14 }
15
16 #[must_use]
17 pub fn table_name(mut self, table_name: impl Into<String>) -> Self {
18 self.table_name = Some(table_name.into());
19 self
20 }
21
22 #[must_use]
23 pub fn field_name(
24 mut self,
25 logical_name: impl Into<String>,
26 db_name: impl Into<String>,
27 ) -> Self {
28 self.field_names.insert(
29 normalize_logical_field(&logical_name.into()),
30 db_name.into(),
31 );
32 self
33 }
34
35 fn table_name_or_default(&self) -> String {
36 self.table_name
37 .clone()
38 .unwrap_or_else(|| "wallet_addresses".to_owned())
39 }
40
41 fn field_name_or_default(&self, logical_name: &str) -> String {
42 self.field_names
43 .get(logical_name)
44 .cloned()
45 .unwrap_or_else(|| logical_name.to_owned())
46 }
47
48 pub(crate) fn metadata(&self) -> serde_json::Value {
49 let mut fields = serde_json::Map::new();
50 for logical_name in ["user_id", "address", "chain_id", "is_primary", "created_at"] {
51 if let Some(db_name) = self.field_names.get(logical_name) {
52 fields.insert(
53 metadata_field_key(logical_name),
54 serde_json::Value::String(db_name.clone()),
55 );
56 }
57 }
58 serde_json::json!({
59 "walletAddress": {
60 "modelName": self.table_name_or_default(),
61 "fields": fields,
62 }
63 })
64 }
65}
66
67fn normalize_logical_field(logical_name: &str) -> String {
68 match logical_name {
69 "userId" => "user_id".to_owned(),
70 "chainId" => "chain_id".to_owned(),
71 "isPrimary" => "is_primary".to_owned(),
72 "createdAt" => "created_at".to_owned(),
73 other => other.to_owned(),
74 }
75}
76
77fn metadata_field_key(logical_name: &str) -> String {
78 match logical_name {
79 "user_id" => "userId".to_owned(),
80 "chain_id" => "chainId".to_owned(),
81 "is_primary" => "isPrimary".to_owned(),
82 "created_at" => "createdAt".to_owned(),
83 other => other.to_owned(),
84 }
85}
86
87pub(crate) fn wallet_address_schema(options: &SiweSchemaOptions) -> PluginSchemaContribution {
88 let mut fields = IndexMap::new();
89 fields.insert(
90 "id".to_owned(),
91 DbField::new("id", DbFieldType::String).generated(),
92 );
93 fields.insert(
94 "user_id".to_owned(),
95 DbField::new(
96 options.field_name_or_default("user_id"),
97 DbFieldType::String,
98 )
99 .indexed()
100 .references(ForeignKey::new("users", "id", OnDelete::Cascade)),
101 );
102 fields.insert(
103 "address".to_owned(),
104 DbField::new(
105 options.field_name_or_default("address"),
106 DbFieldType::String,
107 ),
108 );
109 fields.insert(
110 "chain_id".to_owned(),
111 DbField::new(
112 options.field_name_or_default("chain_id"),
113 DbFieldType::Number,
114 ),
115 );
116 fields.insert(
117 "is_primary".to_owned(),
118 DbField::new(
119 options.field_name_or_default("is_primary"),
120 DbFieldType::Boolean,
121 ),
122 );
123 fields.insert(
124 "created_at".to_owned(),
125 DbField::new(
126 options.field_name_or_default("created_at"),
127 DbFieldType::Timestamp,
128 )
129 .generated(),
130 );
131
132 PluginSchemaContribution::table(
133 "wallet_address",
134 DbTable {
135 name: options.table_name_or_default(),
136 fields,
137 order: Some(20),
138 },
139 )
140}