dbmcp_sql_lineage/lib.rs
1//! Column-level SQL lineage extraction for `dbmcp`.
2//!
3//! Given a single SQL statement and a `sqlparser`
4//! [`Dialect`](sqlparser::dialect::Dialect),
5//! [`extract`] returns a [`Lineage`] mapping each output column to the physical
6//! `table.column` sources that produced it. Read queries and write statements
7//! (`INSERT`, `UPDATE`, `DELETE`, `CREATE TABLE AS SELECT`, `MERGE`) are both
8//! handled; writes also record a [`Lineage::target`]. Resolution is fail-closed:
9//! any column that cannot be bound to a concrete source aborts the whole
10//! extraction. The crate never connects to or executes against a database — it
11//! analyzes SQL text only.
12//!
13//! Wildcards over base tables (`SELECT *`) and unqualified columns in
14//! multi-table joins cannot be resolved without a column catalog, so they fail
15//! closed; qualified references, single-table queries, and wildcards over
16//! CTEs/derived tables resolve normally.
17//!
18//! # Quickstart
19//!
20//! ```
21//! use dbmcp_sql_lineage::extract;
22//! use sqlparser::dialect::PostgreSqlDialect;
23//!
24//! let lineage = extract("SELECT u.id, u.email FROM users u", &PostgreSqlDialect {})?;
25//! assert_eq!(lineage.columns[1].name.as_deref(), Some("email"));
26//! # Ok::<(), dbmcp_sql_lineage::LineageError>(())
27//! ```
28
29mod error;
30mod extract;
31mod model;
32mod resolve;
33mod scope;
34mod statement;
35
36pub use crate::error::LineageError;
37pub use crate::extract::extract;
38pub use crate::model::{Lineage, OutputColumn, SourceRef, TableRef, TableRefBuilder};