1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
//! A query language for Serde data model. //! //! This crate provides [`serde_query::Deserialize`] derive macro that generates //! [`serde::Deserialize`] implementation with queries. //! //! # Example //! //! ```rust //! # use std::error::Error; //! # fn main() -> Result<(), Box<dyn Error + 'static>> { //! #[derive(serde_query::Deserialize)] //! struct Data { //! #[query(".commit.authors.[0]")] //! first_author: String, //! #[query(".hash")] //! hash_value: u64, //! } //! //! let document = serde_json::to_string(&serde_json::json!({ //! "commit": { //! "authors": ["Kou", "Kasumi", "Masaru"], //! "date": "2020-09-10", //! }, //! "hash": 0xabcd, //! }))?; //! //! // The query is compatible with arbitrary data formats with serde support. //! let data: Data = serde_json::from_str(&document)?; //! //! assert_eq!(data.first_author, "Kou"); //! assert_eq!(data.hash_value, 0xabcd); //! # Ok(()) //! # } //! ``` //! //! # Derive macros //! //! This crate provides the following two derive macros for declaring a query: //! * [`serde_query::Deserialize`] generates an implementation of [`serde::Deserialize`] for the struct. //! We recommend using a full-path form (`serde_query::Deserialize`) when deriving to disambiguate //! between serde and this crate. //! * [`serde_query::DeserializeQuery`] generates [`serde::Deserialize`] for [`Query<T>`] wrapper. //! This derive macro is useful if you want two `Deserialize` implementation. //! For example, you may want `DeserializeQuery` for querying an API and `Deserialize` for loading from file. //! //! Each field must have a `#[query(...)]` attribute for specifying //! which part of the document should be retrieved, starting from the root. //! //! # `#[query(...)]` syntax //! `serde-query` currently supports the following syntax for stepping one level inside the document. //! You can combine them to go further. //! //! * `.field` for accessing a field with a name `field` of an object. //! The field name must be an alphabet followed by zero or more alphanumeric characters. //! * `.["field"]` if the field name contains special characters. //! We recommend using a raw string literal for the query parameter (`#[query(r#"..."#)]`). //! * `.[index]` for accessing an array element at position `index`. //! //! Note that mixing field access and index access at the same position of a document //! is a compile error. //! //! [`serde::Deserialize`]: https://docs.serde.rs/serde/trait.Deserialize.html //! [`serde_query::Deserialize`]: trait.Deserialize.html //! [`serde_query::DeserializeQuery`]: trait.DeserializeQuery.html //! [`Query<T>`]: trait.DeserializeQuery.html#associatedtype.Query //! [its derive macro]: derive.DeserializeQuery.html /// Derive macro that generates [`serde::Deserialize`] directly. /// /// Please refer to the [module-level document] for the usage. /// /// [`serde::Deserialize`]: https://docs.serde.rs/serde/trait.Deserialize.html /// [module-level document]: index.html pub use serde_query_derive::Deserialize; /// Derive macro for [`DeserializeQuery`] trait. /// /// # Example /// /// ```rust /// # use std::error::Error; /// # fn main() -> Result<(), Box<dyn Error + 'static>> { /// use serde_query::{DeserializeQuery, Query}; /// /// #[derive(DeserializeQuery)] /// struct Data { /// #[query(".commit.authors.[0]")] /// first_author: String, /// #[query(".hash")] /// hash_value: u64, /// } /// /// let document = serde_json::to_string(&serde_json::json!({ /// "commit": { /// "authors": ["Kou", "Kasumi", "Masaru"], /// "date": "2020-09-10", /// }, /// "hash": 0xabcd, /// }))?; /// /// // You can use `Query<T>` as a `Deserialize` type for any `Deserializer` /// // and convert the result to the desired type using `From`/`Into`. /// let data: Data = serde_json::from_str::<Query<Data>>(&document)?.into(); /// /// assert_eq!(data.first_author, "Kou"); /// assert_eq!(data.hash_value, 0xabcd); /// # Ok(()) /// # } /// ``` /// /// [`DeserializeQuery`]: trait.DeserializeQuery.html /// [module-level document]: index.html pub use serde_query_derive::DeserializeQuery; use core::ops::{Deref, DerefMut}; use serde::de::Deserialize; /// Convenient type alias for the query type. /// /// Please refer to [`DeserializeQuery`] trait for details. /// /// [`DeserializeQuery`]: trait.DeserializeQuery.html /// [module-level document]: index.html pub type Query<'de, T> = <T as DeserializeQuery<'de>>::Query; /// A **data structure** that can be deserialized with a query. /// /// The [`Query`] type is a `#[repr(transparent)]` wrapper automatically generated by /// [the proc macro], and can be converted to the implementor /// (the type with `#[derive(DeserializeQuery)`]) after deserializing from the document /// using `Deserialize` implementation of the query type. /// /// [`Query`]: trait.DeserializeQuery.html#associatedtype.Query /// [the proc macro]: derive.DeserializeQuery.html pub trait DeserializeQuery<'de> where Self: From<<Self as DeserializeQuery<'de>>::Query>, Self::Query: Deserialize<'de> + Deref<Target = Self> + DerefMut, { /// The query type. type Query; }