Skip to main content

uqa_sql/
params.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Bind parameters for `Engine::sql(query, params)`.
8
9use uqa_core::Value;
10
11use crate::ast::ColumnType;
12
13/// Value bound to a `$N` placeholder.
14#[derive(Debug, Clone)]
15pub enum SQLParam {
16    Scalar(Value),
17    /// A scalar value whose declared SQL type must survive runtime [`Value`] carrier normalization.
18    TypedScalar {
19        value: Value,
20        ty: ColumnType,
21    },
22    Vector(Vec<f32>),
23    Tensor(Vec<Vec<f32>>),
24}
25
26impl SQLParam {
27    pub fn scalar(value: Value) -> Self {
28        Self::Scalar(value)
29    }
30
31    #[must_use]
32    pub fn typed_scalar(value: Value, ty: ColumnType) -> Self {
33        Self::TypedScalar { value, ty }
34    }
35
36    /// Return the scalar carrier without changing the semantics of untyped [`SQLParam::Scalar`] values.
37    #[must_use]
38    pub fn scalar_value(&self) -> Option<&Value> {
39        match self {
40            Self::Scalar(value) | Self::TypedScalar { value, .. } => Some(value),
41            Self::Vector(_) | Self::Tensor(_) => None,
42        }
43    }
44
45    /// Return the explicit SQL type carried only by [`SQLParam::TypedScalar`].
46    #[must_use]
47    pub fn declared_scalar_type(&self) -> Option<&ColumnType> {
48        match self {
49            Self::TypedScalar { ty, .. } => Some(ty),
50            Self::Scalar(_) | Self::Vector(_) | Self::Tensor(_) => None,
51        }
52    }
53
54    pub fn vector(v: Vec<f32>) -> Self {
55        Self::Vector(v)
56    }
57
58    pub fn tensor(v: Vec<Vec<f32>>) -> Self {
59        Self::Tensor(v)
60    }
61}
62
63#[cfg(test)]
64mod tests {
65    use super::*;
66
67    #[test]
68    fn typed_scalar_preserves_declared_type_without_changing_scalar_access() {
69        let value = Value::Int(7);
70        let typed = SQLParam::typed_scalar(value.clone(), ColumnType::SmallInteger);
71        assert_eq!(typed.scalar_value(), Some(&value));
72        assert_eq!(
73            typed.declared_scalar_type(),
74            Some(&ColumnType::SmallInteger)
75        );
76
77        let scalar = SQLParam::scalar(value.clone());
78        assert_eq!(scalar.scalar_value(), Some(&value));
79        assert_eq!(scalar.declared_scalar_type(), None);
80    }
81}