pgwire_lite/value.rs
1// src/value.rs
2
3use std::fmt;
4
5/// Represents a value from a PostgreSQL query result.
6///
7/// This enum provides type-safe access to various PostgreSQL data types
8/// and includes conversion methods for common Rust types.
9#[derive(Debug, Clone, Default)]
10pub enum Value {
11 #[default]
12 Null,
13 Bool(bool),
14 Integer(i64),
15 Float(f64),
16 String(String),
17 Bytes(Vec<u8>),
18}
19
20impl fmt::Display for Value {
21 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22 match self {
23 Value::Null => write!(f, "NULL"),
24 Value::Bool(b) => write!(f, "{}", b),
25 Value::Integer(i) => write!(f, "{}", i),
26 Value::Float(fl) => write!(f, "{}", fl),
27 Value::String(s) => write!(f, "{}", s),
28 Value::Bytes(b) => write!(f, "{:?}", b),
29 }
30 }
31}
32
33// Default implementation for Value is Null
34
35// Implement From traits for common types
36impl From<String> for Value {
37 fn from(s: String) -> Self {
38 Value::String(s)
39 }
40}
41
42impl From<&str> for Value {
43 fn from(s: &str) -> Self {
44 Value::String(s.to_string())
45 }
46}
47
48impl From<bool> for Value {
49 fn from(b: bool) -> Self {
50 Value::Bool(b)
51 }
52}
53
54impl From<i64> for Value {
55 fn from(i: i64) -> Self {
56 Value::Integer(i)
57 }
58}
59
60impl From<i32> for Value {
61 fn from(i: i32) -> Self {
62 Value::Integer(i as i64)
63 }
64}
65
66impl From<f64> for Value {
67 fn from(f: f64) -> Self {
68 Value::Float(f)
69 }
70}
71
72impl From<Vec<u8>> for Value {
73 fn from(b: Vec<u8>) -> Self {
74 Value::Bytes(b)
75 }
76}
77
78// Try-conversion traits for getting values out
79impl Value {
80 /// Try to get the value as a string reference.
81 ///
82 /// Returns `None` if the value is not a String.
83 ///
84 /// # Example
85 ///
86 /// ```
87 /// use pgwire_lite::Value;
88 ///
89 /// let val = Value::from("hello");
90 /// assert_eq!(val.as_str(), Some("hello"));
91 ///
92 /// let val = Value::Integer(42);
93 /// assert_eq!(val.as_str(), None);
94 /// ```
95 pub fn as_str(&self) -> Option<&str> {
96 match self {
97 Value::String(s) => Some(s),
98 _ => None,
99 }
100 }
101
102 /// Try to get the value as a boolean.
103 ///
104 /// Returns `Some(bool)` if the value is a boolean or a string that can be
105 /// interpreted as a boolean (e.g., "true", "yes", "1").
106 /// Returns `None` for other types or strings that cannot be parsed as booleans.
107 ///
108 /// # Example
109 ///
110 /// ```
111 /// use pgwire_lite::Value;
112 ///
113 /// let val = Value::Bool(true);
114 /// assert_eq!(val.as_bool(), Some(true));
115 ///
116 /// let val = Value::from("yes");
117 /// assert_eq!(val.as_bool(), Some(true));
118 ///
119 /// let val = Value::from("0");
120 /// assert_eq!(val.as_bool(), Some(false));
121 ///
122 /// let val = Value::from("invalid");
123 /// assert_eq!(val.as_bool(), None);
124 /// ```
125 pub fn as_bool(&self) -> Option<bool> {
126 match self {
127 Value::Bool(b) => Some(*b),
128 Value::String(s) => match s.to_lowercase().as_str() {
129 "true" | "t" | "yes" | "y" | "1" => Some(true),
130 "false" | "f" | "no" | "n" | "0" => Some(false),
131 _ => None,
132 },
133 _ => None,
134 }
135 }
136
137 /// Try to get the value as a 64-bit signed integer.
138 ///
139 /// Returns `Some(i64)` if the value is an integer, a float that can be
140 /// converted to an integer, or a string that can be parsed as an integer.
141 /// Returns `None` for other types or values that cannot be converted.
142 ///
143 /// # Example
144 ///
145 /// ```
146 /// use pgwire_lite::Value;
147 ///
148 /// let val = Value::Integer(42);
149 /// assert_eq!(val.as_i64(), Some(42));
150 ///
151 /// let val = Value::Float(42.0);
152 /// assert_eq!(val.as_i64(), Some(42));
153 ///
154 /// let val = Value::from("42");
155 /// assert_eq!(val.as_i64(), Some(42));
156 ///
157 /// let val = Value::from("invalid");
158 /// assert_eq!(val.as_i64(), None);
159 /// ```
160 pub fn as_i64(&self) -> Option<i64> {
161 match self {
162 Value::Integer(i) => Some(*i),
163 Value::Float(f) => Some(*f as i64),
164 Value::String(s) => s.parse::<i64>().ok(),
165 _ => None,
166 }
167 }
168
169 /// Try to get the value as a 64-bit floating point number.
170 ///
171 /// Returns `Some(f64)` if the value is a float, an integer, or a string
172 /// that can be parsed as a float.
173 /// Returns `None` for other types or values that cannot be converted.
174 ///
175 /// # Example
176 ///
177 /// ```
178 /// use pgwire_lite::Value;
179 ///
180 /// let val = Value::Float(3.14);
181 /// assert_eq!(val.as_f64(), Some(3.14));
182 ///
183 /// let val = Value::Integer(42);
184 /// assert_eq!(val.as_f64(), Some(42.0));
185 ///
186 /// let val = Value::from("3.14");
187 /// assert_eq!(val.as_f64(), Some(3.14));
188 ///
189 /// let val = Value::from("invalid");
190 /// assert_eq!(val.as_f64(), None);
191 /// ```
192 pub fn as_f64(&self) -> Option<f64> {
193 match self {
194 Value::Float(f) => Some(*f),
195 Value::Integer(i) => Some(*i as f64),
196 Value::String(s) => s.parse::<f64>().ok(),
197 _ => None,
198 }
199 }
200
201 /// Check if the value is NULL.
202 ///
203 /// # Example
204 ///
205 /// ```
206 /// use pgwire_lite::Value;
207 ///
208 /// let val = Value::Null;
209 /// assert!(val.is_null());
210 ///
211 /// let val = Value::Integer(42);
212 /// assert!(!val.is_null());
213 /// ```
214 pub fn is_null(&self) -> bool {
215 matches!(self, Value::Null)
216 }
217}