lance_jsonb/raw.rs
1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright The Lance Authors
3// SPDX-FileCopyrightText: Copyright 2023 Datafuse Labs
4// Adapted from databendlabs/jsonb at commit fba895c5ebe77ce2539e187f9c652f51cbf195c3.
5
6use std::cmp::Ordering;
7
8use serde::Serialize;
9
10use crate::OwnedJsonb;
11use crate::core::ArrayIterator;
12use crate::core::Deserializer;
13use crate::core::JsonbItemType;
14use crate::core::ObjectIterator;
15use crate::error::*;
16
17/// Represents JSONB data wrapped around a raw, immutable slice of bytes.
18///
19/// It does not own the underlying data, allowing various operations to be performed on the JSONB data *without copying*.
20/// This is critical for performance when dealing with large JSONB values.
21/// `RawJsonb` provides various methods to inspect and manipulate the JSONB data efficiently.
22#[derive(Debug, Clone, Copy)]
23pub struct RawJsonb<'a> {
24 /// The underlying byte slice representing the JSONB data.
25 pub(crate) data: &'a [u8],
26}
27
28impl<'a> RawJsonb<'a> {
29 /// Creates a new RawJsonb from a byte slice.
30 ///
31 /// # Arguments
32 ///
33 /// * `data` - The byte slice containing the JSONB data.
34 ///
35 /// # Returns
36 ///
37 /// A new `RawJsonb` instance.
38 pub fn new(data: &'a [u8]) -> Self {
39 Self { data }
40 }
41
42 /// Returns the length of the JSONB data in bytes.
43 ///
44 /// # Returns
45 ///
46 /// The length of the data in bytes.
47 pub(crate) fn len(&self) -> usize {
48 self.data.len()
49 }
50
51 /// Creates an `OwnedJsonb` from the `RawJsonb` by copying the underlying data.
52 ///
53 /// This method converts a `RawJsonb`, which holds a reference to JSONB data,
54 /// into an `OwnedJsonb`, which owns its own copy of the JSONB data. This is
55 /// achieved by cloning the byte slice held by the `RawJsonb` into a new `Vec<u8>`.
56 ///
57 /// # Returns
58 ///
59 /// An `OwnedJsonb` instance containing a copy of the JSONB data from the `RawJsonb`.
60 pub(crate) fn to_owned(self) -> OwnedJsonb {
61 OwnedJsonb::new(self.data.to_vec())
62 }
63
64 /// Converts the JSONB value to a JSON string.
65 ///
66 /// This function serializes the JSONB value into a human-readable JSON string representation.
67 /// If the JSONB data is invalid, treat it as a text JSON string and return directly.
68 /// If the JSONB data is empty, return a JSON null for compatibility.
69 ///
70 /// # Returns
71 ///
72 /// * `String` - The JSON string representation of the value.
73 ///
74 /// # Examples
75 ///
76 /// ```rust
77 /// use lance_jsonb::OwnedJsonb;
78 ///
79 /// let arr_jsonb = "[1, 2, 3]".parse::<OwnedJsonb>().unwrap();
80 /// let raw_jsonb = arr_jsonb.as_raw();
81 /// assert_eq!(raw_jsonb.to_string(), "[1,2,3]");
82 ///
83 /// let obj_jsonb = r#"{"a": 1, "b": "hello"}"#.parse::<OwnedJsonb>().unwrap();
84 /// let raw_jsonb = obj_jsonb.as_raw();
85 /// assert_eq!(raw_jsonb.to_string(), r#"{"a":1,"b":"hello"}"#);
86 ///
87 /// let num_jsonb = "123.45".parse::<OwnedJsonb>().unwrap();
88 /// let raw_jsonb = num_jsonb.as_raw();
89 /// assert_eq!(raw_jsonb.to_string(), "123.45");
90 ///
91 /// let string_jsonb = r#""hello, world!""#.parse::<OwnedJsonb>().unwrap();
92 /// let raw_jsonb = string_jsonb.as_raw();
93 /// assert_eq!(raw_jsonb.to_string(), r#""hello, world!""#);
94 ///
95 /// let true_jsonb = "true".parse::<OwnedJsonb>().unwrap();
96 /// let raw_jsonb = true_jsonb.as_raw();
97 /// assert_eq!(raw_jsonb.to_string(), "true");
98 ///
99 /// // Example with invalid JSONB data (fallback to treat as text JSON string)
100 /// let invalid_jsonb = OwnedJsonb::from(vec![1, 2, 3, 4]); // Invalid binary JSONB
101 /// let invalid_raw_jsonb = invalid_jsonb.as_raw();
102 ///
103 /// // It will treat as text JSON string.
104 /// assert_eq!(invalid_raw_jsonb.to_string(), "\u{1}\u{2}\u{3}\u{4}");
105 /// ```
106 #[allow(clippy::inherent_to_string)]
107 pub fn to_string(&self) -> String {
108 let mut buf = Vec::with_capacity(self.len());
109 let formatter = serde_json::ser::CompactFormatter {};
110 let mut ser = serde_json::Serializer::with_formatter(&mut buf, formatter);
111 match self.serialize(&mut ser) {
112 Ok(_) => String::from_utf8(buf).unwrap(),
113 Err(_) => {
114 if self.data.is_empty() {
115 "null".to_string()
116 } else {
117 String::from_utf8_lossy(self.data).to_string()
118 }
119 }
120 }
121 }
122}
123
124/// Converts a borrowed byte slice into a RawJsonb.
125/// This provides a convenient way to create a RawJsonb from existing data without copying.
126impl<'a> From<&'a [u8]> for RawJsonb<'a> {
127 fn from(data: &'a [u8]) -> Self {
128 Self { data }
129 }
130}
131
132/// Allows accessing the underlying byte slice as a reference.
133/// This enables easy integration with functions that expect a &[u8].
134impl AsRef<[u8]> for RawJsonb<'_> {
135 fn as_ref(&self) -> &[u8] {
136 self.data
137 }
138}
139
140impl Eq for RawJsonb<'_> {}
141
142impl PartialEq for RawJsonb<'_> {
143 fn eq(&self, other: &Self) -> bool {
144 self.partial_cmp(other) == Some(Ordering::Equal)
145 }
146}
147
148/// Implements `PartialOrd` for `RawJsonb`, allowing comparison of two `RawJsonb` values.
149///
150/// The comparison logic handles different JSONB types (scalar, array, object) and considers null values.
151/// The ordering is defined as follows:
152///
153/// 1. Null is considered greater than any other type.
154/// 2. Scalars are compared based on their type and value (String > Number > Boolean > ExtensionValue).
155/// 3. Arrays are compared element by element.
156/// 4. Objects are compared based on their keys and values.
157/// 5. Arrays are greater than objects and scalars.
158/// 6. Objects are greater than scalars.
159/// 7. If the types are incompatible, None is returned.
160#[allow(clippy::non_canonical_partial_ord_impl)]
161impl PartialOrd for RawJsonb<'_> {
162 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
163 let self_type = self.jsonb_item_type().ok()?;
164 let other_type = other.jsonb_item_type().ok()?;
165
166 // First use JSONB type to determine the order,
167 // different types must have different orders.
168 if let Some(ord) = self_type.partial_cmp(&other_type) {
169 return Some(ord);
170 }
171
172 match (self_type, other_type) {
173 (JsonbItemType::Array(self_len), JsonbItemType::Array(other_len)) => {
174 let self_array_iter = ArrayIterator::new(*self).ok()?.unwrap();
175 let mut other_array_iter = ArrayIterator::new(*other).ok()?.unwrap();
176 for (self_res, other_res) in &mut self_array_iter.zip(&mut other_array_iter) {
177 let self_item = self_res.ok()?;
178 let other_item = other_res.ok()?;
179
180 let ord = self_item.partial_cmp(&other_item)?;
181 if ord != Ordering::Equal {
182 return Some(ord);
183 }
184 }
185 Some(self_len.cmp(&other_len))
186 }
187 (JsonbItemType::Object(self_len), JsonbItemType::Object(other_len)) => {
188 let self_object_iter = ObjectIterator::new(*self).ok()?.unwrap();
189 let mut other_object_iter = ObjectIterator::new(*other).ok()?.unwrap();
190 for (self_res, other_res) in &mut self_object_iter.zip(&mut other_object_iter) {
191 let (self_key, self_val) = self_res.ok()?;
192 let (other_key, other_val) = other_res.ok()?;
193
194 let key_ord = self_key.partial_cmp(other_key)?;
195 if key_ord != Ordering::Equal {
196 return Some(key_ord);
197 }
198 let val_ord = self_val.partial_cmp(&other_val)?;
199 if val_ord != Ordering::Equal {
200 return Some(val_ord);
201 }
202 }
203 Some(self_len.cmp(&other_len))
204 }
205 (JsonbItemType::String, JsonbItemType::String) => {
206 let self_val = self.as_str();
207 let other_val = other.as_str();
208 match (self_val, other_val) {
209 (Ok(Some(self_val)), Ok(Some(other_val))) => self_val.partial_cmp(&other_val),
210 (_, _) => None,
211 }
212 }
213 (JsonbItemType::Number, JsonbItemType::Number) => {
214 let self_val = self.as_number();
215 let other_val = other.as_number();
216 match (self_val, other_val) {
217 (Ok(Some(self_val)), Ok(Some(other_val))) => self_val.partial_cmp(&other_val),
218 (_, _) => None,
219 }
220 }
221 (JsonbItemType::Boolean, JsonbItemType::Boolean) => {
222 let self_val = self.as_bool();
223 let other_val = other.as_bool();
224 match (self_val, other_val) {
225 (Ok(Some(self_val)), Ok(Some(other_val))) => self_val.partial_cmp(&other_val),
226 (_, _) => None,
227 }
228 }
229 (JsonbItemType::Extension, JsonbItemType::Extension) => {
230 let self_val = self.as_extension_value();
231 let other_val = other.as_extension_value();
232 match (self_val, other_val) {
233 (Ok(Some(self_val)), Ok(Some(other_val))) => self_val.partial_cmp(&other_val),
234 (_, _) => None,
235 }
236 }
237 (_, _) => None,
238 }
239 }
240}
241
242/// Implements `Ord` for `RawJsonb`, allowing comparison of two `RawJsonb` values using the total ordering.
243/// This implementation leverages the `PartialOrd` implementation, returning `Ordering::Equal` for incomparable values.
244impl Ord for RawJsonb<'_> {
245 fn cmp(&self, other: &Self) -> Ordering {
246 match self.partial_cmp(other) {
247 Some(ordering) => ordering,
248 None => Ordering::Equal,
249 }
250 }
251}
252
253/// Deserializes a `RawJsonb` into a Rust data structure using Serde.
254///
255/// This function takes a `RawJsonb` (a borrowed slice of JSONB data) and attempts
256/// to deserialize it into a Rust type `T` that implements the `Deserialize` trait.
257/// It uses a custom `Deserializer` to handle the JSONB data.
258///
259/// # Arguments
260///
261/// * `raw_jsonb`: A reference to the `RawJsonb` containing the JSONB data to deserialize.
262///
263/// # Type Parameters
264///
265/// * `T`: The Rust type to deserialize the JSONB data into. This type must implement
266/// the `serde::de::Deserialize` trait.
267///
268/// # Returns
269///
270/// * `Ok(t)`: If the deserialization is successful, returns the deserialized value of type `T`.
271/// * `Err(Error::InvalidJsonb)`: If the deserialization fails due to invalid JSONB data
272/// (e.g., trailing characters after the expected JSONB structure).
273/// * `Err(e)`: If any other Serde deserialization error occurs.
274///
275/// # Examples
276///
277/// ```
278/// use lance_jsonb::from_raw_jsonb;
279/// use lance_jsonb::OwnedJsonb;
280/// use lance_jsonb::RawJsonb;
281/// use serde::Deserialize;
282///
283/// #[derive(Deserialize, Debug, PartialEq, Eq)]
284/// struct Person {
285/// name: String,
286/// age: u32,
287/// }
288///
289/// let owned_jsonb = r#"{"name": "Alice", "age": 20}"#.parse::<OwnedJsonb>().unwrap();
290/// let raw_jsonb = owned_jsonb.as_raw();
291///
292/// let person: Person = from_raw_jsonb(&raw_jsonb).unwrap();
293/// assert_eq!(person, Person { name: "Alice".to_string(), age: 20 });
294/// println!("{:?}", person); // Output: Person { name: "Alice", age: 20 }
295/// ```
296pub fn from_raw_jsonb<'de, T>(raw_jsonb: &'de RawJsonb) -> Result<T>
297where
298 T: serde::de::Deserialize<'de>,
299{
300 let mut deserializer = Deserializer::new(raw_jsonb);
301 let t = T::deserialize(&mut deserializer)?;
302 if deserializer.end() {
303 Ok(t)
304 } else {
305 // Trailing characters
306 Err(Error::InvalidJsonb)
307 }
308}