Skip to main content

lance_jsonb/
owned.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;
7use std::fmt::Display;
8use std::str::FromStr;
9
10use crate::RawJsonb;
11use crate::error::Error;
12use crate::parse_value;
13
14/// Represents a JSONB data that owns its underlying data.
15///
16/// This struct provides ownership over the binary JSONB representation.
17/// `OwnedJsonb` is primarily used to create JSONB data from other data types (such as JSON String).
18/// However, for most operations, it's necessary to convert an `OwnedJsonb` to a `RawJsonb` using the `as_raw()` method
19/// to avoid unnecessary copying and to take advantage of the performance benefits of the read-only access of the `RawJsonb`.
20#[derive(Debug, Clone)]
21pub struct OwnedJsonb {
22    /// The underlying `Vec<u8>` containing the binary JSONB data.
23    pub(crate) data: Vec<u8>,
24}
25
26impl OwnedJsonb {
27    /// Creates a new OwnedJsonb from a Vec<u8>.
28    ///
29    /// # Arguments
30    ///
31    /// * `data` - The `Vec<u8>` containing the JSONB data.
32    ///
33    /// # Returns
34    ///
35    /// A new `OwnedJsonb` instance.
36    pub(crate) fn new(data: Vec<u8>) -> Self {
37        Self { data }
38    }
39
40    /// Creates a `RawJsonb` view of the owned data.
41    /// This is useful for passing the data to functions that expect a `RawJsonb`.
42    /// This does *not* transfer ownership.
43    ///
44    /// # Returns
45    ///
46    /// A `RawJsonb` instance referencing the owned data.
47    pub fn as_raw(&self) -> RawJsonb<'_> {
48        RawJsonb::new(self.data.as_slice())
49    }
50
51    /// Consumes the OwnedJsonb and returns the underlying `Vec<u8>`.
52    ///
53    /// # Returns
54    ///
55    /// The underlying `Vec<u8>` containing the JSONB data.
56    pub fn to_vec(self) -> Vec<u8> {
57        self.data
58    }
59}
60
61/// Creates an `OwnedJsonb` from a borrowed byte slice.  The byte slice is copied into a new `Vec<u8>`.
62impl From<&[u8]> for OwnedJsonb {
63    fn from(data: &[u8]) -> Self {
64        Self {
65            data: data.to_vec(),
66        }
67    }
68}
69
70/// Creates an `OwnedJsonb` from a `Vec<u8>`. This is a simple ownership transfer.
71impl From<Vec<u8>> for OwnedJsonb {
72    fn from(data: Vec<u8>) -> Self {
73        Self { data }
74    }
75}
76
77/// Parses a string into an `OwnedJsonb`.
78/// The string is parsed into a JSON value, then encoded into the binary JSONB format.
79impl FromStr for OwnedJsonb {
80    type Err = Error;
81
82    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
83        let value = parse_value(s.as_bytes())?;
84        let mut data = Vec::new();
85        value.write_to_vec(&mut data);
86        Ok(Self { data })
87    }
88}
89
90/// Allows accessing the underlying byte slice as a reference.
91/// This enables easy integration with functions that expect a `&[u8]`.
92impl AsRef<[u8]> for OwnedJsonb {
93    fn as_ref(&self) -> &[u8] {
94        self.data.as_ref()
95    }
96}
97
98/// Implements the Display trait, allowing OwnedJsonb to be formatted as a string using the `{}` format specifier.
99impl Display for OwnedJsonb {
100    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
101        let raw_jsonb = self.as_raw();
102        write!(f, "{}", raw_jsonb.to_string())
103    }
104}
105
106impl Eq for OwnedJsonb {}
107
108impl PartialEq for OwnedJsonb {
109    fn eq(&self, other: &Self) -> bool {
110        self.partial_cmp(other) == Some(Ordering::Equal)
111    }
112}
113
114/// Implements `PartialOrd` for `OwnedJsonb`, allowing comparison of two `OwnedJsonb` values.
115///
116/// The comparison logic handles different JSONB types (scalar, array, object) and considers null values.
117/// The ordering is defined as follows:
118///
119/// 1. Null is considered greater than any other type.
120/// 2. Scalars are compared based on their type and value (String > Number > Boolean).
121/// 3. Arrays are compared element by element.
122/// 4. Objects are compared based on their keys and values.
123/// 5. Arrays are greater than objects and scalars.
124/// 6. Objects are greater than scalars.
125/// 7. If the types are incompatible, None is returned.
126#[allow(clippy::non_canonical_partial_ord_impl)]
127impl PartialOrd for OwnedJsonb {
128    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
129        let self_raw = self.as_raw();
130        let other_raw = other.as_raw();
131        self_raw.partial_cmp(&other_raw)
132    }
133}
134
135/// Implements `Ord` for `OwnedJsonb`, allowing comparison of two `OwnedJsonb` values using the total ordering.
136/// This implementation leverages the `PartialOrd` implementation, returning `Ordering::Equal` for incomparable values.
137impl Ord for OwnedJsonb {
138    fn cmp(&self, other: &Self) -> Ordering {
139        let self_raw = self.as_raw();
140        let other_raw = other.as_raw();
141        match self_raw.partial_cmp(&other_raw) {
142            Some(ordering) => ordering,
143            None => Ordering::Equal,
144        }
145    }
146}