This commit is contained in:
2026-06-01 19:05:46 +02:00
parent abb810d544
commit 27e25d5bf4
59 changed files with 5727 additions and 1706 deletions

View File

@@ -0,0 +1,173 @@
// 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<i64, crate::Error> {
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<std::vec::Vec<crate::InstructionObservationDto>, crate::Error> {
if limit == 0 {
return Ok(std::vec::Vec::new());
}
match database.connection() {
crate::DatabaseConnection::Sqlite(pool) => {
let query_result = sqlx::query_as::<sqlx::Sqlite, crate::InstructionObservationEntity>(
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);
},
}
}