Skip to main content

extract_column_operations

Function extract_column_operations 

Source
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:?}"),
}