Skip to content

Commit

Permalink
Adding a very early get_table_rows implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
poplexity committed Jan 12, 2024
1 parent 3a0f184 commit 2caa144
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 4 deletions.
43 changes: 40 additions & 3 deletions crates/antelope/src/api/v1/chain.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
use crate::api::client::Provider;
use crate::api::v1::structs::{
ClientError, GetInfoResponse, ProcessedTransaction, ProcessedTransactionReceipt,
SendTransactionResponse, SendTransactionResponseError,
ClientError, GetInfoResponse, GetTableRowsParams, GetTableRowsResponse, ProcessedTransaction,
ProcessedTransactionReceipt, SendTransactionResponse, SendTransactionResponseError,
TableIndexType,
};
use crate::chain::block_id::BlockId;
use crate::chain::checksum::Checksum256;
use crate::chain::name::Name;
use crate::chain::time::TimePoint;
use crate::chain::transaction::{CompressionType, PackedTransaction, SignedTransaction};
use crate::chain::{Decoder, Packer};
use crate::name;
use crate::serializer::formatter::JSONObject;
use crate::serializer::formatter::{JSONObject, ValueTo};
use crate::util::hex_to_bytes;
use serde_json::Value;

pub struct ChainAPI {
Expand Down Expand Up @@ -103,4 +106,38 @@ impl ChainAPI {
},
})
}

pub fn get_table_rows<T: Packer + Default>(
&self,
params: GetTableRowsParams,
) -> Result<GetTableRowsResponse<T>, ClientError<()>> {
let result = self.provider.post(
String::from("/v1/chain/get_table_rows"),
Some(params.to_json()),
);

let json: Value = serde_json::from_str(result.unwrap().as_str()).unwrap();
let response_obj = JSONObject::new(json);
let more = response_obj.get_bool("more")?;
let next_key_str = response_obj.get_string("next_key")?;
let rows_value = response_obj.get_vec("rows")?;
let mut rows: Vec<T> = Vec::with_capacity(rows_value.len());
for encoded_row in rows_value {
let row_bytes_hex = &ValueTo::string(Some(encoded_row))?;
let row_bytes = hex_to_bytes(row_bytes_hex);
let mut decoder = Decoder::new(&row_bytes);
let mut row = T::default();
decoder.unpack(&mut row);
rows.push(row);
}

let next_key = TableIndexType::NAME(name!(next_key_str.as_str()));

Ok(GetTableRowsResponse {
rows,
more,
ram_payers: None,
next_key: Some(next_key),
})
}
}
58 changes: 58 additions & 0 deletions crates/antelope/src/api/v1/structs.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::chain::checksum::Checksum160;
use crate::chain::{
block_id::BlockId,
checksum::Checksum256,
Expand All @@ -6,6 +7,8 @@ use crate::chain::{
transaction::TransactionHeader,
varint::VarUint32,
};
use serde_json::{json, Value};
use std::collections::HashMap;

#[derive(Debug)]
pub enum ClientError<T> {
Expand Down Expand Up @@ -169,3 +172,58 @@ pub struct SendTransactionResponse {
pub transaction_id: String,
pub processed: ProcessedTransaction,
}

pub enum IndexPosition {
PRIMARY,
SECONDARY,
TERTIARY,
FOURTH,
FIFTH,
SIXTH,
SEVENTH,
EIGHTH,
NINTH,
TENTH,
}

pub enum TableIndexType {
NAME(Name),
UINT64(u64),
UINT128(u128),
FLOAT64(f64),
CHECKSUM256(Checksum256),
CHECKSUM160(Checksum160),
}

pub struct GetTableRowsParams {
pub code: Name,
pub table: Name,
pub scope: Option<Name>,
pub lower_bound: Option<TableIndexType>,
pub upper_bound: Option<TableIndexType>,
pub limit: Option<u32>,
pub reverse: Option<bool>,
pub index_position: Option<IndexPosition>,
pub show_payer: Option<bool>,
}

impl GetTableRowsParams {
pub fn to_json(&self) -> String {
let mut req: HashMap<&str, Value> = HashMap::new();
req.insert("json", Value::Bool(false));
req.insert("code", Value::String(self.code.to_string()));
req.insert("table", Value::String(self.table.to_string()));

let scope = self.scope.unwrap_or(self.code);
req.insert("scope", Value::String(scope.to_string()));

json!(req).to_string()
}
}

pub struct GetTableRowsResponse<T> {
pub rows: Vec<T>,
pub more: bool,
pub ram_payers: Option<Vec<Name>>,
pub next_key: Option<TableIndexType>,
}
28 changes: 28 additions & 0 deletions crates/antelope/src/serializer/formatter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,26 @@ impl ValueTo {
Ok(value.as_str().unwrap().to_string())
}

pub fn bool(v: Option<&Value>) -> Result<bool, EncodingError> {
check_some(v, "bool")?;
let value = v.unwrap();
if !value.is_boolean() {
return Err(EncodingError::new("Value is not bool".into()));
}

Ok(value.as_bool().unwrap())
}

pub fn vec(v: Option<&Value>) -> Result<&Vec<Value>, EncodingError> {
check_some(v, "Vec")?;
let value = v.unwrap();
if !value.is_array() {
return Err(EncodingError::new("Value is not Vec".into()));
}

Ok(value.as_array().unwrap())
}

pub fn hex_bytes(v: Option<&Value>) -> Result<Vec<u8>, EncodingError> {
let value = Self::string(v)?;
return Ok(hex_to_bytes(value.as_str()));
Expand Down Expand Up @@ -84,6 +104,14 @@ impl JSONObject {
ValueTo::string(self.value.get(property))
}

pub fn get_bool(&self, property: &str) -> Result<bool, EncodingError> {
ValueTo::bool(self.value.get(property))
}

pub fn get_vec(&self, property: &str) -> Result<&Vec<Value>, EncodingError> {
ValueTo::vec(self.value.get(property))
}

pub fn get_hex_bytes(&self, property: &str) -> Result<Vec<u8>, EncodingError> {
ValueTo::hex_bytes(self.value.get(property))
}
Expand Down
58 changes: 57 additions & 1 deletion crates/antelope/tests/client.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use antelope::api::client::APIClient;
use antelope::api::v1::structs::ClientError;
use antelope::api::v1::structs::{ClientError, GetTableRowsParams};
use antelope::chain::asset::Asset;
use antelope::chain::block_id::BlockId;
use antelope::chain::name::Name;
use antelope::name;
use antelope::serializer::{Decoder, Encoder, Packer};
use antelope::util::hex_to_bytes;
use antelope::StructPacker;
mod utils;
use crate::utils::mock_provider;
use utils::mock_provider::MockProvider;
Expand Down Expand Up @@ -82,3 +84,57 @@ fn chain_send_transaction() {
}
}
}

#[test]
pub fn chain_get_table_rows() {
#[derive(StructPacker, Default)]
struct UserRow {
balance: Asset,
}

let mock_provider = MockProvider {};
let client = APIClient::custom_provider(Box::new(mock_provider)).unwrap();
//let client = APIClient::default_provider(String::from("https://testnet.telos.caleos.io")).unwrap();

let res1 = client
.v1_chain
.get_table_rows::<UserRow>(GetTableRowsParams {
code: name!("eosio.token"),
table: name!("accounts"),
scope: Some(name!("corecorecore")),
lower_bound: None,
upper_bound: None,
limit: None,
reverse: None,
index_position: None,
show_payer: None,
})
.unwrap();

assert_eq!(res1.rows.len(), 1, "Should get 1 row back");
assert_eq!(
res1.rows[0].balance.symbol().code().to_string(),
"TLOS",
"Should get TLOS symbol back"
);

// const res1 = await eos.v1.chain.get_table_rows({
// code: 'fuel.gm',
// table: 'users',
// type: User,
// limit: 1,
// })
// assert.equal(res1.rows[0].account instanceof Name, true)
// assert.equal(res1.more, true)
// assert.equal(String(res1.rows[0].account), 'aaaa')
// const res2 = await eos.v1.chain.get_table_rows({
// code: 'fuel.gm',
// table: 'users',
// type: User,
// limit: 2,
// lower_bound: res1.next_key,
// })
// assert.equal(String(res2.rows[0].account), 'atomichub')
// assert.equal(String(res2.next_key), 'boidservices')
// assert.equal(Number(res2.rows[1].balance).toFixed(6), (0.02566).toFixed(6))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"rows":["ccd8f5050000000004544c4f53000000"],"more":false,"next_key":""}

0 comments on commit 2caa144

Please sign in to comment.