ITADN
lovasoa/serde-sqlite-jsonb
lovasoa/serde-sqlite-jsonb · 文件 下载 ZIP
文件最后提交记录最后更新时间
README.md
以下内容由 AI 翻译,如有问题请点此提交 issue 反馈

serde-sqlite-jsonb

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

它最初是为纳入 SQLPage 网站构建器而开发的。

为什么

自 3.45.0 版本起,SQLite 支持 JSONB 列, 它可以以二进制格式存储 JSON 数据,该格式比 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 特性已启用,当尝试解析 json5 数据时,本 crate 会返回错误。 要启用 json5 支持,请启用 serde-json5 特性 (并可选择禁用默认特性,以便对 json 数据也使用 json5 解析器):

[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.org/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 字节u812 (0xC)
2^8 到 2^16 - 1 字节u1613 (0xD)
2^16 到 2^32 - 1 字节u3214 (0xE)
2^32 到 2^64 - 1 字节u6415 (0xF)

类型

TypeHex CodeDescription
Null0x0该元素是 JSON "null"。
True0x1该元素是 JSON "true"。
False0x2该元素是 JSON "false"。
Int0x3该元素是符合 RFC 8259 标准格式的 JSON 整数值。
Int50x4该元素是 JSON5 整数,例如 0xABC
Float0x5该元素是符合 RFC 8259 标准格式的 JSON 浮点值。
Float50x6该元素是不符合标准 JSON 格式的 JSON5 浮点值。
Text0x7该元素是不包含任何转义字符的 JSON 字符串值。
TextJ0x8该元素是包含 RFC 8259 字符转义的 JSON 字符串值。
Text50x9该元素是包含字符转义的 JSON5 字符串值,其中包括一些来自 JSON5 的转义。
TextRaw0xA该元素是包含在 JSON 中需要转义的 UTF8 字符的 JSON 字符串值。
Array0xB该元素是 JSON 数组。第一个数组元素的头部紧跟在数组头部之后。
Object0xC该元素是 JSON 对象。对象键(字符串)和值在负载中交替出现。
Reserved130xD保留用于未来扩展。
Reserved140xE保留用于未来扩展。
Reserved150xF保留用于未来扩展。

示例

以下 JSON 对象:

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

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

6c 17 61 02 17 62 01
bytevaluedescription
00x6c头部:负载大小 = 6,类型 = Object (0xC)
10x17头部:负载大小 = 1,类型 = Text (0x7)
20x61负载:'a'
30x02头部:负载大小 = 0,类型 = False (0x2)
40x17头部:负载大小 = 1,类型 = Text (0x7)
50x62负载:'b'
60x01头部:负载大小 = 0,类型 = True (0x1)

MSRV

需要 rust >= 1.63 (debian stable)