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}