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 Decimal(cratestack_core::Decimal),
14 /// A `Vector(n)` field's value (see `docs/design/extensions.md`
15 /// §6). Defined unconditionally — no `pgvector` dependency is
16 /// needed to hold a `Vec<f32>` — but only ever constructed by
17 /// generated code gated on the `pgvector` Cargo feature (#161's
18 /// compile-time check), and only ever bound to a real column by
19 /// `cratestack-sqlx`'s own `pgvector`-gated encode path.
20 Vector(Vec<f32>),
21 NullBool,
22 NullInt,
23 NullFloat,
24 NullString,
25 NullBytes,
26 NullUuid,
27 NullDateTime,
28 NullJson,
29 NullDecimal,
30 NullVector,
31}
32
33#[derive(Debug, Clone, PartialEq)]
34pub enum FilterValue {
35 None,
36 Single(SqlValue),
37 Many(Vec<SqlValue>),
38}
39
40#[derive(Debug, Clone, PartialEq)]
41pub struct SqlColumnValue {
42 pub column: &'static str,
43 pub value: SqlValue,
44}
45
46/// Detect the first duplicate value in a list of `SqlValue`s, used for
47/// batch_upsert input deduplication. Linear-scan with `PartialEq` rather
48/// than the hashed variant in `cratestack-core` because `SqlValue::Float`
49/// and `SqlValue::Decimal` don't admit a sound `Hash` impl.
50///
51/// At the documented batch cap (≤ 1000 items) the O(N²) cost is on the
52/// order of a million `PartialEq` comparisons, which dominates nothing
53/// next to a single round-trip to Postgres. Returns `(first_index,
54/// duplicate_index)` on collision, matching `cratestack_core::find_duplicate_position`.
55pub fn find_duplicate_sql_value(values: &[SqlValue]) -> Option<(usize, usize)> {
56 for (index, value) in values.iter().enumerate() {
57 if let Some(earlier) = values[..index].iter().position(|prior| prior == value) {
58 return Some((earlier, index));
59 }
60 }
61 None
62}