This commit is contained in:
2026-05-14 17:44:01 +02:00
parent 403f271083
commit 3f6d2e9f7f
21 changed files with 775 additions and 88 deletions

View File

@@ -1678,6 +1678,104 @@ LIMIT ?
}
}
/// Lists prioritized samples of tokens whose metadata is still incomplete.
pub async fn query_local_token_metadata_gap_diagnostic_list_samples(
database: &crate::Database,
limit: i64,
) -> Result<std::vec::Vec<crate::LocalTokenMetadataGapDiagnosticSampleDto>, crate::Error> {
match database.connection() {
crate::DatabaseConnection::Sqlite(pool) => {
let rows_result = sqlx::query_as::<
sqlx::Sqlite,
crate::db::dtos::LocalTokenMetadataGapDiagnosticSampleRow,
>(
r#"
WITH token_pair_usage AS (
SELECT
token.id AS token_id,
COUNT(DISTINCT pair.id) AS total_pair_count,
COUNT(DISTINCT CASE WHEN te.id IS NOT NULL THEN pair.id END) AS trade_materialized_pair_count,
COUNT(DISTINCT CASE WHEN pair.quote_token_id = token.id THEN pair.id END) AS quote_pair_count
FROM k_sol_tokens token
LEFT JOIN k_sol_pairs pair
ON pair.base_token_id = token.id
OR pair.quote_token_id = token.id
LEFT JOIN k_sol_trade_events te ON te.pair_id = pair.id
GROUP BY token.id
)
SELECT
token.id AS token_id,
token.mint AS mint,
token.symbol AS symbol,
token.name AS name,
token.decimals AS decimals,
token.token_program AS token_program,
token.is_quote_token AS is_quote_token,
CASE WHEN usage.trade_materialized_pair_count > 0 THEN 1 ELSE 0 END AS used_by_trade_materialized_pair,
CASE WHEN usage.quote_pair_count > 0 THEN 1 ELSE 0 END AS used_as_quote_token,
COALESCE(usage.trade_materialized_pair_count, 0) AS trade_materialized_pair_count,
COALESCE(usage.total_pair_count, 0) AS total_pair_count,
CASE
WHEN usage.trade_materialized_pair_count > 0 AND usage.quote_pair_count > 0 THEN 'tradable_quote_missing_metadata'
WHEN usage.trade_materialized_pair_count > 0 THEN 'tradable_token_missing_metadata'
WHEN usage.quote_pair_count > 0 THEN 'quote_token_missing_metadata'
ELSE 'catalog_token_missing_metadata'
END AS priority
FROM k_sol_tokens token
LEFT JOIN token_pair_usage usage ON usage.token_id = token.id
WHERE token.symbol IS NULL
OR TRIM(token.symbol) = ''
OR token.name IS NULL
OR TRIM(token.name) = ''
ORDER BY
CASE
WHEN usage.trade_materialized_pair_count > 0 AND usage.quote_pair_count > 0 THEN 1
WHEN usage.trade_materialized_pair_count > 0 THEN 2
WHEN usage.quote_pair_count > 0 THEN 3
ELSE 4
END,
usage.trade_materialized_pair_count DESC,
usage.total_pair_count DESC,
token.mint
LIMIT ?
"#,
)
.bind(limit)
.fetch_all(pool)
.await;
let rows = match rows_result {
Ok(rows) => rows,
Err(error) => {
return Err(crate::Error::Db(format!(
"cannot list token metadata gap diagnostic samples on sqlite: {}",
error
)));
},
};
let mut samples = std::vec::Vec::new();
for row in rows {
samples.push(crate::LocalTokenMetadataGapDiagnosticSampleDto {
token_id: row.token_id,
mint: row.mint,
symbol: row.symbol,
name: row.name,
decimals: row.decimals,
token_program: row.token_program,
is_quote_token: sqlite_i64_to_bool(row.is_quote_token),
used_by_trade_materialized_pair: sqlite_i64_to_bool(
row.used_by_trade_materialized_pair,
),
used_as_quote_token: sqlite_i64_to_bool(row.used_as_quote_token),
trade_materialized_pair_count: row.trade_materialized_pair_count,
total_pair_count: row.total_pair_count,
priority: row.priority,
});
}
return Ok(samples);
},
}
}
/// Lists samples of pairs without trade events.
pub async fn query_local_pair_without_trade_diagnostic_list_samples(
database: &crate::Database,