Skip to content
Snippets Groups Projects
Commit 10d6985d authored by Éloïs's avatar Éloïs
Browse files

[feat] gva: blocks: add inputs interval and step & add negative paging

parent b53c922d
Branches ji_emme/181-gva-implement-identity-request
No related tags found
1 merge request!227[feat] gva: blocks: add inputs interval and step & add negative paging
......@@ -8,7 +8,7 @@ type Query {
node: Node! @juniper(ownership: "owned")
current: Block @juniper(ownership: "owned")
block(number: Int!): Block @juniper(ownership: "owned")
blocks(paging: Paging): [Block!]! @juniper(ownership: "owned")
blocks(interval: BlockInterval, paging: Paging, step: Int = 1): [Block!]! @juniper(ownership: "owned")
}
type Mutation {
......@@ -19,12 +19,15 @@ type Mutation {
# Inputs
#################################
input BlockInterval {
from: Int # default value: 0
# If toBlock is null, current block number is used
to: Int
}
input Paging {
pageNumber: Int # default value: 0
pageSize: Int # default value: 50
fromBlock: Int # default value: 0
# If toBlock is null, current block number is used
toBlock: Int
}
#################################
......
......@@ -20,7 +20,6 @@ pub use durs_bc_db_reader::DbError;
use dubp_common_doc::{BlockNumber, Blockstamp};
use durs_bc_db_reader::blocks::DbBlock;
use durs_bc_db_reader::{BcDbRo, DbReadable};
use std::ops::Range;
#[cfg(test)]
use mockall::predicate::*;
......@@ -35,8 +34,10 @@ pub(crate) trait BcDbTrait {
&self,
block_number: BlockNumber,
) -> Result<Option<DbBlock>, DbError>;
fn get_db_blocks_in_local_blockchain(&self, range: Range<u32>)
-> Result<Vec<DbBlock>, DbError>;
fn get_db_blocks_in_local_blockchain(
&self,
numbers: Vec<BlockNumber>,
) -> Result<Vec<DbBlock>, DbError>;
}
impl<'a> BcDbTrait for BcDbRo {
......@@ -70,16 +71,13 @@ impl<'a> BcDbTrait for BcDbRo {
}
fn get_db_blocks_in_local_blockchain(
&self,
range: Range<u32>,
numbers: Vec<BlockNumber>,
) -> Result<Vec<DbBlock>, DbError> {
self.read(|r| {
range
numbers
.into_iter()
.filter_map(|n| {
match durs_bc_db_reader::blocks::get_db_block_in_local_blockchain(
self,
r,
BlockNumber(n),
) {
match durs_bc_db_reader::blocks::get_db_block_in_local_blockchain(self, r, n) {
Ok(Some(db_block)) => Some(Ok(db_block)),
Ok(None) => None,
Err(e) => Some(Err(e)),
......
......@@ -16,7 +16,7 @@
// ! Module define GraphQl schema
mod entities;
mod paging;
pub mod inputs;
mod queries;
use self::entities::block::Block;
......@@ -62,9 +62,20 @@ impl QueryFields for Query {
&self,
executor: &Executor<'_, Context>,
trail: &QueryTrail<'_, Block, Walked>,
block_interval_opt: Option<BlockInterval>,
paging_opt: Option<Paging>,
mut step: i32,
) -> FieldResult<Vec<Block>> {
queries::blocks::execute(executor, trail, paging_opt)
if step <= 0 {
step = 1;
}
queries::blocks::execute(
executor,
trail,
paging_opt,
block_interval_opt,
step as usize,
)
}
}
......
......@@ -63,8 +63,8 @@ impl super::super::BlockFields for Block {
}
}
impl Block {
pub fn from_db_block(db_block: DbBlock) -> Block {
impl From<DbBlock> for Block {
fn from(db_block: DbBlock) -> Block {
Block {
version: db_block.block.version() as i32,
currency: db_block.block.currency().to_string(),
......
// Copyright (C) 2017-2019 The AXIOM TEAM Association.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// ! Schema inputs methods
mod block_interval;
pub mod paging;
......@@ -13,84 +13,53 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// ! Schema paging input
// ! BlockInterval input methods
use super::Paging;
use super::super::BlockInterval;
use crate::db::BcDbTrait;
use durs_bc_db_reader::DbError;
use std::ops::Range;
use std::ops::RangeInclusive;
const DEFAULT_PAGE_NUMBER: i32 = 0;
const DEFAULT_PAGE_SIZE: i32 = 50;
const DEFAULT_FROM_BLOCK: i32 = 0;
const DEFAULT_START: usize = 0;
const END_WHEN_EMPTY_BLOCKCHAIN: usize = 0;
const MAX_PAGE_SIZE: i32 = 500;
/// Paging with all values filled in
pub struct FilledPaging {
page_number: usize,
page_size: usize,
from_block: u32,
to_block: u32,
}
#[inline]
fn i32_opt_to_positive_i32(int_opt: Option<i32>, default: i32) -> i32 {
if let Some(int) = int_opt {
if int < 0 {
0
} else {
int
}
impl BlockInterval {
fn get_default_end<DB: BcDbTrait>(db: &DB) -> Result<usize, DbError> {
if let Some(current_blockstamp) = db.get_current_blockstamp()? {
Ok(current_blockstamp.id.0 as usize)
} else {
default
Ok(END_WHEN_EMPTY_BLOCKCHAIN)
}
}
impl FilledPaging {
pub(crate) fn new<DB: BcDbTrait>(db: &DB, paging_opt: Option<Paging>) -> Result<Self, DbError> {
if let Some(paging) = paging_opt {
Ok(FilledPaging {
page_number: i32_opt_to_positive_i32(paging.page_number, DEFAULT_PAGE_NUMBER)
as usize,
page_size: std::cmp::min(
MAX_PAGE_SIZE,
i32_opt_to_positive_i32(paging.page_size, DEFAULT_PAGE_SIZE),
) as usize,
from_block: i32_opt_to_positive_i32(paging.from_block, DEFAULT_FROM_BLOCK) as u32,
to_block: if let Some(to_block) = paging.to_block {
if to_block < 0 {
pub(crate) fn get_range<DB: BcDbTrait>(
db: &DB,
block_interval_opt: Option<BlockInterval>,
) -> Result<RangeInclusive<usize>, DbError> {
if let Some(block_interval) = block_interval_opt {
let start = if let Some(from) = block_interval.from {
if from.is_negative() {
0
} else {
to_block as u32
from as usize
}
} else {
Self::get_default_to_block(db)?
},
})
DEFAULT_START
};
let mut end = if let Some(to) = block_interval.to {
if to.is_negative() {
0
} else {
Ok(FilledPaging {
page_number: DEFAULT_PAGE_NUMBER as usize,
page_size: DEFAULT_PAGE_SIZE as usize,
from_block: DEFAULT_FROM_BLOCK as u32,
to_block: Self::get_default_to_block(db)?,
})
to as usize
}
}
fn get_default_to_block<DB: BcDbTrait>(db: &DB) -> Result<u32, DbError> {
if let Some(current_blockstamp) = db.get_current_blockstamp()? {
Ok(current_blockstamp.id.0)
} else {
Ok(0)
Self::get_default_end(db)?
};
if start > end {
end = start;
}
}
pub fn get_range(&self) -> Range<u32> {
Range {
start: self.from_block + (self.page_number * self.page_size) as u32,
end: std::cmp::min(
self.to_block + 1,
self.from_block + ((self.page_number + 1) * self.page_size) as u32,
),
Ok(start..=end)
} else {
Ok(DEFAULT_START..=Self::get_default_end(db)?)
}
}
}
......@@ -103,15 +72,7 @@ mod tests {
use dubp_common_doc::{BlockHash, BlockNumber, Blockstamp};
#[test]
fn test_i32_opt_to_positive_i32() {
assert_eq!(3, i32_opt_to_positive_i32(Some(3), 1));
assert_eq!(0, i32_opt_to_positive_i32(Some(-2), 1));
assert_eq!(50, i32_opt_to_positive_i32(None, 50));
assert_eq!(0, i32_opt_to_positive_i32(Some(0), 1));
}
#[test]
fn test_filled_paging_range_with_short_bc() -> Result<(), DbError> {
fn test_block_interval_get_range_with_short_bc() -> Result<(), DbError> {
let mut mock_db = MockBcDbTrait::new();
mock_db
.expect_get_current_blockstamp()
......@@ -122,24 +83,19 @@ mod tests {
hash: BlockHash(dup_crypto::hashs::Hash::default()),
}))
});
let filled_paging = FilledPaging::new(&mock_db, None)?;
assert_eq! {
Range {
start: 0,
end: 43,
},
filled_paging.get_range()
0..=42,
BlockInterval::get_range(&mock_db, None)?
}
Ok(())
}
#[test]
fn test_filled_paging_range() -> Result<(), DbError> {
fn test_block_interval_get_range_with_long_bc() -> Result<(), DbError> {
let mut mock_db = MockBcDbTrait::new();
mock_db
.expect_get_current_blockstamp()
.times(3)
.times(2)
.returning(|| {
Ok(Some(Blockstamp {
id: BlockNumber(750),
......@@ -147,47 +103,25 @@ mod tests {
}))
});
let filled_paging = FilledPaging::new(&mock_db, None)?;
assert_eq! {
Range {
start: 0,
end: 50,
},
filled_paging.get_range()
0..=750,
BlockInterval::get_range(&mock_db, None)?
}
let filled_paging = FilledPaging::new(
&mock_db,
Some(Paging {
page_number: Some(1),
page_size: Some(100),
from_block: Some(500),
to_block: None,
}),
)?;
assert_eq! {
Range {
start: 600,
end: 700,
},
filled_paging.get_range()
500..=750,
BlockInterval::get_range(&mock_db, Some(BlockInterval {
from: Some(500),
to: None,
}))?
}
let filled_paging = FilledPaging::new(
&mock_db,
Some(Paging {
page_number: Some(2),
page_size: Some(100),
from_block: Some(500),
to_block: None,
}),
)?;
assert_eq! {
Range {
start: 700,
end: 751,
},
filled_paging.get_range()
500..=700,
BlockInterval::get_range(&mock_db, Some(BlockInterval {
from: Some(500),
to: Some(700),
}))?
}
Ok(())
......
// Copyright (C) 2017-2019 The AXIOM TEAM Association.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// ! Paging input methods
use super::super::Paging;
use std::ops::Range;
const DEFAULT_PAGE_NUMBER_I32: i32 = 0;
const DEFAULT_PAGE_NUMBER: isize = 0;
const DEFAULT_PAGE_SIZE: usize = 50;
const MIN_PAGE_SIZE: i32 = 1;
const MAX_PAGE_SIZE: i32 = 500;
#[derive(Debug, PartialEq)]
pub struct FilledPaging {
pub page_number: isize,
pub page_size: usize,
}
impl Default for FilledPaging {
fn default() -> Self {
FilledPaging {
page_number: DEFAULT_PAGE_NUMBER,
page_size: DEFAULT_PAGE_SIZE,
}
}
}
impl From<Option<Paging>> for FilledPaging {
fn from(paging_opt: Option<Paging>) -> Self {
if let Some(paging) = paging_opt {
FilledPaging {
page_number: paging.page_number.unwrap_or(DEFAULT_PAGE_NUMBER_I32) as isize,
page_size: if let Some(page_size) = paging.page_size {
if page_size < MIN_PAGE_SIZE {
MIN_PAGE_SIZE as usize
} else if page_size > MAX_PAGE_SIZE {
MAX_PAGE_SIZE as usize
} else {
page_size as usize
}
} else {
DEFAULT_PAGE_SIZE
},
}
} else {
FilledPaging::default()
}
}
}
impl FilledPaging {
pub(crate) fn get_page_range(&self, count_elems: usize, step: usize) -> Range<usize> {
let page_extended_size = self.page_size * step;
let mut count_pages = count_elems / page_extended_size;
if count_elems % page_extended_size > 0 {
count_pages += 1;
}
let page_number = if self.page_number.is_negative() {
std::cmp::max(0, count_pages as isize - self.page_number.abs()) as usize
} else {
self.page_number as usize
};
Range {
start: std::cmp::min(count_elems, page_number * page_extended_size),
end: std::cmp::min(count_elems, (page_number + 1) * page_extended_size),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default() {
assert_eq!(
FilledPaging {
page_number: DEFAULT_PAGE_NUMBER,
page_size: DEFAULT_PAGE_SIZE,
},
FilledPaging::default(),
)
}
#[test]
fn test_from_none_paging() {
assert_eq!(
FilledPaging {
page_number: DEFAULT_PAGE_NUMBER,
page_size: DEFAULT_PAGE_SIZE,
},
FilledPaging::from(None),
)
}
#[test]
fn test_from_some_paging() {
assert_eq!(
FilledPaging {
page_number: 0,
page_size: 10,
},
FilledPaging::from(Some(Paging {
page_number: None,
page_size: Some(10)
})),
);
assert_eq!(
FilledPaging {
page_number: 1,
page_size: 50,
},
FilledPaging::from(Some(Paging {
page_number: Some(1),
page_size: None
})),
);
assert_eq!(
FilledPaging {
page_number: 1,
page_size: 10,
},
FilledPaging::from(Some(Paging {
page_number: Some(1),
page_size: Some(10)
})),
)
}
#[test]
fn test_get_page_range() {
assert_eq!(
Range { start: 10, end: 20 },
FilledPaging {
page_number: 1,
page_size: 10,
}
.get_page_range(5_000, 1),
);
assert_eq!(
Range {
start: 4_980,
end: 4_990
},
FilledPaging {
page_number: -2,
page_size: 10,
}
.get_page_range(5_000, 1),
);
assert_eq!(
Range { start: 10, end: 15 },
FilledPaging {
page_number: 1,
page_size: 10,
}
.get_page_range(15, 1),
);
assert_eq!(
Range { start: 15, end: 15 },
FilledPaging {
page_number: 2,
page_size: 10,
}
.get_page_range(15, 1),
);
assert_eq!(
Range { start: 20, end: 40 },
FilledPaging {
page_number: 1,
page_size: 10,
}
.get_page_range(5_000, 2),
);
assert_eq!(
Range {
start: 4_980,
end: 5_000
},
FilledPaging {
page_number: -1,
page_size: 10,
}
.get_page_range(5_000, 2),
);
assert_eq!(
Range { start: 0, end: 400 },
FilledPaging {
page_number: -1,
page_size: 500,
}
.get_page_range(400, 2),
);
assert_eq!(
Range {
start: 0,
end: 1_000
},
FilledPaging {
page_number: -3,
page_size: 400,
}
.get_page_range(1_000, 5),
);
assert_eq!(
Range {
start: 2_000,
end: 3_000
},
FilledPaging {
page_number: -1,
page_size: 400,
}
.get_page_range(3_000, 5),
);
assert_eq!(
Range { start: 40, end: 80 },
FilledPaging {
page_number: -2,
page_size: 40,
}
.get_page_range(100, 1),
);
}
}
......@@ -40,7 +40,7 @@ pub(crate) fn execute(
.get_db()
.get_db_block_in_local_blockchain(block_number)
.map_err(db_err_to_juniper_err)
.map(|db_block_opt| db_block_opt.map(Block::from_db_block))
.map(|db_block_opt| db_block_opt.map(Into::into))
}
#[cfg(test)]
......
......@@ -19,8 +19,10 @@ use super::db_err_to_juniper_err;
use crate::context::Context;
use crate::db::BcDbTrait;
use crate::schema::entities::block::Block;
use crate::schema::paging;
use crate::schema::inputs::paging::FilledPaging;
use crate::schema::BlockInterval;
use crate::schema::Paging;
use dubp_common_doc::BlockNumber;
use durs_bc_db_reader::blocks::DbBlock;
use juniper::Executor;
use juniper::FieldResult;
......@@ -30,37 +32,47 @@ pub(crate) fn execute(
executor: &Executor<'_, Context>,
_trail: &QueryTrail<'_, Block, Walked>,
paging_opt: Option<Paging>,
block_interval_opt: Option<BlockInterval>,
step: usize,
) -> FieldResult<Vec<Block>> {
let db = executor.context().get_db();
// Get interval
let interval =
BlockInterval::get_range(db, block_interval_opt).map_err(db_err_to_juniper_err)?;
// Get blocks numbers that respect filters
let blocks_numbers: Vec<BlockNumber> =
interval.clone().map(|i| BlockNumber(i as u32)).collect(); // TODO
// Apply interval
let blocks_numbers: Vec<BlockNumber> = blocks_numbers
.into_iter()
.filter(|n| interval.contains(&(n.0 as usize)))
.collect();
let count = blocks_numbers.len();
// Apply paging and step
let paging = FilledPaging::from(paging_opt);
let page_range = paging.get_page_range(count, step);
let blocks_numbers: Vec<BlockNumber> = page_range
.step_by(step)
.map(|i| blocks_numbers[i])
.collect();
// Get blocks
let blocks: Vec<DbBlock> = db
.get_db_blocks_in_local_blockchain(
paging::FilledPaging::new(db, paging_opt)
.map_err(db_err_to_juniper_err)?
.get_range(),
)
.get_db_blocks_in_local_blockchain(blocks_numbers)
.map_err(db_err_to_juniper_err)?;
Ok(blocks.into_iter().map(Block::from_db_block).collect())
/*let db: &BcDbRo = &executor.context().get_db();
db.read(|r| {
paging::FilledPaging::new(db, paging_opt)?
.get_range()
.filter_map(|n| match block::get_block(db, r, BlockNumber(n)) {
Ok(Some(db_block)) => Some(Ok(db_block)),
Ok(None) => None,
Err(e) => Some(Err(e)),
})
.collect::<Result<Vec<Block>, DbError>>()
})
.map_err(db_err_to_juniper_err)*/
Ok(blocks.into_iter().map(Into::into).collect())
}
#[cfg(test)]
mod tests {
use crate::db::MockBcDbTrait;
use crate::schema::queries::tests;
use dubp_block_doc::block::v10::BlockDocumentV10;
use dubp_block_doc::block::BlockDocument;
use dubp_blocks_tests_tools::mocks::gen_empty_timed_block_v10;
use dubp_common_doc::traits::Document;
......@@ -70,12 +82,8 @@ mod tests {
use durs_bc_db_reader::blocks::DbBlock;
use mockall::predicate::eq;
use serde_json::json;
use std::ops::Range;
#[test]
fn test_graphql_blocks() {
let mut mock_db = MockBcDbTrait::new();
fn block_0() -> BlockDocumentV10 {
let mut block_0 = gen_empty_timed_block_v10(
Blockstamp {
id: BlockNumber(0),
......@@ -85,6 +93,20 @@ mod tests {
Hash::default(),
);
block_0.issuers = vec![pubkey('A')];
block_0
}
fn block_0_json() -> serde_json::Value {
json!({
"commonTime": 1_488_987_127.0,
"currency": "test_currency",
"hash": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"issuer": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"number": 0,
"version": 10
})
}
fn block_1() -> BlockDocumentV10 {
let mut block_1 = gen_empty_timed_block_v10(
Blockstamp {
id: BlockNumber(1),
......@@ -94,7 +116,21 @@ mod tests {
Hash::default(),
);
block_1.issuers = vec![pubkey('B')];
let mut current_block = gen_empty_timed_block_v10(
block_1
}
fn block_1_json() -> serde_json::Value {
json!({
"commonTime": 1_488_987_128.0,
"currency": "test_currency",
"hash": "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
"issuer": "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
"number": 1,
"version": 10
})
}
fn block_2() -> BlockDocumentV10 {
let mut block_2 = gen_empty_timed_block_v10(
Blockstamp {
id: BlockNumber(2),
hash: BlockHash(hash('C')),
......@@ -102,7 +138,73 @@ mod tests {
1_488_987_129,
Hash::default(),
);
current_block.issuers = vec![pubkey('C')];
block_2.issuers = vec![pubkey('C')];
block_2
}
fn block_2_json() -> serde_json::Value {
json!({
"commonTime": 1_488_987_129.0,
"currency": "test_currency",
"hash": "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC",
"issuer": "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC",
"number": 2,
"version": 10
})
}
fn block_3() -> BlockDocumentV10 {
let mut block_3 = gen_empty_timed_block_v10(
Blockstamp {
id: BlockNumber(3),
hash: BlockHash(hash('D')),
},
1_488_987_130,
Hash::default(),
);
block_3.issuers = vec![pubkey('D')];
block_3
}
fn block_3_json() -> serde_json::Value {
json!({
"commonTime": 1_488_987_130.0,
"currency": "test_currency",
"hash": "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD",
"issuer": "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD",
"number": 3,
"version": 10
})
}
fn block_4() -> BlockDocumentV10 {
let mut block_4 = gen_empty_timed_block_v10(
Blockstamp {
id: BlockNumber(4),
hash: BlockHash(hash('E')),
},
1_488_987_131,
Hash::default(),
);
block_4.issuers = vec![pubkey('E')];
block_4
}
fn block_4_json() -> serde_json::Value {
json!({
"commonTime": 1_488_987_131.0,
"currency": "test_currency",
"hash": "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE",
"issuer": "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE",
"number": 4,
"version": 10
})
}
#[test]
fn test_graphql_blocks_from_2() {
let mut mock_db = MockBcDbTrait::new();
let block_2 = block_2();
let block_3 = block_3();
let current_block = block_4();
let current_blockstamp = current_block.blockstamp();
mock_db
......@@ -112,15 +214,15 @@ mod tests {
mock_db
.expect_get_db_blocks_in_local_blockchain()
.with(eq(Range { start: 0, end: 3 }))
.with(eq(vec![BlockNumber(2), BlockNumber(3), BlockNumber(4)]))
.returning(move |_| {
Ok(vec![
DbBlock {
block: BlockDocument::V10(block_0.clone()),
block: BlockDocument::V10(block_2.clone()),
expire_certs: None,
},
DbBlock {
block: BlockDocument::V10(block_1.clone()),
block: BlockDocument::V10(block_3.clone()),
expire_certs: None,
},
DbBlock {
......@@ -134,7 +236,53 @@ mod tests {
tests::test_gql_query(
schema,
"{ blocks { commonTime, currency, hash, issuer, number, version } }",
"{ blocks(interval: { from: 2 }) { commonTime, currency, hash, issuer, number, version } }",
json!({
"data": {
"blocks": [
block_2_json(),
block_3_json(),
block_4_json(),
]
}
}),
);
}
#[test]
fn test_graphql_blocks_with_step_2() {
let mut mock_db = MockBcDbTrait::new();
let block_0 = block_0();
let current_block = block_2();
let current_blockstamp = current_block.blockstamp();
mock_db
.expect_get_current_blockstamp()
.times(1)
.returning(move || Ok(Some(current_blockstamp)));
mock_db
.expect_get_db_blocks_in_local_blockchain()
.with(eq(vec![BlockNumber(0), BlockNumber(2)]))
.returning(move |_| {
Ok(vec![
DbBlock {
block: BlockDocument::V10(block_0.clone()),
expire_certs: None,
},
DbBlock {
block: BlockDocument::V10(current_block.clone()),
expire_certs: None,
},
])
});
let schema = tests::setup(mock_db);
tests::test_gql_query(
schema,
"{ blocks(step: 2) { commonTime, currency, hash, issuer, number, version } }",
json!({
"data": {
"blocks": [{
......@@ -145,14 +293,6 @@ mod tests {
"number": 0,
"version": 10
},
{
"commonTime": 1_488_987_128.0,
"currency": "test_currency",
"hash": "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
"issuer": "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
"number": 1,
"version": 10
},
{
"commonTime": 1_488_987_129.0,
"currency": "test_currency",
......@@ -165,4 +305,54 @@ mod tests {
}),
);
}
#[test]
fn test_graphql_blocks() {
let mut mock_db = MockBcDbTrait::new();
let block_0 = block_0();
let block_1 = block_1();
let current_block = block_2();
let current_blockstamp = current_block.blockstamp();
mock_db
.expect_get_current_blockstamp()
.times(1)
.returning(move || Ok(Some(current_blockstamp)));
mock_db
.expect_get_db_blocks_in_local_blockchain()
.with(eq(vec![BlockNumber(0), BlockNumber(1), BlockNumber(2)]))
.returning(move |_| {
Ok(vec![
DbBlock {
block: BlockDocument::V10(block_0.clone()),
expire_certs: None,
},
DbBlock {
block: BlockDocument::V10(block_1.clone()),
expire_certs: None,
},
DbBlock {
block: BlockDocument::V10(current_block.clone()),
expire_certs: None,
},
])
});
let schema = tests::setup(mock_db);
tests::test_gql_query(
schema,
"{ blocks { commonTime, currency, hash, issuer, number, version } }",
json!({
"data": {
"blocks": [
block_0_json(),
block_1_json(),
block_2_json()]
}
}),
);
}
}
......@@ -32,7 +32,7 @@ pub(crate) fn execute(
.get_db()
.get_current_block()
.map_err(db_err_to_juniper_err)
.map(|db_block_opt| db_block_opt.map(Block::from_db_block))
.map(|db_block_opt| db_block_opt.map(Into::into))
}
#[cfg(test)]
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment