-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5295 from msupply-foundation/5212-indicator_row-a…
…nd-column-tables 5212 indicator row and column tables
- Loading branch information
Showing
15 changed files
with
863 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
use super::{ | ||
indicator_column_row::{indicator_column, IndicatorColumnRow}, | ||
DBType, StorageConnection, | ||
}; | ||
|
||
use crate::{diesel_macros::apply_equal_filter, repository_error::RepositoryError}; | ||
|
||
use crate::{EqualFilter, Pagination}; | ||
|
||
use diesel::prelude::*; | ||
|
||
pub struct IndicatorColumnRepository<'a> { | ||
connection: &'a StorageConnection, | ||
} | ||
|
||
#[derive(Clone, Debug, PartialEq, Default)] | ||
pub struct IndicatorColumnFilter { | ||
pub id: Option<EqualFilter<String>>, | ||
pub program_indicator_id: Option<EqualFilter<String>>, | ||
} | ||
|
||
impl<'a> IndicatorColumnRepository<'a> { | ||
pub fn new(connection: &'a StorageConnection) -> Self { | ||
IndicatorColumnRepository { connection } | ||
} | ||
|
||
pub fn count(&self, filter: Option<IndicatorColumnFilter>) -> Result<i64, RepositoryError> { | ||
let query = Self::create_filtered_query(filter); | ||
|
||
Ok(query | ||
.count() | ||
.get_result(self.connection.lock().connection())?) | ||
} | ||
|
||
pub fn query_by_filter( | ||
&self, | ||
filter: IndicatorColumnFilter, | ||
) -> Result<Vec<IndicatorColumnRow>, RepositoryError> { | ||
self.query(Pagination::new(), Some(filter)) | ||
} | ||
|
||
pub fn create_filtered_query(filter: Option<IndicatorColumnFilter>) -> BoxedIndicatorQuery { | ||
let mut query = indicator_column::table.into_boxed(); | ||
// Filter out inactive program_indicators by default | ||
query = query.filter(indicator_column::is_active.eq(true)); | ||
|
||
if let Some(f) = filter { | ||
apply_equal_filter!(query, f.id, indicator_column::id); | ||
apply_equal_filter!( | ||
query, | ||
f.program_indicator_id, | ||
indicator_column::program_indicator_id | ||
); | ||
} | ||
|
||
query | ||
} | ||
|
||
pub fn query( | ||
&self, | ||
pagination: Pagination, | ||
filter: Option<IndicatorColumnFilter>, | ||
) -> Result<Vec<IndicatorColumnRow>, RepositoryError> { | ||
let query = Self::create_filtered_query(filter); | ||
|
||
// Debug diesel query | ||
// println!("{}", diesel::debug_query::<DBType, _>(&query).to_string()); | ||
|
||
let result = query | ||
.offset(pagination.offset as i64) | ||
.limit(pagination.limit as i64) | ||
.load::<IndicatorColumnRow>(self.connection.lock().connection())?; | ||
|
||
Ok(result) | ||
} | ||
} | ||
type BoxedIndicatorQuery = indicator_column::BoxedQuery<'static, DBType>; | ||
|
||
impl IndicatorColumnFilter { | ||
pub fn new() -> IndicatorColumnFilter { | ||
Self::default() | ||
} | ||
|
||
pub fn id(mut self, filter: EqualFilter<String>) -> Self { | ||
self.id = Some(filter); | ||
self | ||
} | ||
|
||
pub fn program_indicator_id(mut self, filter: EqualFilter<String>) -> Self { | ||
self.program_indicator_id = Some(filter); | ||
self | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
use super::{IndicatorValueType, StorageConnection}; | ||
|
||
use crate::{repository_error::RepositoryError, Upsert}; | ||
|
||
use diesel::prelude::*; | ||
|
||
table! { | ||
indicator_column (id) { | ||
id -> Text, | ||
program_indicator_id -> Text, | ||
column_number -> Integer, | ||
header ->Text, | ||
value_type -> Nullable<crate::IndicatorValueTypeMapping>, | ||
default_value -> Text, | ||
is_active -> Bool, | ||
} | ||
} | ||
|
||
#[derive(Clone, Insertable, Queryable, Debug, PartialEq, AsChangeset, Default)] | ||
#[diesel(table_name = indicator_column)] | ||
pub struct IndicatorColumnRow { | ||
pub id: String, | ||
pub program_indicator_id: String, | ||
pub column_number: i32, | ||
pub header: String, | ||
pub value_type: Option<IndicatorValueType>, | ||
pub default_value: String, | ||
pub is_active: bool, | ||
} | ||
|
||
pub struct IndicatorColumnRowRepository<'a> { | ||
connection: &'a StorageConnection, | ||
} | ||
|
||
impl<'a> IndicatorColumnRowRepository<'a> { | ||
pub fn new(connection: &'a StorageConnection) -> Self { | ||
IndicatorColumnRowRepository { connection } | ||
} | ||
|
||
pub fn upsert_one(&self, row: &IndicatorColumnRow) -> Result<(), RepositoryError> { | ||
let query = diesel::insert_into(indicator_column::table) | ||
.values(row) | ||
.on_conflict(indicator_column::id) | ||
.do_update() | ||
.set(row); | ||
|
||
// Debug diesel query | ||
// println!("{}", diesel::debug_query::<DBType, _>(&query).to_string()); | ||
|
||
query.execute(self.connection.lock().connection())?; | ||
|
||
Ok(()) | ||
} | ||
|
||
pub fn find_one_by_id( | ||
&self, | ||
record_id: &str, | ||
) -> Result<Option<IndicatorColumnRow>, RepositoryError> { | ||
let result = indicator_column::table | ||
.filter(indicator_column::id.eq(record_id)) | ||
.first(self.connection.lock().connection()) | ||
.optional()?; | ||
Ok(result) | ||
} | ||
} | ||
|
||
impl Upsert for IndicatorColumnRow { | ||
fn upsert(&self, con: &StorageConnection) -> Result<Option<i64>, RepositoryError> { | ||
IndicatorColumnRowRepository::new(con).upsert_one(self)?; | ||
Ok(None) // Table not in Changelog | ||
} | ||
|
||
// Test only | ||
fn assert_upserted(&self, con: &StorageConnection) { | ||
assert_eq!( | ||
IndicatorColumnRowRepository::new(con).find_one_by_id(&self.id), | ||
Ok(Some(self.clone())) | ||
) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
use super::{ | ||
indicator_line_row::{indicator_line, IndicatorLineRow}, | ||
DBType, StorageConnection, | ||
}; | ||
|
||
use crate::{ | ||
diesel_macros::{apply_equal_filter, apply_string_filter}, | ||
repository_error::RepositoryError, | ||
}; | ||
|
||
use crate::{EqualFilter, Pagination, StringFilter}; | ||
|
||
use diesel::prelude::*; | ||
|
||
pub struct IndicatorLineRepository<'a> { | ||
connection: &'a StorageConnection, | ||
} | ||
|
||
#[derive(Clone, Debug, PartialEq, Default)] | ||
pub struct IndicatorLineFilter { | ||
pub id: Option<EqualFilter<String>>, | ||
pub program_indicator_id: Option<EqualFilter<String>>, | ||
pub code: Option<StringFilter>, | ||
} | ||
|
||
impl<'a> IndicatorLineRepository<'a> { | ||
pub fn new(connection: &'a StorageConnection) -> Self { | ||
IndicatorLineRepository { connection } | ||
} | ||
|
||
pub fn count(&self, filter: Option<IndicatorLineFilter>) -> Result<i64, RepositoryError> { | ||
let query = Self::create_filtered_query(filter); | ||
|
||
Ok(query | ||
.count() | ||
.get_result(self.connection.lock().connection())?) | ||
} | ||
|
||
pub fn query_by_filter( | ||
&self, | ||
filter: IndicatorLineFilter, | ||
) -> Result<Vec<IndicatorLineRow>, RepositoryError> { | ||
self.query(Pagination::new(), Some(filter)) | ||
} | ||
|
||
pub fn create_filtered_query(filter: Option<IndicatorLineFilter>) -> BoxedIndicatorQuery { | ||
let mut query = indicator_line::table.into_boxed(); | ||
// Filter out inactive program_indicators by default | ||
query = query.filter(indicator_line::is_active.eq(true)); | ||
|
||
if let Some(f) = filter { | ||
apply_equal_filter!(query, f.id, indicator_line::id); | ||
apply_equal_filter!( | ||
query, | ||
f.program_indicator_id, | ||
indicator_line::program_indicator_id | ||
); | ||
apply_string_filter!(query, f.code, indicator_line::code); | ||
} | ||
|
||
query | ||
} | ||
|
||
pub fn query( | ||
&self, | ||
pagination: Pagination, | ||
filter: Option<IndicatorLineFilter>, | ||
) -> Result<Vec<IndicatorLineRow>, RepositoryError> { | ||
let query = Self::create_filtered_query(filter); | ||
|
||
// Debug diesel query | ||
// println!("{}", diesel::debug_query::<DBType, _>(&query).to_string()); | ||
|
||
let result = query | ||
.offset(pagination.offset as i64) | ||
.limit(pagination.limit as i64) | ||
.load::<IndicatorLineRow>(self.connection.lock().connection())?; | ||
|
||
Ok(result) | ||
} | ||
} | ||
type BoxedIndicatorQuery = indicator_line::BoxedQuery<'static, DBType>; | ||
|
||
impl IndicatorLineFilter { | ||
pub fn new() -> IndicatorLineFilter { | ||
Self::default() | ||
} | ||
|
||
pub fn id(mut self, filter: EqualFilter<String>) -> Self { | ||
self.id = Some(filter); | ||
self | ||
} | ||
|
||
pub fn program_indicator_id(mut self, filter: EqualFilter<String>) -> Self { | ||
self.program_indicator_id = Some(filter); | ||
self | ||
} | ||
|
||
pub fn code(mut self, filter: StringFilter) -> Self { | ||
self.code = Some(filter); | ||
self | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
use super::StorageConnection; | ||
|
||
use crate::{repository_error::RepositoryError, Upsert}; | ||
|
||
use diesel::prelude::*; | ||
use diesel_derive_enum::DbEnum; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
#[derive(DbEnum, Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] | ||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")] | ||
#[DbValueStyle = "SCREAMING_SNAKE_CASE"] | ||
pub enum IndicatorValueType { | ||
#[serde(rename = "string")] | ||
String, | ||
#[serde(rename = "number")] | ||
#[default] | ||
Number, | ||
} | ||
|
||
table! { | ||
indicator_line (id) { | ||
id -> Text, | ||
program_indicator_id -> Text, | ||
line_number -> Integer, | ||
description->Text, | ||
code -> Text, | ||
value_type -> Nullable<crate::IndicatorValueTypeMapping>, | ||
default_value -> Text, | ||
is_required -> Bool, | ||
is_active -> Bool, | ||
} | ||
} | ||
|
||
#[derive(Clone, Insertable, Queryable, Debug, PartialEq, AsChangeset, Default)] | ||
#[diesel(table_name = indicator_line)] | ||
pub struct IndicatorLineRow { | ||
pub id: String, | ||
pub program_indicator_id: String, | ||
pub line_number: i32, | ||
pub description: String, | ||
pub code: String, | ||
pub value_type: Option<IndicatorValueType>, | ||
pub default_value: String, | ||
pub is_required: bool, | ||
pub is_active: bool, | ||
} | ||
|
||
pub struct IndicatorLineRowRepository<'a> { | ||
connection: &'a StorageConnection, | ||
} | ||
|
||
impl<'a> IndicatorLineRowRepository<'a> { | ||
pub fn new(connection: &'a StorageConnection) -> Self { | ||
IndicatorLineRowRepository { connection } | ||
} | ||
|
||
pub fn upsert_one(&self, row: &IndicatorLineRow) -> Result<(), RepositoryError> { | ||
diesel::insert_into(indicator_line::table) | ||
.values(row) | ||
.on_conflict(indicator_line::id) | ||
.do_update() | ||
.set(row) | ||
.execute(self.connection.lock().connection())?; | ||
Ok(()) | ||
} | ||
|
||
pub fn find_one_by_id( | ||
&self, | ||
record_id: &str, | ||
) -> Result<Option<IndicatorLineRow>, RepositoryError> { | ||
let result = indicator_line::table | ||
.filter(indicator_line::id.eq(record_id)) | ||
.first(self.connection.lock().connection()) | ||
.optional()?; | ||
Ok(result) | ||
} | ||
} | ||
|
||
impl Upsert for IndicatorLineRow { | ||
fn upsert(&self, con: &StorageConnection) -> Result<Option<i64>, RepositoryError> { | ||
IndicatorLineRowRepository::new(con).upsert_one(self)?; | ||
Ok(None) // Table not in Changelog | ||
} | ||
|
||
// Test only | ||
fn assert_upserted(&self, con: &StorageConnection) { | ||
assert_eq!( | ||
IndicatorLineRowRepository::new(con).find_one_by_id(&self.id), | ||
Ok(Some(self.clone())) | ||
) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.