mod.rs
Overview
This file defines the root GraphQL query object for a blockchain-related system, facilitating the retrieval of core data entities such as blockchain blocks, account information, and general system info. It leverages asynchronous GraphQL resolvers combined with a SQLite database connection pool to execute queries efficiently. The file organizes query handling logic for the GraphQL API, interfacing with database models and other GraphQL submodules.
Components
QueryRoot Struct
QueryRoot is the main struct representing the root GraphQL query entry point. It exposes multiple asynchronous query methods decorated with the #[Object] procedural macro from async_graphql to define GraphQL object fields.
Methods on QueryRoot
1. info
async fn info(&self, ctx: &Context<'_>) -> FieldResult<Option<Info>>
Purpose:
Retrieves general information about the blockchain system, specifically the timestamp of the last generated block.Parameters:
ctx: GraphQL context providing access to shared resources such as the database connection pool.
Returns:
A
FieldResultwrapping an optionalInfostruct containing the latest block time (last_block_time).
Behavior:
Checks if the client query requests
last_block_time. If so, queries the database for the most recent block and extracts its generation time (gen_utime).Constructs an
Infoobject withlast_block_timeset to the block's generation time or zero if none found.
Usage Example:
{ info { last_block_time } }
2. account
async fn account(&self, address: String) -> Option<AccountQuery>
Purpose:
Creates anAccountQueryobject for a given blockchain account address, enabling further nested queries on account details.Parameters:
address: A string representing the blockchain account address.
Returns:
An optional
AccountQuerystruct initialized with the given address.
Usage Example:
{ account(address: "0:abc123") { /* nested account query fields */ } }
3. blocks
async fn blocks(
&self,
ctx: &Context<'_>,
filter: Option<BlockFilter>,
order_by: Option<Vec<Option<QueryOrderBy>>>,
limit: Option<i32>,
) -> FieldResult<Option<Vec<Option<Block>>>>
Purpose:
Retrieves a list of blockchain blocks filtered and ordered according to specified criteria, with optional limit on the number of returned blocks.Parameters:
ctx: GraphQL context for accessing shared resources.filter: Optional filter criteria encapsulated inBlockFilterfor block selection.order_by: Optional ordering instructions as a vector ofQueryOrderByoptions.limit: Optional integer limiting the maximum number of blocks returned.
Returns:
A
FieldResultwrapping an optional vector of optionalBlockobjects.
Behavior:
Converts the
BlockFilterinto a SQLWHEREclause string.Converts the
order_byvector into an SQLORDER BYclause string using the helperquery_order_by_str.Queries the database asynchronously for matching blocks.
Converts database block models to GraphQL
Blockobjects.If the client requests the
in_msg_descrfield, fetches inbound messages for each block and attaches descriptions.If
in_msg_descris requested, also loads outbound messages via aDataLoaderto batch fetch message data efficiently.
Implementation Details:
Uses
ctx.look_ahead()to inspect requested GraphQL fields and conditionally execute additional database queries, optimizing data fetching.Leverages
DataLoaderpattern for efficient batch loading of message data, reducing database round-trips.Uses JSON deserialization to parse outbound message IDs from the block data.
Usage Example:
{ blocks( filter: { /* block filter criteria */ }, order_by: [{ field: "gen_utime", direction: DESC }], limit: 10 ) { id gen_utime in_msg_descr out_msgs } }
Implementation Details and Algorithms
Conditional Data Fetching with Lookahead:
The use ofctx.look_ahead().field("in_msg_descr").exists()allows the resolver to fetch additional related data only if the client requests it in the query, reducing unnecessary database load.DataLoader for Batch Fetching:
TheMessageLoaderis used to batch-load outbound messages by their IDs, improving efficiency compared to fetching messages individually.SQL Query Construction:
The filtering and ordering parameters are dynamically converted into SQL snippets (WHEREandORDER BYclauses) to perform flexible queries against the SQLite database.Conversion Between Database and GraphQL Models:
Database block objects (db::Block) are converted into GraphQL block types (Block) usingIntoimplementations, allowing separation between persistence and API layers.
Interactions with Other System Components
Uses
SqlitePoolfrom the application context for asynchronous database access, which is set up elsewhere in the system.Imports and uses submodules:
accountsubmodule exposes theAccountQuerystruct for nested account queries.eventssubmodule is declared but not directly used here, likely handling event-related queries.
Relies on helper functions such as
query_order_by_strto generate SQL-compatible order clauses.Interfaces with the
dbmodule which encapsulates database models and query methods (Block::latest_block,Block::list,Message::in_block_msgs).Works closely with shared GraphQL types such as
Block,BlockFilter,Info,QueryOrderBy, andAccountQueryto structure API responses.
Diagram: QueryRoot Structure and Method Interactions
classDiagram
class QueryRoot {
+info(ctx)
+account(address)
+blocks(ctx, filter, order_by, limit)
}
class SqlitePool
class Context {
+data<T>()
+look_ahead()
+data_unchecked<T>()
}
class Block
class BlockFilter
class QueryOrderBy
class AccountQuery
class Info
class MessageLoader
QueryRoot --> Context
QueryRoot --> SqlitePool
QueryRoot --> Block
QueryRoot --> BlockFilter
QueryRoot --> QueryOrderBy
QueryRoot --> AccountQuery
QueryRoot --> Info
QueryRoot --> MessageLoader
Context --> SqlitePool
Context --> MessageLoader
This file primarily focuses on the GraphQL query API layer responsible for retrieving blockchain data and related entities, orchestrating database access and data transformation to match GraphQL schema expectations. It is a critical integration point between the database schema and the GraphQL schema, enabling flexible queries based on client requirements.