Skip to content

Commit 824d562

Browse files
committed
Share common hydration helpers in a Hydrator struct
This struct is the previous `SignedEntityHydrator` renamed and generalized to works with multiple common types.
1 parent a02d028 commit 824d562

File tree

17 files changed

+85
-143
lines changed

17 files changed

+85
-143
lines changed

internal/mithril-persistence/src/database/signed_entity_hydrator.rs renamed to internal/mithril-persistence/src/database/hydrator.rs

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,42 @@
1-
//! Signed Entity helpers for persistence
1+
//! Shared hydrator helpers for persistence
22
33
use mithril_common::entities::{
44
CardanoDbBeacon, Epoch, SignedEntityType, SignedEntityTypeDiscriminants,
55
};
66

77
use crate::sqlite::HydrationError;
88

9-
/// Helper struct to hydrate [SignedEntityType].
10-
pub struct SignedEntityTypeHydrator {}
9+
/// Helper struct to hydrate common data.
10+
pub struct Hydrator;
11+
12+
impl Hydrator {
13+
/// Read a signed entity beacon column from the database
14+
pub fn read_signed_entity_beacon_column<U: sqlite::RowIndex + Clone>(
15+
row: &sqlite::Row,
16+
column_index: U,
17+
) -> String {
18+
// We need to check first that the cell can be read as a string first
19+
// (e.g. when beacon json is '{"network": "dev", "epoch": 1, "immutable_file_number": 2}').
20+
// If it fails, we fallback on reading the cell as an integer (e.g. when beacon json is '5').
21+
// TODO: Maybe there is a better way of doing this.
22+
match row.try_read::<&str, _>(column_index.clone()) {
23+
Ok(value) => value.to_string(),
24+
Err(_) => (row.read::<i64, _>(column_index)).to_string(),
25+
}
26+
}
27+
28+
/// Try to convert an i64 field from the database to a u64
29+
pub fn try_to_u64(field: &str, value: i64) -> Result<u64, HydrationError> {
30+
u64::try_from(value)
31+
.map_err(|e|
32+
HydrationError::InvalidData(
33+
format!("Integer field {field} (value={value}) is incompatible with u64 representation. Error = {e}")
34+
)
35+
)
36+
}
1137

12-
impl SignedEntityTypeHydrator {
1338
/// Create a [SignedEntityType] from data coming from the database
14-
pub fn hydrate(
39+
pub fn hydrate_signed_entity_type(
1540
signed_entity_type_id: usize,
1641
beacon_str: &str,
1742
) -> Result<SignedEntityType, HydrationError> {

internal/mithril-persistence/src/database/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
44
pub mod cardano_transaction_migration;
55
mod db_version;
6+
mod hydrator;
67
pub(crate) mod provider;
78
pub mod record;
89
pub mod repository;
9-
mod signed_entity_hydrator;
1010
mod version_checker;
1111

1212
pub use db_version::*;
13-
pub use signed_entity_hydrator::SignedEntityTypeHydrator;
13+
pub use hydrator::Hydrator;
1414
pub use version_checker::{DatabaseVersionChecker, SqlMigration};
1515

1616
/// Database version.

internal/mithril-persistence/src/database/record/block_range_root.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use sqlite::Row;
33
use mithril_common::crypto_helper::MKTreeNode;
44
use mithril_common::entities::BlockRange;
55

6-
use crate::database::record::hydrator::try_to_u64;
6+
use crate::database::Hydrator;
77
use crate::sqlite::{HydrationError, Projection, SqLiteEntity};
88

99
/// Block range root record is the representation of block range with its merkle root precomputed.
@@ -35,8 +35,8 @@ impl SqLiteEntity for BlockRangeRootRecord {
3535
where
3636
Self: Sized,
3737
{
38-
let start = try_to_u64("block_range.start", row.read::<i64, _>(0))?;
39-
let end = try_to_u64("block_range.end", row.read::<i64, _>(1))?;
38+
let start = Hydrator::try_to_u64("block_range.start", row.read::<i64, _>(0))?;
39+
let end = Hydrator::try_to_u64("block_range.end", row.read::<i64, _>(1))?;
4040
let range = BlockRange::from_block_number(start);
4141
let merkle_root = row.read::<&str, _>(2);
4242

@@ -69,10 +69,12 @@ impl SqLiteEntity for BlockRangeRootRecord {
6969

7070
#[cfg(test)]
7171
mod tests {
72-
use super::*;
73-
use mithril_common::entities::BlockNumber;
7472
use sqlite::Connection;
7573

74+
use mithril_common::entities::BlockNumber;
75+
76+
use super::*;
77+
7678
fn select_block_range_from_db(start: BlockNumber, end: BlockNumber, merkle_root: &str) -> Row {
7779
let conn = Connection::open(":memory:").unwrap();
7880
let query = format!("SELECT {start}, {end}, '{merkle_root}'");

internal/mithril-persistence/src/database/record/cardano_transaction.rs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use mithril_common::entities::{
44
BlockHash, BlockNumber, CardanoTransaction, ImmutableFileNumber, SlotNumber, TransactionHash,
55
};
66

7+
use crate::database::Hydrator;
78
use crate::sqlite::{HydrationError, Projection, SqLiteEntity};
89

910
/// Cardano Transaction record is the representation of a cardano transaction.
@@ -73,17 +74,12 @@ impl SqLiteEntity for CardanoTransactionRecord {
7374
where
7475
Self: Sized,
7576
{
76-
// TODO: generalize this method to other hydrator
77-
fn try_to_u64(field: &str, value: i64) -> Result<u64, HydrationError> {
78-
u64::try_from(value)
79-
.map_err(|e| HydrationError::InvalidData(format!("Integer field cardano_tx.{field} (value={value}) is incompatible with u64 representation. Error = {e}")))
80-
}
81-
8277
let transaction_hash = row.read::<&str, _>(0);
83-
let block_number = try_to_u64("block_number", row.read::<i64, _>(1))?;
84-
let slot_number = try_to_u64("slot_number", row.read::<i64, _>(2))?;
78+
let block_number = Hydrator::try_to_u64("cardano_tx.block_number", row.read::<i64, _>(1))?;
79+
let slot_number = Hydrator::try_to_u64("cardano_tx.slot_number", row.read::<i64, _>(2))?;
8580
let block_hash = row.read::<&str, _>(3);
86-
let immutable_file_number = try_to_u64("immutable_file_number", row.read::<i64, _>(4))?;
81+
let immutable_file_number =
82+
Hydrator::try_to_u64("cardano_tx.immutable_file_number", row.read::<i64, _>(4))?;
8783

8884
Ok(Self {
8985
transaction_hash: transaction_hash.to_string(),

internal/mithril-persistence/src/database/record/interval_without_block_range_root.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use sqlite::Row;
66
use mithril_common::entities::BlockNumber;
77
use mithril_common::StdResult;
88

9-
use crate::database::record::hydrator::try_to_u64;
9+
use crate::database::Hydrator;
1010
use crate::sqlite::{HydrationError, Projection, SqLiteEntity};
1111

1212
/// Interval of block numbers (`[start, end[`) without block ranges root.
@@ -47,11 +47,11 @@ impl SqLiteEntity for IntervalWithoutBlockRangeRootRecord {
4747
{
4848
let start = row
4949
.read::<Option<i64>, _>(0)
50-
.map(|v| try_to_u64("interval_start.start", v))
50+
.map(|v| Hydrator::try_to_u64("interval_start.start", v))
5151
.transpose()?;
5252
let end = row
5353
.read::<Option<i64>, _>(1)
54-
.map(|v| try_to_u64("interval_end.end", v))
54+
.map(|v| Hydrator::try_to_u64("interval_end.end", v))
5555
.transpose()?;
5656

5757
Ok(Self { start, end })

internal/mithril-persistence/src/database/record/mod.rs

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,31 +7,3 @@ mod interval_without_block_range_root;
77
pub use block_range_root::*;
88
pub use cardano_transaction::*;
99
pub use interval_without_block_range_root::*;
10-
11-
// TODO: this probably should be in `mithril-persistence` crate
12-
pub(crate) mod hydrator {
13-
use crate::sqlite::HydrationError;
14-
15-
pub fn read_signed_entity_beacon_column<U: sqlite::RowIndex + Clone>(
16-
row: &sqlite::Row,
17-
column_index: U,
18-
) -> String {
19-
// TODO: We need to check first that the cell can be read as a string first
20-
// (e.g. when beacon json is '{"network": "dev", "epoch": 1, "immutable_file_number": 2}').
21-
// If it fails, we fallback on reading the cell as an integer (e.g. when beacon json is '5').
22-
// Maybe there is a better way of doing this.
23-
match row.try_read::<&str, _>(column_index.clone()) {
24-
Ok(value) => value.to_string(),
25-
Err(_) => (row.read::<i64, _>(column_index)).to_string(),
26-
}
27-
}
28-
29-
pub fn try_to_u64(field: &str, value: i64) -> Result<u64, HydrationError> {
30-
u64::try_from(value)
31-
.map_err(|e|
32-
HydrationError::InvalidData(
33-
format!("Integer field {field} (value={value}) is incompatible with u64 representation. Error = {e}")
34-
)
35-
)
36-
}
37-
}

mithril-aggregator/src/database/record/block_range_root.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@ use sqlite::Row;
22

33
use mithril_common::crypto_helper::MKTreeNode;
44
use mithril_common::entities::BlockRange;
5+
use mithril_persistence::database::Hydrator;
56
use mithril_persistence::sqlite::{HydrationError, Projection, SqLiteEntity};
67

7-
use crate::database::record::hydrator::try_to_u64;
8-
98
/// Block range root record is the representation of block range with its merkle root precomputed.
109
#[derive(Debug, PartialEq, Clone)]
1110
pub struct BlockRangeRootRecord {
@@ -35,8 +34,8 @@ impl SqLiteEntity for BlockRangeRootRecord {
3534
where
3635
Self: Sized,
3736
{
38-
let start = try_to_u64("block_range.start", row.read::<i64, _>(0))?;
39-
let end = try_to_u64("block_range.end", row.read::<i64, _>(1))?;
37+
let start = Hydrator::try_to_u64("block_range.start", row.read::<i64, _>(0))?;
38+
let end = Hydrator::try_to_u64("block_range.end", row.read::<i64, _>(1))?;
4039
let range = BlockRange::from_block_number(start);
4140
let merkle_root = row.read::<&str, _>(2);
4241

@@ -69,10 +68,12 @@ impl SqLiteEntity for BlockRangeRootRecord {
6968

7069
#[cfg(test)]
7170
mod tests {
72-
use super::*;
73-
use mithril_common::entities::BlockNumber;
7471
use sqlite::Connection;
7572

73+
use mithril_common::entities::BlockNumber;
74+
75+
use super::*;
76+
7677
fn select_block_range_from_db(start: BlockNumber, end: BlockNumber, merkle_root: &str) -> Row {
7778
let conn = Connection::open(":memory:").unwrap();
7879
let query = format!("SELECT {start}, {end}, '{merkle_root}'");

mithril-aggregator/src/database/record/cardano_transaction.rs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use sqlite::Row;
33
use mithril_common::entities::{
44
BlockHash, BlockNumber, CardanoTransaction, ImmutableFileNumber, SlotNumber, TransactionHash,
55
};
6+
use mithril_persistence::database::Hydrator;
67
use mithril_persistence::sqlite::{HydrationError, Projection, SqLiteEntity};
78

89
/// Cardano Transaction record is the representation of a cardano transaction.
@@ -53,17 +54,12 @@ impl SqLiteEntity for CardanoTransactionRecord {
5354
where
5455
Self: Sized,
5556
{
56-
// TODO: generalize this method to other hydrator
57-
fn try_to_u64(field: &str, value: i64) -> Result<u64, HydrationError> {
58-
u64::try_from(value)
59-
.map_err(|e| HydrationError::InvalidData(format!("Integer field cardano_tx.{field} (value={value}) is incompatible with u64 representation. Error = {e}")))
60-
}
61-
6257
let transaction_hash = row.read::<&str, _>(0);
63-
let block_number = try_to_u64("block_number", row.read::<i64, _>(1))?;
64-
let slot_number = try_to_u64("slot_number", row.read::<i64, _>(2))?;
58+
let block_number = Hydrator::try_to_u64("cardano_tx.block_number", row.read::<i64, _>(1))?;
59+
let slot_number = Hydrator::try_to_u64("cardano_tx.slot_number", row.read::<i64, _>(2))?;
6560
let block_hash = row.read::<&str, _>(3);
66-
let immutable_file_number = try_to_u64("immutable_file_number", row.read::<i64, _>(4))?;
61+
let immutable_file_number =
62+
Hydrator::try_to_u64("cardano_tx.immutable_file_number", row.read::<i64, _>(4))?;
6763

6864
Ok(Self {
6965
transaction_hash: transaction_hash.to_string(),

mithril-aggregator/src/database/record/certificate.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,10 @@ use mithril_common::messages::{
1313
#[cfg(test)]
1414
use mithril_common::test_utils::{fake_data, fake_keys};
1515
use mithril_persistence::{
16-
database::SignedEntityTypeHydrator,
16+
database::Hydrator,
1717
sqlite::{HydrationError, Projection, SqLiteEntity},
1818
};
1919

20-
use crate::database::record::hydrator;
21-
2220
era_deprecate!("Remove immutable_file_number");
2321
/// Certificate record is the representation of a stored certificate.
2422
#[derive(Debug, PartialEq, Clone)]
@@ -314,7 +312,7 @@ impl SqLiteEntity for CertificateRecord {
314312
let network = row.read::<&str, _>(6).to_string();
315313
let immutable_file_number = row.read::<i64, _>(7);
316314
let signed_entity_type_id = row.read::<i64, _>(8);
317-
let signed_entity_beacon_string = hydrator::read_signed_entity_beacon_column(&row, 9);
315+
let signed_entity_beacon_string = Hydrator::read_signed_entity_beacon_column(&row, 9);
318316
let protocol_version = row.read::<&str, _>(10).to_string();
319317
let protocol_parameters_string = row.read::<&str, _>(11);
320318
let protocol_message_string = row.read::<&str, _>(12);
@@ -339,7 +337,7 @@ impl SqLiteEntity for CertificateRecord {
339337
"Could not cast i64 ({immutable_file_number}) to u64. Error: '{e}'"
340338
))
341339
})?,
342-
signed_entity_type: SignedEntityTypeHydrator::hydrate(
340+
signed_entity_type: Hydrator::hydrate_signed_entity_type(
343341
signed_entity_type_id.try_into().map_err(|e| {
344342
HydrationError::InvalidData(format!(
345343
"Could not cast i64 ({signed_entity_type_id}) to u64. Error: '{e}'"

mithril-aggregator/src/database/record/interval_without_block_range_root.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,9 @@ use sqlite::Row;
55

66
use mithril_common::entities::BlockNumber;
77
use mithril_common::StdResult;
8+
use mithril_persistence::database::Hydrator;
89
use mithril_persistence::sqlite::{HydrationError, Projection, SqLiteEntity};
910

10-
use crate::database::record::hydrator::try_to_u64;
11-
1211
/// Interval of block numbers (`[start, end[`) without block ranges root.
1312
pub struct IntervalWithoutBlockRangeRootRecord {
1413
/// Start of the interval, fetched from the last block range root end
@@ -47,11 +46,11 @@ impl SqLiteEntity for IntervalWithoutBlockRangeRootRecord {
4746
{
4847
let start = row
4948
.read::<Option<i64>, _>(0)
50-
.map(|v| try_to_u64("interval_start.start", v))
49+
.map(|v| Hydrator::try_to_u64("interval_start.start", v))
5150
.transpose()?;
5251
let end = row
5352
.read::<Option<i64>, _>(1)
54-
.map(|v| try_to_u64("interval_end.end", v))
53+
.map(|v| Hydrator::try_to_u64("interval_end.end", v))
5554
.transpose()?;
5655

5756
Ok(Self { start, end })

0 commit comments

Comments
 (0)