// file: kb_lib/src/db/queries/pair_analytic_signal.rs //! Queries for `k_sol_pair_analytic_signals`. /// Inserts or updates one pair-analytic-signal row and returns its stable internal id. pub async fn query_pair_analytic_signals_upsert( database: &crate::Database, dto: &crate::PairAnalyticSignalDto, ) -> Result { let signal_value_json_result = serde_json::to_string(&dto.signal_value); let signal_value_json = match signal_value_json_result { Ok(signal_value_json) => signal_value_json, Err(error) => { return Err(crate::Error::Db(format!( "cannot serialize pair analytic signal payload: {}", error ))); }, }; match database.connection() { crate::DatabaseConnection::Sqlite(pool) => { let query_result = sqlx::query( r#" INSERT INTO k_sol_pair_analytic_signals ( pair_id, signal_kind, severity, timeframe_seconds, bucket_start_unix, score, signal_value_json, first_transaction_id, last_transaction_id, created_at, updated_at ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(pair_id, signal_kind, timeframe_seconds, bucket_start_unix) DO UPDATE SET severity = excluded.severity, score = excluded.score, signal_value_json = excluded.signal_value_json, last_transaction_id = excluded.last_transaction_id, updated_at = excluded.updated_at "#, ) .bind(dto.pair_id) .bind(dto.signal_kind.clone()) .bind(dto.severity.to_i16()) .bind(dto.timeframe_seconds) .bind(dto.bucket_start_unix) .bind(dto.score) .bind(signal_value_json) .bind(dto.first_transaction_id) .bind(dto.last_transaction_id) .bind(dto.created_at.to_rfc3339()) .bind(dto.updated_at.to_rfc3339()) .execute(pool) .await; if let Err(error) = query_result { return Err(crate::Error::Db(format!( "cannot upsert k_sol_pair_analytic_signals on sqlite: {}", error ))); } let id_result = sqlx::query_scalar::( r#" SELECT id FROM k_sol_pair_analytic_signals WHERE pair_id = ? AND signal_kind = ? AND timeframe_seconds = ? AND bucket_start_unix = ? LIMIT 1 "#, ) .bind(dto.pair_id) .bind(dto.signal_kind.clone()) .bind(dto.timeframe_seconds) .bind(dto.bucket_start_unix) .fetch_one(pool) .await; match id_result { Ok(id) => return Ok(id), Err(error) => { return Err(crate::Error::Db(format!( "cannot fetch k_sol_pair_analytic_signals id on sqlite: {}", error ))); }, } }, } } /// Returns one pair-analytic-signal row identified by its key, if it exists. pub async fn query_pair_analytic_signals_get_by_key( database: &crate::Database, pair_id: i64, signal_kind: &str, timeframe_seconds: i64, bucket_start_unix: i64, ) -> Result, crate::Error> { match database.connection() { crate::DatabaseConnection::Sqlite(pool) => { let query_result = sqlx::query_as::( r#" SELECT id, pair_id, signal_kind, severity, timeframe_seconds, bucket_start_unix, score, signal_value_json, first_transaction_id, last_transaction_id, created_at, updated_at FROM k_sol_pair_analytic_signals WHERE pair_id = ? AND signal_kind = ? AND timeframe_seconds = ? AND bucket_start_unix = ? LIMIT 1 "#, ) .bind(pair_id) .bind(signal_kind) .bind(timeframe_seconds) .bind(bucket_start_unix) .fetch_optional(pool) .await; let entity_option = match query_result { Ok(entity_option) => entity_option, Err(error) => { return Err(crate::Error::Db(format!( "cannot read k_sol_pair_analytic_signals by key on sqlite: {}", error ))); }, }; match entity_option { Some(entity) => return crate::PairAnalyticSignalDto::try_from(entity).map(Some), None => return Ok(None), } }, } } /// Lists all pair-analytic signals for one pair ordered by key. pub async fn query_pair_analytic_signals_list_by_pair_id( database: &crate::Database, pair_id: i64, ) -> Result, crate::Error> { match database.connection() { crate::DatabaseConnection::Sqlite(pool) => { let query_result = sqlx::query_as::( r#" SELECT id, pair_id, signal_kind, severity, timeframe_seconds, bucket_start_unix, score, signal_value_json, first_transaction_id, last_transaction_id, created_at, updated_at FROM k_sol_pair_analytic_signals WHERE pair_id = ? ORDER BY timeframe_seconds ASC, bucket_start_unix ASC, signal_kind ASC, id ASC "#, ) .bind(pair_id) .fetch_all(pool) .await; let entities = match query_result { Ok(entities) => entities, Err(error) => { return Err(crate::Error::Db(format!( "cannot list k_sol_pair_analytic_signals by pair_id '{}' on sqlite: {}", pair_id, error ))); }, }; let mut dtos = std::vec::Vec::new(); for entity in entities { let dto_result = crate::PairAnalyticSignalDto::try_from(entity); let dto = match dto_result { Ok(dto) => dto, Err(error) => return Err(error), }; dtos.push(dto); } return Ok(dtos); }, } }