use std::path::PathBuf;
fn locked_sqlparser_versions() -> Vec<String> {
let lock = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../../Cargo.lock")
.canonicalize()
.expect("workspace Cargo.lock must exist");
let text = std::fs::read_to_string(&lock).expect("Cargo.lock must be readable");
let mut versions = Vec::new();
let mut in_sqlparser = false;
for line in text.lines() {
let line = line.trim();
if line == "[[package]]" {
in_sqlparser = false;
} else if line == r#"name = "sqlparser""# {
in_sqlparser = true;
} else if in_sqlparser {
if let Some(v) = line.strip_prefix("version = ") {
versions.push(v.trim_matches('"').to_string());
in_sqlparser = false;
}
}
}
versions
}
#[test]
fn exactly_one_sqlparser_is_linked() {
let versions = locked_sqlparser_versions();
assert!(
!versions.is_empty(),
"no `sqlparser` in Cargo.lock — did the dependency graph change?"
);
assert_eq!(
versions.len(),
1,
"ddx-core and datafusion must resolve the SAME `sqlparser`, but the \
lockfile has {n}: {versions:?}.\n\n\
Path B's bridge (crates/ddx-datafusion/src/analyzer.rs) passes a \
`sqlparser::ast::Expr` from DataFusion's unparser directly to \
ddx-core. Two versions means two unrelated Rust types and the bridge \
will not compile.\n\n\
Fix by reconciling the pins in the workspace Cargo.toml: ddx-core pins \
`sqlparser` exactly, and the `datafusion` version must be one whose \
own requirement accepts that pin (54.x wants ^0.62.0; 53.x wanted \
^0.61.0). If they genuinely cannot be reconciled, the documented \
fallback is to degrade the bridge to a SQL string round-trip rather \
than break it.",
n = versions.len(),
);
}
#[test]
fn the_bridge_types_are_actually_the_same_type() {
fn assert_same(e: datafusion::sql::sqlparser::ast::Expr) -> ddx_core::sqlparser::ast::Expr {
e
}
let expr =
ddx_core::sqlparser::ast::Expr::Identifier(ddx_core::sqlparser::ast::Ident::new("x"));
assert_eq!(assert_same(expr).to_string(), "x");
}