Skip to content

Commit 3fe3acd

Browse files
authored
Merge pull request #49 from b41sh/feat-to-serde-json
feat: support convert jsonb value to serde_json value
2 parents a7325f4 + e1dd134 commit 3fe3acd

File tree

5 files changed

+186
-13
lines changed

5 files changed

+186
-13
lines changed

Cargo.toml

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,23 +23,25 @@ license = "Apache-2.0"
2323
name = "jsonb"
2424
repository = "https://github.com/datafuselabs/jsonb"
2525
version = "0.3.0"
26-
rust-version = "1.68"
26+
rust-version = "1.77"
2727

2828
[dependencies]
2929
byteorder = "1.5.0"
3030
fast-float = "0.2.0"
31+
itoa = "1.0"
3132
nom = "7.1.3"
32-
ordered-float = { version = "4.1.1", default-features = false }
33+
ordered-float = { version = "4.2", default-features = false }
3334
rand = { version = "0.8.5", features = ["small_rng"] }
34-
serde_json = { version = "1.0.107", default-features = false, features = [
35+
ryu = "1.0"
36+
serde_json = { version = "1.0", default-features = false, features = [
3537
"preserve_order",
3638
] }
3739

3840
[dev-dependencies]
39-
goldenfile = "1.5.2"
40-
serde_json = "1.0.107"
41+
goldenfile = "1.7"
42+
serde_json = "1.0"
4143
json-deserializer = "0.4.4"
42-
simd-json = {version = "0.11.1", features = ["allow-non-simd"]}
44+
simd-json = "0.13.10"
4345
mockalloc = "0.1.2"
4446
criterion = "0.5.1"
4547

src/error.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ pub enum Error {
7575
InvalidToken,
7676
InvalidCast,
7777

78+
InvalidJson,
7879
InvalidJsonb,
7980
InvalidJsonbHeader,
8081
InvalidJsonbJEntry,

src/functions.rs

Lines changed: 126 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use std::collections::BTreeMap;
1919
use std::collections::VecDeque;
2020
use std::str::from_utf8;
2121
use std::str::from_utf8_unchecked;
22+
use std::str::FromStr;
2223

2324
use crate::builder::ArrayBuilder;
2425
use crate::builder::ObjectBuilder;
@@ -1420,6 +1421,130 @@ pub fn is_object(value: &[u8]) -> bool {
14201421
matches!(header & CONTAINER_HEADER_TYPE_MASK, OBJECT_CONTAINER_TAG)
14211422
}
14221423

1424+
/// Convert `JSONB` value to `serde_json` Value
1425+
pub fn to_serde_json(value: &[u8]) -> Result<serde_json::Value, Error> {
1426+
if !is_jsonb(value) {
1427+
let json_str = std::str::from_utf8(value)?;
1428+
return match serde_json::Value::from_str(json_str) {
1429+
Ok(v) => Ok(v),
1430+
Err(_) => Err(Error::InvalidJson),
1431+
};
1432+
}
1433+
1434+
containter_to_serde_json(value)
1435+
}
1436+
1437+
/// Convert `JSONB` value to `serde_json` Object Value
1438+
pub fn to_serde_json_object(
1439+
value: &[u8],
1440+
) -> Result<Option<serde_json::Map<String, serde_json::Value>>, Error> {
1441+
if !is_jsonb(value) {
1442+
let json_str = std::str::from_utf8(value)?;
1443+
return match serde_json::Value::from_str(json_str) {
1444+
Ok(v) => match v {
1445+
serde_json::Value::Object(obj) => Ok(Some(obj.clone())),
1446+
_ => Ok(None),
1447+
},
1448+
Err(_) => Err(Error::InvalidJson),
1449+
};
1450+
}
1451+
1452+
containter_to_serde_json_object(value)
1453+
}
1454+
1455+
fn containter_to_serde_json_object(
1456+
value: &[u8],
1457+
) -> Result<Option<serde_json::Map<String, serde_json::Value>>, Error> {
1458+
let header = read_u32(value, 0).unwrap_or_default();
1459+
let length = (header & CONTAINER_HEADER_LEN_MASK) as usize;
1460+
1461+
let obj_value = match header & CONTAINER_HEADER_TYPE_MASK {
1462+
OBJECT_CONTAINER_TAG => {
1463+
let mut obj = serde_json::Map::with_capacity(length);
1464+
for (key, jentry, val) in iterate_object_entries(value, header) {
1465+
let item = scalar_to_serde_json(jentry, val)?;
1466+
obj.insert(key.to_string(), item);
1467+
}
1468+
Some(obj)
1469+
}
1470+
ARRAY_CONTAINER_TAG | SCALAR_CONTAINER_TAG => None,
1471+
_ => {
1472+
return Err(Error::InvalidJsonb);
1473+
}
1474+
};
1475+
Ok(obj_value)
1476+
}
1477+
1478+
fn containter_to_serde_json(value: &[u8]) -> Result<serde_json::Value, Error> {
1479+
let header = read_u32(value, 0).unwrap_or_default();
1480+
let length = (header & CONTAINER_HEADER_LEN_MASK) as usize;
1481+
1482+
let json_value = match header & CONTAINER_HEADER_TYPE_MASK {
1483+
OBJECT_CONTAINER_TAG => {
1484+
let mut obj = serde_json::Map::with_capacity(length);
1485+
for (key, jentry, val) in iterate_object_entries(value, header) {
1486+
let item = scalar_to_serde_json(jentry, val)?;
1487+
obj.insert(key.to_string(), item);
1488+
}
1489+
serde_json::Value::Object(obj)
1490+
}
1491+
ARRAY_CONTAINER_TAG => {
1492+
let mut arr = Vec::with_capacity(length);
1493+
for (jentry, val) in iterate_array(value, header) {
1494+
let item = scalar_to_serde_json(jentry, val)?;
1495+
arr.push(item);
1496+
}
1497+
serde_json::Value::Array(arr)
1498+
}
1499+
SCALAR_CONTAINER_TAG => {
1500+
let encoded = match read_u32(value, 4) {
1501+
Ok(encoded) => encoded,
1502+
Err(_) => {
1503+
return Err(Error::InvalidJsonb);
1504+
}
1505+
};
1506+
let jentry = JEntry::decode_jentry(encoded);
1507+
scalar_to_serde_json(jentry, &value[8..])?
1508+
}
1509+
_ => {
1510+
return Err(Error::InvalidJsonb);
1511+
}
1512+
};
1513+
Ok(json_value)
1514+
}
1515+
1516+
fn scalar_to_serde_json(jentry: JEntry, value: &[u8]) -> Result<serde_json::Value, Error> {
1517+
let json_value = match jentry.type_code {
1518+
NULL_TAG => serde_json::Value::Null,
1519+
TRUE_TAG => serde_json::Value::Bool(true),
1520+
FALSE_TAG => serde_json::Value::Bool(false),
1521+
NUMBER_TAG => {
1522+
let len = jentry.length as usize;
1523+
let n = Number::decode(&value[..len]);
1524+
match n {
1525+
Number::Int64(v) => serde_json::Value::Number(serde_json::Number::from(v)),
1526+
Number::UInt64(v) => serde_json::Value::Number(serde_json::Number::from(v)),
1527+
Number::Float64(v) => match serde_json::Number::from_f64(v) {
1528+
Some(v) => serde_json::Value::Number(v),
1529+
None => {
1530+
return Err(Error::InvalidJson);
1531+
}
1532+
},
1533+
}
1534+
}
1535+
STRING_TAG => {
1536+
let len = jentry.length as usize;
1537+
let s = unsafe { String::from_utf8_unchecked(value[..len].to_vec()) };
1538+
serde_json::Value::String(s)
1539+
}
1540+
CONTAINER_TAG => containter_to_serde_json(value)?,
1541+
_ => {
1542+
return Err(Error::InvalidJsonb);
1543+
}
1544+
};
1545+
Ok(json_value)
1546+
}
1547+
14231548
/// Convert `JSONB` value to String
14241549
pub fn to_string(value: &[u8]) -> String {
14251550
if !is_jsonb(value) {
@@ -1606,7 +1731,7 @@ fn scalar_to_string(
16061731
FALSE_TAG => json.push_str("false"),
16071732
NUMBER_TAG => {
16081733
let num = Number::decode(&value[*value_offset..*value_offset + length]);
1609-
json.push_str(&format!("{num}"));
1734+
json.push_str(&num.to_string());
16101735
}
16111736
STRING_TAG => {
16121737
escape_scalar_string(value, *value_offset, *value_offset + length, json);

src/number.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -244,9 +244,21 @@ impl Ord for Number {
244244
impl Display for Number {
245245
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
246246
match self {
247-
Number::Int64(v) => write!(f, "{}", v),
248-
Number::UInt64(v) => write!(f, "{}", v),
249-
Number::Float64(v) => write!(f, "{}", v),
247+
Number::Int64(v) => {
248+
let mut buffer = itoa::Buffer::new();
249+
let s = buffer.format(*v);
250+
write!(f, "{}", s)
251+
}
252+
Number::UInt64(v) => {
253+
let mut buffer = itoa::Buffer::new();
254+
let s = buffer.format(*v);
255+
write!(f, "{}", s)
256+
}
257+
Number::Float64(v) => {
258+
let mut buffer = ryu::Buffer::new();
259+
let s = buffer.format(*v);
260+
write!(f, "{}", s)
261+
}
250262
}
251263
}
252264
}

tests/it/functions.rs

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ use jsonb::{
2222
delete_by_name, exists_all_keys, exists_any_keys, from_slice, get_by_index, get_by_keypath,
2323
get_by_name, get_by_path, is_array, is_object, keypath::parse_key_paths, object_each,
2424
object_keys, parse_value, path_exists, path_match, strip_nulls, to_bool, to_f64, to_i64,
25-
to_pretty_string, to_str, to_string, to_u64, traverse_check_string, type_of, Error, Number,
26-
Object, Value,
25+
to_pretty_string, to_serde_json, to_serde_json_object, to_str, to_string, to_u64,
26+
traverse_check_string, type_of, Error, Number, Object, Value,
2727
};
2828

2929
use jsonb::jsonpath::parse_json_path;
@@ -77,7 +77,7 @@ fn test_build_object() {
7777
r#"[1,2,3]"#,
7878
r#"{"k":"v"}"#,
7979
];
80-
let keys = vec![
80+
let keys = [
8181
"k1".to_string(),
8282
"k2".to_string(),
8383
"k3".to_string(),
@@ -1466,6 +1466,39 @@ fn test_delete_by_keypath() {
14661466
}
14671467
}
14681468

1469+
#[test]
1470+
fn test_to_serde_json() {
1471+
let sources = vec![
1472+
r#"true"#,
1473+
r#"1e20"#,
1474+
r#"[100,"abc",{"xx":"✅❌💻"}]"#,
1475+
r#"{"a":1,"b":[1,2,3]}"#,
1476+
r#"{"ab":{"k1":"v1","k2":"v2"},"cd":[true,100.23,"测试"]}"#,
1477+
];
1478+
let mut buf: Vec<u8> = Vec::new();
1479+
for s in sources {
1480+
let value = parse_value(s.as_bytes()).unwrap();
1481+
buf.clear();
1482+
value.write_to_vec(&mut buf);
1483+
let jsonb_val_str = to_string(&buf);
1484+
1485+
let json_val = to_serde_json(&buf).unwrap();
1486+
let json_val_str = json_val.to_string();
1487+
assert_eq!(jsonb_val_str, json_val_str);
1488+
1489+
let obj_val = to_serde_json_object(&buf).unwrap();
1490+
if is_object(&buf) {
1491+
assert!(obj_val.is_some());
1492+
let obj_val = obj_val.unwrap();
1493+
let json_val = serde_json::Value::Object(obj_val);
1494+
let obj_val_str = json_val.to_string();
1495+
assert_eq!(jsonb_val_str, obj_val_str);
1496+
} else {
1497+
assert!(obj_val.is_none());
1498+
}
1499+
}
1500+
}
1501+
14691502
fn init_object<'a>(entries: Vec<(&str, Value<'a>)>) -> Value<'a> {
14701503
let mut map = BTreeMap::new();
14711504
for (key, val) in entries {

0 commit comments

Comments
 (0)