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
No related branches found
No related tags found
No related merge requests found
...@@ -8,7 +8,7 @@ type Query { ...@@ -8,7 +8,7 @@ type Query {
node: Node! @juniper(ownership: "owned") node: Node! @juniper(ownership: "owned")
current: Block @juniper(ownership: "owned") current: Block @juniper(ownership: "owned")
block(number: Int!): 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 { type Mutation {
...@@ -19,12 +19,15 @@ type Mutation { ...@@ -19,12 +19,15 @@ type Mutation {
# Inputs # Inputs
################################# #################################
input BlockInterval {
from: Int # default value: 0
# If toBlock is null, current block number is used
to: Int
}
input Paging { input Paging {
pageNumber: Int # default value: 0 pageNumber: Int # default value: 0
pageSize: Int # default value: 50 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; ...@@ -20,7 +20,6 @@ pub use durs_bc_db_reader::DbError;
use dubp_common_doc::{BlockNumber, Blockstamp}; use dubp_common_doc::{BlockNumber, Blockstamp};
use durs_bc_db_reader::blocks::DbBlock; use durs_bc_db_reader::blocks::DbBlock;
use durs_bc_db_reader::{BcDbRo, DbReadable}; use durs_bc_db_reader::{BcDbRo, DbReadable};
use std::ops::Range;
#[cfg(test)] #[cfg(test)]
use mockall::predicate::*; use mockall::predicate::*;
...@@ -35,8 +34,10 @@ pub(crate) trait BcDbTrait { ...@@ -35,8 +34,10 @@ pub(crate) trait BcDbTrait {
&self, &self,
block_number: BlockNumber, block_number: BlockNumber,
) -> Result<Option<DbBlock>, DbError>; ) -> Result<Option<DbBlock>, DbError>;
fn get_db_blocks_in_local_blockchain(&self, range: Range<u32>) fn get_db_blocks_in_local_blockchain(
-> Result<Vec<DbBlock>, DbError>; &self,
numbers: Vec<BlockNumber>,
) -> Result<Vec<DbBlock>, DbError>;
} }
impl<'a> BcDbTrait for BcDbRo { impl<'a> BcDbTrait for BcDbRo {
...@@ -70,16 +71,13 @@ impl<'a> BcDbTrait for BcDbRo { ...@@ -70,16 +71,13 @@ impl<'a> BcDbTrait for BcDbRo {
} }
fn get_db_blocks_in_local_blockchain( fn get_db_blocks_in_local_blockchain(
&self, &self,
range: Range<u32>, numbers: Vec<BlockNumber>,
) -> Result<Vec<DbBlock>, DbError> { ) -> Result<Vec<DbBlock>, DbError> {
self.read(|r| { self.read(|r| {
range numbers
.into_iter()
.filter_map(|n| { .filter_map(|n| {
match durs_bc_db_reader::blocks::get_db_block_in_local_blockchain( match durs_bc_db_reader::blocks::get_db_block_in_local_blockchain(self, r, n) {
self,
r,
BlockNumber(n),
) {
Ok(Some(db_block)) => Some(Ok(db_block)), Ok(Some(db_block)) => Some(Ok(db_block)),
Ok(None) => None, Ok(None) => None,
Err(e) => Some(Err(e)), Err(e) => Some(Err(e)),
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
// ! Module define GraphQl schema // ! Module define GraphQl schema
mod entities; mod entities;
mod paging; pub mod inputs;
mod queries; mod queries;
use self::entities::block::Block; use self::entities::block::Block;
...@@ -62,9 +62,20 @@ impl QueryFields for Query { ...@@ -62,9 +62,20 @@ impl QueryFields for Query {
&self, &self,
executor: &Executor<'_, Context>, executor: &Executor<'_, Context>,
trail: &QueryTrail<'_, Block, Walked>, trail: &QueryTrail<'_, Block, Walked>,
block_interval_opt: Option<BlockInterval>,
paging_opt: Option<Paging>, paging_opt: Option<Paging>,
mut step: i32,
) -> FieldResult<Vec<Block>> { ) -> 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 { ...@@ -63,8 +63,8 @@ impl super::super::BlockFields for Block {
} }
} }
impl Block { impl From<DbBlock> for Block {
pub fn from_db_block(db_block: DbBlock) -> Block { fn from(db_block: DbBlock) -> Block {
Block { Block {
version: db_block.block.version() as i32, version: db_block.block.version() as i32,
currency: db_block.block.currency().to_string(), 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 @@ ...@@ -13,84 +13,53 @@
// You should have received a copy of the GNU Affero General Public License // 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/>. // 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 crate::db::BcDbTrait;
use durs_bc_db_reader::DbError; use durs_bc_db_reader::DbError;
use std::ops::Range; use std::ops::RangeInclusive;
const DEFAULT_PAGE_NUMBER: i32 = 0; const DEFAULT_START: usize = 0;
const DEFAULT_PAGE_SIZE: i32 = 50; const END_WHEN_EMPTY_BLOCKCHAIN: usize = 0;
const DEFAULT_FROM_BLOCK: i32 = 0;
const MAX_PAGE_SIZE: i32 = 500; impl BlockInterval {
fn get_default_end<DB: BcDbTrait>(db: &DB) -> Result<usize, DbError> {
/// Paging with all values filled in if let Some(current_blockstamp) = db.get_current_blockstamp()? {
pub struct FilledPaging { Ok(current_blockstamp.id.0 as usize)
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
}
} else { } else {
default Ok(END_WHEN_EMPTY_BLOCKCHAIN)
} }
} }
pub(crate) fn get_range<DB: BcDbTrait>(
impl FilledPaging { db: &DB,
pub(crate) fn new<DB: BcDbTrait>(db: &DB, paging_opt: Option<Paging>) -> Result<Self, DbError> { block_interval_opt: Option<BlockInterval>,
if let Some(paging) = paging_opt { ) -> Result<RangeInclusive<usize>, DbError> {
Ok(FilledPaging { if let Some(block_interval) = block_interval_opt {
page_number: i32_opt_to_positive_i32(paging.page_number, DEFAULT_PAGE_NUMBER) let start = if let Some(from) = block_interval.from {
as usize, if from.is_negative() {
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 {
0 0
} else { } else {
to_block as u32 from as usize
} }
} else { } 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 { } else {
Ok(FilledPaging { to as usize
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)?,
})
} }
}
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 { } else {
Ok(0) Self::get_default_end(db)?
};
if start > end {
end = start;
} }
} Ok(start..=end)
pub fn get_range(&self) -> Range<u32> { } else {
Range { Ok(DEFAULT_START..=Self::get_default_end(db)?)
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,
),
} }
} }
} }
...@@ -103,15 +72,7 @@ mod tests { ...@@ -103,15 +72,7 @@ mod tests {
use dubp_common_doc::{BlockHash, BlockNumber, Blockstamp}; use dubp_common_doc::{BlockHash, BlockNumber, Blockstamp};
#[test] #[test]
fn test_i32_opt_to_positive_i32() { fn test_block_interval_get_range_with_short_bc() -> Result<(), DbError> {
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> {
let mut mock_db = MockBcDbTrait::new(); let mut mock_db = MockBcDbTrait::new();
mock_db mock_db
.expect_get_current_blockstamp() .expect_get_current_blockstamp()
...@@ -122,24 +83,19 @@ mod tests { ...@@ -122,24 +83,19 @@ mod tests {
hash: BlockHash(dup_crypto::hashs::Hash::default()), hash: BlockHash(dup_crypto::hashs::Hash::default()),
})) }))
}); });
let filled_paging = FilledPaging::new(&mock_db, None)?;
assert_eq! { assert_eq! {
Range { 0..=42,
start: 0, BlockInterval::get_range(&mock_db, None)?
end: 43,
},
filled_paging.get_range()
} }
Ok(()) Ok(())
} }
#[test] #[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(); let mut mock_db = MockBcDbTrait::new();
mock_db mock_db
.expect_get_current_blockstamp() .expect_get_current_blockstamp()
.times(3) .times(2)
.returning(|| { .returning(|| {
Ok(Some(Blockstamp { Ok(Some(Blockstamp {
id: BlockNumber(750), id: BlockNumber(750),
...@@ -147,47 +103,25 @@ mod tests { ...@@ -147,47 +103,25 @@ mod tests {
})) }))
}); });
let filled_paging = FilledPaging::new(&mock_db, None)?;
assert_eq! { assert_eq! {
Range { 0..=750,
start: 0, BlockInterval::get_range(&mock_db, None)?
end: 50,
},
filled_paging.get_range()
} }
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! { assert_eq! {
Range { 500..=750,
start: 600, BlockInterval::get_range(&mock_db, Some(BlockInterval {
end: 700, from: Some(500),
}, to: None,
filled_paging.get_range() }))?
} }
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! { assert_eq! {
Range { 500..=700,
start: 700, BlockInterval::get_range(&mock_db, Some(BlockInterval {
end: 751, from: Some(500),
}, to: Some(700),
filled_paging.get_range() }))?
} }
Ok(()) 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( ...@@ -40,7 +40,7 @@ pub(crate) fn execute(
.get_db() .get_db()
.get_db_block_in_local_blockchain(block_number) .get_db_block_in_local_blockchain(block_number)
.map_err(db_err_to_juniper_err) .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)] #[cfg(test)]
......
...@@ -19,8 +19,10 @@ use super::db_err_to_juniper_err; ...@@ -19,8 +19,10 @@ use super::db_err_to_juniper_err;
use crate::context::Context; use crate::context::Context;
use crate::db::BcDbTrait; use crate::db::BcDbTrait;
use crate::schema::entities::block::Block; 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 crate::schema::Paging;
use dubp_common_doc::BlockNumber;
use durs_bc_db_reader::blocks::DbBlock; use durs_bc_db_reader::blocks::DbBlock;
use juniper::Executor; use juniper::Executor;
use juniper::FieldResult; use juniper::FieldResult;
...@@ -30,37 +32,47 @@ pub(crate) fn execute( ...@@ -30,37 +32,47 @@ pub(crate) fn execute(
executor: &Executor<'_, Context>, executor: &Executor<'_, Context>,
_trail: &QueryTrail<'_, Block, Walked>, _trail: &QueryTrail<'_, Block, Walked>,
paging_opt: Option<Paging>, paging_opt: Option<Paging>,
block_interval_opt: Option<BlockInterval>,
step: usize,
) -> FieldResult<Vec<Block>> { ) -> FieldResult<Vec<Block>> {
let db = executor.context().get_db(); 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 let blocks: Vec<DbBlock> = db
.get_db_blocks_in_local_blockchain( .get_db_blocks_in_local_blockchain(blocks_numbers)
paging::FilledPaging::new(db, paging_opt)
.map_err(db_err_to_juniper_err)?
.get_range(),
)
.map_err(db_err_to_juniper_err)?; .map_err(db_err_to_juniper_err)?;
Ok(blocks.into_iter().map(Block::from_db_block).collect()) Ok(blocks.into_iter().map(Into::into).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)*/
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::db::MockBcDbTrait; use crate::db::MockBcDbTrait;
use crate::schema::queries::tests; use crate::schema::queries::tests;
use dubp_block_doc::block::v10::BlockDocumentV10;
use dubp_block_doc::block::BlockDocument; use dubp_block_doc::block::BlockDocument;
use dubp_blocks_tests_tools::mocks::gen_empty_timed_block_v10; use dubp_blocks_tests_tools::mocks::gen_empty_timed_block_v10;
use dubp_common_doc::traits::Document; use dubp_common_doc::traits::Document;
...@@ -70,12 +82,8 @@ mod tests { ...@@ -70,12 +82,8 @@ mod tests {
use durs_bc_db_reader::blocks::DbBlock; use durs_bc_db_reader::blocks::DbBlock;
use mockall::predicate::eq; use mockall::predicate::eq;
use serde_json::json; 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( let mut block_0 = gen_empty_timed_block_v10(
Blockstamp { Blockstamp {
id: BlockNumber(0), id: BlockNumber(0),
...@@ -85,6 +93,20 @@ mod tests { ...@@ -85,6 +93,20 @@ mod tests {
Hash::default(), Hash::default(),
); );
block_0.issuers = vec![pubkey('A')]; 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( let mut block_1 = gen_empty_timed_block_v10(
Blockstamp { Blockstamp {
id: BlockNumber(1), id: BlockNumber(1),
...@@ -94,7 +116,21 @@ mod tests { ...@@ -94,7 +116,21 @@ mod tests {
Hash::default(), Hash::default(),
); );
block_1.issuers = vec![pubkey('B')]; 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 { Blockstamp {
id: BlockNumber(2), id: BlockNumber(2),
hash: BlockHash(hash('C')), hash: BlockHash(hash('C')),
...@@ -102,7 +138,73 @@ mod tests { ...@@ -102,7 +138,73 @@ mod tests {
1_488_987_129, 1_488_987_129,
Hash::default(), 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(); let current_blockstamp = current_block.blockstamp();
mock_db mock_db
...@@ -112,15 +214,15 @@ mod tests { ...@@ -112,15 +214,15 @@ mod tests {
mock_db mock_db
.expect_get_db_blocks_in_local_blockchain() .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 |_| { .returning(move |_| {
Ok(vec![ Ok(vec![
DbBlock { DbBlock {
block: BlockDocument::V10(block_0.clone()), block: BlockDocument::V10(block_2.clone()),
expire_certs: None, expire_certs: None,
}, },
DbBlock { DbBlock {
block: BlockDocument::V10(block_1.clone()), block: BlockDocument::V10(block_3.clone()),
expire_certs: None, expire_certs: None,
}, },
DbBlock { DbBlock {
...@@ -134,7 +236,53 @@ mod tests { ...@@ -134,7 +236,53 @@ mod tests {
tests::test_gql_query( tests::test_gql_query(
schema, 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!({ json!({
"data": { "data": {
"blocks": [{ "blocks": [{
...@@ -145,14 +293,6 @@ mod tests { ...@@ -145,14 +293,6 @@ mod tests {
"number": 0, "number": 0,
"version": 10 "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, "commonTime": 1_488_987_129.0,
"currency": "test_currency", "currency": "test_currency",
...@@ -165,4 +305,54 @@ mod tests { ...@@ -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( ...@@ -32,7 +32,7 @@ pub(crate) fn execute(
.get_db() .get_db()
.get_current_block() .get_current_block()
.map_err(db_err_to_juniper_err) .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)] #[cfg(test)]
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment