use std::sync::Arc;
use crate::{ArrowChunk, FromArrow};
use anyhow::{anyhow, Context, Result};
use hyperfuel_format::{BlockHeader, Input, Output, Receipt, Transaction};
use polars_arrow::datatypes::SchemaRef;
#[derive(Default, Debug, Clone)]
pub struct ArrowResponseData {
pub blocks: Vec<ArrowBatch>,
pub transactions: Vec<ArrowBatch>,
pub receipts: Vec<ArrowBatch>,
pub inputs: Vec<ArrowBatch>,
pub outputs: Vec<ArrowBatch>,
}
#[derive(Default, Debug, Clone)]
pub struct ResponseData {
pub blocks: Vec<Vec<BlockHeader>>,
pub transactions: Vec<Vec<Transaction>>,
pub receipts: Vec<Vec<Receipt>>,
pub inputs: Vec<Vec<Input>>,
pub outputs: Vec<Vec<Output>>,
}
impl From<&'_ ArrowResponse> for QueryResponse {
fn from(arrow_response: &ArrowResponse) -> Self {
let blocks = arrow_response
.data
.blocks
.iter()
.map(BlockHeader::from_arrow)
.collect();
let transactions = arrow_response
.data
.transactions
.iter()
.map(Transaction::from_arrow)
.collect();
let receipts = arrow_response
.data
.receipts
.iter()
.map(Receipt::from_arrow)
.collect();
let inputs = arrow_response
.data
.inputs
.iter()
.map(Input::from_arrow)
.collect();
let outputs = arrow_response
.data
.outputs
.iter()
.map(Output::from_arrow)
.collect();
QueryResponse {
archive_height: arrow_response.archive_height,
next_block: arrow_response.next_block,
total_execution_time: arrow_response.total_execution_time,
data: ResponseData {
blocks,
transactions,
receipts,
inputs,
outputs,
},
}
}
}
#[derive(Debug, Clone)]
pub struct QueryResponse<T = ResponseData> {
pub archive_height: Option<u64>,
pub next_block: u64,
pub total_execution_time: u64,
pub data: T,
}
pub type ArrowResponse = QueryResponse<ArrowResponseData>;
#[derive(Debug, Clone)]
pub struct ArrowBatch {
pub chunk: Arc<ArrowChunk>,
pub schema: SchemaRef,
}
impl ArrowBatch {
pub fn column<T: 'static>(&self, name: &str) -> Result<&T> {
match self
.schema
.fields
.iter()
.enumerate()
.find(|(_, f)| f.name == name)
{
Some((idx, _)) => {
let col = self
.chunk
.columns()
.get(idx)
.context("get column using index")?;
let col = col.as_any().downcast_ref::<T>().with_context(|| {
anyhow!(
"cast type of column '{}', it was {:?}",
name,
col.data_type()
)
})?;
Ok(col)
}
None => Err(anyhow!("field {} not found in schema", name)),
}
}
}