Skip to main content

cratestack_sql/values/
sql_value.rs

1use cratestack_core::Value;
2
3#[derive(Debug, Clone, PartialEq)]
4pub enum SqlValue {
5    Bool(bool),
6    Int(i64),
7    Float(f64),
8    String(String),
9    Bytes(Vec<u8>),
10    Uuid(uuid::Uuid),
11    DateTime(chrono::DateTime<chrono::Utc>),
12    Json(Value),
13    /// Only exists when a decimal backend is selected (cratestack#505):
14    /// `cratestack_core::Decimal` itself doesn't exist otherwise — see
15    /// `cratestack-core/src/decimal.rs`'s module doc. `NullDecimal` below
16    /// stays unconditional since it carries no `Decimal` payload.
17    #[cfg(any(feature = "decimal-rust-decimal", feature = "decimal-bigdecimal"))]
18    Decimal(cratestack_core::Decimal),
19    /// A `Vector(n)` field's value (see `docs/design/extensions.md`
20    /// §6). Defined unconditionally — no `pgvector` dependency is
21    /// needed to hold a `Vec<f32>` — but only ever constructed by
22    /// generated code gated on the `pgvector` Cargo feature (#161's
23    /// compile-time check), and only ever bound to a real column by
24    /// `cratestack-sqlx`'s own `pgvector`-gated encode path.
25    Vector(Vec<f32>),
26    NullBool,
27    NullInt,
28    NullFloat,
29    NullString,
30    NullBytes,
31    NullUuid,
32    NullDateTime,
33    NullJson,
34    NullDecimal,
35    NullVector,
36}
37
38#[derive(Debug, Clone, PartialEq)]
39pub enum FilterValue {
40    None,
41    Single(SqlValue),
42    Many(Vec<SqlValue>),
43}
44
45#[derive(Debug, Clone, PartialEq)]
46pub struct SqlColumnValue {
47    pub column: &'static str,
48    pub value: SqlValue,
49}
50
51/// Detect the first duplicate value in a list of `SqlValue`s, used for
52/// batch_upsert input deduplication. Linear-scan with `PartialEq` rather
53/// than the hashed variant in `cratestack-core` because `SqlValue::Float`
54/// and `SqlValue::Decimal` don't admit a sound `Hash` impl.
55///
56/// At the documented batch cap (≤ 1000 items) the O(N²) cost is on the
57/// order of a million `PartialEq` comparisons, which dominates nothing
58/// next to a single round-trip to Postgres. Returns `(first_index,
59/// duplicate_index)` on collision, matching `cratestack_core::find_duplicate_position`.
60pub fn find_duplicate_sql_value(values: &[SqlValue]) -> Option<(usize, usize)> {
61    for (index, value) in values.iter().enumerate() {
62        if let Some(earlier) = values[..index].iter().position(|prior| prior == value) {
63            return Some((earlier, index));
64        }
65    }
66    None
67}