Skip to main content

kivis_derive/
lib.rs

1//! # Kivis Derive Macros
2//!
3//! Procedural macros for the Kivis database schema library.
4//! This crate provides the `Record` derive macro for automatically generating database schema types.
5#![warn(clippy::pedantic)]
6#![deny(clippy::unwrap_used)]
7#![deny(clippy::expect_used)]
8
9use proc_macro::TokenStream;
10use syn::{DeriveInput, parse_macro_input};
11
12mod generator;
13mod schema;
14
15use crate::generator::Generator;
16use crate::schema::Schema;
17
18/// Derive macro for generating database record implementations.
19///
20/// This macro generates the necessary traits and types for a struct to be used as a database record in Kivis.
21/// It creates key types, index types, and implements the required traits for database operations.
22///
23/// # Attributes
24///
25/// - `#[key]`: Marks fields as part of the primary key
26/// - `#[index]`: Marks fields for secondary indexing
27/// - `#[derived_key(Type1, Type2, ...)]`: Specifies types for a derived key (mutually exclusive with `#[key]`)
28///
29/// # Key Strategies
30///
31/// The Record derive macro supports three key strategies:
32///
33/// 1. **Autoincrement keys**: No `#[key]` fields or `#[derived_key]` attribute (default u64 autoincrement)
34/// 2. **Field keys**: Fields marked with `#[key]` attribute (derived from struct fields)
35/// 3. **Derived keys**: Struct with `#[derived_key(...)]` attribute (requires manual `DeriveKey` implementation)
36///
37/// # Examples
38///
39/// ## Autoincrement Key
40/// ```
41/// use serde::{Serialize, Deserialize};
42///
43/// // This shows the basic structure - the actual Record derive would be used in practice
44/// #[derive(Serialize, Deserialize, Debug, Clone)]
45/// struct AutoIncrement {
46///     name: String,
47///     email: String,
48/// }
49/// ```
50///
51/// ## Field Key
52/// ```
53/// use serde::{Serialize, Deserialize};
54///
55/// // This shows the basic structure with key field - the actual Record derive would be used in practice
56/// #[derive(Serialize, Deserialize, Debug)]
57/// struct User {
58///     id: u64,        // Would be marked with #[key] in actual usage
59///     name: String,   // Would be marked with #[index] in actual usage
60///     email: String,
61/// }
62/// ```
63///
64/// For complete working examples, see the tests in the `tests/` directory.
65#[proc_macro_derive(Record, attributes(key, index, derived_key))]
66pub fn derive_record(input: TokenStream) -> TokenStream {
67    // Parse the input tokens into a syntax tree
68    let input = parse_macro_input!(input as DeriveInput);
69
70    let visibility = input.vis.clone();
71
72    // Create schema from the parsed input
73    let schema = match Schema::from_derive_input(input) {
74        Ok(schema) => schema,
75        Err(error_tokens) => return error_tokens,
76    };
77
78    // Generate the implementation
79    Generator::new(schema).generate_record_impl(&visibility)
80}