diff --git a/crates/sqlbuild-rules-native/src/compiler/_helpers/sql_tests/errors.rs b/crates/sqlbuild-rules-native/src/compiler/_helpers/sql_tests/errors.rs deleted file mode 100644 index c2b2ea399e..0000000000 --- a/crates/sqlbuild-rules-native/src/compiler/_helpers/sql_tests/errors.rs +++ /dev/null @@ -1,23 +0,0 @@ -//! Error types owned by SQL-test planning helpers. - -use std::fmt::Display; - -use serde::ser; - -/// A parsed statement that `serde_json::to_value` could not represent. -#[derive(Debug)] -pub(crate) struct RelationMarkerError; - -impl Display for RelationMarkerError { - fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - formatter.write_str("value cannot be represented as JSON") - } -} - -impl std::error::Error for RelationMarkerError {} - -impl ser::Error for RelationMarkerError { - fn custom(_message: M) -> Self { - RelationMarkerError - } -} diff --git a/crates/sqlbuild-rules-native/src/compiler/_helpers/sql_tests/mod.rs b/crates/sqlbuild-rules-native/src/compiler/_helpers/sql_tests/mod.rs index 2efa1df628..28677d435b 100644 --- a/crates/sqlbuild-rules-native/src/compiler/_helpers/sql_tests/mod.rs +++ b/crates/sqlbuild-rules-native/src/compiler/_helpers/sql_tests/mod.rs @@ -1,7 +1,6 @@ pub(crate) mod cte_rename; pub(crate) mod cte_slices; pub(crate) mod cte_sql; -pub(crate) mod errors; pub(crate) mod expected_columns; pub(crate) mod extraction; pub(crate) mod helper_scope; diff --git a/crates/sqlbuild-rules-native/src/compiler/_helpers/sql_tests/planning.rs b/crates/sqlbuild-rules-native/src/compiler/_helpers/sql_tests/planning.rs index 705ee2c626..7f83a43a60 100644 --- a/crates/sqlbuild-rules-native/src/compiler/_helpers/sql_tests/planning.rs +++ b/crates/sqlbuild-rules-native/src/compiler/_helpers/sql_tests/planning.rs @@ -13,7 +13,6 @@ use crate::compiler::_helpers::sql_tests::cte_slices::SliceDialect; use crate::compiler::_helpers::sql_tests::cte_sql::{ cte_definition_sql, leading_with_prefix_end, with_leading_ctes, with_unique_ctes, }; -use crate::compiler::_helpers::sql_tests::errors::RelationMarkerError; use crate::compiler::_helpers::sql_tests::expected_columns::expected_columns; use crate::compiler::_helpers::sql_tests::helper_scope::{ ScopeGraph, helper_scope_ctes, merged_scoped_ctes, @@ -1305,13 +1304,9 @@ fn analysis_template( return None; } let expression = statements.remove(0); - let marker_calls = match relation_marker_calls(&expression) { - Ok(marker_calls) => marker_calls, - Err(RelationMarkerError) => return None, - }; Some(AnalysisTemplate { existing_cte_names: top_level_cte_names(&expression), - marker_calls, + marker_calls: relation_marker_calls(&expression), }) }) }) diff --git a/crates/sqlbuild-rules-native/src/compiler/_helpers/sql_tests/relation_markers.rs b/crates/sqlbuild-rules-native/src/compiler/_helpers/sql_tests/relation_markers.rs index c7b3dea5d6..9c36ee4206 100644 --- a/crates/sqlbuild-rules-native/src/compiler/_helpers/sql_tests/relation_markers.rs +++ b/crates/sqlbuild-rules-native/src/compiler/_helpers/sql_tests/relation_markers.rs @@ -1,809 +1,73 @@ -//! Relation marker calls read from a parsed statement's serialized shape without a JSON tree. +//! Relation marker calls in a serialized pre-order walk of a parsed statement's relations. -use std::cell::RefCell; +use polyglot_sql::expressions::{From, Join}; +use polyglot_sql::{Expression, ExpressionWalk}; -use serde::Serialize; -use serde::ser::{ - self, SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, SerializeTuple, - SerializeTupleStruct, SerializeTupleVariant, -}; - -use crate::compiler::_helpers::sql_tests::errors::RelationMarkerError; use crate::compiler::_helpers::sql_tests::planning::DBT_REF_FUNCTION; pub(crate) type MarkerCall = (String, String); -/// Return the marker relations a walk of `serde_json::to_value(value)` finds, in the same order. -pub(crate) fn relation_marker_calls(value: &T) -> Result> { - let stack: RefCell> = RefCell::new(Vec::new()); - let out = value.serialize(Collector { - need: Need::Walk, - stack: &stack, - })?; - Ok(out.calls) -} - -/// What the parent reads from a value besides the marker calls found beneath it. -#[derive(Clone, Copy, PartialEq, Eq)] -enum Need { - Walk, - From, - FromExpressions, - Joins, - Marker, - ThisMarker, - Function, - Args, - Arg, - Column, - Name, - Str, -} - -impl Need { - fn field(self, key: &str) -> Need { - match (self, key) { - (_, "from") => Need::From, - (_, "joins") => Need::Joins, - (Need::From, "expressions") => Need::FromExpressions, - (Need::Marker, "alias") => Need::ThisMarker, - (Need::Marker, "function") => Need::Function, - (Need::ThisMarker, "this") => Need::Marker, - (Need::Function, "name") | (Need::Name, "name") => Need::Str, - (Need::Function, "args") => Need::Args, - (Need::Arg, "column") => Need::Column, - (Need::Column, "name") => Need::Name, - _ => Need::Walk, - } - } - - fn element(self) -> Need { - match self { - Need::FromExpressions => Need::Marker, - Need::Joins => Need::ThisMarker, - Need::Args => Need::Arg, - _ => Need::Walk, - } - } -} - -#[derive(Default)] -enum Info { - #[default] - None, - Str(String), - Marker(MarkerCall), - Markers(Vec>), - Names(Vec>), - Function(Option, Option>>), +/// Return marker calls in node order, where Polyglot children follow declared field order. +pub(crate) fn relation_marker_calls(expression: &Expression) -> Vec { + expression.dfs().flat_map(node_marker_calls).collect() } -impl Info { - fn into_str(self) -> Option { - match self { - Info::Str(value) => Some(value), - _ => None, - } - } - - fn into_marker(self) -> Option { - match self { - Info::Marker(value) => Some(value), - _ => None, - } +/// FROM then JOIN marker calls of one node, plus the serialized `on` that traversal skips. +fn node_marker_calls(node: &Expression) -> Vec { + match node { + Expression::Select(select) => select + .from + .iter() + .flat_map(from_markers) + .chain(join_markers(&select.joins)) + .collect(), + Expression::From(from) => from_markers(from).collect(), + Expression::Delete(delete) => join_markers(&delete.joins).collect(), + Expression::JoinedTable(table) => join_markers(&table.joins).collect(), + Expression::DataDeletionProperty(property) => relation_marker_calls(&property.on), + _ => Vec::new(), } } -#[derive(Default)] -struct Out { - calls: Vec, - info: Info, -} - -impl Out { - fn leaf() -> Self { - Self::default() - } +fn from_markers(from: &From) -> impl Iterator + '_ { + from.expressions.iter().filter_map(marker) } -type Result = std::result::Result; - -enum Key { - Static(&'static str), - Owned(String), +fn join_markers(joins: &[Join]) -> impl Iterator + '_ { + joins.iter().filter_map(|join| marker(&join.this)) } -impl Key { - fn as_str(&self) -> &str { - match self { - Key::Static(value) => value, - Key::Owned(value) => value, +fn marker(expression: &Expression) -> Option { + match expression { + Expression::Alias(alias) => marker(&alias.this), + Expression::Function(function) => { + let names: Vec> = function + .args + .iter() + .map(|argument| match argument { + Expression::Column(column) => Some(column.name.name.as_str()), + _ => None, + }) + .collect(); + function_marker(&function.name, &names) } + _ => None, } } -type Stack = RefCell>; - -/// Pop the entries pushed since `start` as one object; a repeated key keeps its first position. -fn finish_object(need: Need, stack: &Stack, start: usize, may_repeat_keys: bool) -> Out { - let mut stack = stack.borrow_mut(); - let mut index = start + 1; - while may_repeat_keys && index < stack.len() { - let name = stack[index].0.as_str(); - match stack[start..index] - .iter() - .position(|(key, _)| key.as_str() == name) - { - Some(first) => { - let (_, out) = stack.remove(index); - stack[start + first].1 = out; - } - None => index += 1, - } - } - let entries = &mut stack[start..]; - let mut take = |name: &str| -> Option { - entries - .iter_mut() - .find(|(key, _)| key.as_str() == name) - .map(|(_, out)| std::mem::take(&mut out.info)) - }; - let mut calls: Vec = Vec::new(); - for name in ["from", "joins"] { - if let Some(Info::Markers(markers)) = take(name) { - calls.extend(markers.into_iter().flatten()); - } - } - let info = match need { - Need::Marker => match take("alias") { - Some(alias) => alias.into_marker().map_or(Info::None, Info::Marker), - None => match take("function") { - Some(Info::Function(Some(name), Some(args))) => { - function_marker(&name, args).map_or(Info::None, Info::Marker) - } - _ => Info::None, - }, - }, - Need::ThisMarker => take("this").unwrap_or_default(), - Need::From => match take("expressions") { - Some(markers @ Info::Markers(_)) => markers, - _ => Info::None, - }, - Need::Function => Info::Function( - take("name").and_then(Info::into_str), - match take("args") { - Some(Info::Names(names)) => Some(names), - _ => None, - }, - ), - Need::Arg => take("column").unwrap_or_default(), - Need::Column | Need::Name => take("name").unwrap_or_default(), - Need::Walk | Need::FromExpressions | Need::Joins | Need::Args | Need::Str => Info::None, - }; - for (_, out) in stack.drain(start..) { - calls.extend(out.calls); - } - Out { calls, info } -} - -/// One bit per key shape, so repeated keys are checked exactly only when a bit repeats. -fn key_bit(key: &str) -> u64 { - let bytes = key.as_bytes(); - let shape = bytes.len() - ^ usize::from(bytes.first().copied().unwrap_or(0)).rotate_left(3) - ^ usize::from(bytes.last().copied().unwrap_or(0)).rotate_left(7); - 1u64 << (shape % 64) -} - -fn function_marker(name: &str, args: Vec>) -> Option { +fn function_marker(name: &str, args: &[Option<&str>]) -> Option { let function_name = name.to_ascii_lowercase(); let referenced_name = if function_name == DBT_REF_FUNCTION { - match args.as_slice() { - [Some(first)] => first.clone(), + match args { + [Some(first)] => (*first).to_string(), [Some(first), Some(second)] => format!("{first}__{second}"), _ => return None, } } else { - let [Some(first)] = args.as_slice() else { + let [Some(first)] = args else { return None; }; - first.clone() + (*first).to_string() }; Some((function_name, referenced_name)) } - -fn finish_array(need: Need, stack: &Stack, start: usize) -> Out { - let mut calls: Vec = Vec::new(); - let mut stack = stack.borrow_mut(); - let info = match need { - Need::FromExpressions | Need::Joins => Info::Markers( - stack[start..] - .iter_mut() - .map(|(_, out)| std::mem::take(&mut out.info).into_marker()) - .collect(), - ), - Need::Args => Info::Names( - stack[start..] - .iter_mut() - .map(|(_, out)| std::mem::take(&mut out.info).into_str()) - .collect(), - ), - _ => Info::None, - }; - for (_, out) in stack.drain(start..) { - calls.extend(out.calls); - } - Out { calls, info } -} - -#[derive(Clone, Copy)] -struct Collector<'a> { - need: Need, - stack: &'a Stack, -} - -impl<'a> Collector<'a> { - fn string(self, value: impl FnOnce() -> String) -> Out { - Out { - calls: Vec::new(), - info: if self.need == Need::Str { - Info::Str(value()) - } else { - Info::None - }, - } - } - - fn array(self, need: Need) -> ArrayFrame<'a> { - ArrayFrame { - need, - stack: self.stack, - start: self.stack.borrow().len(), - } - } - - /// Open `{variant: payload}`; the outer object is empty until the payload closes. - fn variant( - self, - variant: &'static str, - payload: fn(Self, Need) -> F, - ) -> VariantFrame<'a, F> { - VariantFrame { - outer: self.object(self.need), - variant, - inner: payload(self, self.need.field(variant)), - } - } - - fn object(self, need: Need) -> ObjectFrame<'a> { - ObjectFrame { - need, - stack: self.stack, - start: self.stack.borrow().len(), - key_bits: 0, - may_repeat_keys: false, - pending_key: None, - } - } -} - -struct ArrayFrame<'a> { - need: Need, - stack: &'a Stack, - start: usize, -} - -impl ArrayFrame<'_> { - fn push(&mut self, value: &T) -> Result<()> { - let out = value.serialize(Collector { - need: self.need.element(), - stack: self.stack, - })?; - self.stack.borrow_mut().push((Key::Static(""), out)); - Ok(()) - } - - fn finish(self) -> Out { - finish_array(self.need, self.stack, self.start) - } -} - -struct ObjectFrame<'a> { - need: Need, - stack: &'a Stack, - start: usize, - key_bits: u64, - may_repeat_keys: bool, - pending_key: Option, -} - -impl ObjectFrame<'_> { - fn push(&mut self, key: Key, value: &T) -> Result<()> { - let out = value.serialize(Collector { - need: self.need.field(key.as_str()), - stack: self.stack, - })?; - let bit = key_bit(key.as_str()); - self.may_repeat_keys |= self.key_bits & bit != 0; - self.key_bits |= bit; - self.stack.borrow_mut().push((key, out)); - Ok(()) - } - - fn finish(self) -> Out { - finish_object(self.need, self.stack, self.start, self.may_repeat_keys) - } -} - -/// A variant wrapper object `{variant: inner}` around an array or object payload. -struct VariantFrame<'a, F> { - outer: ObjectFrame<'a>, - variant: &'static str, - inner: F, -} - -impl VariantFrame<'_, F> { - fn finish(self, inner: Out) -> Out { - let outer = self.outer; - outer - .stack - .borrow_mut() - .push((Key::Static(self.variant), inner)); - outer.finish() - } -} - -impl<'a> ser::Serializer for Collector<'a> { - type Ok = Out; - type Error = RelationMarkerError; - type SerializeSeq = ArrayFrame<'a>; - type SerializeTuple = ArrayFrame<'a>; - type SerializeTupleStruct = ArrayFrame<'a>; - type SerializeTupleVariant = VariantFrame<'a, ArrayFrame<'a>>; - type SerializeMap = ObjectFrame<'a>; - type SerializeStruct = ObjectFrame<'a>; - type SerializeStructVariant = VariantFrame<'a, ObjectFrame<'a>>; - - fn serialize_bool(self, _value: bool) -> Result { - Ok(Out::leaf()) - } - - fn serialize_i8(self, _value: i8) -> Result { - Ok(Out::leaf()) - } - - fn serialize_i16(self, _value: i16) -> Result { - Ok(Out::leaf()) - } - - fn serialize_i32(self, _value: i32) -> Result { - Ok(Out::leaf()) - } - - fn serialize_i64(self, _value: i64) -> Result { - Ok(Out::leaf()) - } - - fn serialize_i128(self, value: i128) -> Result { - if (i128::from(i64::MIN)..=i128::from(u64::MAX)).contains(&value) { - Ok(Out::leaf()) - } else { - Err(RelationMarkerError) - } - } - - fn serialize_u8(self, _value: u8) -> Result { - Ok(Out::leaf()) - } - - fn serialize_u16(self, _value: u16) -> Result { - Ok(Out::leaf()) - } - - fn serialize_u32(self, _value: u32) -> Result { - Ok(Out::leaf()) - } - - fn serialize_u64(self, _value: u64) -> Result { - Ok(Out::leaf()) - } - - fn serialize_u128(self, value: u128) -> Result { - if value <= u128::from(u64::MAX) { - Ok(Out::leaf()) - } else { - Err(RelationMarkerError) - } - } - - fn serialize_f32(self, _value: f32) -> Result { - Ok(Out::leaf()) - } - - fn serialize_f64(self, _value: f64) -> Result { - Ok(Out::leaf()) - } - - fn serialize_char(self, value: char) -> Result { - Ok(self.string(|| value.to_string())) - } - - fn serialize_str(self, value: &str) -> Result { - Ok(self.string(|| value.to_string())) - } - - fn serialize_bytes(self, _value: &[u8]) -> Result { - Ok(Out::leaf()) - } - - fn serialize_none(self) -> Result { - Ok(Out::leaf()) - } - - fn serialize_some(self, value: &T) -> Result { - value.serialize(self) - } - - fn serialize_unit(self) -> Result { - Ok(Out::leaf()) - } - - fn serialize_unit_struct(self, _name: &'static str) -> Result { - Ok(Out::leaf()) - } - - fn serialize_unit_variant( - self, - _name: &'static str, - _variant_index: u32, - variant: &'static str, - ) -> Result { - Ok(self.string(|| variant.to_string())) - } - - fn serialize_newtype_struct( - self, - _name: &'static str, - value: &T, - ) -> Result { - value.serialize(self) - } - - fn serialize_newtype_variant( - self, - _name: &'static str, - _variant_index: u32, - variant: &'static str, - value: &T, - ) -> Result { - let mut frame = self.object(self.need); - frame.push(Key::Static(variant), value)?; - Ok(frame.finish()) - } - - fn serialize_seq(self, _len: Option) -> Result> { - Ok(self.array(self.need)) - } - - fn serialize_tuple(self, _len: usize) -> Result> { - Ok(self.array(self.need)) - } - - fn serialize_tuple_struct(self, _name: &'static str, _len: usize) -> Result> { - Ok(self.array(self.need)) - } - - fn serialize_tuple_variant( - self, - _name: &'static str, - _variant_index: u32, - variant: &'static str, - _len: usize, - ) -> Result>> { - Ok(self.variant(variant, Collector::array)) - } - - fn serialize_map(self, _len: Option) -> Result> { - Ok(self.object(self.need)) - } - - fn serialize_struct(self, _name: &'static str, _len: usize) -> Result> { - Ok(self.object(self.need)) - } - - fn serialize_struct_variant( - self, - _name: &'static str, - _variant_index: u32, - variant: &'static str, - _len: usize, - ) -> Result>> { - Ok(self.variant(variant, Collector::object)) - } -} - -impl SerializeSeq for ArrayFrame<'_> { - type Ok = Out; - type Error = RelationMarkerError; - - fn serialize_element(&mut self, value: &T) -> Result<()> { - self.push(value) - } - - fn end(self) -> Result { - Ok(self.finish()) - } -} - -impl SerializeTuple for ArrayFrame<'_> { - type Ok = Out; - type Error = RelationMarkerError; - - fn serialize_element(&mut self, value: &T) -> Result<()> { - self.push(value) - } - - fn end(self) -> Result { - Ok(self.finish()) - } -} - -impl SerializeTupleStruct for ArrayFrame<'_> { - type Ok = Out; - type Error = RelationMarkerError; - - fn serialize_field(&mut self, value: &T) -> Result<()> { - self.push(value) - } - - fn end(self) -> Result { - Ok(self.finish()) - } -} - -impl SerializeTupleVariant for VariantFrame<'_, ArrayFrame<'_>> { - type Ok = Out; - type Error = RelationMarkerError; - - fn serialize_field(&mut self, value: &T) -> Result<()> { - self.inner.push(value) - } - - fn end(self) -> Result { - let inner = finish_array(self.inner.need, self.inner.stack, self.inner.start); - Ok(self.finish(inner)) - } -} - -impl SerializeMap for ObjectFrame<'_> { - type Ok = Out; - type Error = RelationMarkerError; - - fn serialize_key(&mut self, key: &T) -> Result<()> { - self.pending_key = Some(Key::Owned(key.serialize(MapKeyCollector)?)); - Ok(()) - } - - fn serialize_value(&mut self, value: &T) -> Result<()> { - let key = self.pending_key.take().ok_or(RelationMarkerError)?; - self.push(key, value) - } - - fn end(self) -> Result { - Ok(self.finish()) - } -} - -impl SerializeStruct for ObjectFrame<'_> { - type Ok = Out; - type Error = RelationMarkerError; - - fn serialize_field( - &mut self, - key: &'static str, - value: &T, - ) -> Result<()> { - self.push(Key::Static(key), value) - } - - fn end(self) -> Result { - Ok(self.finish()) - } -} - -impl SerializeStructVariant for VariantFrame<'_, ObjectFrame<'_>> { - type Ok = Out; - type Error = RelationMarkerError; - - fn serialize_field( - &mut self, - key: &'static str, - value: &T, - ) -> Result<()> { - self.inner.push(Key::Static(key), value) - } - - fn end(self) -> Result { - let inner = finish_object( - self.inner.need, - self.inner.stack, - self.inner.start, - self.inner.may_repeat_keys, - ); - Ok(self.finish(inner)) - } -} - -/// Map keys as `serde_json` stringifies them; unsupported key types fail as they do there. -struct MapKeyCollector; - -impl ser::Serializer for MapKeyCollector { - type Ok = String; - type Error = RelationMarkerError; - type SerializeSeq = ser::Impossible; - type SerializeTuple = ser::Impossible; - type SerializeTupleStruct = ser::Impossible; - type SerializeTupleVariant = ser::Impossible; - type SerializeMap = ser::Impossible; - type SerializeStruct = ser::Impossible; - type SerializeStructVariant = ser::Impossible; - - fn serialize_bool(self, value: bool) -> Result { - Ok(value.to_string()) - } - - fn serialize_i8(self, value: i8) -> Result { - Ok(value.to_string()) - } - - fn serialize_i16(self, value: i16) -> Result { - Ok(value.to_string()) - } - - fn serialize_i32(self, value: i32) -> Result { - Ok(value.to_string()) - } - - fn serialize_i64(self, value: i64) -> Result { - Ok(value.to_string()) - } - - fn serialize_i128(self, value: i128) -> Result { - Ok(value.to_string()) - } - - fn serialize_u8(self, value: u8) -> Result { - Ok(value.to_string()) - } - - fn serialize_u16(self, value: u16) -> Result { - Ok(value.to_string()) - } - - fn serialize_u32(self, value: u32) -> Result { - Ok(value.to_string()) - } - - fn serialize_u64(self, value: u64) -> Result { - Ok(value.to_string()) - } - - fn serialize_u128(self, value: u128) -> Result { - Ok(value.to_string()) - } - - fn serialize_f32(self, value: f32) -> Result { - if value.is_finite() { - Ok(format!("{value:?}")) - } else { - Err(RelationMarkerError) - } - } - - fn serialize_f64(self, value: f64) -> Result { - if value.is_finite() { - Ok(format!("{value:?}")) - } else { - Err(RelationMarkerError) - } - } - - fn serialize_char(self, value: char) -> Result { - Ok(value.to_string()) - } - - fn serialize_str(self, value: &str) -> Result { - Ok(value.to_string()) - } - - fn serialize_bytes(self, _value: &[u8]) -> Result { - Err(RelationMarkerError) - } - - fn serialize_none(self) -> Result { - Err(RelationMarkerError) - } - - fn serialize_some(self, _value: &T) -> Result { - Err(RelationMarkerError) - } - - fn serialize_unit(self) -> Result { - Err(RelationMarkerError) - } - - fn serialize_unit_struct(self, _name: &'static str) -> Result { - Err(RelationMarkerError) - } - - fn serialize_unit_variant( - self, - _name: &'static str, - _variant_index: u32, - variant: &'static str, - ) -> Result { - Ok(variant.to_string()) - } - - fn serialize_newtype_struct( - self, - _name: &'static str, - value: &T, - ) -> Result { - value.serialize(self) - } - - fn serialize_newtype_variant( - self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - _value: &T, - ) -> Result { - Err(RelationMarkerError) - } - - fn serialize_seq(self, _len: Option) -> Result { - Err(RelationMarkerError) - } - - fn serialize_tuple(self, _len: usize) -> Result { - Err(RelationMarkerError) - } - - fn serialize_tuple_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - Err(RelationMarkerError) - } - - fn serialize_tuple_variant( - self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - _len: usize, - ) -> Result { - Err(RelationMarkerError) - } - - fn serialize_map(self, _len: Option) -> Result { - Err(RelationMarkerError) - } - - fn serialize_struct(self, _name: &'static str, _len: usize) -> Result { - Err(RelationMarkerError) - } - - fn serialize_struct_variant( - self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - _len: usize, - ) -> Result { - Err(RelationMarkerError) - } -} diff --git a/crates/sqlbuild-rules-native/src/compiler/tests/helpers.rs b/crates/sqlbuild-rules-native/src/compiler/tests/helpers.rs index 2b6f36eb73..9d721acaec 100644 --- a/crates/sqlbuild-rules-native/src/compiler/tests/helpers.rs +++ b/crates/sqlbuild-rules-native/src/compiler/tests/helpers.rs @@ -1662,7 +1662,7 @@ fn generic_lexical_syntax() -> Value { type MarkerCalls = Option>; -/// The previous JSON-tree walk, kept as the oracle the streaming collector must match. +/// The original JSON-tree walk, kept as the oracle the direct relation walk must match. fn json_relation_marker_calls(value: &Value) -> Vec<(String, String)> { let from_markers = value .get("from") @@ -1728,7 +1728,7 @@ pub(crate) fn owned_marker_calls(calls: &[(&str, &str)]) -> MarkerCalls { ) } -/// Parse one statement and return the streaming collector's and the JSON oracle's marker calls. +/// Parse one statement and return the direct walk's and the JSON oracle's marker calls. pub(crate) fn relation_markers_and_json_oracle( dialect: &str, sql: &str, @@ -1740,7 +1740,7 @@ pub(crate) fn relation_markers_and_json_oracle( assert_eq!(statements.len(), 1, "{sql}"); let expression = statements.remove(0); ( - relation_marker_calls(&expression).ok(), + Some(relation_marker_calls(&expression)), serde_json::to_value(&expression) .ok() .map(|value| json_relation_marker_calls(&value)), @@ -1764,6 +1764,12 @@ pub(crate) fn relation_marker_oracle_mismatches(dialect: &str) -> Vec { "SELECT * FROM {a} WHERE EXISTS (SELECT 1 FROM {b})", "SELECT * FROM {a} UNION SELECT * FROM {b}", "SELECT * FROM {a}, {b}", + "SELECT * FROM ({a} JOIN {b} ON TRUE)", + "SELECT * FROM {a} AS x LEFT JOIN LATERAL (SELECT * FROM {b}) AS y ON TRUE", + "SELECT * FROM (SELECT * FROM {a}) AS x CROSS JOIN {b} WHERE x.id IN (SELECT id FROM {a})", + "UPDATE orders SET amount = 1 FROM {a} JOIN {b} ON TRUE", + "DELETE FROM orders USING {a} JOIN {b} ON TRUE", + "INSERT INTO orders SELECT * FROM {a} JOIN {b} ON TRUE", ]; let parser = Dialect::get_by_name(dialect).expect("test dialect must exist"); wrappers @@ -1781,7 +1787,7 @@ pub(crate) fn relation_marker_oracle_mismatches(dialect: &str) -> Vec { .unwrap_or_default() .iter() .any(|expression| { - relation_marker_calls(expression).ok() + Some(relation_marker_calls(expression)) != serde_json::to_value(expression) .ok() .map(|value| json_relation_marker_calls(&value)) diff --git a/crates/sqlbuild-rules-native/src/compiler/tests/test_sql_test_relation_markers.rs b/crates/sqlbuild-rules-native/src/compiler/tests/test_sql_test_relation_markers.rs index d1f123948a..9a9c4a061d 100644 --- a/crates/sqlbuild-rules-native/src/compiler/tests/test_sql_test_relation_markers.rs +++ b/crates/sqlbuild-rules-native/src/compiler/tests/test_sql_test_relation_markers.rs @@ -99,6 +99,16 @@ fn given_generated_relation_shapes_when_collecting_markers_then_json_oracle_matc dialect: "bigquery", expected_mismatches: &[], }, + RelationMarkerOracleTestCase { + description: "tsql relation shapes", + dialect: "tsql", + expected_mismatches: &[], + }, + RelationMarkerOracleTestCase { + description: "databricks relation shapes", + dialect: "databricks", + expected_mismatches: &[], + }, ]; for test_case in test_cases { assert_eq!(