reef/json.rs
1//! Typed JSON column wrappers.
2//!
3//! - [`Json<T>`] stores as TEXT (human-readable JSON)
4//! - [`Jsonb<T>`] stores as BLOB (SQLite 3.45+ binary JSONB encoding)
5//!
6//! Both newtypes are `#[serde(transparent)]`, so when used in RPC return
7//! types they serialize as the inner `T` directly — no extra wrapping in
8//! the wire format.
9//!
10//! `cargo reef db:push` recognizes these wrappers in schema field types and
11//! emits the corresponding SQL column type (`TEXT` or `BLOB`).
12//!
13//! SQL marshaling helpers (libsql `FromValue` / `IntoValue`) are not yet
14//! implemented — write your queries with `serde_json::to_string` / `from_str`
15//! against the inner `T` for now.
16
17use serde::{Deserialize, Serialize};
18use std::ops::{Deref, DerefMut};
19
20/// Wrap a serde-serializable value to mark a column as JSON-stored TEXT.
21#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
22#[serde(transparent)]
23pub struct Json<T>(pub T);
24
25/// Wrap a serde-serializable value to mark a column as JSONB-stored BLOB.
26///
27/// Requires SQLite 3.45+ (libSQL inherits this). Faster to parse than
28/// [`Json<T>`] at the cost of opacity in the `sqlite3` shell.
29#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
30#[serde(transparent)]
31pub struct Jsonb<T>(pub T);
32
33macro_rules! impl_wrapper {
34 ($name:ident) => {
35 impl<T> $name<T> {
36 pub fn new(inner: T) -> Self {
37 Self(inner)
38 }
39 pub fn into_inner(self) -> T {
40 self.0
41 }
42 }
43 impl<T> Deref for $name<T> {
44 type Target = T;
45 fn deref(&self) -> &T {
46 &self.0
47 }
48 }
49 impl<T> DerefMut for $name<T> {
50 fn deref_mut(&mut self) -> &mut T {
51 &mut self.0
52 }
53 }
54 impl<T> From<T> for $name<T> {
55 fn from(inner: T) -> Self {
56 Self(inner)
57 }
58 }
59 };
60}
61
62impl_wrapper!(Json);
63impl_wrapper!(Jsonb);