Skip to main content

nautilus_blockchain/cache/
types.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2026 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16use std::str::FromStr;
17
18use alloy::primitives::{I256, U160, U256};
19use sqlx::{
20    Database, Decode, Encode, Postgres, Type,
21    encode::IsNull,
22    error::BoxDynError,
23    postgres::{PgHasArrayType, PgTypeInfo},
24};
25
26#[derive(Debug, Clone, PartialEq, Eq)]
27pub struct I256Pg(pub I256);
28
29#[derive(Debug, Clone, PartialEq, Eq)]
30pub struct U256Pg(pub U256);
31
32#[derive(Debug, Clone, PartialEq, Eq)]
33pub struct U160Pg(pub U160);
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq)]
36pub struct U128Pg(pub u128);
37
38// Implement Type trait for SqlI256
39impl Type<Postgres> for I256Pg {
40    fn type_info() -> PgTypeInfo {
41        PgTypeInfo::with_name("i256")
42    }
43}
44
45// Implement Type trait for SqlU256
46impl Type<Postgres> for U256Pg {
47    fn type_info() -> PgTypeInfo {
48        PgTypeInfo::with_name("u256")
49    }
50}
51
52// Implement Type trait for U160Pg
53impl Type<Postgres> for U160Pg {
54    fn type_info() -> PgTypeInfo {
55        PgTypeInfo::with_name("u160")
56    }
57}
58
59// Implement Type trait for U128Pg
60impl Type<Postgres> for U128Pg {
61    fn type_info() -> PgTypeInfo {
62        PgTypeInfo::with_name("u128")
63    }
64}
65
66impl<'q> Encode<'q, Postgres> for I256Pg {
67    fn encode_by_ref(
68        &self,
69        buf: &mut <Postgres as Database>::ArgumentBuffer<'_>,
70    ) -> Result<IsNull, BoxDynError> {
71        let s = self.0.to_string();
72        <&str as Encode<Postgres>>::encode(&s, buf)
73    }
74}
75
76impl<'q> Encode<'q, Postgres> for U256Pg {
77    fn encode_by_ref(
78        &self,
79        buf: &mut <Postgres as Database>::ArgumentBuffer<'_>,
80    ) -> Result<IsNull, BoxDynError> {
81        // Ensure we send decimal format, not hex format to PostgreSQL
82        let decimal_str = format!("{}", self.0);
83        <&str as Encode<Postgres>>::encode(&decimal_str, buf)
84    }
85}
86
87impl<'q> Encode<'q, Postgres> for U160Pg {
88    fn encode_by_ref(
89        &self,
90        buf: &mut <Postgres as Database>::ArgumentBuffer<'_>,
91    ) -> Result<IsNull, BoxDynError> {
92        let decimal_str = format!("{}", self.0);
93        <&str as Encode<Postgres>>::encode(&decimal_str, buf)
94    }
95}
96
97impl<'q> Encode<'q, Postgres> for U128Pg {
98    fn encode_by_ref(
99        &self,
100        buf: &mut <Postgres as Database>::ArgumentBuffer<'_>,
101    ) -> Result<IsNull, BoxDynError> {
102        let decimal_str = self.0.to_string();
103        <&str as Encode<Postgres>>::encode(&decimal_str, buf)
104    }
105}
106
107// Implement Decode trait for SqlI256
108impl<'r> Decode<'r, Postgres> for I256Pg {
109    fn decode(value: sqlx::postgres::PgValueRef<'r>) -> Result<Self, sqlx::error::BoxDynError> {
110        let s = <String as Decode<Postgres>>::decode(value)?;
111        let i256 = I256::from_str(&s).map_err(|e| format!("Failed to parse I256: {e}"))?;
112        Ok(Self(i256))
113    }
114}
115
116// Implement Decode trait for SqlU256
117impl<'r> Decode<'r, Postgres> for U256Pg {
118    fn decode(value: sqlx::postgres::PgValueRef<'r>) -> Result<Self, sqlx::error::BoxDynError> {
119        let s = <String as Decode<Postgres>>::decode(value)?;
120        let u256 = U256::from_str(&s).map_err(|e| format!("Failed to parse U256: {e}"))?;
121        Ok(Self(u256))
122    }
123}
124
125// Implement Decode trait for U160Pg
126impl<'r> Decode<'r, Postgres> for U160Pg {
127    fn decode(value: sqlx::postgres::PgValueRef<'r>) -> Result<Self, sqlx::error::BoxDynError> {
128        let s = <String as Decode<Postgres>>::decode(value)?;
129        let u160 = U160::from_str(&s).map_err(|e| format!("Failed to parse U160: {e}"))?;
130        Ok(Self(u160))
131    }
132}
133
134// Implement Decode trait for U128Pg
135impl<'r> Decode<'r, Postgres> for U128Pg {
136    fn decode(value: sqlx::postgres::PgValueRef<'r>) -> Result<Self, sqlx::error::BoxDynError> {
137        let s = <String as Decode<Postgres>>::decode(value)?;
138        let u128_val = u128::from_str(&s).map_err(|e| format!("Failed to parse U128: {e}"))?;
139        Ok(Self(u128_val))
140    }
141}
142
143// Implement PgHasArrayType for array support
144impl PgHasArrayType for I256Pg {
145    fn array_type_info() -> PgTypeInfo {
146        PgTypeInfo::with_name("_i256")
147    }
148}
149
150impl PgHasArrayType for U256Pg {
151    fn array_type_info() -> PgTypeInfo {
152        PgTypeInfo::with_name("_u256")
153    }
154}
155
156impl PgHasArrayType for U160Pg {
157    fn array_type_info() -> PgTypeInfo {
158        PgTypeInfo::with_name("_u160")
159    }
160}
161
162impl PgHasArrayType for U128Pg {
163    fn array_type_info() -> PgTypeInfo {
164        PgTypeInfo::with_name("_u128")
165    }
166}