toasty_driver_integration_suite/stmt.rs
1//! Expression utilities for testing with assert_struct!
2//!
3//! This module provides test utilities like the Any wildcard
4//! for use with the Like trait in assert_struct! macros.
5
6use assert_struct::Like;
7use toasty_core::stmt::{Expr, Value, ValueStream};
8
9/// Wildcard type that matches any expression - useful for ignoring fields in patterns
10#[derive(Debug, Clone)]
11pub struct Any;
12
13/// Any wildcard matches any expression
14impl Like<Any> for Expr {
15 fn like(&self, _pattern: &Any) -> bool {
16 true // Any matches everything
17 }
18}
19
20impl PartialEq<Any> for Expr {
21 fn eq(&self, _: &Any) -> bool {
22 true
23 }
24}
25
26/// Any wildcard matches any value
27impl Like<Any> for Value {
28 fn like(&self, _pattern: &Any) -> bool {
29 true // Any matches everything
30 }
31}
32
33impl PartialEq<Any> for Value {
34 fn eq(&self, _: &Any) -> bool {
35 true
36 }
37}
38
39/// Matches either an extracted bind-parameter placeholder (`Expr::Arg`, emitted
40/// by SQL drivers after parameter extraction) at a specific position, or an
41/// inline `Expr::Value` matching the contained pattern (emitted by non-SQL
42/// drivers like DynamoDB).
43///
44/// Use this when a single assertion needs to cover both representations:
45///
46/// ```ignore
47/// let val = if test.capability().sql {
48/// ArgOr::Arg(0)
49/// } else {
50/// ArgOr::Value(1i64)
51/// };
52/// assert_struct!(op, ..., rows: [=~ (Any, Any, val)]);
53/// ```
54pub enum ArgOr<V> {
55 /// Matches `Expr::Arg(_)` whose `position` equals the given index.
56 Arg(usize),
57 /// Matches `Expr::Value(_)` using the inner pattern via `Like<V>`.
58 Value(V),
59}
60
61impl<V> Like<ArgOr<V>> for Expr
62where
63 Expr: Like<V>,
64{
65 fn like(&self, pattern: &ArgOr<V>) -> bool {
66 match pattern {
67 ArgOr::Arg(pos) => matches!(self, Expr::Arg(arg) if arg.position == *pos),
68 ArgOr::Value(v) => self.like(v),
69 }
70 }
71}
72
73/// Extension trait for ValueStream providing convenient testing methods
74pub trait ValueStreamExt {
75 /// Returns buffered values, asserting that the stream is fully buffered
76 ///
77 /// This method will panic if the stream is not fully buffered (i.e., if there
78 /// are still pending values in the stream that haven't been loaded into the buffer).
79 /// Use this in tests when you want to access buffered values synchronously.
80 fn buffered(&self) -> Vec<Value>;
81}
82
83/// Blanket implementation of ValueStreamExt for ValueStream
84impl ValueStreamExt for ValueStream {
85 fn buffered(&self) -> Vec<Value> {
86 assert!(
87 self.is_buffered(),
88 "ValueStream is not fully buffered - call .buffer().await first"
89 );
90 self.buffered_to_vec()
91 }
92}