Skip to content

Commit 381be19

Browse files
authored
Merge pull request #4284 from JMLX42/feature/sqlite-json
Add SQLite support for serde_json::Value using the Json/Jsonb
2 parents dcc7241 + de6b847 commit 381be19

File tree

7 files changed

+1207
-89
lines changed

7 files changed

+1207
-89
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Increasing the minimal supported Rust version will always be coupled at least wi
2020
* Support for postgres multirange type
2121
* Added `diesel::r2d2::TestCustomizer`, which allows users to customize their `diesel::r2d2::Pool`s
2222
in a way that makes the pools suitable for use in parallel tests.
23+
* Added `Json` and `Jsonb` support for the SQLite backend.
2324

2425
## [2.2.2] 2024-07-19
2526

diesel/src/pg/types/mod.rs

Lines changed: 0 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -310,92 +310,6 @@ pub mod sql_types {
310310
#[doc(hidden)]
311311
pub type Bpchar = crate::sql_types::VarChar;
312312

313-
/// The [`jsonb`] SQL type. This type can only be used with `feature =
314-
/// "serde_json"`
315-
///
316-
/// `jsonb` offers [several advantages][adv] over regular JSON:
317-
///
318-
/// > There are two JSON data types: `json` and `jsonb`. They accept almost
319-
/// > identical sets of values as input. The major practical difference
320-
/// > is one of efficiency. The `json` data type stores an exact copy of
321-
/// > the input text, which processing functions must reparse on each
322-
/// > execution; while `jsonb` data is stored in a decomposed binary format
323-
/// > that makes it slightly slower to input due to added conversion
324-
/// > overhead, but significantly faster to process, since no reparsing
325-
/// > is needed. `jsonb` also supports indexing, which can be a significant
326-
/// > advantage.
327-
/// >
328-
/// > ...In general, most applications should prefer to store JSON data as
329-
/// > `jsonb`, unless there are quite specialized needs, such as legacy
330-
/// > assumptions about ordering of object keys.
331-
///
332-
/// [adv]: https://www.postgresql.org/docs/current/static/datatype-json.html
333-
///
334-
/// ### [`ToSql`] impls
335-
///
336-
/// - [`serde_json::Value`]
337-
///
338-
/// ### [`FromSql`] impls
339-
///
340-
/// - [`serde_json::Value`]
341-
///
342-
/// [`ToSql`]: crate::serialize::ToSql
343-
/// [`FromSql`]: crate::deserialize::FromSql
344-
/// [`jsonb`]: https://www.postgresql.org/docs/current/datatype-json.html
345-
#[cfg_attr(
346-
feature = "serde_json",
347-
doc = "[`serde_json::Value`]: serde_json::value::Value"
348-
)]
349-
#[cfg_attr(
350-
not(feature = "serde_json"),
351-
doc = "[`serde_json::Value`]: https://docs.rs/serde_json/1.0.64/serde_json/value/enum.Value.html"
352-
)]
353-
///
354-
/// # Examples
355-
///
356-
/// ```rust
357-
/// # #![allow(dead_code)]
358-
/// # include!("../../doctest_setup.rs");
359-
/// #
360-
/// table! {
361-
/// contacts {
362-
/// id -> Integer,
363-
/// name -> VarChar,
364-
/// address -> Jsonb,
365-
/// }
366-
/// }
367-
///
368-
/// # #[cfg(feature = "serde_json")]
369-
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
370-
/// # use diesel::insert_into;
371-
/// # use self::contacts::dsl::*;
372-
/// # let connection = &mut connection_no_data();
373-
/// # diesel::sql_query("CREATE TABLE contacts (
374-
/// # id SERIAL PRIMARY KEY,
375-
/// # name VARCHAR NOT NULL,
376-
/// # address JSONB NOT NULL
377-
/// # )").execute(connection)?;
378-
/// let santas_address: serde_json::Value = serde_json::from_str(r#"{
379-
/// "street": "Article Circle Expressway 1",
380-
/// "city": "North Pole",
381-
/// "postcode": "99705",
382-
/// "state": "Alaska"
383-
/// }"#)?;
384-
/// let inserted_address = insert_into(contacts)
385-
/// .values((name.eq("Claus"), address.eq(&santas_address)))
386-
/// .returning(address)
387-
/// .get_result::<serde_json::Value>(connection)?;
388-
/// assert_eq!(santas_address, inserted_address);
389-
/// # Ok(())
390-
/// # }
391-
/// # #[cfg(not(feature = "serde_json"))]
392-
/// # fn main() {}
393-
/// ```
394-
#[cfg(feature = "postgres_backend")]
395-
#[derive(Debug, Clone, Copy, Default, QueryId, SqlType)]
396-
#[diesel(postgres_type(oid = 3802, array_oid = 3807))]
397-
pub struct Jsonb;
398-
399313
/// The PostgreSQL [Money](https://www.postgresql.org/docs/current/static/datatype-money.html) type.
400314
///
401315
/// ### [`ToSql`] impls

diesel/src/sql_types/mod.rs

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,8 +398,132 @@ pub struct Timestamp;
398398
#[derive(Debug, Clone, Copy, Default, QueryId, SqlType)]
399399
#[diesel(postgres_type(oid = 114, array_oid = 199))]
400400
#[diesel(mysql_type(name = "String"))]
401+
#[diesel(sqlite_type(name = "Text"))]
401402
pub struct Json;
402403

404+
/// The [`jsonb`] SQL type. This type can only be used with `feature =
405+
/// "serde_json"`
406+
///
407+
/// In SQLite, `jsonb` brings mainly [performance improvements][sqlite-adv] over
408+
/// regular JSON:
409+
///
410+
/// > The advantage of JSONB in SQLite is that it is smaller and faster than
411+
/// > text JSON - potentially several times faster. There is space in the
412+
/// > on-disk JSONB format to add enhancements and future versions of SQLite
413+
/// > might include options to provide O(1) lookup of elements in JSONB, but no
414+
/// > such capability is currently available.
415+
///
416+
/// <div class="warning">
417+
/// In SQLite, JSONB is intended for internal use by SQLite only. Thus, future
418+
/// SQLite updates might break our JSONB implementation. And one might have to
419+
/// wait and then upgrade <code>diesel</code> for those changes to be accounted
420+
/// for. If you do not want this, prefer the regular
421+
/// <a href="./struct.Json.html"><code>Json</code></a> type.
422+
/// </div>
423+
///
424+
/// In PostgreSQL, `jsonb` offers [several advantages][pg-adv] over regular JSON:
425+
///
426+
/// > There are two JSON data types: `json` and `jsonb`. They accept almost
427+
/// > identical sets of values as input. The major practical difference
428+
/// > is one of efficiency. The `json` data type stores an exact copy of
429+
/// > the input text, which processing functions must reparse on each
430+
/// > execution; while `jsonb` data is stored in a decomposed binary format
431+
/// > that makes it slightly slower to input due to added conversion
432+
/// > overhead, but significantly faster to process, since no reparsing
433+
/// > is needed. `jsonb` also supports indexing, which can be a significant
434+
/// > advantage.
435+
/// >
436+
/// > ...In general, most applications should prefer to store JSON data as
437+
/// > `jsonb`, unless there are quite specialized needs, such as legacy
438+
/// > assumptions about ordering of object keys.
439+
///
440+
/// [pg-adv]: https://www.postgresql.org/docs/current/static/datatype-json.html
441+
/// [sqlite-adv]: https://sqlite.org/draft/jsonb.html
442+
///
443+
/// ### [`ToSql`] impls
444+
///
445+
/// - [`serde_json::Value`]
446+
///
447+
/// ### [`FromSql`] impls
448+
///
449+
/// - [`serde_json::Value`]
450+
///
451+
/// [`ToSql`]: crate::serialize::ToSql
452+
/// [`FromSql`]: crate::deserialize::FromSql
453+
/// [`jsonb`]: https://www.postgresql.org/docs/current/datatype-json.html
454+
#[cfg_attr(
455+
feature = "serde_json",
456+
doc = "[`serde_json::Value`]: serde_json::value::Value"
457+
)]
458+
#[cfg_attr(
459+
not(feature = "serde_json"),
460+
doc = "[`serde_json::Value`]: https://docs.rs/serde_json/1.0.64/serde_json/value/enum.Value.html"
461+
)]
462+
///
463+
/// ## Examples
464+
///
465+
/// ```rust
466+
/// # #![allow(dead_code)]
467+
/// # include!("../doctest_setup.rs");
468+
/// #
469+
/// table! {
470+
/// contacts {
471+
/// id -> Integer,
472+
/// name -> Text,
473+
/// address -> Jsonb,
474+
/// }
475+
/// }
476+
///
477+
/// # #[cfg(all(
478+
/// # feature = "serde_json",
479+
/// # any(
480+
/// # feature = "postgres_backend",
481+
/// # all(feature = "sqlite", feature = "returning_clauses_for_sqlite_3_35"),
482+
/// # )
483+
/// # ))]
484+
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
485+
/// # use diesel::insert_into;
486+
/// # use self::contacts::dsl::*;
487+
/// # let connection = &mut connection_no_data();
488+
/// # #[cfg(feature = "postgres_backend")]
489+
/// # diesel::sql_query("CREATE TABLE contacts (
490+
/// # id SERIAL PRIMARY KEY,
491+
/// # name VARCHAR NOT NULL,
492+
/// # address JSONB NOT NULL
493+
/// # )").execute(connection)?;
494+
/// # #[cfg(feature = "sqlite")]
495+
/// # diesel::sql_query("CREATE TABLE contacts (
496+
/// # id INT PRIMARY KEY,
497+
/// # name TEXT NOT NULL,
498+
/// # address BLOB NOT NULL
499+
/// # )").execute(connection)?;
500+
/// let santas_address: serde_json::Value = serde_json::from_str(r#"{
501+
/// "street": "Article Circle Expressway 1",
502+
/// "city": "North Pole",
503+
/// "postcode": "99705",
504+
/// "state": "Alaska"
505+
/// }"#)?;
506+
/// let inserted_address = insert_into(contacts)
507+
/// .values((name.eq("Claus"), address.eq(&santas_address)))
508+
/// .returning(address)
509+
/// .get_result::<serde_json::Value>(connection)?;
510+
/// assert_eq!(santas_address, inserted_address);
511+
/// # Ok(())
512+
/// # }
513+
/// # #[cfg(not(all(
514+
/// # feature = "serde_json",
515+
/// # any(
516+
/// # feature = "postgres_backend",
517+
/// # all(feature = "sqlite", feature = "returning_clauses_for_sqlite_3_35"),
518+
/// # )
519+
/// # )))]
520+
/// # fn main() {}
521+
/// ```
522+
#[derive(Debug, Clone, Copy, Default, QueryId, SqlType)]
523+
#[diesel(postgres_type(oid = 3802, array_oid = 3807))]
524+
#[diesel(sqlite_type(name = "Binary"))]
525+
pub struct Jsonb;
526+
403527
/// The nullable SQL type.
404528
///
405529
/// This wraps another SQL type to indicate that it can be null.

0 commit comments

Comments
 (0)