resolver.rs
Overview
This file implements a data loader utility for efficient batch loading of transaction records from a SQLite database. It defines the TransactionLoader struct that conforms to the async_graphql::dataloader::Loader trait, enabling asynchronous, batched queries of Transaction entities by their string IDs. This pattern is commonly used to optimize GraphQL resolver performance by minimizing redundant database queries.
The main responsibility of this file is to provide a mechanism to load multiple transactions given a set of transaction IDs (keys), returning a map of transaction IDs to their corresponding Transaction objects. It leverages the sqlx crate for asynchronous SQL query building and execution on SQLite, and the futures crate for stream processing.
Structs
TransactionLoader
pub struct TransactionLoader {
pub pool: SqlitePool,
}
Purpose: Holds a connection pool (
SqlitePool) to the SQLite database for executing queries.Fields:
pool: SqlitePool— A connection pool for SQLite, used to perform database operations asynchronously.
Trait Implementations
Loader for TransactionLoader
This implementation enables TransactionLoader to act as a data loader that fetches Transaction objects keyed by String IDs.
impl Loader<String> for TransactionLoader {
type Error = Error;
type Value = super::Transaction;
async fn load(
&self,
keys: &[String],
) -> anyhow::Result<HashMap<String, Self::Value>, Self::Error>;
}
Associated Types:
Error— Usesasync_graphql::Errorto represent loading errors.Value— The type of the value being loaded, which isTransaction(imported from the parent module).
Methods:
load(&self, keys: &[String]) -> anyhow::Result<HashMap<String, Self::Value>, Self::Error>
Parameters:
keys: Slice ofStringidentifiers representing transaction IDs to be loaded.
Returns:
A
HashMapmapping each transaction ID (String) to its correspondingTransactionobject.Wrapped in an
anyhow::Resultthat handles potential errors during query execution.
Functionality:
Converts the list of transaction IDs into a comma-separated string to be used in the SQL
INclause.Constructs a SQL query to select transactions whose IDs are in the provided list.
Logs the SQL query at trace level for debugging purposes.
Uses
sqlx::QueryBuilderto build and execute the query asynchronously against the SQLite pool.Maps the database
Transactionrows (fromcrate::schema::db::Transaction) into the domainTransactiontype.Collects the results into a
HashMapkeyed by transaction ID.
Usage Example:
let loader = TransactionLoader { pool: sqlite_pool.clone() }; let transaction_ids = vec!["tx123".to_string(), "tx456".to_string()]; let transactions_map = loader.load(&transaction_ids).await?; // transactions_map is a HashMap<String, Transaction>
Implementation Details
SQL Query Construction:
The SQL query is dynamically constructed as:SELECT * FROM transactions WHERE id IN (<comma-separated-ids>)The IDs are formatted using Rust's debug formatter (
{:?}) which wraps strings in quotes, ensuring proper SQL string literal syntax.Async Query Execution:
Usessqlx::QueryBuilderandfetchto perform asynchronous query execution with streaming of results. The stream is processed with.map_ok()to convert rows and.try_collect()to aggregate into aHashMap.Error Handling:
Any SQL or stream errors propagate viaanyhow::Resultcombined with the trait's error typeasync_graphql::Error.Tracing:
Usestracing::trace!for logging the generated SQL query to aid in debugging and performance monitoring.
Interactions with Other Modules
Database Schema (
crate::schema::db):
The loader maps SQL query results from the database schema'sTransactionstruct to the domain-levelTransactionstruct defined in the parent module (super::Transaction), implying conversion logic (likelyFromorIntoimplementation).GraphQL DataLoader:
Integration withasync_graphql::dataloader::Loaderenables this loader to be used transparently within GraphQL resolvers to batch and cache requests for transaction data.SQLx and Futures:
Usessqlxfor database interaction andfuturesfor asynchronous stream processing, ensuring non-blocking I/O and efficient resource usage.
Diagram
classDiagram
class TransactionLoader {
+pool: SqlitePool
+load(keys: &[String]) Result<HashMap<String, Transaction>, Error>
}
TransactionLoader ..|> Loader
Loader <|-- TransactionLoader
Diagram Explanation:
TransactionLoaderhas apoolproperty and aloadmethod.Implements the
Loadertrait for batch loading.The
loadmethod asynchronously fetches transactions keyed by IDs.