Overview
Georm is a lightweight, opinionated Object-Relational Mapping (ORM) library built on top of SQLx for PostgreSQL. It provides a clean, type-safe interface for common database operations while leveraging SQLx's compile-time query verification.
Key Features
- Type Safety: Compile-time verified SQL queries using SQLx macros
- Zero Runtime Cost: No reflection or runtime query building
- Simple API: Intuitive derive macros for common operations
- Relationship Support: One-to-one, one-to-many, and many-to-many relationships
- Composite Primary Keys: Support for multi-field primary keys
- Defaultable Fields: Easy entity creation with database defaults and auto-generated values
- PostgreSQL Native: Optimized for PostgreSQL features and data types
Quick Start
Installation
Add Georm and SQLx to your Cargo.toml:
[]
= { = "0.8.6", = ["runtime-tokio-rustls", "postgres", "macros"] }
= "0.1"
Basic Usage
- Define your database schema:
(
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL
);
(
id SERIAL PRIMARY KEY,
title VARCHAR(200) NOT NULL,
content TEXT NOT NULL,
published BOOLEAN DEFAULT FALSE,
author_id INT NOT NULL REFERENCES authors(id),
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW
);
- Define your Rust entities:
use Georm;
- Use the generated methods:
use PgPool;
async
Advanced Features
Composite Primary Keys
Georm supports composite primary keys by marking multiple fields with #[georm(id)]:
This automatically generates a composite ID struct:
// Generated automatically
// Usage
let id = UserRoleId ;
let user_role = find.await?;
Note: Relationships are not yet supported for entities with composite primary keys.
Defaultable Fields
For fields with database defaults or auto-generated values, use the defaultable attribute:
This generates a PostDefault struct for easier creation:
use Defaultable;
let post_default = PostDefault ;
let created_post = post_default.create.await?;
Relationships
Georm supports comprehensive relationship modeling with two approaches: field-level relationships for foreign keys and struct-level relationships for reverse lookups.
Field-Level Relationships (Foreign Keys)
Use the relation attribute on foreign key fields to generate lookup methods:
Generated method: post.get_author(pool).await? -> Author
For nullable relationships:
Generated method: post.get_category(pool).await? -> Option<Category>
Struct-Level Relationships (Reverse Lookups)
Define relationships at the struct level to query related entities that reference this entity:
One-to-One Relationships
)]
Generated method: user.get_profile(pool).await? -> Option<Profile>
One-to-Many Relationships
)]
Generated methods:
author.get_posts(pool).await? -> Vec<Post>author.get_comments(pool).await? -> Vec<Comment>
Many-to-Many Relationships
For many-to-many relationships, specify the link table that connects the entities:
-- Example schema for books and genres
(
id SERIAL PRIMARY KEY,
title VARCHAR(200) NOT NULL
);
(
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL
);
(
book_id INT NOT NULL REFERENCES books(id),
genre_id INT NOT NULL REFERENCES genres(id),
PRIMARY KEY (book_id, genre_id)
);
)]
Generated methods:
book.get_genres(pool).await? -> Vec<Genre>genre.get_books(pool).await? -> Vec<Book>
Relationship Attribute Reference
| Attribute | Description | Required | Default |
|---|---|---|---|
entity |
Target entity type | Yes | N/A |
name |
Method name (generates get_{name}) |
Yes | N/A |
table |
Target table name | Yes | N/A |
remote_id |
Target table's key column | No | "id" |
nullable |
Whether relationship can be null (field-level only) | No | false |
link.table |
Join table name (many-to-many only) | Yes* | N/A |
link.from |
Column referencing this entity (many-to-many only) | Yes* | N/A |
link.to |
Column referencing target entity (many-to-many only) | Yes* | N/A |
*Required for many-to-many relationships
Complex Relationship Example
Here's a comprehensive example showing multiple relationship types:
Generated methods:
post.get_author(pool).await? -> Author(from field relation)post.get_category(pool).await? -> Option<Category>(nullable field relation)post.get_comments(pool).await? -> Vec<Comment>(one-to-many)post.get_tags(pool).await? -> Vec<Tag>(many-to-many)
API Reference
Core Operations
All entities implementing Georm<Id> get these methods:
// Query operations
find_all.await?; // Find all posts
find.await?; // Find by ID
// Mutation operations
post.create.await?; // Insert new record
post.update.await?; // Update existing record
post.create_or_update.await?; // Upsert operation
post.delete.await?; // Delete this record
delete_by_id.await?; // Delete by ID
// Utility
post.get_id; // Get entity ID
Defaultable Operations
Entities with defaultable fields get a companion <Entity>Default struct:
// Create with defaults
post_default.create.await?;
Configuration
Attributes Reference
Struct-level attributes
Field-level attributes
// Mark as primary key
// Mark as defaultable field
// Define relationship
Performance
Georm is designed for zero runtime overhead:
- Compile-time queries: All SQL is verified at compile time
- No reflection: Direct field access, no runtime introspection
- Minimal allocations: Efficient use of owned vs borrowed data
- SQLx integration: Leverages SQLx's optimized PostgreSQL driver
Examples
Comprehensive Example
For an example showcasing user management, comments, and follower relationships, see the example in examples/postgres/users-comments-and-followers/. This example demonstrates:
- User management and profile management
- Comment system with user associations
- Follower/following relationships (many-to-many)
- Interactive CLI interface with CRUD operations
- Database migrations and schema setup
To run the example:
# Set up your database
# Run migrations
# Run the example
Comparison
| Feature | Georm | SeaORM | Diesel |
|---|---|---|---|
| Compile-time safety | ✅ | ✅ | ✅ |
| Relationship support | ✅ | ✅ | ✅ |
| Async support | ✅ | ✅ | ⚠️ |
| Learning curve | Low | Medium | High |
| Macro simplicity | ✅ | ❌ | ❌ |
| Advanced queries | ❌ | ✅ | ✅ |
Roadmap
High Priority
- Transaction Support: Comprehensive transaction handling with atomic operations
Medium Priority
- Composite Key Relationships: Add relationship support (one-to-one, one-to-many, many-to-many) for entities with composite primary keys
- Multi-Database Support: MySQL and SQLite support with feature flags
- Field-Based Queries: Generate
find_by_{field_name}methods that returnVec<T>for regular fields orOption<T>for unique fields - Relationship Optimization: Eager loading and N+1 query prevention
- Soft Delete: Optional soft delete with
deleted_attimestamps
Lower Priority
- Migration Support: Schema generation and evolution utilities
- Enhanced Error Handling: Custom error types with better context
Contributing
We welcome contributions! Please see our Contributing Guide for details.
Development Setup
Prerequisites
- Rust 1.86+: Georm uses modern Rust features and follows the MSRV specified in
rust-toolchain.toml - PostgreSQL 12+: Required for running tests and development
- Git: For version control
- Jujutsu: For version control (alternative to Git)
Required Tools
The following tools are used in the development workflow:
- just: Task runner for common development commands
- cargo-deny: License and security auditing
- sqlx-cli: Database migrations and management
- bacon: Background code checker (optional but recommended)
Install these tools:
# Install just (task runner)
# Install cargo-deny (for auditing)
# Install sqlx-cli (for database management)
# Install bacon (optional, for live feedback)
Quick Start
# Clone the repository
# Set up your PostgreSQL database and set DATABASE_URL
# Run migrations
# Run all tests
# Run linting
# Run security audit
# Run all checks (format, lint, audit, test)
Available Commands (via just)
Running Specific Tests
# Run tests for a specific module
# Run tests with output
# Run a specific test function
Development with Bacon (Optional)
For continuous feedback during development:
# Run clippy continuously
# Run tests continuously
# Build docs continuously
Devenv Development Environment (Optional)
If you use Nix, you can use the provided devenv configuration for a reproducible development environment:
# Enter the development shell with all tools pre-installed
# Or use direnv for automatic environment activation
The devenv configuration provides:
- Exact Rust version (1.86) with required components
- All development tools (just, cargo-deny, sqlx-cli, bacon)
- LSP support (rust-analyzer)
- SQL tooling (sqls for SQL language server)
- PostgreSQL database for development
Devenv configuration:
- Rust toolchain: Specified version with rustfmt, clippy, and rust-analyzer
- Development tools: just, cargo-deny, sqlx-cli, bacon
- SQL tools: sqls (SQL language server)
- Database: PostgreSQL with automatic setup
- Platform support: Cross-platform (Linux, macOS, etc.)
Database Setup for Tests
Tests require a PostgreSQL database. Set up a test database:
-- Connect to PostgreSQL as superuser
;
;
ALL PRIVILEGES ON DATABASE georm_test TO georm_user;
Set the environment variable:
IDE Setup
- Ensure
rust-analyzeris configured - Set up PostgreSQL connection for SQL syntax highlighting
Code Style
The project uses standard Rust formatting:
# Format code
# Check formatting (CI)
Clippy linting is enforced:
# Run linting
# Fix auto-fixable lints
License
Licensed under either of
- MIT License (LICENSE-MIT or http://opensource.org/licenses/MIT)
- GNU General Public License v3.0 (LICENSE-GPL or https://www.gnu.org/licenses/gpl-3.0.html)
at your option.