georm/README.md

198 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<div align="center">
<a href="https://github.com/Phundrak/georm">
<img src="assets/logo.png" alt="Georm logo" width="150px" />
</a>
</div>
<h1 align="center">Georm</h1>
<div align="center">
<strong>
A simple, opinionated SQLx ORM for PostgreSQL
</strong>
</div>
<br/>
<div align="center">
<!-- Github Actions -->
<a href="https://github.com/phundrak/georm/actions/workflows/ci.yaml?query=branch%3Amain">
<img src="https://img.shields.io/github/actions/workflow/status/phundrak/georm/ci.yaml?branch=main&style=flat-square" alt="actions status" /></a>
<!-- Version -->
<a href="https://crates.io/crates/georm">
<img src="https://img.shields.io/crates/v/georm.svg?style=flat-square" alt="Crates.io version" />
</a>
<!-- Docs -->
<a href="https://docs.rs/georm">
<img src="https://img.shields.io/badge/docs-latest-blue.svg?style=flat-square" alt="docs.rs docs" />
</a>
</div>
## What is Georm?
Georm is a quite simple ORM built around
[SQLx](https://crates.io/crates/sqlx) that gives access to a few
useful functions when interacting with a database, implementing
automatically the most basic SQL interactions youre tired of writing.
## Why is Georm?
I wanted an ORM thats easy and straightforward to use. I am aware
some other projects exist, such as
[SeaORM](https://www.sea-ql.org/SeaORM/), but they generally dont fit
my needs and/or my wants of a simple interface. I ended up writing the
ORM I wanted to use.
## How is Georm?
I use it in a few projects, and Im quite happy with it right now. But
of course, Im open to constructive criticism and suggestions!
## How can I use it?
Georm works with SQLx, but does not re-export it itself. To get
started, install both Georm and SQLx in your Rust project:
```sh
cargo add sqlx --features postgres,macros # and any other feature you might want
cargo add georm
```
As Georm relies heavily on the macro
[`query_as!`](https://docs.rs/sqlx/latest/sqlx/macro.query_as.html),
the `macros` feature is not optional. Declare your tables in your
Postgres database (you may want to use SQLxs `migrate` feature for
this), and then declare their equivalent in Rust.
```sql
CREATE TABLE biographies (
id SERIAL PRIMARY KEY,
content TEXT NOT NULL
);
CREATE TABLE authors (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
biography_id INT,
FOREIGN KEY (biography_id) REFERENCES biographies(id)
);
```
```rust
pub struct Author {
pub id: i32,
pub name: String,
}
```
To link a struct to a table in your database, derive the
`sqlx::FromRow` and the `georm::Georm` traits.
```rust
#[derive(sqlx::FromRow, Georm)]
pub struct Author {
pub id: i32,
pub name: String,
}
```
Now, indicate with the `georm` proc-macro which table they refer to.
```rust
#[derive(sqlx::FromRow, Georm)]
#[georm(table = "authors")]
pub struct Author {
pub id: i32,
pub name: String,
}
```
Finally, indicate with the same proc-macro which field of your struct
is the primary key in your database.
```rust
#[derive(sqlx::FromRow, Georm)]
#[georm(table = "authors")]
pub struct Author {
#[georm(id)]
pub id: i32,
pub name: String,
}
```
Congratulations, your struct `Author` now has access to all the
functions described in the `Georm` trait!
## Entity relationship
It is possible to implement one-to-one, one-to-many, and many-to-many
relationships with Georm. This is a quick example of how a struct with
several relationships of different types may be declared:
```rust
#[derive(sqlx::FromRow, Georm)]
#[georm(
table = "books",
one_to_one = [
{ name = "draft", remote_id = "book_id", table = "drafts", entity = Draft }
],
one_to_many = [
{ name = "reviews", remote_id = "book_id", table = "reviews", entity = Review },
{ name = "reprints", remote_id = "book_id", table = "reprints", entity = Reprint }
],
many_to_many = [{
name = "genres",
table = "genres",
entity = Genre,
link = { table = "book_genres", from = "book_id", to = "genre_id" }
}]
)]
pub struct Book {
#[georm(id)]
ident: i32,
title: String,
#[georm(relation = {entity = Author, table = "authors", name = "author"})]
author_id: i32,
}
```
To read more about these features, you can refer to the [online
documentation](https://docs.rs/georm/).
## Roadmap / TODO
The following features are being considered for future development:
### High Priority
- **Transaction Support**: Add comprehensive transaction support with
transaction-aware CRUD methods and relationship handling for atomic
operations across multiple entities
- **Race Condition Fix**: Replace the current `create_or_update`
implementation with database-specific UPSERT operations (PostgreSQL
`ON CONFLICT`, MySQL `ON DUPLICATE KEY UPDATE`, SQLite `ON
CONFLICT`) to prevent race conditions
### Medium Priority
- **Multi-Database Support**: Extend Georm to support MySQL and SQLite
in addition to PostgreSQL, with database-specific optimizations and
dialect handling
- **Relationship Optimization**: Implement eager loading and N+1 query
prevention with circular dependency protection to dramatically
improve performance when working with related entities
- **Composite Primary Keys**: Add support for entities with multiple
primary key fields using auto-generated ID structs and type-safe
composite key handling
- **Soft Delete**: Implement optional soft delete functionality with
`deleted_at` timestamps, allowing entities to be marked as deleted
without physical removal
### Lower Priority
- **Migration Support**: Add optional migration utilities that
leverage SQLx's existing infrastructure for schema generation,
verification, and evolution
- **Enhanced Error Handling**: Consider implementing custom error
types with better categorization and operation context while
maintaining compatibility with SQLx errors
- **Many-to-Many Relationship Improvements**: Add direct methods to
add or remove items from many-to-many relationships without manually
handling the join table
### Recently Completed
-**Defaultable Fields**: Support for fields with database defaults
or auto-generated values, creating companion structs with optional
fields for easier entity creation