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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
pub use ;
pub use ;
pub use CustomOption;
pub use ;
pub use ;
pub use ;
// macros
/// Derives an implementation for the [`Select`] trait on a struct with named
/// fields, allowing it to be constructed from a response from a query against
/// the store.
///
/// Configuration for `#[select(...)]` field attr
///
/// * `cursor` *Optional - once* Indicate that the annotated field is to be used
/// for pagination at the store layer. This will cause [`Cursored`] to be
/// implemented for the struct.
///
/// # Examples
/// ```
/// use bodega::{Select, uuid_id};
/// use chrono::{DateTime, Utc};
/// use serde::{Deserialize, Serialize};
/// use uuid::Uuid;
///
/// #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
/// #[uuid_id]
/// pub struct BookId(Uuid);
///
/// #[derive(Debug, Clone, PartialEq, Eq, sqlx::FromRow, Select)]
/// #[sea_query::enum_def]
/// pub struct Book {
/// #[select(cursor)]
/// id: BookId,
/// title: String,
/// author: String,
/// pages: i64,
/// created_at: DateTime<Utc>,
/// updated_at: DateTime<Utc>,
/// }
/// ```
pub use Select;
/// Derives an implementation for [`Insert`] on a struct with named fields,
/// allowing that struct to be used to be used to create an entry in the store.
///
/// Configuration for `#[insert(...)]` container attr
///
/// * `iden_enum` *Required.* The enum of `Iden` variants for the corresponding
/// model.
///
/// Configuration for `#[insert(...)]` field attr
///
/// * `iden` *Optional.* Override the computed `Iden` variant for this field.
///
/// # Examples
/// ```
/// use bodega::{Select, Insert, uuid_id};
/// use chrono::{DateTime, Utc};
/// use serde::{Deserialize, Serialize};
/// use uuid::Uuid;
///
/// #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
/// #[uuid_id]
/// pub struct BookId(Uuid);
///
/// #[derive(Debug, Clone, PartialEq, Eq, sqlx::FromRow, Select)]
/// #[sea_query::enum_def]
/// pub struct Book {
/// id: BookId,
/// title: String,
/// author: String,
/// pages: i64,
/// created_at: DateTime<Utc>,
/// updated_at: DateTime<Utc>,
/// }
///
/// #[derive(Debug, Clone, Insert)]
/// #[insert(iden_enum = BookIden)]
/// pub struct BookCreate {
/// title: String,
/// // unnecessary override for example
/// #[insert(iden = BookIden::Author)]
/// author: String,
/// pages: i64,
/// }
/// ```
pub use Insert;
/// Derives an implementation for [`Update`] on a struct with named fields,
/// allowing that struct to be used to be used to update an entry in the store.
///
/// Configuration for `#[update(...)]` container attr
///
/// * `iden_enum` *Required.* The enum of `Iden` variants for the corresponding
/// model.
///
/// Configuration for `#[update(...)]` field attr
///
/// * `iden` *Optional.* Override the computed `Iden` variant for this field.
///
/// # Examples
/// ```
/// use bodega::{Select, Update, uuid_id};
/// use chrono::{DateTime, Utc};
/// use serde::{Deserialize, Serialize};
/// use uuid::Uuid;
///
/// #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
/// #[uuid_id]
/// pub struct BookId(Uuid);
///
/// #[derive(Debug, Clone, PartialEq, Eq, sqlx::FromRow, Select)]
/// #[sea_query::enum_def]
/// pub struct Book {
/// id: BookId,
/// title: String,
/// author: String,
/// pages: i64,
/// created_at: DateTime<Utc>,
/// updated_at: DateTime<Utc>,
/// }
///
/// #[derive(Debug, Clone, Update)]
/// #[update(iden_enum = BookIden)]
/// pub struct BookUpdate {
/// title: Option<String>,
/// author: Option<String>,
/// pages: Option<i64>,
/// updated_at: DateTime<Utc>,
/// }
/// ```
pub use Update;
/// Implement [`DbBmc`] on a type, and optionally add basic CRUD implementations.
///
/// While you're free to implement additional methods and custom CRUD actions,
/// this macro can generate reasonable implementations for most simple models.
///
/// Configuration for `#[db_bmc(...)]` container attr
///
/// * `model = ...` *Required.* The type of model returned from things like SELECT
/// statements.
/// * `id_type = ...` *Required.* The [`IdType`] of the model.
/// * `model_name = "..."` *Optional.* A specific model name like `"foo"`, for use when
/// deriving the model name from the `model` is not sufficient.
/// * `table_name = "..."` *Optional.* A specific table name like `"foos"`, for use when
/// deriving the table name from the model name is not sufficient.
/// * `id_iden = ...` *Optional.* Override the derived `Iden` enum for this `model`.
/// * `error = ...` *Optional.* Return this error type instead of [`crate::Error`].
/// The type passed must implement `From<bodega::Error>`.
/// * `private_methods` *Optional.* Generate methods as private methods, prefixed
/// with an underscore `_`. Useful if you still need to wrap the generated
/// method in something like an internal transaction or some sort of authz.
/// The type passed must implement `From<bodega::Error>`.
/// * `methods(...)` *Optional.* A comma-separated list of methods to implement
/// from the following:
/// * `create = ...`, `get`, `list`, `list_paginated = ...`, `update = ...`, `delete`, `count`.
///
/// Specific configuration for `#[db_bmc(methods(...))]`
///
/// * `create = ...` Generate a `create` method on the controller accepting an
/// instance of the specified type that implements [`Insert`]. Returns the
/// created instance as an instance of `model`.
/// * `get` Generate a `get` method on the controller accepting an id. Returns
/// the corresponding instance of the `model` on success.
/// * `list` Generate a `list` method on the controller. Returns a [`Vec<T>`]
/// of the specified `model` containing every row from the store.
/// * `list_paginated = ...` Generate a `list_paginated` method on the controller
/// using the specified type as the [`Filter`]/[`CursoredFilter`]. Returns
/// a single page [`Paginated<T>`] of the given `model` that satisfies the
/// filters.
/// * `update = ...` Generate an `update` method on the controller accepting an
/// id and the specified type. Returns the updated instance as an instance of
/// `model`.
/// * `delete` Generate a `delete` method on the controller accepting an id.
/// * `count` Generate a `count` method on the controller returning the count of
/// all rows of this controller's model in the store.
///
/// # Examples
/// ```
/// use bodega::{
/// Select, Insert, Update, Filter, CursoredFilter, DbBmc, IdType, uuid_id
/// };
/// use chrono::{DateTime, Utc};
/// use derive_builder::Builder;
/// use sea_query::Expr;
/// use serde::{Deserialize, Serialize};
/// use uuid::Uuid;
///
/// #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
/// #[uuid_id]
/// pub struct BookId(Uuid);
///
/// #[derive(Debug, Clone, PartialEq, Eq, sqlx::FromRow, Select)]
/// #[sea_query::enum_def]
/// pub struct Book {
/// #[select(cursor)]
/// id: BookId,
/// title: String,
/// author: String,
/// pages: i64,
/// created_at: DateTime<Utc>,
/// updated_at: DateTime<Utc>,
/// }
///
/// #[derive(Debug, Clone, Insert)]
/// #[insert(iden_enum = BookIden)]
/// pub struct BookCreate {
/// title: String,
/// author: String,
/// pages: i64,
/// }
///
/// #[derive(Debug, Clone, Update)]
/// #[update(iden_enum = BookIden)]
/// pub struct BookUpdate {
/// title: Option<String>,
/// author: Option<String>,
/// pages: Option<i64>,
/// updated_at: DateTime<Utc>,
/// }
///
/// #[derive(Debug, Clone, Builder)]
/// pub struct BookFilters {
/// #[builder(default = 20)]
/// limit: usize,
/// #[builder(setter(strip_option), default)]
/// cursor: Option<BookId>,
/// #[builder(setter(strip_option), default)]
/// author: Option<String>,
/// }
///
/// impl CursoredFilter for BookFilters {
/// type Entity = Book;
///
/// fn cursor(&self) -> Option<<Self::Entity as bodega::Cursored>::CursorType> {
/// self.cursor
/// }
///
/// fn set_cursor(&mut self, cursor: <Self::Entity as bodega::Cursored>::CursorType) {
/// self.cursor = Some(cursor);
/// }
///
/// fn page_limit(&self) -> usize {
/// self.limit
/// }
/// }
///
/// impl Filter for BookFilters {
/// fn filter_query(&self, query: &mut sea_query::SelectStatement) {
/// if let Some(ref author) = self.author {
/// query.and_where(Expr::col(BookIden::Author).eq(author));
/// }
/// }
/// }
///
/// #[derive(Debug, Clone, DbBmc)]
/// #[db_bmc(
/// model = Book,
/// id_type = BookId,
/// methods(
/// create = BookCreate,
/// get,
/// list,
/// update = BookUpdate,
/// delete,
/// count,
/// )
/// )]
/// pub struct BookBmc;
///
/// assert_eq!(BookBmc::ENTITY, "book");
/// assert_eq!(BookBmc::TABLE, "books");
/// ```
pub use DbBmc;
/// Adds conversions from a type to a `serde_json::Value` for use with `sea_query`.
///
/// # Examples
/// ```
/// use bodega::JsonValue;
/// use serde::{Deserialize, Serialize};
///
/// #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonValue)]
/// pub struct Meta {
/// spine_size: u32,
/// book_weight: u32,
/// }
/// ```
pub use JsonValue;
/// Modifies a newtype in the form of `Foo(Uuid)` to have functionality that
/// makes it compatible with a store layer.
///
/// # Examples
/// ```
/// use bodega::uuid_id;
/// use serde::{Deserialize, Serialize};
/// use uuid::Uuid;
///
/// #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
/// #[uuid_id]
/// pub struct BookId(Uuid);
/// ```
pub use uuid_id;
/// Modifies an enum corresponding to a postgres enum to support various
/// `sea_query` operations.
///
/// # Examples
/// ```
/// use bodega::store_enum;
/// use serde::{Deserialize, Serialize};
/// use strum::AsRefStr;
///
/// #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, AsRefStr)]
/// #[store_enum]
/// pub enum Genre {
/// Mystery,
/// ScienceFiction,
/// Fantasy,
/// }
///
/// // we can also proxy a rename_all instruction to the underlying sqlx::Type
/// #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, AsRefStr)]
/// #[store_enum(rename_all = "snake_case")]
/// pub enum Mood {
/// Good,
/// Bad,
/// }
/// ```
pub use store_enum;