// file: kb_lib/src/db/queries/instruction_observation.rs //! Queries for `k_sol_instruction_observations`. /// Upserts one instruction observation row. pub async fn query_instruction_observations_upsert( database: &crate::Database, dto: &crate::InstructionObservationDto, ) -> Result { match database.connection() { crate::DatabaseConnection::Sqlite(pool) => { let query_result = sqlx::query( r#" INSERT INTO k_sol_instruction_observations ( observation_key, transaction_id, signature, slot, block_time, failed, instruction_id, parent_instruction_id, instruction_index, inner_instruction_index, program_id, decoder_code, discriminator_hex, instruction_name, accounts_json, data_json, pool_account, decoded_event_kind, decoded_event_id, observed_at, updated_at ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(observation_key) DO UPDATE SET transaction_id = excluded.transaction_id, signature = excluded.signature, slot = excluded.slot, block_time = excluded.block_time, failed = excluded.failed, instruction_id = excluded.instruction_id, parent_instruction_id = excluded.parent_instruction_id, instruction_index = excluded.instruction_index, inner_instruction_index = excluded.inner_instruction_index, program_id = excluded.program_id, decoder_code = excluded.decoder_code, discriminator_hex = excluded.discriminator_hex, instruction_name = excluded.instruction_name, accounts_json = excluded.accounts_json, data_json = excluded.data_json, pool_account = excluded.pool_account, decoded_event_kind = excluded.decoded_event_kind, decoded_event_id = excluded.decoded_event_id, updated_at = excluded.updated_at "#, ) .bind(dto.observation_key.clone()) .bind(dto.transaction_id) .bind(dto.signature.clone()) .bind(dto.slot) .bind(dto.block_time) .bind(if dto.failed { 1_i64 } else { 0_i64 }) .bind(dto.instruction_id) .bind(dto.parent_instruction_id) .bind(dto.instruction_index) .bind(dto.inner_instruction_index) .bind(dto.program_id.clone()) .bind(dto.decoder_code.clone()) .bind(dto.discriminator_hex.clone()) .bind(dto.instruction_name.clone()) .bind(dto.accounts_json.clone()) .bind(dto.data_json.clone()) .bind(dto.pool_account.clone()) .bind(dto.decoded_event_kind.clone()) .bind(dto.decoded_event_id) .bind(dto.observed_at.to_rfc3339()) .bind(dto.updated_at.to_rfc3339()) .execute(pool) .await; let query_result = match query_result { Ok(query_result) => query_result, Err(error) => { return Err(crate::Error::Db(format!( "cannot upsert k_sol_instruction_observations on sqlite: {}", error ))); }, }; return Ok(query_result.last_insert_rowid()); }, } } /// Lists instruction observations by optional decoder/discriminator/instruction filters. pub async fn query_instruction_observations_list_by_filter( database: &crate::Database, decoder_code: std::option::Option<&str>, discriminator_hex: std::option::Option<&str>, instruction_name: std::option::Option<&str>, limit: u32, ) -> Result, crate::Error> { if limit == 0 { return Ok(std::vec::Vec::new()); } match database.connection() { crate::DatabaseConnection::Sqlite(pool) => { let query_result = sqlx::query_as::( r#" SELECT id, observation_key, transaction_id, signature, slot, block_time, failed, instruction_id, parent_instruction_id, instruction_index, inner_instruction_index, program_id, decoder_code, discriminator_hex, instruction_name, accounts_json, data_json, pool_account, decoded_event_kind, decoded_event_id, observed_at, updated_at FROM k_sol_instruction_observations WHERE (? IS NULL OR decoder_code = ?) AND (? IS NULL OR discriminator_hex = ?) AND (? IS NULL OR instruction_name = ?) ORDER BY slot DESC, transaction_id DESC, instruction_id ASC LIMIT ? "#, ) .bind(decoder_code.map(str::to_string)) .bind(decoder_code.map(str::to_string)) .bind(discriminator_hex.map(str::to_string)) .bind(discriminator_hex.map(str::to_string)) .bind(instruction_name.map(str::to_string)) .bind(instruction_name.map(str::to_string)) .bind(i64::from(limit)) .fetch_all(pool) .await; let entities = match query_result { Ok(entities) => entities, Err(error) => { return Err(crate::Error::Db(format!( "cannot list k_sol_instruction_observations on sqlite: {}", error ))); }, }; let mut dtos = std::vec::Vec::new(); for entity in entities { let dto_result = crate::InstructionObservationDto::try_from(entity); let dto = match dto_result { Ok(dto) => dto, Err(error) => return Err(error), }; dtos.push(dto); } return Ok(dtos); }, } }