#json #sqlite #jsonb #json-format #serde #deserialize-json #serializer-deserializer

serde_sqlite_jsonb

SQLite jsonb 二进制格式的序列化和反序列化器

2 个不稳定版本

0.1.0 2024年4月12日
0.0.1-alpha2024年4月7日

#555 in 编码

Download history 1/week @ 2024-05-26 1/week @ 2024-06-02

每月55次下载

MIT/Apache

62KB
1.5K SLoC

serde-sqlite-jsonb

此crate提供了一个用于SQLite JSONB列的自定义Serde反序列化器。

它最初是为包含在SQLPage网站构建器中而开发的。

原因

从版本3.45.0开始,SQLite支持JSONB列,可以将JSON数据以更高效操作的二进制格式存储。

问题是,当前使用SQLite的应用程序需要将数据从JSONB转换为JSON,然后从JSON转换为它们自己的数据结构才能使用。这阻止了使用SQLite的blob流API以流式方式直接从数据库中读取blob数据,并且需要执行SQL查询以提取并转换数据为JSON。

此crate提供了一个用于JSONB的直接自定义Serde序列化和反序列化器,允许跳过JSON转换步骤。

这可以在某些场景中带来显著的性能提升,如此crate的基准测试所示。

基准测试

这些图表显示了以下时间

  • 使用此crate将JSONB列直接反序列化为结构体
  • 执行SQL查询以提取JSONB列作为JSON,然后使用serde_json将其反序列化为结构体

正在反序列化的数据包含一个字符串,其长度从50到1000个字符不等,以展示性能随数据大小的演变。

Benchmark results Benchmark results

免责声明:应谨慎看待这些基准测试。当性能很重要时,您应使用自己的数据在自己的应用程序中测量性能。 serde_json 非常优化,在某些场景中可能比此crate更快,尤其是在JSON数据较小的情况下。

crate功能

二进制格式可以包含原始json数据,因此此crate依赖于 serde_json crate来解析JSON数据。由于SQLite也支持json5,如果需要json5支持,可以使用 serde-json5 功能。

默认情况下,(更快的) serde_json 功能已启用,此crate在尝试解析json5数据时返回错误。要启用json5支持,启用 serde-json5 功能(可选地禁用默认功能以使用json5解析器解析json数据)

[dependencies]
serde-sqlite-jsonb = { version = "0.1", features = ["serde-json5"], default-features = false }

用法

该库不处理SQLite连接,因此您需要使用类似rusqlitesqlx的crate来与数据库进行交互。

一旦您已从数据库中提取出JSONB数据,无论是作为Vec<u8>还是作为从数据库流式传输BLOB数据的std::io::Read对象,您都可以使用serde_sqlite_jsonb crate来反序列化JSON数据,无论是到您自己的数据结构还是到serde_json::Value

从查询结果反序列化JSONB

let conn = rusqlite::Connection::open_in_memory()?;
let blob: Vec<u8> = conn.query_row(
    r#"select jsonb('{"id": 1, "name": "John Doe"}')"#, [], |row| row.get(0),
)?;
let person: Person = serde_sqlite_jsonb::from_bytes(&blob).unwrap();

从SQLite BLOB流式反序列化

let my_blob = conn.blob_open( // returns an object that implements std::io::Read
    DatabaseName::Main,
    "my_table", // table name
    "my_jsonb_column", // column name
    42, // primary key (rowid)
    true // read-only
)?;
let parsed: serde_json::Value = // or any other type that implements Deserialize
    serde_sqlite_jsonb::from_reader(my_blob).unwrap();

格式

JSONB列的格式在SQLite文档中描述:[https://sqlite.ac.cn/draft/jsonb.html](https://sqlite.ac.cn/draft/jsonb.html)

数据格式是一个带有头部和有效负载的二进制格式。头部包含有关元素类型和有效负载大小的信息。有效负载包含实际数据。

以下是粗略的ASCII表示

bits:  0  1  2  3  4  5  6  7  8
    +-------------+-------------+
    |  size(4)    | type(4)     | first header byte
    +-------------+-------------+
    |   payload size (0 - 64)   | header bytes number 2 to 9
    +---------------------------+
    |   payload data            | payload bytes (JSON strings or numbers in text format)
    +---------------------------+

头部

有效负载大小

如果有效负载数据在0到11字节(包含)之间,则大小编码在头部的第一个4位中。否则,有效负载的大小编码在下一个字节中,第一个4位表示用于编码有效负载大小的字节数,如下表所示

有效负载数据大小范围 大小编码 头部第一个4位
0到11字节 u4(嵌入在第一个4位中) 0到11(0x0到0xB)
12到2^8 - 1字节 u8 12(0xC)
2^8到2^16 - 1字节 u16 13(0xD)
2^16到2^32 - 1字节 u32 14(0xE)
2^32到2^64 - 1字节 u64 15(0xF)

类型

类型 十六进制代码 描述
0x0 元素是JSON "null"。
0x1 元素是JSON "true"。
0x2 元素是JSON "false"。
整型 0x3 元素是JSON整数,采用RFC 8259规范的标准格式。
整型5 0x4 元素是JSON5整数,例如0xABC
浮点型 0x5 元素是JSON浮点值,采用RFC 8259规范的标准格式。
浮点型5 0x6 元素是JSON5浮点值,它不是标准JSON格式。
文本 0x7 元素是JSON字符串值,不包含任何转义字符。
文本J 0x8 元素是包含RFC 8259字符转义的JSON字符串值。
文本5 0x9 元素是包含字符转义的JSON5字符串值,包括一些来自JSON5的。
文本原始 0xA 元素是包含需要转义于JSON中的UTF8字符的JSON字符串值。
数组 0xB 元素是JSON数组。第一个数组元素的头部紧接在数组头部之后。
对象 0xC 元素是JSON对象。对象键(字符串)和值交替出现在有效负载中。
保留13 0xD 为将来扩展保留。
保留14 0xE 为将来扩展保留。
保留15 0xF 为将来扩展保留。

示例

以下JSON对象

{"a": false, "b":true}

编码为以下7字节的二进制数据

6c 17 61 02 17 62 01
字节 描述
0 0x6c 头部:有效负载大小 = 6,类型 = 对象(0xC)
1 0x17 头部:有效负载大小 = 1,类型 = 文本(0x7)
2 0x61 有效负载:'a'
3 0x02 头部:有效负载大小 = 0,类型 = 假(0x2)
4 0x17 头部:有效负载大小 = 1,类型 = 文本(0x7)
5 0x62 有效负载:'b'
6 0x01 头部:有效负载大小 = 0,类型 = 真(0x1)

MSRV

需要 rust >= 1.63(debian 稳定版)

依赖项

~0.5–1.3MB
~26K SLoC