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 Ok(int_val * multiplier + frac_val)
178 }
179 _ => Err(QueryError::TypeMismatch {
180 expected: format!("decimal with scale {scale}"),
181 actual: s.to_string(),
182 }),
183 }
184}
185
186fn parse_uuid_string(s: &str) -> Result<[u8; 16]> {
188 let hex_str = s.replace('-', "");
190
191 if hex_str.len() != 32 {
192 return Err(QueryError::TypeMismatch {
193 expected: "UUID (32 hex digits)".to_string(),
194 actual: s.to_string(),
195 });
196 }
197
198 let mut bytes = [0u8; 16];
199 for (i, chunk) in hex_str.as_bytes().chunks(2).enumerate() {
200 let hex_byte = std::str::from_utf8(chunk).map_err(|_| QueryError::TypeMismatch {
201 expected: "UUID (valid hex)".to_string(),
202 actual: s.to_string(),
203 })?;
204
205 bytes[i] = u8::from_str_radix(hex_byte, 16).map_err(|_| QueryError::TypeMismatch {
206 expected: "UUID (valid hex)".to_string(),
207 actual: s.to_string(),
208 })?;
209 }
210
211 Ok(bytes)
212}
213
214fn total_cmp_f64(a: f64, b: f64) -> Ordering {
220 let a_bits = a.to_bits();
222 let b_bits = b.to_bits();
223
224 let a_key = if a.is_sign_negative() {
226 !a_bits
227 } else {
228 a_bits ^ (1u64 << 63)
229 };
230
231 let b_key = if b.is_sign_negative() {
232 !b_bits
233 } else {
234 b_bits ^ (1u64 << 63)
235 };
236
237 a_key.cmp(&b_key)
238}
239
240impl Value {
241 pub fn data_type(&self) -> Option<DataType> {
245 match self {
246 Value::Null | Value::Placeholder(_) => None,
247 Value::TinyInt(_) => Some(DataType::TinyInt),
248 Value::SmallInt(_) => Some(DataType::SmallInt),
249 Value::Integer(_) => Some(DataType::Integer),
250 Value::BigInt(_) => Some(DataType::BigInt),
251 Value::Real(_) => Some(DataType::Real),
252 Value::Decimal(_, scale) => Some(DataType::Decimal {
253 precision: 38, scale: *scale,
255 }),
256 Value::Text(_) => Some(DataType::Text),
257 Value::Bytes(_) => Some(DataType::Bytes),
258 Value::Boolean(_) => Some(DataType::Boolean),
259 Value::Date(_) => Some(DataType::Date),
260 Value::Time(_) => Some(DataType::Time),
261 Value::Timestamp(_) => Some(DataType::Timestamp),
262 Value::Uuid(_) => Some(DataType::Uuid),
263 Value::Json(_) => Some(DataType::Json),
264 }
265 }
266
267 pub fn is_null(&self) -> bool {
269 matches!(self, Value::Null)
270 }
271
272 pub fn as_bigint(&self) -> Option<i64> {
274 match self {
275 Value::BigInt(v) => Some(*v),
276 _ => None,
277 }
278 }
279
280 pub fn as_text(&self) -> Option<&str> {
282 match self {
283 Value::Text(s) => Some(s),
284 _ => None,
285 }
286 }
287
288 pub fn as_boolean(&self) -> Option<bool> {
290 match self {
291 Value::Boolean(b) => Some(*b),
292 _ => None,
293 }
294 }
295
296 pub fn as_timestamp(&self) -> Option<Timestamp> {
298 match self {
299 Value::Timestamp(ts) => Some(*ts),
300 _ => None,
301 }
302 }
303
304 pub fn as_bytes(&self) -> Option<&Bytes> {
306 match self {
307 Value::Bytes(b) => Some(b),
308 _ => None,
309 }
310 }
311
312 pub fn as_tinyint(&self) -> Option<i8> {
314 match self {
315 Value::TinyInt(v) => Some(*v),
316 _ => None,
317 }
318 }
319
320 pub fn as_smallint(&self) -> Option<i16> {
322 match self {
323 Value::SmallInt(v) => Some(*v),
324 _ => None,
325 }
326 }
327
328 pub fn as_integer(&self) -> Option<i32> {
330 match self {
331 Value::Integer(v) => Some(*v),
332 _ => None,
333 }
334 }
335
336 pub fn as_real(&self) -> Option<f64> {
338 match self {
339 Value::Real(v) => Some(*v),
340 _ => None,
341 }
342 }
343
344 pub fn as_decimal(&self) -> Option<(i128, u8)> {
346 match self {
347 Value::Decimal(v, s) => Some((*v, *s)),
348 _ => None,
349 }
350 }
351
352 pub fn as_uuid(&self) -> Option<&[u8; 16]> {
354 match self {
355 Value::Uuid(u) => Some(u),
356 _ => None,
357 }
358 }
359
360 pub fn as_json(&self) -> Option<&serde_json::Value> {
362 match self {
363 Value::Json(j) => Some(j),
364 _ => None,
365 }
366 }
367
368 pub fn as_date(&self) -> Option<i32> {
370 match self {
371 Value::Date(d) => Some(*d),
372 _ => None,
373 }
374 }
375
376 pub fn as_time(&self) -> Option<i64> {
378 match self {
379 Value::Time(t) => Some(*t),
380 _ => None,
381 }
382 }
383
384 pub fn compare(&self, other: &Value) -> Option<Ordering> {
391 match (self, other) {
392 (Value::Null, Value::Null) => Some(Ordering::Equal),
393 (Value::Null, _) => Some(Ordering::Less),
394 (_, Value::Null) => Some(Ordering::Greater),
395 (Value::TinyInt(a), Value::TinyInt(b)) => Some(a.cmp(b)),
396 (Value::SmallInt(a), Value::SmallInt(b)) => Some(a.cmp(b)),
397 (Value::Integer(a), Value::Integer(b)) => Some(a.cmp(b)),
398 (Value::BigInt(a), Value::BigInt(b)) => Some(a.cmp(b)),
399 (Value::Real(a), Value::Real(b)) => Some(total_cmp_f64(*a, *b)),
400 (Value::Decimal(a_val, a_scale), Value::Decimal(b_val, b_scale)) => {
401 if a_scale == b_scale {
403 Some(a_val.cmp(b_val))
404 } else {
405 None
406 }
407 }
408 (Value::Text(a), Value::Text(b)) => Some(a.cmp(b)),
409 (Value::Bytes(a), Value::Bytes(b)) => Some(a.as_ref().cmp(b.as_ref())),
410 (Value::Boolean(a), Value::Boolean(b)) => Some(a.cmp(b)),
411 (Value::Date(a), Value::Date(b)) => Some(a.cmp(b)),
412 (Value::Time(a), Value::Time(b)) => Some(a.cmp(b)),
413 (Value::Timestamp(a), Value::Timestamp(b)) => Some(a.cmp(b)),
414 (Value::Uuid(a), Value::Uuid(b)) => Some(a.cmp(b)),
415 (Value::Json(a), Value::Json(b)) => {
416 Some(a.to_string().cmp(&b.to_string()))
418 }
419 _ => None, }
421 }
422
423 pub fn is_compatible_with(&self, data_type: DataType) -> bool {
425 match self {
426 Value::Null => true, Value::Placeholder(_) => true, Value::TinyInt(_) => data_type == DataType::TinyInt,
429 Value::SmallInt(_) => data_type == DataType::SmallInt,
430 Value::Integer(_) => data_type == DataType::Integer,
431 Value::BigInt(_) => data_type == DataType::BigInt,
432 Value::Real(_) => data_type == DataType::Real,
433 Value::Decimal(_, scale) => {
434 matches!(data_type, DataType::Decimal { scale: s, .. } if s == *scale)
435 }
436 Value::Text(_) => data_type == DataType::Text,
437 Value::Bytes(_) => data_type == DataType::Bytes,
438 Value::Boolean(_) => data_type == DataType::Boolean,
439 Value::Date(_) => data_type == DataType::Date,
440 Value::Time(_) => data_type == DataType::Time,
441 Value::Timestamp(_) => data_type == DataType::Timestamp,
442 Value::Uuid(_) => data_type == DataType::Uuid,
443 Value::Json(_) => data_type == DataType::Json,
444 }
445 }
446
447 pub fn to_json(&self) -> serde_json::Value {
453 match self {
454 Value::Null => serde_json::Value::Null,
455 Value::TinyInt(v) => serde_json::Value::Number((*v).into()),
456 Value::SmallInt(v) => serde_json::Value::Number((*v).into()),
457 Value::Integer(v) => serde_json::Value::Number((*v).into()),
458 Value::BigInt(v) => serde_json::Value::Number((*v).into()),
459 Value::Real(v) => {
460 serde_json::Number::from_f64(*v)
461 .map_or(serde_json::Value::Null, serde_json::Value::Number) }
463 Value::Decimal(val, scale) => {
464 let divisor = 10_i128.pow(u32::from(*scale));
466 let int_part = val / divisor;
467 let frac_part = (val % divisor).abs();
468 let s = format!("{int_part}.{frac_part:0width$}", width = *scale as usize);
469 serde_json::Value::String(s)
470 }
471 Value::Text(s) => serde_json::Value::String(s.clone()),
472 Value::Bytes(b) => {
473 use base64::Engine;
474 let encoded = base64::engine::general_purpose::STANDARD.encode(b);
475 serde_json::Value::String(encoded)
476 }
477 Value::Boolean(b) => serde_json::Value::Bool(*b),
478 Value::Date(d) => serde_json::Value::Number((*d).into()),
479 Value::Time(t) => serde_json::Value::Number((*t).into()),
480 Value::Timestamp(ts) => serde_json::Value::Number(ts.as_nanos().into()),
481 Value::Uuid(u) => {
482 let s = format!(
484 "{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
485 u[0],
486 u[1],
487 u[2],
488 u[3],
489 u[4],
490 u[5],
491 u[6],
492 u[7],
493 u[8],
494 u[9],
495 u[10],
496 u[11],
497 u[12],
498 u[13],
499 u[14],
500 u[15]
501 );
502 serde_json::Value::String(s)
503 }
504 Value::Json(j) => j.clone(),
505 Value::Placeholder(idx) => {
506 panic!("Cannot convert unbound placeholder ${idx} to JSON - bind parameters first")
507 }
508 }
509 }
510
511 pub fn from_json(json: &serde_json::Value, data_type: DataType) -> Result<Self> {
513 match (json, data_type) {
514 (serde_json::Value::Null, _) => Ok(Value::Null),
515 (serde_json::Value::Number(n), DataType::TinyInt) => n
516 .as_i64()
517 .and_then(|v| i8::try_from(v).ok())
518 .map(Value::TinyInt)
519 .ok_or_else(|| QueryError::TypeMismatch {
520 expected: "tinyint (-128 to 127)".to_string(),
521 actual: format!("number {n}"),
522 }),
523 (serde_json::Value::Number(n), DataType::SmallInt) => n
524 .as_i64()
525 .and_then(|v| i16::try_from(v).ok())
526 .map(Value::SmallInt)
527 .ok_or_else(|| QueryError::TypeMismatch {
528 expected: "smallint (-32768 to 32767)".to_string(),
529 actual: format!("number {n}"),
530 }),
531 (serde_json::Value::Number(n), DataType::Integer) => n
532 .as_i64()
533 .and_then(|v| i32::try_from(v).ok())
534 .map(Value::Integer)
535 .ok_or_else(|| QueryError::TypeMismatch {
536 expected: "integer (-2^31 to 2^31-1)".to_string(),
537 actual: format!("number {n}"),
538 }),
539 (serde_json::Value::Number(n), DataType::BigInt) => n
540 .as_i64()
541 .map(Value::BigInt)
542 .ok_or_else(|| QueryError::TypeMismatch {
543 expected: "bigint".to_string(),
544 actual: format!("number {n}"),
545 }),
546 (serde_json::Value::Number(n), DataType::Real) => n
547 .as_f64()
548 .map(Value::Real)
549 .ok_or_else(|| QueryError::TypeMismatch {
550 expected: "real (f64)".to_string(),
551 actual: format!("number {n}"),
552 }),
553 (
554 serde_json::Value::String(s),
555 DataType::Decimal {
556 precision: _,
557 scale,
558 },
559 ) => {
560 parse_decimal_string(s, scale).map(|val| Value::Decimal(val, scale))
562 }
563 (serde_json::Value::String(s), DataType::Text) => Ok(Value::Text(s.clone())),
564 (serde_json::Value::String(s), DataType::Bytes) => {
565 use base64::Engine;
566 let decoded = base64::engine::general_purpose::STANDARD
567 .decode(s)
568 .map_err(|e| QueryError::TypeMismatch {
569 expected: "base64 bytes".to_string(),
570 actual: e.to_string(),
571 })?;
572 Ok(Value::Bytes(Bytes::from(decoded)))
573 }
574 (serde_json::Value::Bool(b), DataType::Boolean) => Ok(Value::Boolean(*b)),
575 (serde_json::Value::Number(n), DataType::Date) => n
576 .as_i64()
577 .and_then(|v| i32::try_from(v).ok())
578 .map(Value::Date)
579 .ok_or_else(|| QueryError::TypeMismatch {
580 expected: "date (i32 days)".to_string(),
581 actual: format!("number {n}"),
582 }),
583 (serde_json::Value::Number(n), DataType::Time) => n
584 .as_i64()
585 .map(Value::Time)
586 .ok_or_else(|| QueryError::TypeMismatch {
587 expected: "time (i64 nanos)".to_string(),
588 actual: format!("number {n}"),
589 }),
590 (serde_json::Value::Number(n), DataType::Timestamp) => n
591 .as_u64()
592 .map(|nanos| Value::Timestamp(Timestamp::from_nanos(nanos)))
593 .ok_or_else(|| QueryError::TypeMismatch {
594 expected: "timestamp".to_string(),
595 actual: format!("number {n}"),
596 }),
597 (serde_json::Value::String(s), DataType::Uuid) => parse_uuid_string(s).map(Value::Uuid),
598 (
599 json @ (serde_json::Value::Object(_)
600 | serde_json::Value::Array(_)
601 | serde_json::Value::String(_)
602 | serde_json::Value::Number(_)
603 | serde_json::Value::Bool(_)),
604 DataType::Json,
605 ) => Ok(Value::Json(json.clone())),
606 (json, dt) => Err(QueryError::TypeMismatch {
607 expected: format!("{dt:?}"),
608 actual: format!("{json:?}"),
609 }),
610 }
611 }
612}
613
614impl Display for Value {
615 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
616 match self {
617 Value::Null => write!(f, "NULL"),
618 Value::TinyInt(v) => write!(f, "{v}"),
619 Value::SmallInt(v) => write!(f, "{v}"),
620 Value::Integer(v) => write!(f, "{v}"),
621 Value::BigInt(v) => write!(f, "{v}"),
622 Value::Real(v) => write!(f, "{v}"),
623 Value::Decimal(val, scale) => {
624 let divisor = 10_i128.pow(u32::from(*scale));
625 let int_part = val / divisor;
626 let frac_part = (val % divisor).abs();
627 write!(f, "{int_part}.{frac_part:0width$}", width = *scale as usize)
628 }
629 Value::Text(s) => write!(f, "'{s}'"),
630 Value::Bytes(b) => write!(f, "<{} bytes>", b.len()),
631 Value::Boolean(b) => write!(f, "{b}"),
632 Value::Date(d) => write!(f, "DATE({d})"),
633 Value::Time(t) => write!(f, "TIME({t})"),
634 Value::Timestamp(ts) => write!(f, "{ts}"),
635 Value::Uuid(u) => {
636 write!(
637 f,
638 "{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
639 u[0],
640 u[1],
641 u[2],
642 u[3],
643 u[4],
644 u[5],
645 u[6],
646 u[7],
647 u[8],
648 u[9],
649 u[10],
650 u[11],
651 u[12],
652 u[13],
653 u[14],
654 u[15]
655 )
656 }
657 Value::Json(j) => write!(f, "{j}"),
658 Value::Placeholder(idx) => write!(f, "${idx}"),
659 }
660 }
661}
662
663impl From<i8> for Value {
664 fn from(v: i8) -> Self {
665 Value::TinyInt(v)
666 }
667}
668
669impl From<i16> for Value {
670 fn from(v: i16) -> Self {
671 Value::SmallInt(v)
672 }
673}
674
675impl From<i32> for Value {
676 fn from(v: i32) -> Self {
677 Value::Integer(v)
678 }
679}
680
681impl From<i64> for Value {
682 fn from(v: i64) -> Self {
683 Value::BigInt(v)
684 }
685}
686
687impl From<f64> for Value {
688 fn from(v: f64) -> Self {
689 Value::Real(v)
690 }
691}
692
693impl From<String> for Value {
694 fn from(s: String) -> Self {
695 Value::Text(s)
696 }
697}
698
699impl From<&str> for Value {
700 fn from(s: &str) -> Self {
701 Value::Text(s.to_string())
702 }
703}
704
705impl From<bool> for Value {
706 fn from(b: bool) -> Self {
707 Value::Boolean(b)
708 }
709}
710
711impl From<Timestamp> for Value {
712 fn from(ts: Timestamp) -> Self {
713 Value::Timestamp(ts)
714 }
715}
716
717impl From<Bytes> for Value {
718 fn from(b: Bytes) -> Self {
719 Value::Bytes(b)
720 }
721}
722
723impl From<[u8; 16]> for Value {
724 fn from(u: [u8; 16]) -> Self {
725 Value::Uuid(u)
726 }
727}
728
729impl From<serde_json::Value> for Value {
730 fn from(j: serde_json::Value) -> Self {
731 Value::Json(j)
732 }
733}
734
735mod bytes_base64 {
737 use base64::Engine;
738 use bytes::Bytes;
739 use serde::{Deserialize, Deserializer, Serializer};
740
741 pub fn serialize<S>(bytes: &Bytes, serializer: S) -> Result<S::Ok, S::Error>
742 where
743 S: Serializer,
744 {
745 let encoded = base64::engine::general_purpose::STANDARD.encode(bytes);
746 serializer.serialize_str(&encoded)
747 }
748
749 pub fn deserialize<'de, D>(deserializer: D) -> Result<Bytes, D::Error>
750 where
751 D: Deserializer<'de>,
752 {
753 let s = String::deserialize(deserializer)?;
754 let decoded = base64::engine::general_purpose::STANDARD
755 .decode(&s)
756 .map_err(serde::de::Error::custom)?;
757 Ok(Bytes::from(decoded))
758 }
759}