pub fn extract_column_operations(
dialect: &dyn Dialect,
sql: &str,
) -> Result<Vec<Result<ColumnOperation, Error>>, Error>Expand description
Convenience function to extract column-level operations from SQL using
the dialect defaults (no catalog, dialect-derived casing). For a
catalog or a casing override, use
extract_column_operations_with_options; with a catalog, table
references are matched against it (right-anchored, dialect-cased) and
column resolution turns strict.
§Example
use sql_insight::sqlparser::dialect::GenericDialect;
use sql_insight::ResolutionKind;
use sql_insight::extractor::{
extract_column_operations, ColumnLineageKind, ColumnTarget, StatementKind,
};
let dialect = GenericDialect {};
let result =
extract_column_operations(&dialect, "SELECT a FROM t1").unwrap();
let ops = result[0].as_ref().unwrap();
// SELECT contributes reads + lineage but no writes.
assert_eq!(ops.statement_kind, StatementKind::Select);
assert!(ops.writes.is_empty());
// `t1.a` surfaces as a single read, walk-time resolved to t1.
// Catalog-less mode → resolution is `Inferred` (we adopted the
// sole `Unknown`-schema candidate without firm evidence).
assert_eq!(ops.reads.len(), 1);
let read = &ops.reads[0];
assert_eq!(read.reference.name.value, "a");
assert_eq!(read.reference.table.as_ref().unwrap().name.value, "t1");
assert_eq!(read.resolution, ResolutionKind::Inferred);
// The projection emits one lineage edge into the SELECT's QueryOutput slot,
// marked Passthrough (no expression wrapping the column).
assert_eq!(ops.lineage.len(), 1);
let edge = &ops.lineage[0];
assert_eq!(edge.kind, ColumnLineageKind::Passthrough);
match &edge.target {
ColumnTarget::QueryOutput { name, position } => {
assert_eq!(name.as_ref().unwrap().value, "a");
assert_eq!(*position, 0);
}
other => panic!("expected QueryOutput, got {other:?}"),
}