ledb_derive/lib.rs
1/*!
2
3# Derive macro for defining storable documents
4
5This crate helps to turn rust structures into documents which can be stored, indexed and queried.
6
7## Defining documents
8
9You may turn any struct into a document using `Document` in derive annotation like this:
10
11```rust
12use serde::{Serialize, Deserialize};
13use ledb::{Document};
14
15#[derive(Serialize, Deserialize, Document)]
16struct MyDoc {
17 // primary field
18 #[document(primary)]
19 id: Option<u32>,
20 // other fields
21}
22```
23
24This generates `Document` trait implementation for struct `MyDoc`.
25It requires single field marked as primary key per document.
26Currently primary key should be an integer only.
27Also it not needed to be an optional field, but in this case you should take care of parsing (for example add `serde(default)` annotation).
28
29## Defining key fields for indexing
30
31To turn document field into key you can add document index annotation to it:
32
33```rust
34# extern crate serde;
35# extern crate ledb;
36#
37use serde::{Serialize, Deserialize};
38use ledb::{Document};
39
40#[derive(Serialize, Deserialize, Document)]
41struct MyDoc {
42 // primary field
43 #[serde(default)]
44 #[document(primary)]
45 id: u32,
46 // unique string key
47 #[document(unique)]
48 title: String,
49 // normal string index
50 #[document(index)]
51 keywords: Vec<String>,
52 // unique int key
53 #[document(unique)]
54 timestamp: u64,
55}
56```
57
58## Overriding key types
59
60In some cases it may be ambiguous to determine actual type of key by field type.
61For example, when you try to index binary data using `Vec<u8>`, the actually determined key type is an integer (u8).
62So you required to override key type manually using annotation like so:
63
64```rust
65# extern crate serde;
66# extern crate serde_bytes;
67# extern crate ledb;
68#
69use serde::{Serialize, Deserialize};
70use serde_bytes;
71use ledb::{Document};
72
73#[derive(Serialize, Deserialize, Document)]
74struct MyDoc {
75 #[document(primary)]
76 id: u32,
77 // ...
78 #[document(unique binary)]
79 #[serde(with = "serde_bytes")]
80 hash: Vec<u8>,
81}
82```
83
84## Nested documents
85
86Of course you can add nested documents which may also have key fields:
87
88```rust
89# extern crate serde;
90# extern crate ledb;
91#
92use std::collections::HashMap;
93use serde::{Serialize, Deserialize};
94use ledb::{Document};
95
96#[derive(Serialize, Deserialize, Document)]
97struct MyDoc {
98 // primary field
99 #[document(primary)]
100 #[serde(default)]
101 id: u32,
102 // ...fields
103 // simple nested document
104 #[document(nested)]
105 meta: Meta,
106 // list of nested documents
107 #[document(nested)]
108 links: Vec<Link>,
109 // map of nested documents
110 #[document(nested)]
111 props: HashMap<String, Prop>,
112}
113
114#[derive(Serialize, Deserialize, Document)]
115#[document(nested)]
116struct Meta {
117 #[document(index)]
118 title: String,
119 #[document(index)]
120 author: String,
121 annotation: String,
122}
123
124#[derive(Serialize, Deserialize, Document)]
125#[document(nested)]
126struct Link {
127 href: String,
128 text: String,
129}
130
131#[derive(Serialize, Deserialize, Document)]
132#[document(nested)]
133struct Prop {
134 value: String,
135 required: bool,
136}
137```
138
139The primary key field is omitted for nested documents.
140The nested documents should be explicitly marked as nested using `#[document(nested)]` directive as shown above.
141
142**NOTE**: When the `#[serde(flatten)]` directive is used the key fields of nested documents will be transferred to owner.
143
144## Simple usage example
145
146```rust
147# extern crate serde;
148# extern crate ledb;
149#
150use serde::{Serialize, Deserialize};
151use ledb::{Document};
152
153#[derive(Serialize, Deserialize, Document)]
154struct MyDoc {
155 // define optional primary key field
156 #[document(primary)]
157 id: Option<u64>,
158 // define unique key field
159 #[document(unique)]
160 title: String,
161 // define index fields
162 #[document(index)]
163 tag: Vec<String>,
164 #[document(unique)]
165 timestamp: u32,
166 // define nested document
167 #[document(nested)]
168 meta: MetaData,
169}
170
171#[derive(Serialize, Deserialize, Document)]
172#[document(nested)]
173struct MetaData {
174 // define index field
175 #[document(index)]
176 keywords: Vec<String>,
177 // define other fields
178 description: String,
179}
180```
181
182It will generate the `Document` traits like so:
183
184```ignore
185impl Document for MyDoc {
186 // declare primary key field name
187 fn primary_field() -> Identifier {
188 "id".into()
189 }
190
191 // declare other key fields for index
192 fn key_fields() -> KeyFields {
193 KeyFields::new()
194 // add key fields of document
195 .with_field(("title", String::key_type(), IndexKind::Unique))
196 .with_field(("tag", String::key_type(), IndexKind::Index))
197 .with_field(("timestamp", u32::key_type(), IndexKind::Unique))
198 // add key fields from nested document
199 .with_fields(MetaData::key_fields().with_parent("meta"))
200 }
201}
202
203impl Document for MetaData {
204 // declare key fields for index
205 fn key_fields() -> KeyFields {
206 KeyFields::new()
207 // add key fields of document
208 .with_field(("keywords", KeyType::String, IndexKind::Index))
209 }
210}
211```
212
213*/
214
215mod document;
216mod wrapper;
217
218use document::derive_document_wrapped;
219use proc_macro::TokenStream;
220use quote::quote;
221use syn::{parse_macro_input, DeriveInput};
222
223#[proc_macro_derive(Document, attributes(document))]
224pub fn derive_document(input: TokenStream) -> TokenStream {
225 let input = parse_macro_input!(input as DeriveInput);
226 derive_document_wrapped(&input)
227 .unwrap_or_else(compile_error)
228 .into()
229}
230
231fn compile_error(message: String) -> proc_macro2::TokenStream {
232 quote! {
233 compile_error!(#message);
234 }
235}