nautilus_infrastructure/sql/models/
enums.rs1use std::str::FromStr;
17
18use nautilus_model::enums::{
19 AggregationSource, AggressorSide, AssetClass, BarAggregation, CurrencyType, PriceType,
20 TrailingOffsetType,
21};
22use sqlx::{
23 Database, Decode, Postgres, encode::IsNull, error::BoxDynError, postgres::PgTypeInfo,
24 types::Type,
25};
26
27#[derive(Debug)]
28pub struct CurrencyTypeModel(pub CurrencyType);
29
30#[derive(Debug)]
31pub struct PriceTypeModel(pub PriceType);
32
33#[derive(Debug)]
34pub struct BarAggregationModel(pub BarAggregation);
35
36#[derive(Debug)]
37pub struct AssetClassModel(pub AssetClass);
38
39#[derive(Debug)]
40pub struct TrailingOffsetTypeModel(pub TrailingOffsetType);
41
42#[derive(Debug)]
43pub struct AggressorSideModel(pub AggressorSide);
44
45#[derive(Debug)]
46pub struct AggregationSourceModel(pub AggregationSource);
47
48impl sqlx::Encode<'_, sqlx::Postgres> for CurrencyTypeModel {
49 fn encode_by_ref(
50 &self,
51 buf: &mut <Postgres as Database>::ArgumentBuffer<'_>,
52 ) -> Result<IsNull, BoxDynError> {
53 let currency_type_str = match self.0 {
54 CurrencyType::Crypto => "CRYPTO",
55 CurrencyType::Fiat => "FIAT",
56 CurrencyType::CommodityBacked => "COMMODITY_BACKED",
57 };
58 <&str as sqlx::Encode<sqlx::Postgres>>::encode(currency_type_str, buf)
59 }
60}
61
62impl<'r> sqlx::Decode<'r, sqlx::Postgres> for CurrencyTypeModel {
63 fn decode(value: <Postgres as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {
64 let currency_type_str: &str = <&str as Decode<sqlx::Postgres>>::decode(value)?;
65 let currency_type = CurrencyType::from_str(currency_type_str).map_err(|_| {
66 sqlx::Error::Decode(format!("Invalid currency type: {currency_type_str}").into())
67 })?;
68 Ok(Self(currency_type))
69 }
70}
71
72impl sqlx::Type<sqlx::Postgres> for CurrencyTypeModel {
73 fn type_info() -> sqlx::postgres::PgTypeInfo {
74 PgTypeInfo::with_name("currency_type")
75 }
76
77 fn compatible(ty: &sqlx::postgres::PgTypeInfo) -> bool {
78 *ty == Self::type_info() || <&str as Type<sqlx::Postgres>>::compatible(ty)
79 }
80}
81
82impl sqlx::Encode<'_, sqlx::Postgres> for AssetClassModel {
83 fn encode_by_ref(
84 &self,
85 buf: &mut <Postgres as Database>::ArgumentBuffer<'_>,
86 ) -> Result<IsNull, BoxDynError> {
87 let asset_type_str = match self.0 {
88 AssetClass::FX => "FX",
89 AssetClass::Equity => "EQUITY",
90 AssetClass::Commodity => "COMMODITY",
91 AssetClass::Debt => "DEBT",
92 AssetClass::Index => "INDEX",
93 AssetClass::Cryptocurrency => "CRYPTOCURRENCY",
94 AssetClass::Alternative => "ALTERNATIVE",
95 };
96 <&str as sqlx::Encode<sqlx::Postgres>>::encode(asset_type_str, buf)
97 }
98}
99
100impl<'r> sqlx::Decode<'r, sqlx::Postgres> for AssetClassModel {
101 fn decode(value: <Postgres as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {
102 let asset_class_str: &str = <&str as Decode<sqlx::Postgres>>::decode(value)?;
103 let asset_class = AssetClass::from_str(asset_class_str).map_err(|_| {
104 sqlx::Error::Decode(format!("Invalid asset class: {asset_class_str}").into())
105 })?;
106 Ok(Self(asset_class))
107 }
108}
109
110impl sqlx::Type<sqlx::Postgres> for AssetClassModel {
111 fn type_info() -> sqlx::postgres::PgTypeInfo {
112 PgTypeInfo::with_name("asset_class")
113 }
114
115 fn compatible(ty: &sqlx::postgres::PgTypeInfo) -> bool {
116 *ty == Self::type_info() || <&str as Type<sqlx::Postgres>>::compatible(ty)
117 }
118}
119
120impl sqlx::Encode<'_, sqlx::Postgres> for TrailingOffsetTypeModel {
121 fn encode_by_ref(
122 &self,
123 buf: &mut <Postgres as Database>::ArgumentBuffer<'_>,
124 ) -> Result<IsNull, BoxDynError> {
125 let trailing_offset_type_str = match self.0 {
126 TrailingOffsetType::NoTrailingOffset => "NO_TRAILING_OFFSET",
127 TrailingOffsetType::Price => "PRICE",
128 TrailingOffsetType::BasisPoints => "BASIS_POINTS",
129 TrailingOffsetType::Ticks => "TICKS",
130 TrailingOffsetType::PriceTier => "PRICE_TIER",
131 };
132 <&str as sqlx::Encode<sqlx::Postgres>>::encode(trailing_offset_type_str, buf)
133 }
134}
135
136impl<'r> sqlx::Decode<'r, sqlx::Postgres> for TrailingOffsetTypeModel {
137 fn decode(value: <Postgres as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {
138 let trailing_offset_type_str: &str = <&str as Decode<sqlx::Postgres>>::decode(value)?;
139 let trailing_offset_type =
140 TrailingOffsetType::from_str(trailing_offset_type_str).map_err(|_| {
141 sqlx::Error::Decode(
142 format!("Invalid trailing offset type: {trailing_offset_type_str}").into(),
143 )
144 })?;
145 Ok(Self(trailing_offset_type))
146 }
147}
148
149impl sqlx::Type<sqlx::Postgres> for TrailingOffsetTypeModel {
150 fn type_info() -> sqlx::postgres::PgTypeInfo {
151 PgTypeInfo::with_name("trailing_offset_type")
152 }
153
154 fn compatible(ty: &sqlx::postgres::PgTypeInfo) -> bool {
155 *ty == Self::type_info() || <&str as Type<sqlx::Postgres>>::compatible(ty)
156 }
157}
158
159impl sqlx::Encode<'_, sqlx::Postgres> for AggressorSideModel {
160 fn encode_by_ref(
161 &self,
162 buf: &mut <Postgres as Database>::ArgumentBuffer<'_>,
163 ) -> Result<IsNull, BoxDynError> {
164 let aggressor_side_str = match self.0 {
165 AggressorSide::NoAggressor => "NO_AGGRESSOR",
166 AggressorSide::Buyer => "BUYER",
167 AggressorSide::Seller => "SELLER",
168 };
169 <&str as sqlx::Encode<sqlx::Postgres>>::encode(aggressor_side_str, buf)
170 }
171}
172
173impl<'r> sqlx::Decode<'r, sqlx::Postgres> for AggressorSideModel {
174 fn decode(value: <Postgres as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {
175 let aggressor_side_str: &str = <&str as Decode<sqlx::Postgres>>::decode(value)?;
176 let aggressor_side = AggressorSide::from_str(aggressor_side_str).map_err(|_| {
177 sqlx::Error::Decode(format!("Invalid aggressor side: {aggressor_side_str}").into())
178 })?;
179 Ok(Self(aggressor_side))
180 }
181}
182
183impl sqlx::Type<sqlx::Postgres> for AggressorSideModel {
184 fn type_info() -> sqlx::postgres::PgTypeInfo {
185 PgTypeInfo::with_name("aggressor_side")
186 }
187
188 fn compatible(ty: &sqlx::postgres::PgTypeInfo) -> bool {
189 *ty == Self::type_info() || <&str as Type<sqlx::Postgres>>::compatible(ty)
190 }
191}
192
193impl sqlx::Encode<'_, sqlx::Postgres> for AggregationSourceModel {
194 fn encode_by_ref(
195 &self,
196 buf: &mut <Postgres as Database>::ArgumentBuffer<'_>,
197 ) -> Result<IsNull, BoxDynError> {
198 let aggregation_source_str = match self.0 {
199 AggregationSource::Internal => "INTERNAL",
200 AggregationSource::External => "EXTERNAL",
201 };
202 <&str as sqlx::Encode<sqlx::Postgres>>::encode(aggregation_source_str, buf)
203 }
204}
205
206impl<'r> sqlx::Decode<'r, sqlx::Postgres> for AggregationSourceModel {
207 fn decode(value: <Postgres as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {
208 let aggregation_source_str: &str = <&str as Decode<sqlx::Postgres>>::decode(value)?;
209 let aggregation_source =
210 AggregationSource::from_str(aggregation_source_str).map_err(|_| {
211 sqlx::Error::Decode(
212 format!("Invalid aggregation source: {aggregation_source_str}").into(),
213 )
214 })?;
215 Ok(Self(aggregation_source))
216 }
217}
218
219impl sqlx::Type<sqlx::Postgres> for AggregationSourceModel {
220 fn type_info() -> sqlx::postgres::PgTypeInfo {
221 PgTypeInfo::with_name("aggregation_source")
222 }
223
224 fn compatible(ty: &sqlx::postgres::PgTypeInfo) -> bool {
225 *ty == Self::type_info() || <&str as Type<sqlx::Postgres>>::compatible(ty)
226 }
227}
228
229impl sqlx::Encode<'_, sqlx::Postgres> for BarAggregationModel {
230 fn encode_by_ref(
231 &self,
232 buf: &mut <Postgres as Database>::ArgumentBuffer<'_>,
233 ) -> Result<IsNull, BoxDynError> {
234 let bar_aggregation_str = match self.0 {
235 BarAggregation::Tick => "TICK",
236 BarAggregation::TickImbalance => "TICK_IMBALANCE",
237 BarAggregation::TickRuns => "TICK_RUNS",
238 BarAggregation::Volume => "VOLUME",
239 BarAggregation::VolumeImbalance => "VOLUME_IMBALANCE",
240 BarAggregation::VolumeRuns => "VOLUME_RUNS",
241 BarAggregation::Value => "VALUE",
242 BarAggregation::ValueImbalance => "VALUE_IMBALANCE",
243 BarAggregation::ValueRuns => "VALUE_RUNS",
244 BarAggregation::Millisecond => "TIME",
245 BarAggregation::Second => "SECOND",
246 BarAggregation::Minute => "MINUTE",
247 BarAggregation::Hour => "HOUR",
248 BarAggregation::Day => "DAY",
249 BarAggregation::Week => "WEEK",
250 BarAggregation::Month => "MONTH",
251 };
252 <&str as sqlx::Encode<sqlx::Postgres>>::encode(bar_aggregation_str, buf)
253 }
254}
255
256impl<'r> sqlx::Decode<'r, sqlx::Postgres> for BarAggregationModel {
257 fn decode(value: <Postgres as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {
258 let bar_aggregation_str: &str = <&str as Decode<sqlx::Postgres>>::decode(value)?;
259 let bar_aggregation = BarAggregation::from_str(bar_aggregation_str).map_err(|_| {
260 sqlx::Error::Decode(format!("Invalid bar aggregation: {bar_aggregation_str}").into())
261 })?;
262 Ok(Self(bar_aggregation))
263 }
264}
265
266impl sqlx::Type<sqlx::Postgres> for BarAggregationModel {
267 fn type_info() -> sqlx::postgres::PgTypeInfo {
268 PgTypeInfo::with_name("bar_aggregation")
269 }
270
271 fn compatible(ty: &sqlx::postgres::PgTypeInfo) -> bool {
272 *ty == Self::type_info() || <&str as Type<sqlx::Postgres>>::compatible(ty)
273 }
274}
275
276impl sqlx::Encode<'_, sqlx::Postgres> for PriceTypeModel {
277 fn encode_by_ref(
278 &self,
279 buf: &mut <Postgres as Database>::ArgumentBuffer<'_>,
280 ) -> Result<IsNull, BoxDynError> {
281 let price_type_str = match self.0 {
282 PriceType::Bid => "BID",
283 PriceType::Ask => "ASK",
284 PriceType::Mid => "MID",
285 PriceType::Last => "LAST",
286 PriceType::Mark => "MARK",
287 };
288 <&str as sqlx::Encode<sqlx::Postgres>>::encode(price_type_str, buf)
289 }
290}
291
292impl<'r> sqlx::Decode<'r, sqlx::Postgres> for PriceTypeModel {
293 fn decode(value: <Postgres as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {
294 let price_type_str: &str = <&str as Decode<sqlx::Postgres>>::decode(value)?;
295 let price_type = PriceType::from_str(price_type_str).map_err(|_| {
296 sqlx::Error::Decode(format!("Invalid price type: {price_type_str}").into())
297 })?;
298 Ok(Self(price_type))
299 }
300}
301
302impl sqlx::Type<sqlx::Postgres> for PriceTypeModel {
303 fn type_info() -> sqlx::postgres::PgTypeInfo {
304 PgTypeInfo::with_name("price_type")
305 }
306
307 fn compatible(ty: &sqlx::postgres::PgTypeInfo) -> bool {
308 *ty == Self::type_info() || <&str as Type<sqlx::Postgres>>::compatible(ty)
309 }
310}