Skip to content

Commit 0b86b1c

Browse files
authored
Merge pull request #625 from input-output-hk/greg/sqlite_refacto
make SQL entities to create their projection
2 parents 9cf597c + c11aa24 commit 0b86b1c

File tree

4 files changed

+63
-99
lines changed

4 files changed

+63
-99
lines changed

mithril-common/src/database/db_version.rs

Lines changed: 20 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::{
88
use chrono::NaiveDateTime;
99
use sqlite::{Connection, Row, Value};
1010

11-
use crate::sqlite::{HydrationError, Projection, ProjectionField, Provider, SqLiteEntity};
11+
use crate::sqlite::{HydrationError, Projection, Provider, SqLiteEntity};
1212

1313
use super::DbVersion;
1414

@@ -69,35 +69,9 @@ impl SqLiteEntity for DatabaseVersion {
6969
.map_err(|e| HydrationError::InvalidData(format!("{}", e)))?,
7070
})
7171
}
72-
}
73-
74-
impl PartialOrd for DatabaseVersion {
75-
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
76-
if self.application_type != other.application_type {
77-
None
78-
} else {
79-
self.version.partial_cmp(&other.version)
80-
}
81-
}
82-
}
8372

84-
/// Projection dedicated to [DatabaseVersion] entities.
85-
struct DatabaseVersionProjection {
86-
fields: Vec<ProjectionField>,
87-
}
88-
89-
impl Projection for DatabaseVersionProjection {
90-
fn set_field(&mut self, field: ProjectionField) {
91-
self.fields.push(field);
92-
}
93-
94-
fn get_fields(&self) -> &Vec<ProjectionField> {
95-
&self.fields
96-
}
97-
}
98-
impl DatabaseVersionProjection {
99-
pub fn new() -> Self {
100-
let mut projection = Self { fields: Vec::new() };
73+
fn get_projection() -> Projection {
74+
let mut projection = Projection::default();
10175
projection.add_field("version", "{:db_version:}.version", "text");
10276
projection.add_field(
10377
"application_type",
@@ -110,18 +84,28 @@ impl DatabaseVersionProjection {
11084
}
11185
}
11286

87+
impl PartialOrd for DatabaseVersion {
88+
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
89+
if self.application_type != other.application_type {
90+
None
91+
} else {
92+
self.version.partial_cmp(&other.version)
93+
}
94+
}
95+
}
96+
11397
/// Provider for the [DatabaseVersion] entities using the `DatabaseVersionProjection`.
11498
pub struct DatabaseVersionProvider<'conn> {
11599
connection: &'conn Connection,
116-
projection: DatabaseVersionProjection,
100+
projection: Projection,
117101
}
118102

119103
impl<'conn> DatabaseVersionProvider<'conn> {
120104
/// [DatabaseVersionProvider] constructor.
121105
pub fn new(connection: &'conn Connection) -> Self {
122106
Self {
123107
connection,
124-
projection: DatabaseVersionProjection::new(),
108+
projection: DatabaseVersion::get_projection(),
125109
}
126110
}
127111

@@ -169,7 +153,7 @@ insert into db_version (application_type, version) values ('{application_type}',
169153
impl<'conn> Provider<'conn> for DatabaseVersionProvider<'conn> {
170154
type Entity = DatabaseVersion;
171155

172-
fn get_projection(&self) -> &dyn Projection {
156+
fn get_projection(&self) -> &Projection {
173157
&self.projection
174158
}
175159

@@ -197,15 +181,15 @@ where {where_clause}
197181
/// This will perform an UPSERT and return the updated entity.
198182
pub struct DatabaseVersionUpdater<'conn> {
199183
connection: &'conn Connection,
200-
projection: DatabaseVersionProjection,
184+
projection: Projection,
201185
}
202186

203187
impl<'conn> DatabaseVersionUpdater<'conn> {
204188
/// [DatabaseVersionUpdater] constructor.
205189
pub fn new(connection: &'conn Connection) -> Self {
206190
Self {
207191
connection,
208-
projection: DatabaseVersionProjection::new(),
192+
projection: DatabaseVersion::get_projection(),
209193
}
210194
}
211195

@@ -227,7 +211,7 @@ impl<'conn> DatabaseVersionUpdater<'conn> {
227211
impl<'conn> Provider<'conn> for DatabaseVersionUpdater<'conn> {
228212
type Entity = DatabaseVersion;
229213

230-
fn get_projection(&self) -> &dyn Projection {
214+
fn get_projection(&self) -> &Projection {
231215
&self.projection
232216
}
233217

@@ -257,7 +241,7 @@ mod tests {
257241

258242
#[test]
259243
fn test_projection() {
260-
let projection = DatabaseVersionProjection::new();
244+
let projection = DatabaseVersion::get_projection();
261245
let mut aliases: HashMap<String, String> = HashMap::new();
262246
let _ = aliases.insert("{:db_version:}".to_string(), "whatever".to_string());
263247

mithril-common/src/sqlite/entity.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use sqlite::Row;
22
use thiserror::Error;
33

4+
use super::Projection;
5+
46
/// SqLite hydration error
57
#[derive(Error, Debug, Clone)]
68
pub enum HydrationError {
@@ -25,4 +27,7 @@ pub trait SqLiteEntity {
2527
fn hydrate(row: Row) -> Result<Self, HydrationError>
2628
where
2729
Self: Sized;
30+
31+
/// Construct a [Projection] that will allow to hydrate this `SqLiteEntity`.
32+
fn get_projection() -> Projection;
2833
}

mithril-common/src/sqlite/projection.rs

Lines changed: 28 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -39,27 +39,34 @@ impl ProjectionField {
3939
/// Projection is a definition of field mapping during a query.
4040
/// Fields come from one or several source structures (can be tables, views or
4141
/// sub queries) and are mapped to a Provider query as output.
42-
pub trait Projection {
42+
pub struct Projection {
43+
fields: Vec<ProjectionField>,
44+
}
45+
46+
impl Projection {
47+
/// Instanciate a new Projection
48+
pub fn new(fields: Vec<ProjectionField>) -> Self {
49+
Self { fields }
50+
}
51+
4352
/// Add a new field to the definition. This is one of the projection
4453
/// building tool to create a projection out of an existing structure.
4554
/// This is a blanket implementation.
46-
fn add_field(&mut self, field_name: &str, definition: &str, output_type: &str) {
47-
self.set_field(ProjectionField {
55+
pub fn add_field(&mut self, field_name: &str, definition: &str, output_type: &str) {
56+
self.fields.push(ProjectionField {
4857
name: field_name.to_string(),
4958
definition: definition.to_string(),
5059
output_type: output_type.to_string(),
5160
})
5261
}
5362

54-
/// This method is requested by `add_field` to actually save the state in
55-
/// the current Provider implementation.
56-
fn set_field(&mut self, field: ProjectionField);
57-
5863
/// Returns the list of the ProjectionFields of this Projection.
59-
fn get_fields(&self) -> &Vec<ProjectionField>;
64+
pub fn get_fields(&self) -> &Vec<ProjectionField> {
65+
&self.fields
66+
}
6067

6168
/// Turn the Projection into a string suitable for use in SQL queries.
62-
fn expand(&self, aliases: HashMap<String, String>) -> String {
69+
pub fn expand(&self, aliases: HashMap<String, String>) -> String {
6370
let mut fields: String = self
6471
.get_fields()
6572
.iter()
@@ -75,40 +82,24 @@ pub trait Projection {
7582
}
7683
}
7784

85+
impl Default for Projection {
86+
fn default() -> Self {
87+
Self::new(Vec::new())
88+
}
89+
}
90+
7891
#[cfg(test)]
7992
mod tests {
8093
use super::*;
8194

82-
struct TestProjection {
83-
fields: Vec<ProjectionField>,
84-
}
85-
86-
impl TestProjection {
87-
pub fn new() -> Self {
88-
let mut projection = Self { fields: Vec::new() };
89-
90-
projection.add_field("test_id", "{:test:}.test_id", "integer");
91-
projection.add_field("name", "{:test:}.name", "text");
92-
projection.add_field("created_at", "{:test:}.created_at", "timestamp");
93-
projection.add_field("thing_count", "count({:thing:}.*)", "integer");
94-
95-
projection
96-
}
97-
}
98-
99-
impl Projection for TestProjection {
100-
fn get_fields(&self) -> &Vec<ProjectionField> {
101-
&self.fields
102-
}
103-
104-
fn set_field(&mut self, field: ProjectionField) {
105-
self.fields.push(field);
106-
}
107-
}
108-
10995
#[test]
11096
fn simple_projection() {
111-
let projection = TestProjection::new();
97+
let mut projection = Projection::default();
98+
projection.add_field("test_id", "{:test:}.test_id", "integer");
99+
projection.add_field("name", "{:test:}.name", "text");
100+
projection.add_field("created_at", "{:test:}.created_at", "timestamp");
101+
projection.add_field("thing_count", "count({:thing:}.*)", "integer");
102+
112103
let aliases: HashMap<String, String> = [("{:test:}", "pika"), ("{:thing:}", "thing_alias")]
113104
.into_iter()
114105
.map(|(a, b)| (a.to_string(), b.to_string()))

mithril-common/src/sqlite/provider.rs

Lines changed: 10 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ pub trait Provider<'conn> {
1414
fn get_connection(&'conn self) -> &'conn Connection;
1515

1616
/// Share the projection.
17-
fn get_projection(&self) -> &dyn Projection;
17+
fn get_projection(&self) -> &Projection;
1818

1919
/// Perform the parametrized definition query.
2020
fn find(
@@ -41,7 +41,7 @@ pub trait Provider<'conn> {
4141

4242
#[cfg(test)]
4343
mod tests {
44-
use super::super::{entity::HydrationError, ProjectionField, SqLiteEntity};
44+
use super::super::{entity::HydrationError, SqLiteEntity};
4545
use super::*;
4646

4747
#[derive(Debug, PartialEq)]
@@ -61,25 +61,9 @@ mod tests {
6161
maybe_null: row.get::<Option<i64>, _>(3),
6262
})
6363
}
64-
}
65-
66-
pub struct TestProjection {
67-
fields: Vec<ProjectionField>,
68-
}
69-
70-
impl Projection for TestProjection {
71-
fn get_fields(&self) -> &Vec<ProjectionField> {
72-
&self.fields
73-
}
74-
75-
fn set_field(&mut self, field: ProjectionField) {
76-
self.fields.push(field);
77-
}
78-
}
7964

80-
impl TestProjection {
81-
pub fn new() -> Self {
82-
let mut projection = Self { fields: Vec::new() };
65+
fn get_projection() -> Projection {
66+
let mut projection = Projection::default();
8367

8468
projection.add_field("text_data", "{:test:}.text_data", "text");
8569
projection.add_field("real_data", "{:test:}.real_data", "real");
@@ -92,14 +76,14 @@ mod tests {
9276

9377
struct TestEntityProvider {
9478
connection: Connection,
95-
projection: TestProjection,
79+
projection: Projection,
9680
}
9781

9882
impl TestEntityProvider {
9983
pub fn new(connection: Connection) -> Self {
10084
Self {
10185
connection,
102-
projection: TestProjection::new(),
86+
projection: TestEntity::get_projection(),
10387
}
10488
}
10589
}
@@ -111,7 +95,7 @@ mod tests {
11195
&self.connection
11296
}
11397

114-
fn get_projection(&self) -> &dyn Projection {
98+
fn get_projection(&self) -> &Projection {
11599
&self.projection
116100
}
117101

@@ -128,14 +112,14 @@ mod tests {
128112

129113
struct TestEntityUpdateProvider {
130114
connection: Connection,
131-
projection: TestProjection,
115+
projection: Projection,
132116
}
133117

134118
impl TestEntityUpdateProvider {
135119
pub fn new(connection: Connection) -> Self {
136120
Self {
137121
connection,
138-
projection: TestProjection::new(),
122+
projection: TestEntity::get_projection(),
139123
}
140124
}
141125
}
@@ -147,7 +131,7 @@ mod tests {
147131
&self.connection
148132
}
149133

150-
fn get_projection(&self) -> &dyn Projection {
134+
fn get_projection(&self) -> &Projection {
151135
&self.projection
152136
}
153137

0 commit comments

Comments
 (0)