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