hinge 0.1.0

SQL-native ELT engine — dependency graph resolved automatically from FROM/JOIN clauses, parallel execution, single binary
Documentation
use crate::application::Engine;
use crate::application::{Executor, ExecutorError};
use crate::domain::{Asset, Graph};
use futures::future::try_join_all;

/// Executes all ancestors of a target asset, then the asset itself.
///
/// Use this to rebuild everything a specific asset depends on before refreshing it.
///
/// Execution order:
/// ```text
/// wave 0: [raw.events]           ← ancestors (parallel within each wave)
/// wave 1: [staging.orders]       ← ancestor
/// final:  [mart.revenue]         ← target
/// ```
pub struct RunUpstream<E> {
    engine: Engine,
    executor: E,
}

impl<E: Executor> RunUpstream<E> {
    pub fn new(graph: Graph, executor: E) -> Self {
        Self { engine: Engine::new(graph), executor }
    }

    /// Run all ancestors (parallel waves), then `start`.
    pub async fn execute(&self, start: &Asset) -> Result<(), ExecutorError> {
        for wave in self.engine.upstream_levels(start) {
            let futs: Vec<_> = wave.iter().map(|asset| self.executor.run(asset)).collect();
            try_join_all(futs).await?;
        }
        self.executor.run(start).await
    }

    /// Returns the planned execution order (flat topo, for display / dry-run).
    pub fn plan(&self, start: &Asset) -> Vec<Asset> {
        let mut plan = self.engine.propagate_upstream(start);
        plan.push(start.clone());
        plan
    }
}