From 1e0bf3de72afd59cbad73ade0db35c9c9e89e858 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Tue, 23 Nov 2021 22:47:03 +1100 Subject: [PATCH] Implement sqlx::Type for more datatypes This maker our DB code slightly simpler because we can directly use our newtypes in the query and they are also constructed right away by sqlx. --- daemon/sqlx-data.json | 138 ++++++++++++++++++++-------------------- daemon/src/db.rs | 117 +++++++++++++++++----------------- daemon/src/lib.rs | 2 + daemon/src/model.rs | 11 +++- daemon/src/model/cfd.rs | 2 +- daemon/src/sqlx_ext.rs | 30 +++++++++ 6 files changed, 169 insertions(+), 131 deletions(-) create mode 100644 daemon/src/sqlx_ext.rs diff --git a/daemon/sqlx-data.json b/daemon/sqlx-data.json index 6722eb5..84a8edf 100644 --- a/daemon/sqlx-data.json +++ b/daemon/sqlx-data.json @@ -1,7 +1,25 @@ { "db": "SQLite", - "04399897350d026ee0830ccaba3638f8aa8f4ef9694d59286f32b9e2449a99fa": { - "query": "\n with ord as (\n select\n id as order_id,\n uuid,\n trading_pair,\n position,\n initial_price,\n min_quantity,\n max_quantity,\n leverage,\n liquidation_price,\n creation_timestamp_seconds as ts_secs,\n settlement_time_interval_seconds as settlement_time_interval_secs,\n origin,\n oracle_event_id\n from orders\n ),\n\n cfd as (\n select\n ord.order_id,\n id as cfd_id,\n quantity_usd\n from cfds\n inner join ord on ord.order_id = cfds.order_id\n ),\n\n state as (\n select\n id as state_id,\n cfd.order_id,\n cfd.quantity_usd,\n state\n from cfd_states\n inner join cfd on cfd.cfd_id = cfd_states.cfd_id\n where id in (\n select\n max(id) as id\n from cfd_states\n group by (cfd_id)\n )\n )\n\n select\n ord.uuid as \"uuid: crate::model::cfd::OrderId\",\n ord.trading_pair as \"trading_pair: crate::model::TradingPair\",\n ord.position as \"position: crate::model::Position\",\n ord.initial_price,\n ord.min_quantity,\n ord.max_quantity,\n ord.leverage as \"leverage: crate::model::Leverage\",\n ord.liquidation_price,\n ord.ts_secs as \"ts_secs: crate::model::Timestamp\",\n ord.settlement_time_interval_secs as \"settlement_time_interval_secs: i64\",\n ord.origin as \"origin: crate::model::cfd::Origin\",\n ord.oracle_event_id,\n state.quantity_usd,\n state.state\n\n from ord\n inner join state on state.order_id = ord.order_id\n\n where ord.uuid = $1\n ", + "221a6283db798bacaba99e7e85130f9a8bbea1299d8cb99d272b1d478dc19775": { + "query": "\n select\n state\n from cfd_states\n where cfd_id = $1\n order by id desc\n limit 1;\n ", + "describe": { + "columns": [ + { + "name": "state", + "ordinal": 0, + "type_info": "Text" + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + false + ] + } + }, + "3d41b8a81df84252dae228d8512b7491416520a6ad89561f67cdfb673f864a5a": { + "query": "\n with ord as (\n select\n id as order_id,\n uuid,\n trading_pair,\n position,\n initial_price,\n min_quantity,\n max_quantity,\n leverage,\n liquidation_price,\n creation_timestamp_seconds as ts_secs,\n settlement_time_interval_seconds as settlement_time_interval_secs,\n origin,\n oracle_event_id\n from orders\n ),\n\n cfd as (\n select\n ord.order_id,\n id as cfd_id,\n quantity_usd\n from cfds\n inner join ord on ord.order_id = cfds.order_id\n ),\n\n state as (\n select\n id as state_id,\n cfd.order_id,\n cfd.quantity_usd,\n state\n from cfd_states\n inner join cfd on cfd.cfd_id = cfd_states.cfd_id\n where id in (\n select\n max(id) as id\n from cfd_states\n group by (cfd_id)\n )\n )\n\n select\n ord.uuid as \"uuid: crate::model::cfd::OrderId\",\n ord.trading_pair as \"trading_pair: crate::model::TradingPair\",\n ord.position as \"position: crate::model::Position\",\n ord.initial_price as \"initial_price: crate::model::Price\",\n ord.min_quantity as \"min_quantity: crate::model::Usd\",\n ord.max_quantity as \"max_quantity: crate::model::Usd\",\n ord.leverage as \"leverage: crate::model::Leverage\",\n ord.liquidation_price as \"liquidation_price: crate::model::Price\",\n ord.ts_secs as \"ts_secs: crate::model::Timestamp\",\n ord.settlement_time_interval_secs as \"settlement_time_interval_secs: i64\",\n ord.origin as \"origin: crate::model::cfd::Origin\",\n ord.oracle_event_id as \"oracle_event_id: crate::model::BitMexPriceEventId\",\n state.quantity_usd as \"quantity_usd: crate::model::Usd\",\n state.state\n\n from ord\n inner join state on state.order_id = ord.order_id\n ", "describe": { "columns": [ { @@ -20,17 +38,17 @@ "type_info": "Text" }, { - "name": "initial_price", + "name": "initial_price: crate::model::Price", "ordinal": 3, "type_info": "Text" }, { - "name": "min_quantity", + "name": "min_quantity: crate::model::Usd", "ordinal": 4, "type_info": "Text" }, { - "name": "max_quantity", + "name": "max_quantity: crate::model::Usd", "ordinal": 5, "type_info": "Text" }, @@ -40,7 +58,7 @@ "type_info": "Int64" }, { - "name": "liquidation_price", + "name": "liquidation_price: crate::model::Price", "ordinal": 7, "type_info": "Text" }, @@ -60,12 +78,12 @@ "type_info": "Text" }, { - "name": "oracle_event_id", + "name": "oracle_event_id: crate::model::BitMexPriceEventId", "ordinal": 11, "type_info": "Text" }, { - "name": "quantity_usd", + "name": "quantity_usd: crate::model::Usd", "ordinal": 12, "type_info": "Text" }, @@ -76,7 +94,7 @@ } ], "parameters": { - "Right": 1 + "Right": 0 }, "nullable": [ false, @@ -96,26 +114,8 @@ ] } }, - "221a6283db798bacaba99e7e85130f9a8bbea1299d8cb99d272b1d478dc19775": { - "query": "\n select\n state\n from cfd_states\n where cfd_id = $1\n order by id desc\n limit 1;\n ", - "describe": { - "columns": [ - { - "name": "state", - "ordinal": 0, - "type_info": "Text" - } - ], - "parameters": { - "Right": 1 - }, - "nullable": [ - false - ] - } - }, - "22aae04782d6d9d6fa025e7606e3dcce91bfb9aca4aef9089a9ff9407c9f2715": { - "query": "\n with ord as (\n select\n id as order_id,\n uuid,\n trading_pair,\n position,\n initial_price,\n min_quantity,\n max_quantity,\n leverage,\n liquidation_price,\n creation_timestamp_seconds as ts_secs,\n settlement_time_interval_seconds as settlement_time_interval_secs,\n origin,\n oracle_event_id\n from orders\n ),\n\n cfd as (\n select\n ord.order_id,\n id as cfd_id,\n quantity_usd\n from cfds\n inner join ord on ord.order_id = cfds.order_id\n ),\n\n state as (\n select\n id as state_id,\n cfd.order_id,\n cfd.quantity_usd,\n state\n from cfd_states\n inner join cfd on cfd.cfd_id = cfd_states.cfd_id\n where id in (\n select\n max(id) as id\n from cfd_states\n group by (cfd_id)\n )\n )\n\n select\n ord.uuid as \"uuid: crate::model::cfd::OrderId\",\n ord.trading_pair as \"trading_pair: crate::model::TradingPair\",\n ord.position as \"position: crate::model::Position\",\n ord.initial_price,\n ord.min_quantity,\n ord.max_quantity,\n ord.leverage as \"leverage: crate::model::Leverage\",\n ord.liquidation_price,\n ord.ts_secs as \"ts_secs: crate::model::Timestamp\",\n ord.settlement_time_interval_secs as \"settlement_time_interval_secs: i64\",\n ord.origin as \"origin: crate::model::cfd::Origin\",\n ord.oracle_event_id,\n state.quantity_usd,\n state.state\n\n from ord\n inner join state on state.order_id = ord.order_id\n ", + "414ecf7f0cfce0a1a482b1b430d960867df835aae7fe1b306aa7f22353795dcf": { + "query": "\n with ord as (\n select\n id as order_id,\n uuid,\n trading_pair,\n position,\n initial_price,\n min_quantity,\n max_quantity,\n leverage,\n liquidation_price,\n creation_timestamp_seconds as ts_secs,\n settlement_time_interval_seconds as settlement_time_interval_secs,\n origin,\n oracle_event_id\n from orders\n ),\n\n cfd as (\n select\n ord.order_id,\n id as cfd_id,\n quantity_usd\n from cfds\n inner join ord on ord.order_id = cfds.order_id\n ),\n\n state as (\n select\n id as state_id,\n cfd.order_id,\n cfd.quantity_usd,\n state\n from cfd_states\n inner join cfd on cfd.cfd_id = cfd_states.cfd_id\n where id in (\n select\n max(id) as id\n from cfd_states\n group by (cfd_id)\n )\n )\n\n select\n ord.uuid as \"uuid: crate::model::cfd::OrderId\",\n ord.trading_pair as \"trading_pair: crate::model::TradingPair\",\n ord.position as \"position: crate::model::Position\",\n ord.initial_price as \"initial_price: crate::model::Price\",\n ord.min_quantity as \"min_quantity: crate::model::Usd\",\n ord.max_quantity as \"max_quantity: crate::model::Usd\",\n ord.leverage as \"leverage: crate::model::Leverage\",\n ord.liquidation_price as \"liquidation_price: crate::model::Price\",\n ord.ts_secs as \"ts_secs: crate::model::Timestamp\",\n ord.settlement_time_interval_secs as \"settlement_time_interval_secs: i64\",\n ord.origin as \"origin: crate::model::cfd::Origin\",\n ord.oracle_event_id as \"oracle_event_id: crate::model::BitMexPriceEventId\",\n state.quantity_usd as \"quantity_usd: crate::model::Usd\",\n state.state\n\n from ord\n inner join state on state.order_id = ord.order_id\n\n where ord.uuid = $1\n ", "describe": { "columns": [ { @@ -134,17 +134,17 @@ "type_info": "Text" }, { - "name": "initial_price", + "name": "initial_price: crate::model::Price", "ordinal": 3, "type_info": "Text" }, { - "name": "min_quantity", + "name": "min_quantity: crate::model::Usd", "ordinal": 4, "type_info": "Text" }, { - "name": "max_quantity", + "name": "max_quantity: crate::model::Usd", "ordinal": 5, "type_info": "Text" }, @@ -154,7 +154,7 @@ "type_info": "Int64" }, { - "name": "liquidation_price", + "name": "liquidation_price: crate::model::Price", "ordinal": 7, "type_info": "Text" }, @@ -174,12 +174,12 @@ "type_info": "Text" }, { - "name": "oracle_event_id", + "name": "oracle_event_id: crate::model::BitMexPriceEventId", "ordinal": 11, "type_info": "Text" }, { - "name": "quantity_usd", + "name": "quantity_usd: crate::model::Usd", "ordinal": 12, "type_info": "Text" }, @@ -190,7 +190,7 @@ } ], "parameters": { - "Right": 0 + "Right": 1 }, "nullable": [ false, @@ -210,8 +210,8 @@ ] } }, - "4bb5424ebcd683a149f15df5560fdea6727174f4cd6e0709e526ac3a690e2e5e": { - "query": "\n select\n uuid as \"uuid: crate::model::cfd::OrderId\",\n trading_pair as \"trading_pair: crate::model::TradingPair\",\n position as \"position: crate::model::Position\",\n initial_price,\n min_quantity,\n max_quantity,\n leverage as \"leverage: crate::model::Leverage\",\n liquidation_price,\n creation_timestamp_seconds as \"ts_secs: crate::model::Timestamp\",\n settlement_time_interval_seconds as \"settlement_time_interval_secs: i64\",\n origin as \"origin: crate::model::cfd::Origin\",\n oracle_event_id\n\n from orders\n where uuid = $1\n ", + "5569292de42c8ce5cff83beb43af1f8e6c3c12b17e740550c1303a1a6d151100": { + "query": "\n select\n uuid as \"uuid: crate::model::cfd::OrderId\",\n trading_pair as \"trading_pair: crate::model::TradingPair\",\n position as \"position: crate::model::Position\",\n initial_price as \"initial_price: crate::model::Price\",\n min_quantity as \"min_quantity: crate::model::Usd\",\n max_quantity as \"max_quantity: crate::model::Usd\",\n leverage as \"leverage: crate::model::Leverage\",\n liquidation_price as \"liquidation_price: crate::model::Price\",\n creation_timestamp_seconds as \"ts_secs: crate::model::Timestamp\",\n settlement_time_interval_seconds as \"settlement_time_interval_secs: i64\",\n origin as \"origin: crate::model::cfd::Origin\",\n oracle_event_id as \"oracle_event_id: crate::model::BitMexPriceEventId\"\n from\n orders\n where\n uuid = $1\n ", "describe": { "columns": [ { @@ -230,17 +230,17 @@ "type_info": "Text" }, { - "name": "initial_price", + "name": "initial_price: crate::model::Price", "ordinal": 3, "type_info": "Text" }, { - "name": "min_quantity", + "name": "min_quantity: crate::model::Usd", "ordinal": 4, "type_info": "Text" }, { - "name": "max_quantity", + "name": "max_quantity: crate::model::Usd", "ordinal": 5, "type_info": "Text" }, @@ -250,7 +250,7 @@ "type_info": "Int64" }, { - "name": "liquidation_price", + "name": "liquidation_price: crate::model::Price", "ordinal": 7, "type_info": "Text" }, @@ -270,7 +270,7 @@ "type_info": "Text" }, { - "name": "oracle_event_id", + "name": "oracle_event_id: crate::model::BitMexPriceEventId", "ordinal": 11, "type_info": "Text" } @@ -294,8 +294,26 @@ ] } }, - "6dbd14a613a982521b4cc9179fd6f6b0298c0a4475508536379e9b82c9f2d0a0": { - "query": "\n with ord as (\n select\n id as order_id,\n uuid,\n trading_pair,\n position,\n initial_price,\n min_quantity,\n max_quantity,\n leverage,\n liquidation_price,\n creation_timestamp_seconds as ts_secs,\n settlement_time_interval_seconds as settlement_time_interval_secs,\n origin,\n oracle_event_id\n from orders\n ),\n\n cfd as (\n select\n ord.order_id,\n id as cfd_id,\n quantity_usd\n from cfds\n inner join ord on ord.order_id = cfds.order_id\n ),\n\n state as (\n select\n id as state_id,\n cfd.order_id,\n cfd.quantity_usd,\n state\n from cfd_states\n inner join cfd on cfd.cfd_id = cfd_states.cfd_id\n where id in (\n select\n max(id) as id\n from cfd_states\n group by (cfd_id)\n )\n )\n\n select\n ord.uuid as \"uuid: crate::model::cfd::OrderId\",\n ord.trading_pair as \"trading_pair: crate::model::TradingPair\",\n ord.position as \"position: crate::model::Position\",\n ord.initial_price,\n ord.min_quantity,\n ord.max_quantity,\n ord.leverage as \"leverage: crate::model::Leverage\",\n ord.liquidation_price,\n ord.ts_secs as \"ts_secs: crate::model::Timestamp\",\n ord.settlement_time_interval_secs as \"settlement_time_interval_secs: i64\",\n ord.origin as \"origin: crate::model::cfd::Origin\",\n ord.oracle_event_id,\n state.quantity_usd,\n state.state\n\n from ord\n inner join state on state.order_id = ord.order_id\n\n where ord.oracle_event_id = $1\n ", + "8cbe349911b35d8e79763d64b4f5813b4bd98f12e0bba5ada84d2cae8b08ef4f": { + "query": "\n select\n id\n from cfds\n where order_uuid = $1;\n ", + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int64" + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + true + ] + } + }, + "f822252e3d3eb70a03300529d8de8f553e8d97b1aac72fb964cbde49d65fe153": { + "query": "\n with ord as (\n select\n id as order_id,\n uuid,\n trading_pair,\n position,\n initial_price,\n min_quantity,\n max_quantity,\n leverage,\n liquidation_price,\n creation_timestamp_seconds as ts_secs,\n settlement_time_interval_seconds as settlement_time_interval_secs,\n origin,\n oracle_event_id\n from orders\n ),\n\n cfd as (\n select\n ord.order_id,\n id as cfd_id,\n quantity_usd\n from cfds\n inner join ord on ord.order_id = cfds.order_id\n ),\n\n state as (\n select\n id as state_id,\n cfd.order_id,\n cfd.quantity_usd,\n state\n from cfd_states\n inner join cfd on cfd.cfd_id = cfd_states.cfd_id\n where id in (\n select\n max(id) as id\n from cfd_states\n group by (cfd_id)\n )\n )\n\n select\n ord.uuid as \"uuid: crate::model::cfd::OrderId\",\n ord.trading_pair as \"trading_pair: crate::model::TradingPair\",\n ord.position as \"position: crate::model::Position\",\n ord.initial_price as \"initial_price: crate::model::Price\",\n ord.min_quantity as \"min_quantity: crate::model::Usd\",\n ord.max_quantity as \"max_quantity: crate::model::Usd\",\n ord.leverage as \"leverage: crate::model::Leverage\",\n ord.liquidation_price as \"liquidation_price: crate::model::Price\",\n ord.ts_secs as \"ts_secs: crate::model::Timestamp\",\n ord.settlement_time_interval_secs as \"settlement_time_interval_secs: i64\",\n ord.origin as \"origin: crate::model::cfd::Origin\",\n ord.oracle_event_id as \"oracle_event_id: crate::model::BitMexPriceEventId\",\n state.quantity_usd as \"quantity_usd: crate::model::Usd\",\n state.state\n\n from ord\n inner join state on state.order_id = ord.order_id\n\n where ord.oracle_event_id = $1\n ", "describe": { "columns": [ { @@ -314,17 +332,17 @@ "type_info": "Text" }, { - "name": "initial_price", + "name": "initial_price: crate::model::Price", "ordinal": 3, "type_info": "Text" }, { - "name": "min_quantity", + "name": "min_quantity: crate::model::Usd", "ordinal": 4, "type_info": "Text" }, { - "name": "max_quantity", + "name": "max_quantity: crate::model::Usd", "ordinal": 5, "type_info": "Text" }, @@ -334,7 +352,7 @@ "type_info": "Int64" }, { - "name": "liquidation_price", + "name": "liquidation_price: crate::model::Price", "ordinal": 7, "type_info": "Text" }, @@ -354,12 +372,12 @@ "type_info": "Text" }, { - "name": "oracle_event_id", + "name": "oracle_event_id: crate::model::BitMexPriceEventId", "ordinal": 11, "type_info": "Text" }, { - "name": "quantity_usd", + "name": "quantity_usd: crate::model::Usd", "ordinal": 12, "type_info": "Text" }, @@ -389,23 +407,5 @@ false ] } - }, - "8cbe349911b35d8e79763d64b4f5813b4bd98f12e0bba5ada84d2cae8b08ef4f": { - "query": "\n select\n id\n from cfds\n where order_uuid = $1;\n ", - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int64" - } - ], - "parameters": { - "Right": 1 - }, - "nullable": [ - true - ] - } } } \ No newline at end of file diff --git a/daemon/src/db.rs b/daemon/src/db.rs index cffc11f..4fe35a7 100644 --- a/daemon/src/db.rs +++ b/daemon/src/db.rs @@ -1,11 +1,9 @@ use crate::model::cfd::{Cfd, CfdState, Order, OrderId}; -use crate::model::{BitMexPriceEventId, Usd}; +use crate::model::BitMexPriceEventId; use anyhow::{bail, Context, Result}; -use rust_decimal::Decimal; use sqlx::pool::PoolConnection; use sqlx::{Sqlite, SqlitePool}; use std::mem; -use std::str::FromStr; use time::Duration; pub async fn run_migrations(pool: &SqlitePool) -> anyhow::Result<()> { @@ -33,15 +31,15 @@ pub async fn insert_order(order: &Order, conn: &mut PoolConnection) -> a .bind(&order.id) .bind(&order.trading_pair) .bind(&order.position) - .bind(&order.price.to_string()) - .bind(&order.min_quantity.to_string()) - .bind(&order.max_quantity.to_string()) - .bind(order.leverage.get()) - .bind(&order.liquidation_price.to_string()) + .bind(&order.price) + .bind(&order.min_quantity) + .bind(&order.max_quantity) + .bind(&order.leverage) + .bind(&order.liquidation_price) .bind(&order.creation_timestamp.seconds()) .bind(&order.settlement_interval.whole_seconds()) .bind(&order.origin) - .bind(&order.oracle_event_id.to_string()) + .bind(&order.oracle_event_id) .execute(conn) .await?; @@ -62,18 +60,19 @@ pub async fn load_order_by_id( uuid as "uuid: crate::model::cfd::OrderId", trading_pair as "trading_pair: crate::model::TradingPair", position as "position: crate::model::Position", - initial_price, - min_quantity, - max_quantity, + initial_price as "initial_price: crate::model::Price", + min_quantity as "min_quantity: crate::model::Usd", + max_quantity as "max_quantity: crate::model::Usd", leverage as "leverage: crate::model::Leverage", - liquidation_price, + liquidation_price as "liquidation_price: crate::model::Price", creation_timestamp_seconds as "ts_secs: crate::model::Timestamp", settlement_time_interval_seconds as "settlement_time_interval_secs: i64", origin as "origin: crate::model::cfd::Origin", - oracle_event_id - - from orders - where uuid = $1 + oracle_event_id as "oracle_event_id: crate::model::BitMexPriceEventId" + from + orders + where + uuid = $1 "#, id ) @@ -84,15 +83,15 @@ pub async fn load_order_by_id( id: row.uuid, trading_pair: row.trading_pair, position: row.position, - price: row.initial_price.parse()?, - min_quantity: row.min_quantity.parse()?, - max_quantity: row.max_quantity.parse()?, + price: row.initial_price, + min_quantity: row.min_quantity, + max_quantity: row.max_quantity, leverage: row.leverage, - liquidation_price: row.liquidation_price.parse()?, + liquidation_price: row.liquidation_price, creation_timestamp: row.ts_secs, settlement_interval: Duration::new(row.settlement_time_interval_secs, 0), origin: row.origin, - oracle_event_id: row.oracle_event_id.parse()?, + oracle_event_id: row.oracle_event_id, }) } @@ -131,7 +130,7 @@ pub async fn insert_cfd(cfd: &Cfd, conn: &mut PoolConnection) -> anyhow: "#, ) .bind(&cfd.order.id) - .bind(&cfd.quantity_usd.to_string()) + .bind(&cfd.quantity_usd) .bind(state) .execute(conn) .await?; @@ -275,16 +274,16 @@ pub async fn load_cfd_by_order_id( ord.uuid as "uuid: crate::model::cfd::OrderId", ord.trading_pair as "trading_pair: crate::model::TradingPair", ord.position as "position: crate::model::Position", - ord.initial_price, - ord.min_quantity, - ord.max_quantity, + ord.initial_price as "initial_price: crate::model::Price", + ord.min_quantity as "min_quantity: crate::model::Usd", + ord.max_quantity as "max_quantity: crate::model::Usd", ord.leverage as "leverage: crate::model::Leverage", - ord.liquidation_price, + ord.liquidation_price as "liquidation_price: crate::model::Price", ord.ts_secs as "ts_secs: crate::model::Timestamp", ord.settlement_time_interval_secs as "settlement_time_interval_secs: i64", ord.origin as "origin: crate::model::cfd::Origin", - ord.oracle_event_id, - state.quantity_usd, + ord.oracle_event_id as "oracle_event_id: crate::model::BitMexPriceEventId", + state.quantity_usd as "quantity_usd: crate::model::Usd", state.state from ord @@ -301,15 +300,15 @@ pub async fn load_cfd_by_order_id( id: row.uuid, trading_pair: row.trading_pair, position: row.position, - price: row.initial_price.parse()?, - min_quantity: row.min_quantity.parse()?, - max_quantity: row.max_quantity.parse()?, + price: row.initial_price, + min_quantity: row.min_quantity, + max_quantity: row.max_quantity, leverage: row.leverage, - liquidation_price: row.liquidation_price.parse()?, + liquidation_price: row.liquidation_price, creation_timestamp: row.ts_secs, settlement_interval: Duration::new(row.settlement_time_interval_secs, 0), origin: row.origin, - oracle_event_id: row.oracle_event_id.parse()?, + oracle_event_id: row.oracle_event_id, }; // TODO: @@ -317,7 +316,7 @@ pub async fn load_cfd_by_order_id( // via https://github.com/comit-network/hermes/issues/290 Ok(Cfd { order, - quantity_usd: Usd::new(Decimal::from_str(&row.quantity_usd)?), + quantity_usd: row.quantity_usd, state: serde_json::from_str(row.state.as_str())?, }) } @@ -373,16 +372,16 @@ pub async fn load_all_cfds(conn: &mut PoolConnection) -> anyhow::Result< ord.uuid as "uuid: crate::model::cfd::OrderId", ord.trading_pair as "trading_pair: crate::model::TradingPair", ord.position as "position: crate::model::Position", - ord.initial_price, - ord.min_quantity, - ord.max_quantity, + ord.initial_price as "initial_price: crate::model::Price", + ord.min_quantity as "min_quantity: crate::model::Usd", + ord.max_quantity as "max_quantity: crate::model::Usd", ord.leverage as "leverage: crate::model::Leverage", - ord.liquidation_price, + ord.liquidation_price as "liquidation_price: crate::model::Price", ord.ts_secs as "ts_secs: crate::model::Timestamp", ord.settlement_time_interval_secs as "settlement_time_interval_secs: i64", ord.origin as "origin: crate::model::cfd::Origin", - ord.oracle_event_id, - state.quantity_usd, + ord.oracle_event_id as "oracle_event_id: crate::model::BitMexPriceEventId", + state.quantity_usd as "quantity_usd: crate::model::Usd", state.state from ord @@ -399,20 +398,20 @@ pub async fn load_all_cfds(conn: &mut PoolConnection) -> anyhow::Result< id: row.uuid, trading_pair: row.trading_pair, position: row.position, - price: row.initial_price.parse()?, - min_quantity: row.min_quantity.parse()?, - max_quantity: row.max_quantity.parse()?, + price: row.initial_price, + min_quantity: row.min_quantity, + max_quantity: row.max_quantity, leverage: row.leverage, - liquidation_price: row.liquidation_price.parse()?, + liquidation_price: row.liquidation_price, creation_timestamp: row.ts_secs, settlement_interval: Duration::new(row.settlement_time_interval_secs, 0), origin: row.origin, - oracle_event_id: row.oracle_event_id.parse()?, + oracle_event_id: row.oracle_event_id, }; Ok(Cfd { order, - quantity_usd: Usd::new(Decimal::from_str(&row.quantity_usd)?), + quantity_usd: row.quantity_usd, state: serde_json::from_str(row.state.as_str())?, }) }) @@ -476,16 +475,16 @@ pub async fn load_cfds_by_oracle_event_id( ord.uuid as "uuid: crate::model::cfd::OrderId", ord.trading_pair as "trading_pair: crate::model::TradingPair", ord.position as "position: crate::model::Position", - ord.initial_price, - ord.min_quantity, - ord.max_quantity, + ord.initial_price as "initial_price: crate::model::Price", + ord.min_quantity as "min_quantity: crate::model::Usd", + ord.max_quantity as "max_quantity: crate::model::Usd", ord.leverage as "leverage: crate::model::Leverage", - ord.liquidation_price, + ord.liquidation_price as "liquidation_price: crate::model::Price", ord.ts_secs as "ts_secs: crate::model::Timestamp", ord.settlement_time_interval_secs as "settlement_time_interval_secs: i64", ord.origin as "origin: crate::model::cfd::Origin", - ord.oracle_event_id, - state.quantity_usd, + ord.oracle_event_id as "oracle_event_id: crate::model::BitMexPriceEventId", + state.quantity_usd as "quantity_usd: crate::model::Usd", state.state from ord @@ -505,20 +504,20 @@ pub async fn load_cfds_by_oracle_event_id( id: row.uuid, trading_pair: row.trading_pair, position: row.position, - price: row.initial_price.parse()?, - min_quantity: row.min_quantity.parse()?, - max_quantity: row.max_quantity.parse()?, + price: row.initial_price, + min_quantity: row.min_quantity, + max_quantity: row.max_quantity, leverage: row.leverage, - liquidation_price: row.liquidation_price.parse()?, + liquidation_price: row.liquidation_price, creation_timestamp: row.ts_secs, settlement_interval: Duration::new(row.settlement_time_interval_secs, 0), origin: row.origin, - oracle_event_id: row.oracle_event_id.parse()?, + oracle_event_id: row.oracle_event_id, }; Ok(Cfd { order, - quantity_usd: row.quantity_usd.parse()?, + quantity_usd: row.quantity_usd, state: serde_json::from_str(row.state.as_str())?, }) }) diff --git a/daemon/src/lib.rs b/daemon/src/lib.rs index 54e2b17..a7ebded 100644 --- a/daemon/src/lib.rs +++ b/daemon/src/lib.rs @@ -16,6 +16,8 @@ use tokio::sync::watch; use xtra::message_channel::{MessageChannel, StrongMessageChannel}; use xtra::{Actor, Address}; +pub mod sqlx_ext; // Must come first because it is a macro. + pub mod actors; pub mod auth; pub mod bitmex_price_feed; diff --git a/daemon/src/model.rs b/daemon/src/model.rs index 759c8f4..7b34e2a 100644 --- a/daemon/src/model.rs +++ b/daemon/src/model.rs @@ -1,4 +1,4 @@ -use crate::olivia; +use crate::{impl_sqlx_type_display_from_str, olivia}; use anyhow::{Context, Result}; use bdk::bitcoin::{Address, Amount, Denomination}; use chrono::DateTime; @@ -62,9 +62,13 @@ impl str::FromStr for Usd { } } +impl_sqlx_type_display_from_str!(Usd); + #[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Serialize, Deserialize)] pub struct Price(Decimal); +impl_sqlx_type_display_from_str!(Price); + impl Price { pub fn new(value: Decimal) -> Result { if value == Decimal::ZERO { @@ -133,6 +137,7 @@ impl InversePrice { } #[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, sqlx::Type)] +#[sqlx(transparent)] pub struct Leverage(u8); impl Leverage { @@ -377,7 +382,7 @@ pub enum TradingPair { BtcUsd, } -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, sqlx::Type)] +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, sqlx::Type)] pub enum Position { Long, Short, @@ -507,6 +512,8 @@ impl str::FromStr for BitMexPriceEventId { } } +impl_sqlx_type_display_from_str!(BitMexPriceEventId); + #[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, sqlx::Type)] pub struct Timestamp(i64); diff --git a/daemon/src/model/cfd.rs b/daemon/src/model/cfd.rs index 625585d..17dc8ba 100644 --- a/daemon/src/model/cfd.rs +++ b/daemon/src/model/cfd.rs @@ -660,7 +660,7 @@ impl Cfd { pub fn position(&self) -> Position { match self.order.origin { - Origin::Ours => self.order.position.clone(), + Origin::Ours => self.order.position, // If the order is not our own we take the counter-position in the CFD Origin::Theirs => match self.order.position { diff --git a/daemon/src/sqlx_ext.rs b/daemon/src/sqlx_ext.rs new file mode 100644 index 0000000..0be3a77 --- /dev/null +++ b/daemon/src/sqlx_ext.rs @@ -0,0 +1,30 @@ +#[macro_export] +macro_rules! impl_sqlx_type_display_from_str { + ($ty:ty) => { + impl sqlx::Type for $ty { + fn type_info() -> sqlx::sqlite::SqliteTypeInfo { + String::type_info() + } + } + + impl<'q> sqlx::Encode<'q, sqlx::Sqlite> for $ty { + fn encode_by_ref( + &self, + args: &mut Vec>, + ) -> sqlx::encode::IsNull { + self.to_string().encode_by_ref(args) + } + } + + impl<'r> sqlx::Decode<'r, sqlx::Sqlite> for $ty { + fn decode( + value: sqlx::sqlite::SqliteValueRef<'r>, + ) -> Result { + let string = String::decode(value)?; + let value = string.parse()?; + + Ok(value) + } + } + }; +}