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 a target asset, then all assets that depend on it.
///
/// Use this to propagate a change downstream — rebuild the changed asset and
/// everything that reads from it.
///
/// Execution order:
/// ```text
/// first:  [staging.orders]               ← target
/// wave 0: [mart.revenue, mart.sessions]  ← descendants (parallel within each wave)
/// ```
pub struct RunDownstream<E> {
    engine: Engine,
    executor: E,
}

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

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

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