product_os_store_macros/lib.rs
1//! # Product OS Store Macros
2//!
3//! This crate provides procedural macros for generating SQL query builders from Rust structs.
4//! It works in conjunction with the `product-os-store` crate to provide a type-safe, ergonomic
5//! interface for database operations.
6//!
7//! ## Features
8//!
9//! - **Automatic SQL Generation**: Derive SQL operations from struct definitions
10//! - **Type Safety**: Compile-time verification of field types and constraints
11//! - **Flexible Naming**: Automatic table name pluralization or custom names
12//! - **Constraint Support**: Primary keys, foreign keys, unique constraints, and more
13//! - **No-std Compatible**: Works in `no_std` environments with `alloc`
14//!
15//! ## Usage
16//!
17//! ### Basic Example
18//!
19//! ```rust,ignore
20//! use product_os_store_macros::ProductOSRelational;
21//! use product_os_store::ProductOSRelationalObject;
22//!
23//! #[derive(ProductOSRelational, Debug, Default)]
24//! struct User {
25//! #[primary_key]
26//! id: i32,
27//! name: String,
28//! email: String,
29//! active: bool,
30//! }
31//!
32//! let user = User::default();
33//! let insert_instruction = user.relational_insert();
34//! ```
35//!
36//! ### Table Naming
37//!
38//! By default, table names are automatically pluralized:
39//!
40//! ```rust,ignore
41//! #[derive(ProductOSRelational)]
42//! struct User { /* ... */ } // Table name: "Users"
43//!
44//! #[derive(ProductOSRelational)]
45//! struct Category { /* ... */ } // Table name: "Categories"
46//! ```
47//!
48//! To disable pluralization:
49//!
50//! ```rust,ignore
51//! #[derive(ProductOSRelational)]
52//! #[do_not_pluralize]
53//! struct Data { /* ... */ } // Table name: "Data"
54//! ```
55//!
56//! ### Field Attributes
57//!
58//! - `#[primary_key]` - Marks a field as the primary key
59//! - `#[foreign_key]` - Marks a field as a foreign key
60//! - `#[not_null]` - Ensures the field cannot be null (implied for non-Option types)
61//! - `#[unique]` - Adds a unique constraint
62//! - `#[always_identity]` - Marks the field as always generated (e.g., auto-increment)
63//! - `#[default_identity]` - Marks the field as generated by default
64//!
65//! ### Supported Types
66//!
67//! #### Primitive Types
68//! - `bool` → Boolean
69//! - `String`, `&str` → Text
70//! - `i8` → Char (single byte)
71//! - `i16`, `u8` → SmallInt
72//! - `i32`, `u16`, `isize` → Int
73//! - `i64`, `u32` → BigInt
74//! - `f32` → Real
75//! - `f64` → Precision
76//!
77//! #### Special Types
78//! - `Vec<u8>` → ByteA (binary data)
79//! - `Vec` of any type → JsonB (serialized as JSON)
80//! - `chrono::DateTime` with `Utc` → TimestampTZ
81//! - `uuid::Uuid` → Uuid
82//! - `serde_json::Value` → JsonB
83//! - Custom types implementing `Serialize`/`Deserialize` → JsonB
84//!
85//! #### Optional Types
86//!
87//! Wrap any type in `Option` to make it nullable:
88//!
89//! ```rust,ignore
90//! #[derive(ProductOSRelational)]
91//! struct User {
92//! id: i32, // NOT NULL
93//! name: String, // NOT NULL
94//! email: Option<String>, // Nullable
95//! age: Option<i32>, // Nullable
96//! }
97//! ```
98//!
99//! ## Generated Methods
100//!
101//! The `ProductOSRelational` derive macro generates implementations for the
102//! `ProductOSRelationalObject` trait, including:
103//!
104//! ### DDL Operations
105//! - `relational_create()` - Generate CREATE TABLE instruction
106//! - `relational_alter()` - Generate ALTER TABLE instruction
107//! - `relational_drop()` - Generate DROP TABLE instruction
108//!
109//! ### DML Operations
110//! - `relational_insert()` - Generate INSERT instruction
111//! - `relational_update()` - Generate UPDATE instruction
112//! - `relational_delete()` - Generate DELETE instruction (static)
113//! - `relational_upsert()` - Generate UPSERT instruction
114//!
115//! ### Query Operations
116//! - `relational_query_all()` - Generate SELECT * query (static)
117//! - `relational_query_basic()` - Generate basic SELECT query (static)
118//! - `relational_query()` - Generate SELECT with conditions (static)
119//! - `relational_query_advanced()` - Generate SELECT with joins (static)
120//!
121//! ### Utility Methods
122//! - `relational_from_row()` - Populate struct from database row
123//! - `relational_test()` - Debug helper for generated field information
124//!
125//! ## Compatibility
126//!
127//! This crate requires:
128//! - Rust 1.69 or later
129//! - Works with `no_std` (requires `alloc`)
130//! - Designed for use with `product-os-store`
131
132#![no_std]
133extern crate no_std_compat as std;
134
135use std::prelude::v1::*;
136
137
138mod relational;
139mod type_parsing;
140
141use crate::relational::{ impl_relational_macro };
142
143
144/// Derives the `ProductOSRelationalObject` trait for a struct.
145///
146/// This macro generates methods for creating SQL queries and instructions from Rust structs.
147/// The struct name is automatically used as the table name (pluralized by default).
148///
149/// # Attributes
150///
151/// ## Struct-level Attributes
152///
153/// - `#[do_not_pluralize]` - Prevents automatic pluralization of the table name
154///
155/// ## Field-level Attributes
156///
157/// - `#[primary_key]` - Marks the field as a primary key
158/// - `#[foreign_key]` - Marks the field as a foreign key
159/// - `#[not_null]` - Adds a NOT NULL constraint (automatic for non-Option types)
160/// - `#[unique]` - Adds a UNIQUE constraint
161/// - `#[always_identity]` - Field is always generated (e.g., SERIAL)
162/// - `#[default_identity]` - Field is generated by default
163///
164/// # Examples
165///
166/// ```rust,ignore
167/// use product_os_store_macros::ProductOSRelational;
168///
169/// #[derive(ProductOSRelational, Debug, Default)]
170/// struct User {
171/// #[primary_key]
172/// id: i32,
173/// name: String,
174/// email: Option<String>,
175/// }
176///
177/// let user = User { id: 1, name: "Alice".to_string(), email: None };
178/// let insert = user.relational_insert();
179/// ```
180///
181/// # Generated Code
182///
183/// The macro generates an implementation of `ProductOSRelationalObject` with methods for:
184/// - Creating SQL DDL statements (CREATE, ALTER, DROP)
185/// - Creating SQL DML statements (INSERT, UPDATE, DELETE, UPSERT)
186/// - Building queries (SELECT with various options)
187/// - Mapping database rows to struct instances
188///
189/// # Table Naming
190///
191/// By default, the table name is the pluralized form of the struct name:
192/// - `User` → `Users`
193/// - `Category` → `Categories`
194/// - `Person` → `People`
195///
196/// Use `#[do_not_pluralize]` to keep the original name.
197#[proc_macro_derive(ProductOSRelational, attributes(primary_key, foreign_key, not_null, unique, always_identity, default_identity))]
198pub fn relational_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
199 let ast = syn::parse_macro_input!(input as syn::DeriveInput);
200
201 impl_relational_macro(&ast)
202}
203
204/// Prevents automatic pluralization of the table name.
205///
206/// By default, the `ProductOSRelational` derive macro pluralizes struct names to create
207/// table names (e.g., `User` → `Users`). Use this attribute to keep the original name.
208///
209/// # Example
210///
211/// ```rust,ignore
212/// use product_os_store_macros::ProductOSRelational;
213///
214/// #[derive(ProductOSRelational)]
215/// #[do_not_pluralize]
216/// struct Data {
217/// id: i32,
218/// value: String,
219/// }
220/// // Table name will be "Data", not "Datas"
221/// ```
222#[proc_macro_attribute]
223pub fn do_not_pluralize(_: proc_macro::TokenStream, input: proc_macro::TokenStream) -> proc_macro::TokenStream {
224 input
225}
226