Skip to content

Commit fc60de8

Browse files
committed
v0.8.0
1 parent 97b9f33 commit fc60de8

File tree

3 files changed

+79
-8
lines changed

3 files changed

+79
-8
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
### v0.8.0
2+
- (Improvement, **breaking**) The `record` macro no longer derives `Debug` and `Clone`, but now accepts custom attributes (such as derives and doc comments) similar to `sql_enum`.
3+
- Added some additional doc examples.
4+
15
### v0.7.1
26
- (Improvement) Tests generated by the `#[check(...)]` attribute now verify that there are no columns that exist in the schema but not in the model. (Previously, it only checked in one direction - verifying that all fields of the model existed in the schema.)
37
- (Improvement) The `sql_enum` macro now accepts an optional `Type` parameter that can be used to specify the discriminant type. By default, `i64` is still used.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ members = [
77
]
88

99
[workspace.package]
10-
version = "0.7.1"
10+
version = "0.8.0"
1111
authors = ["Colonial"]
1212
edition = "2021"
1313
license = "MIT OR Apache-2.0"

exemplar/src/macros.rs

Lines changed: 74 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22
///
33
/// # Requirements
44
///
5-
/// [`Model`](crate::Model) can *only* be derived for `struct`s with suitable named fields.
5+
/// [`Model`](crate::Model) can *only* be derived for non-generic `struct`s with suitable named fields.
66
///
77
/// | Type | Example | Supported? |
88
/// | ---- | ------- | ---------- |
99
/// | Standard `struct` | `struct Person { name: String }` | ✔ |
10+
/// | Generic `struct` | `struct Person<'a, T, const N: usize> { ... }` | ✘ |
1011
/// | Tuple struct | `struct Point(i64, i64)` | ✘ |
1112
/// | Unit/ZST struct | `struct Unit;` or `struct Unit {}` | ✘ |
1213
/// | `enum`s | `enum Direction { Up, Down }` | ✘ |
@@ -64,7 +65,7 @@
6465
///
6566
/// More specifically, the generated test verifies that:
6667
/// - The specified table exists.
67-
/// - All specified columns/fields exist.
68+
/// - The columns in the schema match up with those specified by the model type. If the model has fields not present in the schema (or vice versa) the test will fail.
6869
///
6970
/// It does *not* verify the validity of column types, nor does it test actual insertion/retrieval.
7071
///
@@ -86,6 +87,32 @@
8687
///
8788
/// In both cases `T` is the type of the field being annotated. For some types (e.g. `PathBuf`) you may also be able to use a type it derefs to, like `Path`.
8889
///
90+
/// Example implementations for `PathBuf`:
91+
/// ```rust
92+
/// # use exemplar::*;
93+
/// # use std::path::{Path, PathBuf};
94+
/// # use rusqlite::types::ValueRef;
95+
/// pub fn bind_path(value: &Path) -> BindResult {
96+
/// use rusqlite::types::Value;
97+
/// use rusqlite::types::ToSqlOutput;
98+
///
99+
/// // Depending on your program, it may make more sense
100+
/// // to error if a lossless conversion isn't possible.
101+
/// let str = value.to_string_lossy().into_owned();
102+
///
103+
/// Ok(ToSqlOutput::Owned(
104+
/// Value::Text(str)
105+
/// ))
106+
/// }
107+
///
108+
/// pub fn extr_path(value: &ValueRef) -> ExtrResult<PathBuf> {
109+
/// let path = value.as_str()?;
110+
/// let path = PathBuf::from(path);
111+
///
112+
/// Ok(path)
113+
/// }
114+
/// ```
115+
///
89116
/// ### `#[column]`
90117
/// Usage:
91118
/// ```ignore
@@ -139,13 +166,51 @@ pub use exemplar_proc_macro::Model;
139166
/// .query_and_then([], Age::from_row)?
140167
/// .map(|age| ...);
141168
/// ```
169+
///
170+
/// # Notes
171+
///
172+
/// Doc comments (and other attributes) are supported:
173+
/// ```rust
174+
/// # use exemplar::*;
175+
/// record! {
176+
/// /// A person's name.
177+
/// name => String,
178+
/// /// A person's age.
179+
/// age => u16,
180+
/// }
181+
/// ```
182+
/// Additionally, you can apply type-level attributes like derives on the `Name` argument.
183+
/// ```rust
184+
/// # use exemplar::*;
185+
/// record! {
186+
/// #[derive(Debug, Clone)]
187+
/// Name => Age,
188+
/// age => u16,
189+
/// }
190+
/// ```
191+
/// (`record!` does not apply any derives automatically.)
192+
///
193+
/// This does *not* work without the `Name` argument, due to macro limitations - Rust can't
194+
/// disambiguate between "attributes for the struct" and "attributes for the field."
195+
///
196+
/// ```compile_fail
197+
/// # use exemplar::*;
198+
/// record! {
199+
/// #[derive(Debug, Clone)]
200+
/// /// A person's name.
201+
/// name => String,
202+
/// /// A person's age.
203+
/// age => u16,
204+
/// }
205+
/// ```
142206
#[macro_export]
143207
macro_rules! record {
144-
(Name => $name:ident, $($fname:ident => $ftype:ty),* $(,)?) => {
145-
#[derive(Debug, Clone)]
208+
($(#[$struct_doc:meta])* Name => $name:ident, $($(#[$field_doc:meta])* $fname:ident => $ftype:ty),* $(,)?) => {
209+
$(#[$struct_doc])*
210+
///
146211
/// Automatically generated record type for storing query results.
147212
pub struct $name {
148-
$(pub $fname : $ftype),*
213+
$($(#[$field_doc])* pub $fname : $ftype),*
149214
}
150215

151216
impl $name {
@@ -164,8 +229,8 @@ macro_rules! record {
164229
}
165230
}
166231
};
167-
($($fname:ident => $ftype:ty),* $(,)?) => {
168-
record!(Name => Record, $($fname => $ftype),*);
232+
($($(#[$field_doc:meta])* $fname:ident => $ftype:ty),* $(,)?) => {
233+
record!(Name => Record, $($(#[$field_doc])* $fname => $ftype),*);
169234
};
170235
}
171236

@@ -225,9 +290,11 @@ macro_rules! record {
225290
/// ```rust
226291
/// # use exemplar::sql_enum;
227292
/// sql_enum! {
293+
/// #[derive(Default)]
228294
/// /// An RGB color tag.
229295
/// Name => Color,
230296
/// /// Red
297+
/// #[default]
231298
/// Red,
232299
/// /// Green
233300
/// Green,

0 commit comments

Comments
 (0)