Table of Contents
- The Problem
- The Solution
- Features
- Installation
- Quick Start
- Attribute Reference
- Generated Code
- Architecture
- Comparison
- Code Coverage
The Problem
Building a typical CRUD application requires writing the same boilerplate over and over:
// 1. Your domain entity
// 2. DTO for creating (without id, without auto-generated fields)
// 3. DTO for updating (all fields optional for partial updates)
// 4. DTO for API response (without sensitive fields)
// 5. Database row struct
// 6. Insertable struct
// 7. Repository trait
// 8. SQL implementation
// 9. Six From implementations for mapping between types
// ... and more
That's 200+ lines of boilerplate for a single entity.
The Solution
use Entity;
Done. The macro generates everything else.
Features
- Zero Runtime Cost — All code generation happens at compile time
- Type Safe — Change a field type once, everything updates automatically
- Flexible Attributes — Fine-grained control over what goes where
- SQL Generation — Complete CRUD operations for PostgreSQL (via sqlx)
- Partial Updates — Non-optional fields automatically wrapped in
Optionfor updates - Security by Default —
#[field(skip)]ensures sensitive data never leaks to responses
Installation
Add to your Cargo.toml:
[]
= { = "0.2", = ["postgres"] }
# Required peer dependencies
= { = "1", = ["v4", "v7"] }
= { = "0.4", = ["serde"] }
= { = "1", = ["derive"] }
= "0.1"
# For PostgreSQL support
= { = "0.8", = ["runtime-tokio", "postgres"] }
Available Features
| Feature | Description |
|---|---|
postgres |
PostgreSQL support via sqlx (stable) |
clickhouse |
ClickHouse support (planned) |
mongodb |
MongoDB support (planned) |
api |
OpenAPI schema generation via utoipa |
validate |
Validation derives via validator |
Quick Start
use Entity;
use Uuid;
use ;
// Now you have:
// - CreatePostRequest { title, content, author_id }
// - UpdatePostRequest { title?, content? }
// - PostResponse { id, title, content, author_id, created_at, updated_at }
// - PostRow, InsertablePost
// - PostRepository trait
// - impl PostRepository for sqlx::PgPool
Attribute Reference
Entity-Level: #[entity(...)]
| Attribute | Required | Default | Description |
|---|---|---|---|
table |
Yes | — | Database table name |
schema |
No | "public" |
Database schema |
sql |
No | "full" |
SQL generation level |
dialect |
No | "postgres" |
Database dialect |
uuid |
No | "v7" |
UUID version for ID generation |
Database Dialects
| Dialect | Alias | Client | Status |
|---|---|---|---|
postgres |
pg, postgresql |
sqlx::PgPool |
Stable |
clickhouse |
ch |
clickhouse::Client |
Planned |
mongodb |
mongo |
mongodb::Client |
Planned |
UUID Versions
| Version | Method | Properties |
|---|---|---|
v7 |
Uuid::now_v7() |
Time-ordered, sortable (recommended for databases) |
v4 |
Uuid::new_v4() |
Random, widely compatible |
SQL Levels
| Level | Repository Trait | PgPool Impl | Use Case |
|---|---|---|---|
full |
Yes | Yes | Simple entities with standard CRUD |
trait |
Yes | No | Custom queries (joins, CTEs, full-text search) |
none |
No | No | DTOs only, no database layer |
Field-Level Attributes
| Attribute | Effect |
|---|---|
#[id] |
Primary key, auto-generated UUID (v7 by default, configurable with uuid attribute), always in response |
#[auto] |
Auto-generated field (timestamps), excluded from create/update |
#[field(create)] |
Include in CreateRequest |
#[field(update)] |
Include in UpdateRequest (wrapped in Option if not already) |
#[field(response)] |
Include in Response |
#[field(skip)] |
Exclude from all DTOs (for sensitive data) |
Combine multiple: #[field(create, update, response)]
Example with All Options
Generated Code
For a User entity, the macro generates:
DTOs
Repository Trait
SQL Implementation
Mappers
// ... and more
Architecture
┌─────────────────────────────────────────────────────────────┐
│ Your Code │
│ #[derive(Entity)] │
│ pub struct User { ... } │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ entity-derive │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ Parser │ │ Generators │ │ Output │ │
│ │ │ │ │ │ │ │
│ │ EntityDef │─>│ dto.rs │─>│ CreateRequest │ │
│ │ FieldDef │ │ row.rs │ │ UpdateRequest │ │
│ │ SqlLevel │ │ repository │ │ Response │ │
│ │ │ │ sql.rs │ │ Row, Insertable │ │
│ │ │ │ mappers.rs │ │ Repository trait │ │
│ │ │ │ │ │ PgPool impl │ │
│ │ │ │ │ │ From impls │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
Comparison
| Aspect | Without entity-derive | With entity-derive |
|---|---|---|
| Lines of code | 200+ per entity | ~15 per entity |
| Type safety | Manual sync required | Automatic |
| Sensitive data leaks | Possible | Prevented by #[field(skip)] |
| Partial updates | Manual wrapping | Automatic |
| SQL bindings | Error-prone | Always in sync |
| Refactoring | Update 8+ places | Update 1 place |
Code Coverage
We maintain high test coverage to ensure reliability. Below are visual representations of our codebase coverage:
Sunburst
The inner circle represents the entire project. Moving outward: folders, then individual files. Size = number of statements, color = coverage percentage.
Grid
Each block represents a file. Size = number of statements, color = coverage level (green = high, red = low).
Icicle
Hierarchical view: top = entire project, descending through folders to individual files. Size and color represent statements and coverage.