Skip to content

Commit

Permalink
Merge pull request #5327 from msupply-foundation/5310-add-graphql-loa…
Browse files Browse the repository at this point in the history
…der-for-values

5310 add graphql loader for values
  • Loading branch information
roxy-dao authored Nov 14, 2024
2 parents f203d4e + 8938492 commit 6e232d8
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 3 deletions.
8 changes: 8 additions & 0 deletions server/graphql/core/src/loader/loader_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,13 @@ pub async fn get_loaders(
async_std::task::spawn,
);

let program_indicator_value_loader = DataLoader::new(
IndicatorValueLoader {
service_provider: service_provider.clone(),
},
async_std::task::spawn,
);

loaders.insert(item_loader);
loaders.insert(name_by_id_loader);
loaders.insert(store_by_id_loader);
Expand Down Expand Up @@ -276,6 +283,7 @@ pub async fn get_loaders(
loaders.insert(file_sync_reference_loader);
loaders.insert(asset_log_reason_loader);
loaders.insert(return_reason_loader);
loaders.insert(program_indicator_value_loader);
loaders.insert(DataLoader::new(
PatientLoader {
service_provider: service_provider.clone(),
Expand Down
2 changes: 2 additions & 0 deletions server/graphql/core/src/loader/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ mod packaging_variant;
mod patient;
mod program;
mod program_enrolment;
mod program_indicator_value;
mod reason_option;
mod requisition;
mod requisition_line;
Expand Down Expand Up @@ -81,6 +82,7 @@ pub use packaging_variant::*;
pub use patient::*;
pub use program::*;
pub use program_enrolment::*;
pub use program_indicator_value::*;
pub use reason_option::ReasonOptionLoader;
pub use requisition::*;
pub use requisition_line::*;
Expand Down
86 changes: 86 additions & 0 deletions server/graphql/core/src/loader/program_indicator_value.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
use actix_web::web::Data;
use async_graphql::dataloader::*;
use async_graphql::*;
use repository::{
indicator_value::{IndicatorValueFilter, IndicatorValueRepository},
EqualFilter, IndicatorValueRow,
};
use service::service_provider::ServiceProvider;
use std::collections::HashMap;

use super::IdPair;

#[derive(Clone)]
pub struct IndicatorValuePayload {
pub period_id: String,
pub store_id: String,
pub customer_name_link_id: String,
}

pub type IndicatorValueLoaderInput = IdPair<IndicatorValuePayload>;
impl IndicatorValueLoaderInput {
pub fn new(line_id: &str, column_id: &str, extra_filter: IndicatorValuePayload) -> Self {
IndicatorValueLoaderInput {
primary_id: line_id.to_string(),
secondary_id: column_id.to_string(),
// later add store and period and facility ids to this payload
payload: extra_filter,
}
}
}

pub struct IndicatorValueLoader {
pub service_provider: Data<ServiceProvider>,
}

impl Loader<IndicatorValueLoaderInput> for IndicatorValueLoader {
type Value = IndicatorValueRow;
type Error = async_graphql::Error;

async fn load(
&self,
loader_inputs: &[IndicatorValueLoaderInput],
) -> Result<HashMap<IndicatorValueLoaderInput, Self::Value>, Self::Error> {
let service_context = self.service_provider.basic_context()?;

let (period_id, store_id, customer_name_link_id) =
// TODO replace with logic to not assume only one combination queried at any time.
if let Some(loader_input) = loader_inputs.first() {
(
loader_input.payload.period_id.clone(),
loader_input.payload.store_id.clone(),
loader_input.payload.customer_name_link_id.clone(),
)
} else {
return Ok(HashMap::new());
};

let filter = IndicatorValueFilter::new()
.store_id(EqualFilter::equal_to(&store_id))
.customer_name_link_id(EqualFilter::equal_to(&customer_name_link_id))
.period_id(EqualFilter::equal_to(&period_id));

let values =
IndicatorValueRepository::new(&service_context.connection).query_by_filter(filter)?;

let payload = IndicatorValuePayload {
period_id,
store_id,
customer_name_link_id,
};

Ok(values
.into_iter()
.map(|value| {
(
IndicatorValueLoaderInput::new(
&value.indicator_line_id,
&value.indicator_column_id,
payload.clone(),
),
value,
)
})
.collect())
}
}
63 changes: 60 additions & 3 deletions server/graphql/types/src/types/program/program_indicator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@ use async_graphql::{
dataloader::DataLoader, Context, Enum, Error, InputObject, Object, SimpleObject, Union,
};
use graphql_core::{
generic_filters::EqualFilterStringInput, loader::ProgramByIdLoader, ContextExt,
generic_filters::EqualFilterStringInput,
loader::{
IndicatorValueLoader, IndicatorValueLoaderInput, IndicatorValuePayload, ProgramByIdLoader,
},
standard_graphql_error::StandardGraphqlError,
ContextExt,
};
use repository::{
EqualFilter, IndicatorColumnRow, IndicatorLineRow, IndicatorValueType, ProgramIndicatorFilter,
ProgramIndicatorSort, ProgramIndicatorSortField,
EqualFilter, IndicatorColumnRow, IndicatorLineRow, IndicatorValueRow, IndicatorValueType,
ProgramIndicatorFilter, ProgramIndicatorSort, ProgramIndicatorSortField,
};
use service::programs::program_indicator::query::{IndicatorLine, ProgramIndicator};

Expand Down Expand Up @@ -177,6 +182,37 @@ impl IndicatorColumnNode {
pub async fn column_number(&self) -> i32 {
self.column.column_number
}

pub async fn value(
&self,
ctx: &Context<'_>,
period_id: String,
store_id: String,
customer_name_link_id: String,
) -> Result<Option<IndicatorValueNode>, Error> {
let loader = ctx.get_loader::<DataLoader<IndicatorValueLoader>>();
let payload = IndicatorValuePayload {
period_id,
store_id,
customer_name_link_id,
};

let result = loader
.load_one(IndicatorValueLoaderInput::new(
&self.line_id,
&self.column.id,
payload,
))
.await?
.ok_or_else(|| {
StandardGraphqlError::InternalError(format!(
"Cannot find value for column {} with header {}",
&self.line_id, &self.column.id,
))
})?;

Ok(Some(IndicatorValueNode::from_domain(result)))
}
}

#[derive(Enum, Copy, Clone, PartialEq, Eq, Debug)]
Expand All @@ -194,3 +230,24 @@ impl IndicatorValueTypeNode {
}
}
}

pub struct IndicatorValueNode {
pub value: IndicatorValueRow,
}

#[Object]
impl IndicatorValueNode {
pub async fn id(&self) -> &str {
&self.value.id
}

pub async fn value(&self) -> &str {
&self.value.value
}
}

impl IndicatorValueNode {
pub fn from_domain(value: IndicatorValueRow) -> IndicatorValueNode {
IndicatorValueNode { value }
}
}

0 comments on commit 6e232d8

Please sign in to comment.