1#![allow(clippy::match_same_arms)]
4
5use std::cmp::Ordering;
6use std::fmt::{self, Display};
7
8use bytes::Bytes;
9use kimberlite_types::Timestamp;
10use serde::{Deserialize, Serialize};
11
12use crate::error::{QueryError, Result};
13use crate::schema::DataType;
14
15#[derive(Debug, Clone, Default, Serialize, Deserialize)]
23#[serde(untagged)]
24pub enum Value {
25 #[default]
27 Null,
28
29 TinyInt(i8),
32 SmallInt(i16),
34 Integer(i32),
36 BigInt(i64),
38
39 Real(f64),
42 #[serde(skip)] Decimal(i128, u8),
48
49 Text(String),
52
53 #[serde(with = "bytes_base64")]
56 Bytes(Bytes),
57
58 Boolean(bool),
61
62 Date(i32),
65 Time(i64),
67 Timestamp(Timestamp),
69
70 Uuid([u8; 16]),
73 Json(serde_json::Value),
75
76 #[serde(skip)]
80 Placeholder(usize),
81}
82
83impl PartialEq for Value {
84 fn eq(&self, other: &Self) -> bool {
85 match (self, other) {
86 (Value::Null, Value::Null) => true,
87 (Value::TinyInt(a), Value::TinyInt(b)) => a == b,
88 (Value::SmallInt(a), Value::SmallInt(b)) => a == b,
89 (Value::Integer(a), Value::Integer(b)) => a == b,
90 (Value::BigInt(a), Value::BigInt(b)) => a == b,
91 (Value::Real(a), Value::Real(b)) => {
92 a.to_bits() == b.to_bits()
94 }
95 (Value::Decimal(a_val, a_scale), Value::Decimal(b_val, b_scale)) => {
96 a_val == b_val && a_scale == b_scale
97 }
98 (Value::Text(a), Value::Text(b)) => a == b,
99 (Value::Bytes(a), Value::Bytes(b)) => a == b,
100 (Value::Boolean(a), Value::Boolean(b)) => a == b,
101 (Value::Date(a), Value::Date(b)) => a == b,
102 (Value::Time(a), Value::Time(b)) => a == b,
103 (Value::Timestamp(a), Value::Timestamp(b)) => a == b,
104 (Value::Uuid(a), Value::Uuid(b)) => a == b,
105 (Value::Json(a), Value::Json(b)) => a == b,
106 (Value::Placeholder(a), Value::Placeholder(b)) => a == b,
107 _ => false, }
109 }
110}
111
112impl Eq for Value {}
113
114impl std::hash::Hash for Value {
115 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
116 std::mem::discriminant(self).hash(state);
118
119 match self {
121 Value::Null => {}
122 Value::TinyInt(v) => v.hash(state),
123 Value::SmallInt(v) => v.hash(state),
124 Value::Integer(v) => v.hash(state),
125 Value::BigInt(v) => v.hash(state),
126 Value::Real(v) => v.to_bits().hash(state), Value::Decimal(val, scale) => {
128 val.hash(state);
129 scale.hash(state);
130 }
131 Value::Text(v) => v.hash(state),
132 Value::Bytes(v) => v.hash(state),
133 Value::Boolean(v) => v.hash(state),
134 Value::Date(v) => v.hash(state),
135 Value::Time(v) => v.hash(state),
136 Value::Timestamp(v) => v.hash(state),
137 Value::Uuid(v) => v.hash(state),
138 Value::Json(v) => v.to_string().hash(state), Value::Placeholder(v) => v.hash(state),
140 }
141 }
142}
143
144fn parse_decimal_string(s: &str, scale: u8) -> Result<i128> {
146 let parts: Vec<&str> = s.split('.').collect();
147 match parts.as_slice() {
148 [int_part] => {
149 let int_val: i128 = int_part.parse().map_err(|_| QueryError::TypeMismatch {
151 expected: format!("decimal with scale {scale}"),
152 actual: s.to_string(),
153 })?;
154 Ok(int_val * 10_i128.pow(u32::from(scale)))
155 }
156 [int_part, frac_part] => {
157 let int_val: i128 = int_part.parse().map_err(|_| QueryError::TypeMismatch {
159 expected: format!("decimal with scale {scale}"),
160 actual: s.to_string(),
161 })?;
162
163 let mut frac_str = (*frac_part).to_string();
165 if frac_str.len() > scale as usize {
166 frac_str.truncate(scale as usize);
167 } else {
168 frac_str.push_str(&"0".repeat(scale as usize - frac_str.len()));
169 }
170
171 let frac_val: i128 = frac_str.parse().map_err(|_| QueryError::TypeMismatch {
172 expected: format!("decimal with scale {scale}"),
173 actual: s.to_string(),
174 })?;
175
176 let multiplier = 10_i128.pow(u32::from(scale));
177 let is_negative = s.starts_with('-');
181 if is_negative {
182 Ok(int_val * multiplier - frac_val)
183 } else {
184 Ok(int_val * multiplier + frac_val)
185 }
186 }
187 _ => Err(QueryError::TypeMismatch {
188 expected: format!("decimal with scale {scale}"),
189 actual: s.to_string(),
190 }),
191 }
192}
193
194fn parse_uuid_string(s: &str) -> Result<[u8; 16]> {
196 let hex_str = s.replace('-', "");
198
199 if hex_str.len() != 32 {
200 return Err(QueryError::TypeMismatch {
201 expected: "UUID (32 hex digits)".to_string(),
202 actual: s.to_string(),
203 });
204 }
205
206 let mut bytes = [0u8; 16];
207 for (i, chunk) in hex_str.as_bytes().chunks(2).enumerate() {
208 let hex_byte = std::str::from_utf8(chunk).map_err(|_| QueryError::TypeMismatch {
209 expected: "UUID (valid hex)".to_string(),
210 actual: s.to_string(),
211 })?;
212
213 bytes[i] = u8::from_str_radix(hex_byte, 16).map_err(|_| QueryError::TypeMismatch {
214 expected: "UUID (valid hex)".to_string(),
215 actual: s.to_string(),
216 })?;
217 }
218
219 Ok(bytes)
220}
221
222fn total_cmp_f64(a: f64, b: f64) -> Ordering {
228 let a_bits = a.to_bits();
230 let b_bits = b.to_bits();
231
232 let a_key = if a.is_sign_negative() {
234 !a_bits
235 } else {
236 a_bits ^ (1u64 << 63)
237 };
238
239 let b_key = if b.is_sign_negative() {
240 !b_bits
241 } else {
242 b_bits ^ (1u64 << 63)
243 };
244
245 a_key.cmp(&b_key)
246}
247
248impl Value {
249 pub fn data_type(&self) -> Option<DataType> {
253 match self {
254 Value::Null | Value::Placeholder(_) => None,
255 Value::TinyInt(_) => Some(DataType::TinyInt),
256 Value::SmallInt(_) => Some(DataType::SmallInt),
257 Value::Integer(_) => Some(DataType::Integer),
258 Value::BigInt(_) => Some(DataType::BigInt),
259 Value::Real(_) => Some(DataType::Real),
260 Value::Decimal(_, scale) => Some(DataType::Decimal {
261 precision: 38, scale: *scale,
263 }),
264 Value::Text(_) => Some(DataType::Text),
265 Value::Bytes(_) => Some(DataType::Bytes),
266 Value::Boolean(_) => Some(DataType::Boolean),
267 Value::Date(_) => Some(DataType::Date),
268 Value::Time(_) => Some(DataType::Time),
269 Value::Timestamp(_) => Some(DataType::Timestamp),
270 Value::Uuid(_) => Some(DataType::Uuid),
271 Value::Json(_) => Some(DataType::Json),
272 }
273 }
274
275 pub fn is_null(&self) -> bool {
277 matches!(self, Value::Null)
278 }
279
280 pub fn as_bigint(&self) -> Option<i64> {
282 match self {
283 Value::BigInt(v) => Some(*v),
284 _ => None,
285 }
286 }
287
288 pub fn as_text(&self) -> Option<&str> {
290 match self {
291 Value::Text(s) => Some(s),
292 _ => None,
293 }
294 }
295
296 pub fn as_boolean(&self) -> Option<bool> {
298 match self {
299 Value::Boolean(b) => Some(*b),
300 _ => None,
301 }
302 }
303
304 pub fn as_timestamp(&self) -> Option<Timestamp> {
306 match self {
307 Value::Timestamp(ts) => Some(*ts),
308 _ => None,
309 }
310 }
311
312 pub fn as_bytes(&self) -> Option<&Bytes> {
314 match self {
315 Value::Bytes(b) => Some(b),
316 _ => None,
317 }
318 }
319
320 pub fn as_tinyint(&self) -> Option<i8> {
322 match self {
323 Value::TinyInt(v) => Some(*v),
324 _ => None,
325 }
326 }
327
328 pub fn as_smallint(&self) -> Option<i16> {
330 match self {
331 Value::SmallInt(v) => Some(*v),
332 _ => None,
333 }
334 }
335
336 pub fn as_integer(&self) -> Option<i32> {
338 match self {
339 Value::Integer(v) => Some(*v),
340 _ => None,
341 }
342 }
343
344 pub fn as_real(&self) -> Option<f64> {
346 match self {
347 Value::Real(v) => Some(*v),
348 _ => None,
349 }
350 }
351
352 pub fn as_decimal(&self) -> Option<(i128, u8)> {
354 match self {
355 Value::Decimal(v, s) => Some((*v, *s)),
356 _ => None,
357 }
358 }
359
360 pub fn as_uuid(&self) -> Option<&[u8; 16]> {
362 match self {
363 Value::Uuid(u) => Some(u),
364 _ => None,
365 }
366 }
367
368 pub fn as_json(&self) -> Option<&serde_json::Value> {
370 match self {
371 Value::Json(j) => Some(j),
372 _ => None,
373 }
374 }
375
376 pub fn as_date(&self) -> Option<i32> {
378 match self {
379 Value::Date(d) => Some(*d),
380 _ => None,
381 }
382 }
383
384 pub fn as_time(&self) -> Option<i64> {
386 match self {
387 Value::Time(t) => Some(*t),
388 _ => None,
389 }
390 }
391
392 pub fn compare(&self, other: &Value) -> Option<Ordering> {
399 match (self, other) {
400 (Value::Null, Value::Null) => Some(Ordering::Equal),
401 (Value::Null, _) => Some(Ordering::Less),
402 (_, Value::Null) => Some(Ordering::Greater),
403 (Value::TinyInt(a), Value::TinyInt(b)) => Some(a.cmp(b)),
404 (Value::SmallInt(a), Value::SmallInt(b)) => Some(a.cmp(b)),
405 (Value::Integer(a), Value::Integer(b)) => Some(a.cmp(b)),
406 (Value::BigInt(a), Value::BigInt(b)) => Some(a.cmp(b)),
407 (Value::Real(a), Value::Real(b)) => Some(total_cmp_f64(*a, *b)),
408 (Value::Decimal(a_val, a_scale), Value::Decimal(b_val, b_scale)) => {
409 if a_scale == b_scale {
411 Some(a_val.cmp(b_val))
412 } else {
413 None
414 }
415 }
416 (Value::Text(a), Value::Text(b)) => Some(a.cmp(b)),
417 (Value::Bytes(a), Value::Bytes(b)) => Some(a.as_ref().cmp(b.as_ref())),
418 (Value::Boolean(a), Value::Boolean(b)) => Some(a.cmp(b)),
419 (Value::Date(a), Value::Date(b)) => Some(a.cmp(b)),
420 (Value::Time(a), Value::Time(b)) => Some(a.cmp(b)),
421 (Value::Timestamp(a), Value::Timestamp(b)) => Some(a.cmp(b)),
422 (Value::Uuid(a), Value::Uuid(b)) => Some(a.cmp(b)),
423 (Value::Json(a), Value::Json(b)) => {
424 Some(a.to_string().cmp(&b.to_string()))
426 }
427 _ => None, }
429 }
430
431 pub fn is_compatible_with(&self, data_type: DataType) -> bool {
433 match self {
434 Value::Null => true, Value::Placeholder(_) => true, Value::TinyInt(_) => data_type == DataType::TinyInt,
437 Value::SmallInt(_) => data_type == DataType::SmallInt,
438 Value::Integer(_) => data_type == DataType::Integer,
439 Value::BigInt(_) => data_type == DataType::BigInt,
440 Value::Real(_) => data_type == DataType::Real,
441 Value::Decimal(_, scale) => {
442 matches!(data_type, DataType::Decimal { scale: s, .. } if s == *scale)
443 }
444 Value::Text(_) => data_type == DataType::Text,
445 Value::Bytes(_) => data_type == DataType::Bytes,
446 Value::Boolean(_) => data_type == DataType::Boolean,
447 Value::Date(_) => data_type == DataType::Date,
448 Value::Time(_) => data_type == DataType::Time,
449 Value::Timestamp(_) => data_type == DataType::Timestamp,
450 Value::Uuid(_) => data_type == DataType::Uuid,
451 Value::Json(_) => data_type == DataType::Json,
452 }
453 }
454
455 pub fn to_json(&self) -> serde_json::Value {
461 match self {
462 Value::Null => serde_json::Value::Null,
463 Value::TinyInt(v) => serde_json::Value::Number((*v).into()),
464 Value::SmallInt(v) => serde_json::Value::Number((*v).into()),
465 Value::Integer(v) => serde_json::Value::Number((*v).into()),
466 Value::BigInt(v) => serde_json::Value::Number((*v).into()),
467 Value::Real(v) => {
468 serde_json::Number::from_f64(*v)
469 .map_or(serde_json::Value::Null, serde_json::Value::Number) }
471 Value::Decimal(val, scale) => {
472 let divisor = 10_i128.pow(u32::from(*scale));
474 let int_part = val / divisor;
475 let frac_part = (val % divisor).abs();
476 let s = format!("{int_part}.{frac_part:0width$}", width = *scale as usize);
477 serde_json::Value::String(s)
478 }
479 Value::Text(s) => serde_json::Value::String(s.clone()),
480 Value::Bytes(b) => {
481 use base64::Engine;
482 let encoded = base64::engine::general_purpose::STANDARD.encode(b);
483 serde_json::Value::String(encoded)
484 }
485 Value::Boolean(b) => serde_json::Value::Bool(*b),
486 Value::Date(d) => serde_json::Value::Number((*d).into()),
487 Value::Time(t) => serde_json::Value::Number((*t).into()),
488 Value::Timestamp(ts) => serde_json::Value::Number(ts.as_nanos().into()),
489 Value::Uuid(u) => {
490 let s = format!(
492 "{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
493 u[0],
494 u[1],
495 u[2],
496 u[3],
497 u[4],
498 u[5],
499 u[6],
500 u[7],
501 u[8],
502 u[9],
503 u[10],
504 u[11],
505 u[12],
506 u[13],
507 u[14],
508 u[15]
509 );
510 serde_json::Value::String(s)
511 }
512 Value::Json(j) => j.clone(),
513 Value::Placeholder(idx) => {
514 panic!("Cannot convert unbound placeholder ${idx} to JSON - bind parameters first")
515 }
516 }
517 }
518
519 pub fn from_json(json: &serde_json::Value, data_type: DataType) -> Result<Self> {
521 match (json, data_type) {
522 (serde_json::Value::Null, _) => Ok(Value::Null),
523 (serde_json::Value::Number(n), DataType::TinyInt) => n
524 .as_i64()
525 .and_then(|v| i8::try_from(v).ok())
526 .map(Value::TinyInt)
527 .ok_or_else(|| QueryError::TypeMismatch {
528 expected: "tinyint (-128 to 127)".to_string(),
529 actual: format!("number {n}"),
530 }),
531 (serde_json::Value::Number(n), DataType::SmallInt) => n
532 .as_i64()
533 .and_then(|v| i16::try_from(v).ok())
534 .map(Value::SmallInt)
535 .ok_or_else(|| QueryError::TypeMismatch {
536 expected: "smallint (-32768 to 32767)".to_string(),
537 actual: format!("number {n}"),
538 }),
539 (serde_json::Value::Number(n), DataType::Integer) => n
540 .as_i64()
541 .and_then(|v| i32::try_from(v).ok())
542 .map(Value::Integer)
543 .ok_or_else(|| QueryError::TypeMismatch {
544 expected: "integer (-2^31 to 2^31-1)".to_string(),
545 actual: format!("number {n}"),
546 }),
547 (serde_json::Value::Number(n), DataType::BigInt) => n
548 .as_i64()
549 .map(Value::BigInt)
550 .ok_or_else(|| QueryError::TypeMismatch {
551 expected: "bigint".to_string(),
552 actual: format!("number {n}"),
553 }),
554 (serde_json::Value::Number(n), DataType::Real) => n
555 .as_f64()
556 .map(Value::Real)
557 .ok_or_else(|| QueryError::TypeMismatch {
558 expected: "real (f64)".to_string(),
559 actual: format!("number {n}"),
560 }),
561 (
562 serde_json::Value::String(s),
563 DataType::Decimal {
564 precision: _,
565 scale,
566 },
567 ) => {
568 parse_decimal_string(s, scale).map(|val| Value::Decimal(val, scale))
570 }
571 (serde_json::Value::String(s), DataType::Text) => Ok(Value::Text(s.clone())),
572 (serde_json::Value::String(s), DataType::Bytes) => {
573 use base64::Engine;
574 let decoded = base64::engine::general_purpose::STANDARD
575 .decode(s)
576 .map_err(|e| QueryError::TypeMismatch {
577 expected: "base64 bytes".to_string(),
578 actual: e.to_string(),
579 })?;
580 Ok(Value::Bytes(Bytes::from(decoded)))
581 }
582 (serde_json::Value::Bool(b), DataType::Boolean) => Ok(Value::Boolean(*b)),
583 (serde_json::Value::Number(n), DataType::Date) => n
584 .as_i64()
585 .and_then(|v| i32::try_from(v).ok())
586 .map(Value::Date)
587 .ok_or_else(|| QueryError::TypeMismatch {
588 expected: "date (i32 days)".to_string(),
589 actual: format!("number {n}"),
590 }),
591 (serde_json::Value::Number(n), DataType::Time) => n
592 .as_i64()
593 .map(Value::Time)
594 .ok_or_else(|| QueryError::TypeMismatch {
595 expected: "time (i64 nanos)".to_string(),
596 actual: format!("number {n}"),
597 }),
598 (serde_json::Value::Number(n), DataType::Timestamp) => n
599 .as_u64()
600 .map(|nanos| Value::Timestamp(Timestamp::from_nanos(nanos)))
601 .ok_or_else(|| QueryError::TypeMismatch {
602 expected: "timestamp".to_string(),
603 actual: format!("number {n}"),
604 }),
605 (serde_json::Value::String(s), DataType::Uuid) => parse_uuid_string(s).map(Value::Uuid),
606 (
607 json @ (serde_json::Value::Object(_)
608 | serde_json::Value::Array(_)
609 | serde_json::Value::String(_)
610 | serde_json::Value::Number(_)
611 | serde_json::Value::Bool(_)),
612 DataType::Json,
613 ) => Ok(Value::Json(json.clone())),
614 (json, dt) => Err(QueryError::TypeMismatch {
615 expected: format!("{dt:?}"),
616 actual: format!("{json:?}"),
617 }),
618 }
619 }
620}
621
622impl Display for Value {
623 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
624 match self {
625 Value::Null => write!(f, "NULL"),
626 Value::TinyInt(v) => write!(f, "{v}"),
627 Value::SmallInt(v) => write!(f, "{v}"),
628 Value::Integer(v) => write!(f, "{v}"),
629 Value::BigInt(v) => write!(f, "{v}"),
630 Value::Real(v) => write!(f, "{v}"),
631 Value::Decimal(val, scale) => {
632 let divisor = 10_i128.pow(u32::from(*scale));
633 let int_part = val / divisor;
634 let frac_part = (val % divisor).abs();
635 write!(f, "{int_part}.{frac_part:0width$}", width = *scale as usize)
636 }
637 Value::Text(s) => write!(f, "'{s}'"),
638 Value::Bytes(b) => write!(f, "<{} bytes>", b.len()),
639 Value::Boolean(b) => write!(f, "{b}"),
640 Value::Date(d) => write!(f, "DATE({d})"),
641 Value::Time(t) => write!(f, "TIME({t})"),
642 Value::Timestamp(ts) => write!(f, "{ts}"),
643 Value::Uuid(u) => {
644 write!(
645 f,
646 "{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
647 u[0],
648 u[1],
649 u[2],
650 u[3],
651 u[4],
652 u[5],
653 u[6],
654 u[7],
655 u[8],
656 u[9],
657 u[10],
658 u[11],
659 u[12],
660 u[13],
661 u[14],
662 u[15]
663 )
664 }
665 Value::Json(j) => write!(f, "{j}"),
666 Value::Placeholder(idx) => write!(f, "${idx}"),
667 }
668 }
669}
670
671impl From<i8> for Value {
672 fn from(v: i8) -> Self {
673 Value::TinyInt(v)
674 }
675}
676
677impl From<i16> for Value {
678 fn from(v: i16) -> Self {
679 Value::SmallInt(v)
680 }
681}
682
683impl From<i32> for Value {
684 fn from(v: i32) -> Self {
685 Value::Integer(v)
686 }
687}
688
689impl From<i64> for Value {
690 fn from(v: i64) -> Self {
691 Value::BigInt(v)
692 }
693}
694
695impl From<f64> for Value {
696 fn from(v: f64) -> Self {
697 Value::Real(v)
698 }
699}
700
701impl From<String> for Value {
702 fn from(s: String) -> Self {
703 Value::Text(s)
704 }
705}
706
707impl From<&str> for Value {
708 fn from(s: &str) -> Self {
709 Value::Text(s.to_string())
710 }
711}
712
713impl From<bool> for Value {
714 fn from(b: bool) -> Self {
715 Value::Boolean(b)
716 }
717}
718
719impl From<Timestamp> for Value {
720 fn from(ts: Timestamp) -> Self {
721 Value::Timestamp(ts)
722 }
723}
724
725impl From<Bytes> for Value {
726 fn from(b: Bytes) -> Self {
727 Value::Bytes(b)
728 }
729}
730
731impl From<[u8; 16]> for Value {
732 fn from(u: [u8; 16]) -> Self {
733 Value::Uuid(u)
734 }
735}
736
737impl From<serde_json::Value> for Value {
738 fn from(j: serde_json::Value) -> Self {
739 Value::Json(j)
740 }
741}
742
743mod bytes_base64 {
745 use base64::Engine;
746 use bytes::Bytes;
747 use serde::{Deserialize, Deserializer, Serializer};
748
749 pub fn serialize<S>(bytes: &Bytes, serializer: S) -> Result<S::Ok, S::Error>
750 where
751 S: Serializer,
752 {
753 let encoded = base64::engine::general_purpose::STANDARD.encode(bytes);
754 serializer.serialize_str(&encoded)
755 }
756
757 pub fn deserialize<'de, D>(deserializer: D) -> Result<Bytes, D::Error>
758 where
759 D: Deserializer<'de>,
760 {
761 let s = String::deserialize(deserializer)?;
762 let decoded = base64::engine::general_purpose::STANDARD
763 .decode(&s)
764 .map_err(serde::de::Error::custom)?;
765 Ok(Bytes::from(decoded))
766 }
767}