1use std::str::FromStr;
17
18use indexmap::IndexMap;
19use nautilus_core::{UUID4, UnixNanos};
20use nautilus_model::{
21 enums::{
22 ContingencyType, LiquiditySide, OrderSide, OrderStatus, OrderType, TimeInForce, TriggerType,
23 },
24 events::{
25 OrderAccepted, OrderCancelRejected, OrderCanceled, OrderDenied, OrderEmulated,
26 OrderEventAny, OrderExpired, OrderFilled, OrderInitialized, OrderModifyRejected,
27 OrderPendingCancel, OrderPendingUpdate, OrderRejected, OrderReleased, OrderSnapshot,
28 OrderSubmitted, OrderTriggered, OrderUpdated,
29 },
30 identifiers::{
31 AccountId, ClientOrderId, ExecAlgorithmId, InstrumentId, OrderListId, PositionId,
32 StrategyId, TradeId, TraderId, VenueOrderId,
33 },
34 types::{Currency, Money, Price, Quantity},
35};
36use rust_decimal::Decimal;
37use sqlx::{FromRow, Row, postgres::PgRow};
38use ustr::Ustr;
39
40use crate::sql::models::enums::TrailingOffsetTypeModel;
41
42#[derive(Debug)]
43pub struct OrderEventAnyModel(pub OrderEventAny);
44
45#[derive(Debug)]
46pub struct OrderAcceptedModel(pub OrderAccepted);
47
48#[derive(Debug)]
49pub struct OrderCancelRejectedModel(pub OrderCancelRejected);
50
51#[derive(Debug)]
52pub struct OrderCanceledModel(pub OrderCanceled);
53
54#[derive(Debug)]
55pub struct OrderDeniedModel(pub OrderDenied);
56
57#[derive(Debug)]
58pub struct OrderEmulatedModel(pub OrderEmulated);
59
60#[derive(Debug)]
61pub struct OrderExpiredModel(pub OrderExpired);
62
63#[derive(Debug)]
64pub struct OrderFilledModel(pub OrderFilled);
65
66#[derive(Debug)]
67pub struct OrderInitializedModel(pub OrderInitialized);
68
69#[derive(Debug)]
70pub struct OrderModifyRejectedModel(pub OrderModifyRejected);
71
72#[derive(Debug)]
73pub struct OrderPendingCancelModel(pub OrderPendingCancel);
74
75#[derive(Debug)]
76pub struct OrderPendingUpdateModel(pub OrderPendingUpdate);
77
78#[derive(Debug)]
79pub struct OrderRejectedModel(pub OrderRejected);
80
81#[derive(Debug)]
82pub struct OrderReleasedModel(pub OrderReleased);
83
84#[derive(Debug)]
85pub struct OrderSubmittedModel(pub OrderSubmitted);
86
87#[derive(Debug)]
88pub struct OrderTriggeredModel(pub OrderTriggered);
89
90#[derive(Debug)]
91pub struct OrderUpdatedModel(pub OrderUpdated);
92
93#[derive(Debug)]
94pub struct OrderSnapshotModel(pub OrderSnapshot);
95
96impl<'r> FromRow<'r, PgRow> for OrderEventAnyModel {
97 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
98 let kind = row.get::<String, _>("kind");
99 if kind == "OrderAccepted" {
100 let model = OrderAcceptedModel::from_row(row)?;
101 Ok(Self(OrderEventAny::Accepted(model.0)))
102 } else if kind == "OrderCancelRejected" {
103 let model = OrderCancelRejectedModel::from_row(row)?;
104 Ok(Self(OrderEventAny::CancelRejected(model.0)))
105 } else if kind == "OrderCanceled" {
106 let model = OrderCanceledModel::from_row(row)?;
107 Ok(Self(OrderEventAny::Canceled(model.0)))
108 } else if kind == "OrderDenied" {
109 let model = OrderDeniedModel::from_row(row)?;
110 Ok(Self(OrderEventAny::Denied(model.0)))
111 } else if kind == "OrderEmulated" {
112 let model = OrderEmulatedModel::from_row(row)?;
113 Ok(Self(OrderEventAny::Emulated(model.0)))
114 } else if kind == "OrderExpired" {
115 let model = OrderExpiredModel::from_row(row)?;
116 Ok(Self(OrderEventAny::Expired(model.0)))
117 } else if kind == "OrderFilled" {
118 let model = OrderFilledModel::from_row(row)?;
119 Ok(Self(OrderEventAny::Filled(model.0)))
120 } else if kind == "OrderInitialized" {
121 let model = OrderInitializedModel::from_row(row)?;
122 Ok(Self(OrderEventAny::Initialized(model.0)))
123 } else if kind == "OrderModifyRejected" {
124 let model = OrderModifyRejectedModel::from_row(row)?;
125 Ok(Self(OrderEventAny::ModifyRejected(model.0)))
126 } else if kind == "OrderPendingCancel" {
127 let model = OrderPendingCancelModel::from_row(row)?;
128 Ok(Self(OrderEventAny::PendingCancel(model.0)))
129 } else if kind == "OrderPendingUpdate" {
130 let model = OrderPendingUpdateModel::from_row(row)?;
131 Ok(Self(OrderEventAny::PendingUpdate(model.0)))
132 } else if kind == "OrderRejected" {
133 let model = OrderRejectedModel::from_row(row)?;
134 Ok(Self(OrderEventAny::Rejected(model.0)))
135 } else if kind == "OrderReleased" {
136 let model = OrderReleasedModel::from_row(row)?;
137 Ok(Self(OrderEventAny::Released(model.0)))
138 } else if kind == "OrderSubmitted" {
139 let model = OrderSubmittedModel::from_row(row)?;
140 Ok(Self(OrderEventAny::Submitted(model.0)))
141 } else if kind == "OrderTriggered" {
142 let model = OrderTriggeredModel::from_row(row)?;
143 Ok(Self(OrderEventAny::Triggered(model.0)))
144 } else if kind == "OrderUpdated" {
145 let model = OrderUpdatedModel::from_row(row)?;
146 Ok(Self(OrderEventAny::Updated(model.0)))
147 } else {
148 Err(sqlx::Error::Decode(
149 format!("Unknown order event kind: {kind} in Postgres transformation").into(),
150 ))
151 }
152 }
153}
154
155impl<'r> FromRow<'r, PgRow> for OrderInitializedModel {
156 #[expect(
157 clippy::too_many_lines,
158 reason = "SQL row mapping mirrors the full order initialized event constructor"
159 )]
160 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
161 let event_id = row.try_get::<&str, _>("id").map(UUID4::from)?;
162 let client_order_id = row
163 .try_get::<&str, _>("client_order_id")
164 .map(ClientOrderId::from)?;
165 let trader_id = row.try_get::<&str, _>("trader_id").map(TraderId::from)?;
166 let strategy_id = row
167 .try_get::<&str, _>("strategy_id")
168 .map(StrategyId::from)?;
169 let instrument_id = row
170 .try_get::<&str, _>("instrument_id")
171 .map(InstrumentId::from)?;
172 let order_type = row
173 .try_get::<&str, _>("order_type")
174 .map(|x| OrderType::from_str(x).unwrap())?;
175 let order_side = row
176 .try_get::<&str, _>("order_side")
177 .map(|x| OrderSide::from_str(x).unwrap())?;
178 let quantity = row.try_get::<&str, _>("quantity").map(Quantity::from)?;
179 let time_in_force = row
180 .try_get::<&str, _>("time_in_force")
181 .map(|x| TimeInForce::from_str(x).unwrap())?;
182 let post_only = row.try_get::<bool, _>("post_only")?;
183 let reduce_only = row.try_get::<bool, _>("reduce_only")?;
184 let quote_quantity = row.try_get::<bool, _>("quote_quantity")?;
185 let reconciliation = row.try_get::<bool, _>("reconciliation")?;
186 let ts_event = row.try_get::<String, _>("ts_event").map(UnixNanos::from)?;
187 let ts_init = row.try_get::<String, _>("ts_init").map(UnixNanos::from)?;
188 let price = row
189 .try_get::<Option<&str>, _>("price")
190 .ok()
191 .and_then(|x| x.map(Price::from));
192 let trigger_price = row
193 .try_get::<Option<&str>, _>("trigger_price")
194 .ok()
195 .and_then(|x| x.map(Price::from));
196 let trigger_type = row
197 .try_get::<Option<&str>, _>("trigger_type")
198 .ok()
199 .and_then(|x| x.map(|x| TriggerType::from_str(x).unwrap()));
200 let limit_offset = row
201 .try_get::<Option<&str>, _>("limit_offset")
202 .ok()
203 .and_then(|x| x.and_then(|s| Decimal::from_str(s).ok()));
204 let trailing_offset = row
205 .try_get::<Option<&str>, _>("trailing_offset")
206 .ok()
207 .and_then(|x| x.and_then(|s| Decimal::from_str(s).ok()));
208 let trailing_offset_type = row
209 .try_get::<Option<TrailingOffsetTypeModel>, _>("trailing_offset_type")
210 .ok()
211 .and_then(|x| x.map(|x| x.0));
212 let expire_time = row
213 .try_get::<Option<&str>, _>("expire_time")
214 .ok()
215 .and_then(|x| x.map(UnixNanos::from));
216 let display_qty = row
217 .try_get::<Option<&str>, _>("display_qty")
218 .ok()
219 .and_then(|x| x.map(Quantity::from));
220 let emulation_trigger = row
221 .try_get::<Option<&str>, _>("emulation_trigger")
222 .ok()
223 .and_then(|x| x.map(|x| TriggerType::from_str(x).unwrap()));
224 let trigger_instrument_id = row
225 .try_get::<Option<&str>, _>("trigger_instrument_id")
226 .ok()
227 .and_then(|x| x.map(InstrumentId::from));
228 let contingency_type = row
229 .try_get::<Option<&str>, _>("contingency_type")
230 .ok()
231 .and_then(|x| x.map(|x| ContingencyType::from_str(x).unwrap()));
232 let order_list_id = row
233 .try_get::<Option<&str>, _>("order_list_id")
234 .ok()
235 .and_then(|x| x.map(OrderListId::from));
236 let linked_order_ids = row
237 .try_get::<Vec<String>, _>("linked_order_ids")
238 .ok()
239 .map(|x| x.iter().map(|x| ClientOrderId::from(x.as_str())).collect());
240 let parent_order_id = row
241 .try_get::<Option<&str>, _>("parent_order_id")
242 .ok()
243 .and_then(|x| x.map(ClientOrderId::from));
244 let exec_algorithm_id = row
245 .try_get::<Option<&str>, _>("exec_algorithm_id")
246 .ok()
247 .and_then(|x| x.map(ExecAlgorithmId::from));
248 let exec_algorithm_params: Option<IndexMap<Ustr, Ustr>> = row
249 .try_get::<Option<serde_json::Value>, _>("exec_algorithm_params")
250 .ok()
251 .and_then(|x| x.map(|x| serde_json::from_value::<IndexMap<String, String>>(x).unwrap()))
252 .map(|x| {
253 x.into_iter()
254 .map(|(k, v)| (Ustr::from(k.as_str()), Ustr::from(v.as_str())))
255 .collect()
256 });
257 let exec_spawn_id = row
258 .try_get::<Option<&str>, _>("exec_spawn_id")
259 .ok()
260 .and_then(|x| x.map(ClientOrderId::from));
261 let tags: Option<Vec<Ustr>> = row
262 .try_get::<Option<serde_json::Value>, _>("tags")
263 .ok()
264 .and_then(|x| x.map(|x| serde_json::from_value::<Vec<String>>(x).unwrap()))
265 .map(|x| x.into_iter().map(|x| Ustr::from(x.as_str())).collect());
266 let order_event = OrderInitialized::new(
267 trader_id,
268 strategy_id,
269 instrument_id,
270 client_order_id,
271 order_side,
272 order_type,
273 quantity,
274 time_in_force,
275 post_only,
276 reduce_only,
277 quote_quantity,
278 reconciliation,
279 event_id,
280 ts_event,
281 ts_init,
282 price,
283 trigger_price,
284 trigger_type,
285 limit_offset,
286 trailing_offset,
287 trailing_offset_type,
288 expire_time,
289 display_qty,
290 emulation_trigger,
291 trigger_instrument_id,
292 contingency_type,
293 order_list_id,
294 linked_order_ids,
295 parent_order_id,
296 exec_algorithm_id,
297 exec_algorithm_params,
298 exec_spawn_id,
299 tags,
300 );
301 Ok(Self(order_event))
302 }
303}
304
305impl<'r> FromRow<'r, PgRow> for OrderAcceptedModel {
306 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
307 let event_id = row.try_get::<&str, _>("id").map(UUID4::from)?;
308 let trader_id = row.try_get::<&str, _>("trader_id").map(TraderId::from)?;
309 let strategy_id = row
310 .try_get::<&str, _>("strategy_id")
311 .map(StrategyId::from)?;
312 let instrument_id = row
313 .try_get::<&str, _>("instrument_id")
314 .map(InstrumentId::from)?;
315 let client_order_id = row
316 .try_get::<&str, _>("client_order_id")
317 .map(ClientOrderId::from)?;
318 let venue_order_id = row
319 .try_get::<&str, _>("venue_order_id")
320 .map(VenueOrderId::from)?;
321 let account_id = row.try_get::<&str, _>("account_id").map(AccountId::from)?;
322 let ts_event = row.try_get::<&str, _>("ts_event").map(UnixNanos::from)?;
323 let ts_init = row.try_get::<&str, _>("ts_init").map(UnixNanos::from)?;
324 let order_event = OrderAccepted::new(
325 trader_id,
326 strategy_id,
327 instrument_id,
328 client_order_id,
329 venue_order_id,
330 account_id,
331 event_id,
332 ts_event,
333 ts_init,
334 false,
335 );
336 Ok(Self(order_event))
337 }
338}
339
340impl<'r> FromRow<'r, PgRow> for OrderCancelRejectedModel {
341 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
342 let trader_id = row.try_get::<&str, _>("trader_id").map(TraderId::from)?;
343 let strategy_id = row
344 .try_get::<&str, _>("strategy_id")
345 .map(StrategyId::from)?;
346 let instrument_id = row
347 .try_get::<&str, _>("instrument_id")
348 .map(InstrumentId::from)?;
349 let client_order_id = row
350 .try_get::<&str, _>("client_order_id")
351 .map(ClientOrderId::from)?;
352 let reason = row.try_get::<&str, _>("reason").map(Ustr::from)?;
353 let event_id = row.try_get::<&str, _>("id").map(UUID4::from)?;
354 let ts_event = row.try_get::<&str, _>("ts_event").map(UnixNanos::from)?;
355 let ts_init = row.try_get::<&str, _>("ts_init").map(UnixNanos::from)?;
356 let reconciliation = row.try_get::<bool, _>("reconciliation")?;
357 let venue_order_id = row
358 .try_get::<Option<&str>, _>("venue_order_id")?
359 .map(Into::into);
360 let account_id = row
361 .try_get::<Option<&str>, _>("account_id")?
362 .map(Into::into);
363 let order_event = OrderCancelRejected::new(
364 trader_id,
365 strategy_id,
366 instrument_id,
367 client_order_id,
368 reason,
369 event_id,
370 ts_event,
371 ts_init,
372 reconciliation,
373 venue_order_id,
374 account_id,
375 );
376 Ok(Self(order_event))
377 }
378}
379
380impl<'r> FromRow<'r, PgRow> for OrderCanceledModel {
381 fn from_row(_row: &'r PgRow) -> Result<Self, sqlx::Error> {
382 todo!()
383 }
384}
385
386impl<'r> FromRow<'r, PgRow> for OrderDeniedModel {
387 fn from_row(_row: &'r PgRow) -> Result<Self, sqlx::Error> {
388 todo!()
389 }
390}
391
392impl<'r> FromRow<'r, PgRow> for OrderEmulatedModel {
393 fn from_row(_row: &'r PgRow) -> Result<Self, sqlx::Error> {
394 todo!()
395 }
396}
397
398impl<'r> FromRow<'r, PgRow> for OrderExpiredModel {
399 fn from_row(_row: &'r PgRow) -> Result<Self, sqlx::Error> {
400 todo!()
401 }
402}
403
404impl<'r> FromRow<'r, PgRow> for OrderFilledModel {
405 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
406 let event_id = row.try_get::<&str, _>("id").map(UUID4::from)?;
407 let trader_id = row.try_get::<&str, _>("trader_id").map(TraderId::from)?;
408 let strategy_id = row
409 .try_get::<&str, _>("strategy_id")
410 .map(StrategyId::from)?;
411 let instrument_id = row
412 .try_get::<&str, _>("instrument_id")
413 .map(InstrumentId::from)?;
414 let client_order_id = row
415 .try_get::<&str, _>("client_order_id")
416 .map(ClientOrderId::from)?;
417 let venue_order_id = row
418 .try_get::<&str, _>("venue_order_id")
419 .map(VenueOrderId::from)?;
420 let account_id = row.try_get::<&str, _>("account_id").map(AccountId::from)?;
421 let trade_id = row.try_get::<&str, _>("trade_id").map(TradeId::from)?;
422 let order_side = row
423 .try_get::<&str, _>("order_side")
424 .map(|x| OrderSide::from_str(x).unwrap())?;
425 let order_type = row
426 .try_get::<&str, _>("order_type")
427 .map(|x| OrderType::from_str(x).unwrap())?;
428 let last_px = row.try_get::<&str, _>("last_px").map(Price::from)?;
429 let last_qty = row.try_get::<&str, _>("last_qty").map(Quantity::from)?;
430 let currency = row.try_get::<&str, _>("currency").map(Currency::from)?;
431 let liquidity_side = row
432 .try_get::<&str, _>("liquidity_side")
433 .map(|x| LiquiditySide::from_str(x).unwrap())?;
434 let ts_event = row.try_get::<&str, _>("ts_event").map(UnixNanos::from)?;
435 let ts_init = row.try_get::<&str, _>("ts_init").map(UnixNanos::from)?;
436 let position_id = row
437 .try_get::<Option<&str>, _>("position_id")
438 .map(|x| x.map(PositionId::from))?;
439 let commission = row
440 .try_get::<Option<&str>, _>("commission")
441 .map(|x| x.map(|x| Money::from_str(x).unwrap()))?;
442 let order_event = OrderFilled::new(
443 trader_id,
444 strategy_id,
445 instrument_id,
446 client_order_id,
447 venue_order_id,
448 account_id,
449 trade_id,
450 order_side,
451 order_type,
452 last_qty,
453 last_px,
454 currency,
455 liquidity_side,
456 event_id,
457 ts_event,
458 ts_init,
459 false,
460 position_id,
461 commission,
462 );
463 Ok(Self(order_event))
464 }
465}
466
467impl<'r> FromRow<'r, PgRow> for OrderModifyRejectedModel {
468 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
469 let trader_id = row.try_get::<&str, _>("trader_id").map(TraderId::from)?;
470 let strategy_id = row
471 .try_get::<&str, _>("strategy_id")
472 .map(StrategyId::from)?;
473 let instrument_id = row
474 .try_get::<&str, _>("instrument_id")
475 .map(InstrumentId::from)?;
476 let client_order_id = row
477 .try_get::<&str, _>("client_order_id")
478 .map(ClientOrderId::from)?;
479 let reason = row.try_get::<&str, _>("reason").map(Ustr::from)?;
480 let event_id = row.try_get::<&str, _>("id").map(UUID4::from)?;
481 let ts_event = row.try_get::<&str, _>("ts_event").map(UnixNanos::from)?;
482 let ts_init = row.try_get::<&str, _>("ts_init").map(UnixNanos::from)?;
483 let reconciliation = row.try_get::<bool, _>("reconciliation")?;
484 let venue_order_id = row
485 .try_get::<Option<&str>, _>("venue_order_id")?
486 .map(Into::into);
487 let account_id = row
488 .try_get::<Option<&str>, _>("account_id")?
489 .map(Into::into);
490 let order_event = OrderModifyRejected::new(
491 trader_id,
492 strategy_id,
493 instrument_id,
494 client_order_id,
495 reason,
496 event_id,
497 ts_event,
498 ts_init,
499 reconciliation,
500 venue_order_id,
501 account_id,
502 );
503 Ok(Self(order_event))
504 }
505}
506
507impl<'r> FromRow<'r, PgRow> for OrderPendingCancelModel {
508 fn from_row(_row: &'r PgRow) -> Result<Self, sqlx::Error> {
509 todo!()
510 }
511}
512
513impl<'r> FromRow<'r, PgRow> for OrderPendingUpdateModel {
514 fn from_row(_row: &'r PgRow) -> Result<Self, sqlx::Error> {
515 todo!()
516 }
517}
518
519impl<'r> FromRow<'r, PgRow> for OrderRejectedModel {
520 fn from_row(_row: &'r PgRow) -> Result<Self, sqlx::Error> {
521 todo!()
522 }
523}
524
525impl<'r> FromRow<'r, PgRow> for OrderReleasedModel {
526 fn from_row(_row: &'r PgRow) -> Result<Self, sqlx::Error> {
527 todo!()
528 }
529}
530
531impl<'r> FromRow<'r, PgRow> for OrderSubmittedModel {
532 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
533 let trader_id = row.try_get::<&str, _>("trader_id").map(TraderId::from)?;
534 let strategy_id = row
535 .try_get::<&str, _>("strategy_id")
536 .map(StrategyId::from)?;
537 let instrument_id = row
538 .try_get::<&str, _>("instrument_id")
539 .map(InstrumentId::from)?;
540 let client_order_id = row
541 .try_get::<&str, _>("client_order_id")
542 .map(ClientOrderId::from)?;
543 let account_id = row.try_get::<&str, _>("account_id").map(AccountId::from)?;
544 let event_id = row.try_get::<&str, _>("id").map(UUID4::from)?;
545 let ts_event = row
546 .try_get::<String, _>("ts_event")
547 .map(|res| UnixNanos::from(res.as_str()))?;
548 let ts_init = row
549 .try_get::<String, _>("ts_init")
550 .map(|res| UnixNanos::from(res.as_str()))?;
551 let order_event = OrderSubmitted::new(
552 trader_id,
553 strategy_id,
554 instrument_id,
555 client_order_id,
556 account_id,
557 event_id,
558 ts_event,
559 ts_init,
560 );
561 Ok(Self(order_event))
562 }
563}
564
565impl<'r> FromRow<'r, PgRow> for OrderTriggeredModel {
566 fn from_row(_row: &'r PgRow) -> Result<Self, sqlx::Error> {
567 todo!()
568 }
569}
570
571impl<'r> FromRow<'r, PgRow> for OrderUpdatedModel {
572 fn from_row(_row: &'r PgRow) -> Result<Self, sqlx::Error> {
573 todo!()
574 }
575}
576
577impl<'r> FromRow<'r, PgRow> for OrderSnapshotModel {
578 #[expect(
579 clippy::too_many_lines,
580 reason = "SQL row mapping mirrors the full order snapshot constructor"
581 )]
582 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
583 let trader_id = row.try_get::<&str, _>("trader_id").map(TraderId::from)?;
584 let strategy_id = row
585 .try_get::<&str, _>("strategy_id")
586 .map(StrategyId::from)?;
587 let instrument_id = row
588 .try_get::<&str, _>("instrument_id")
589 .map(InstrumentId::from)?;
590 let client_order_id = row
591 .try_get::<&str, _>("client_order_id")
592 .map(ClientOrderId::from)?;
593 let venue_order_id = row
594 .try_get::<Option<&str>, _>("venue_order_id")
595 .ok()
596 .and_then(|x| x.map(VenueOrderId::from));
597 let position_id = row
598 .try_get::<Option<&str>, _>("position_id")
599 .ok()
600 .and_then(|x| x.map(PositionId::from));
601 let account_id = row
602 .try_get::<Option<&str>, _>("account_id")
603 .ok()
604 .and_then(|x| x.map(AccountId::from));
605 let last_trade_id = row
606 .try_get::<Option<&str>, _>("last_trade_id")
607 .ok()
608 .and_then(|x| x.map(TradeId::from));
609 let order_type = row
610 .try_get::<&str, _>("order_type")
611 .map(|x| OrderType::from_str(x).expect("Invalid `OrderType`"))?;
612 let order_side = row
613 .try_get::<&str, _>("order_side")
614 .map(|x| OrderSide::from_str(x).expect("Invalid `OrderSide`"))?;
615 let quantity = row.try_get::<&str, _>("quantity").map(Quantity::from)?;
616 let price = row
617 .try_get::<Option<&str>, _>("price")
618 .ok()
619 .and_then(|x| x.map(Price::from));
620 let trigger_price = row
621 .try_get::<Option<&str>, _>("trigger_price")
622 .ok()
623 .and_then(|x| x.map(Price::from));
624 let trigger_type = row
625 .try_get::<Option<&str>, _>("trigger_type")
626 .ok()
627 .and_then(|x| x.map(|x| TriggerType::from_str(x).expect("Invalid `TriggerType`")));
628 let limit_offset = row
629 .try_get::<Option<&str>, _>("limit_offset")
630 .ok()
631 .and_then(|x| x.and_then(|s| Decimal::from_str(s).ok()));
632 let trailing_offset = row
633 .try_get::<Option<&str>, _>("trailing_offset")
634 .ok()
635 .and_then(|x| x.and_then(|s| Decimal::from_str(s).ok()));
636 let trailing_offset_type = row
637 .try_get::<Option<TrailingOffsetTypeModel>, _>("trailing_offset_type")
638 .ok()
639 .and_then(|x| x.map(|x| x.0));
640 let time_in_force = row
641 .try_get::<&str, _>("time_in_force")
642 .map(|x| TimeInForce::from_str(x).expect("Invalid `TimeInForce`"))?;
643 let expire_time = row
644 .try_get::<Option<&str>, _>("expire_time")
645 .ok()
646 .and_then(|x| x.map(UnixNanos::from));
647 let filled_qty = row.try_get::<&str, _>("filled_qty").map(Quantity::from)?;
648 let liquidity_side = row
649 .try_get::<Option<&str>, _>("liquidity_side")
650 .ok()
651 .and_then(|x| x.map(|x| LiquiditySide::from_str(x).expect("Invalid `LiquiditySide`")));
652 let avg_px = row.try_get::<Option<f64>, _>("avg_px").ok().flatten();
653 let slippage = row.try_get::<Option<f64>, _>("slippage").ok().flatten();
654 let commissions = row
655 .try_get::<Option<Vec<String>>, _>("commissions")?
656 .map_or_else(Vec::new, |c| {
657 c.into_iter().map(|s| Money::from(&s)).collect()
658 });
659 let status = row
660 .try_get::<&str, _>("status")
661 .map(|x| OrderStatus::from_str(x).expect("Invalid `OrderStatus`"))?;
662 let is_post_only = row.try_get::<bool, _>("is_post_only")?;
663 let is_reduce_only = row.try_get::<bool, _>("is_reduce_only")?;
664 let is_quote_quantity = row.try_get::<bool, _>("is_quote_quantity")?;
665 let display_qty = row
666 .try_get::<Option<&str>, _>("display_qty")
667 .ok()
668 .and_then(|x| x.map(Quantity::from));
669 let emulation_trigger = row
670 .try_get::<Option<&str>, _>("emulation_trigger")
671 .ok()
672 .and_then(|x| x.map(|x| TriggerType::from_str(x).expect("Invalid `TriggerType`")));
673 let trigger_instrument_id = row
674 .try_get::<Option<&str>, _>("trigger_instrument_id")
675 .ok()
676 .and_then(|x| x.map(InstrumentId::from));
677 let contingency_type = row
678 .try_get::<Option<&str>, _>("contingency_type")
679 .ok()
680 .and_then(|x| {
681 x.map(|x| ContingencyType::from_str(x).expect("Invalid `ContingencyType`"))
682 });
683 let order_list_id = row
684 .try_get::<Option<&str>, _>("order_list_id")
685 .ok()
686 .and_then(|x| x.map(OrderListId::from));
687 let linked_order_ids = row
688 .try_get::<Option<Vec<String>>, _>("linked_order_ids")
689 .ok()
690 .and_then(|ids| ids.map(|ids| ids.into_iter().map(ClientOrderId::from).collect()));
691 let parent_order_id = row
692 .try_get::<Option<&str>, _>("parent_order_id")
693 .ok()
694 .and_then(|x| x.map(ClientOrderId::from));
695 let exec_algorithm_id = row
696 .try_get::<Option<&str>, _>("exec_algorithm_id")
697 .ok()
698 .and_then(|x| x.map(ExecAlgorithmId::from));
699 let exec_algorithm_params: Option<IndexMap<Ustr, Ustr>> = row
700 .try_get::<Option<serde_json::Value>, _>("exec_algorithm_params")
701 .ok()
702 .and_then(|x| {
703 x.map(|x| {
704 serde_json::from_value::<IndexMap<String, String>>(x)
705 .expect("Invalid exec algorithm params")
706 })
707 })
708 .map(|x| {
709 x.into_iter()
710 .map(|(k, v)| (Ustr::from(k.as_str()), Ustr::from(v.as_str())))
711 .collect()
712 });
713 let exec_spawn_id = row
714 .try_get::<Option<&str>, _>("exec_spawn_id")
715 .ok()
716 .and_then(|x| x.map(ClientOrderId::from));
717 let tags = row
718 .try_get::<Option<serde_json::Value>, _>("tags")
719 .ok()
720 .flatten()
721 .and_then(|tags_value| {
722 serde_json::from_value::<Vec<String>>(tags_value)
723 .ok()
724 .map(|vec| {
725 vec.into_iter()
726 .map(|tag| Ustr::from(tag.as_str()))
727 .collect::<Vec<Ustr>>()
728 })
729 });
730 let init_id = row.try_get::<&str, _>("init_id").map(UUID4::from)?;
731 let ts_init = row.try_get::<String, _>("ts_init").map(UnixNanos::from)?;
732 let ts_last = row.try_get::<String, _>("ts_last").map(UnixNanos::from)?;
733
734 let snapshot = OrderSnapshot {
735 trader_id,
736 strategy_id,
737 instrument_id,
738 client_order_id,
739 venue_order_id,
740 position_id,
741 account_id,
742 last_trade_id,
743 order_type,
744 order_side,
745 quantity,
746 price,
747 trigger_price,
748 trigger_type,
749 limit_offset,
750 trailing_offset,
751 trailing_offset_type,
752 time_in_force,
753 expire_time,
754 filled_qty,
755 liquidity_side,
756 avg_px,
757 slippage,
758 commissions,
759 status,
760 is_post_only,
761 is_reduce_only,
762 is_quote_quantity,
763 display_qty,
764 emulation_trigger,
765 trigger_instrument_id,
766 contingency_type,
767 order_list_id,
768 linked_order_ids,
769 parent_order_id,
770 exec_algorithm_id,
771 exec_algorithm_params,
772 exec_spawn_id,
773 tags,
774 init_id,
775 ts_init,
776 ts_last,
777 causation_id: None,
778 };
779
780 Ok(Self(snapshot))
781 }
782}