Refactor steps_for_targets to accept Vec<ReportingProductId>

This commit is contained in:
RunasSudo 2025-05-24 01:01:03 +10:00
parent fd761934e0
commit 004f749c33
Signed by: RunasSudo
GPG Key ID: 7234E476BF21C61A
3 changed files with 62 additions and 37 deletions

View File

@ -21,13 +21,10 @@ use libdrcr::db::DbConnection;
use libdrcr::reporting::builders::register_dynamic_builders; use libdrcr::reporting::builders::register_dynamic_builders;
use libdrcr::reporting::calculator::{steps_as_graphviz, steps_for_targets}; use libdrcr::reporting::calculator::{steps_as_graphviz, steps_for_targets};
use libdrcr::reporting::generate_report; use libdrcr::reporting::generate_report;
use libdrcr::reporting::steps::{ use libdrcr::reporting::steps::register_lookup_fns;
register_lookup_fns, AllTransactionsExceptEarningsToEquity,
AllTransactionsIncludingEarningsToEquity, CalculateIncomeTax,
};
use libdrcr::reporting::types::{ use libdrcr::reporting::types::{
DateArgs, DateStartDateEndArgs, ReportingContext, ReportingProductId, ReportingProductKind, DateArgs, DateStartDateEndArgs, ReportingContext, ReportingProductId, ReportingProductKind,
ReportingStep, VoidArgs,
}; };
fn main() { fn main() {
@ -46,13 +43,19 @@ fn main() {
// Print Graphviz // Print Graphviz
let targets: Vec<Box<dyn ReportingStep>> = vec![ let targets = vec![
Box::new(CalculateIncomeTax {}), ReportingProductId {
Box::new(AllTransactionsIncludingEarningsToEquity { name: "CalculateIncomeTax",
args: DateArgs { kind: ReportingProductKind::Transactions,
args: Box::new(VoidArgs {}),
},
ReportingProductId {
name: "AllTransactionsIncludingEarningsToEquity",
kind: ReportingProductKind::BalancesAt,
args: Box::new(DateArgs {
date: NaiveDate::from_ymd_opt(2025, 6, 30).unwrap(), date: NaiveDate::from_ymd_opt(2025, 6, 30).unwrap(),
}, }),
}), },
]; ];
let (sorted_steps, dependencies) = steps_for_targets(targets, &context).unwrap(); let (sorted_steps, dependencies) = steps_for_targets(targets, &context).unwrap();
@ -61,15 +64,20 @@ fn main() {
// Get income statement // Get income statement
let targets: Vec<Box<dyn ReportingStep>> = vec![ let targets = vec![
Box::new(CalculateIncomeTax {}), ReportingProductId {
Box::new(AllTransactionsExceptEarningsToEquity { name: "CalculateIncomeTax",
product_kinds: &[ReportingProductKind::BalancesBetween], kind: ReportingProductKind::Transactions,
args: Box::new(VoidArgs {}),
},
ReportingProductId {
name: "AllTransactionsExceptEarningsToEquity",
kind: ReportingProductKind::BalancesBetween,
args: Box::new(DateStartDateEndArgs { args: Box::new(DateStartDateEndArgs {
date_start: NaiveDate::from_ymd_opt(2024, 7, 1).unwrap(), date_start: NaiveDate::from_ymd_opt(2024, 7, 1).unwrap(),
date_end: NaiveDate::from_ymd_opt(2025, 6, 30).unwrap(), date_end: NaiveDate::from_ymd_opt(2025, 6, 30).unwrap(),
}), }),
}), },
]; ];
let products = generate_report(targets, &context).unwrap(); let products = generate_report(targets, &context).unwrap();
@ -89,13 +97,19 @@ fn main() {
// Get balance sheet // Get balance sheet
let targets: Vec<Box<dyn ReportingStep>> = vec![ let targets = vec![
Box::new(CalculateIncomeTax {}), ReportingProductId {
Box::new(AllTransactionsIncludingEarningsToEquity { name: "CalculateIncomeTax",
args: DateArgs { kind: ReportingProductKind::Transactions,
args: Box::new(VoidArgs {}),
},
ReportingProductId {
name: "AllTransactionsIncludingEarningsToEquity",
kind: ReportingProductKind::BalancesAt,
args: Box::new(DateArgs {
date: NaiveDate::from_ymd_opt(2025, 6, 30).unwrap(), date: NaiveDate::from_ymd_opt(2025, 6, 30).unwrap(),
}, }),
}), },
]; ];
let products = generate_report(targets, &context).unwrap(); let products = generate_report(targets, &context).unwrap();

View File

@ -207,33 +207,41 @@ fn would_be_ready_to_execute(
true true
} }
/// Recursively resolve the dependencies of the target [ReportingStep]s and return a sorted [Vec] of [ReportingStep]s /// Recursively resolve the dependencies of the target [ReportingProductId]s and return a sorted [Vec] of [ReportingStep]s
pub fn steps_for_targets( pub fn steps_for_targets(
targets: Vec<Box<dyn ReportingStep>>, targets: Vec<ReportingProductId>,
context: &ReportingContext, context: &ReportingContext,
) -> Result<(Vec<Box<dyn ReportingStep>>, ReportingGraphDependencies), ReportingCalculationError> { ) -> Result<(Vec<Box<dyn ReportingStep>>, ReportingGraphDependencies), ReportingCalculationError> {
let mut steps: Vec<Box<dyn ReportingStep>> = Vec::new(); let mut steps: Vec<Box<dyn ReportingStep>> = Vec::new();
let mut dependencies = ReportingGraphDependencies { vec: Vec::new() }; let mut dependencies = ReportingGraphDependencies { vec: Vec::new() };
// Initialise targets // Process initial targets
for target in targets { for target in targets.iter() {
steps.push(target); if !steps.iter().any(|s| {
let target = steps.last().unwrap(); s.id().name == target.name
for dependency in target.requires(&context) { && s.id().args == target.args
dependencies.add_dependency(target.id(), dependency); && s.id().product_kinds.contains(&target.kind)
}) {
// No current step generates the product - try to lookup or build
if let Some(new_step) = build_step_for_product(&target, &steps, &dependencies, context)
{
steps.push(new_step);
let new_step = steps.last().unwrap();
for dependency in new_step.requires(&context) {
dependencies.add_dependency(new_step.id(), dependency);
}
new_step.init_graph(&steps, &mut dependencies, &context);
}
} }
target
.as_ref()
.init_graph(&steps, &mut dependencies, &context);
} }
// Call after_init_graph on targets // Call after_init_graph
for step in steps.iter() { for step in steps.iter() {
step.as_ref() step.as_ref()
.after_init_graph(&steps, &mut dependencies, &context); .after_init_graph(&steps, &mut dependencies, &context);
} }
// Process dependencies // Recursively process dependencies
loop { loop {
let mut new_steps = Vec::new(); let mut new_steps = Vec::new();

View File

@ -18,7 +18,7 @@
use calculator::{steps_for_targets, ReportingCalculationError}; use calculator::{steps_for_targets, ReportingCalculationError};
use executor::{execute_steps, ReportingExecutionError}; use executor::{execute_steps, ReportingExecutionError};
use types::{ReportingContext, ReportingProducts, ReportingStep}; use types::{ReportingContext, ReportingProductId, ReportingProducts};
pub mod builders; pub mod builders;
pub mod calculator; pub mod calculator;
@ -44,8 +44,11 @@ impl From<ReportingExecutionError> for ReportingError {
} }
} }
/// Calculate the steps required to generate the requested [ReportingProductId]s and then execute them
///
/// Helper function to call [steps_for_targets] followed by [execute_steps].
pub fn generate_report( pub fn generate_report(
targets: Vec<Box<dyn ReportingStep>>, targets: Vec<ReportingProductId>,
context: &ReportingContext, context: &ReportingContext,
) -> Result<ReportingProducts, ReportingError> { ) -> Result<ReportingProducts, ReportingError> {
// Solve dependencies // Solve dependencies