An open API service indexing awesome lists of open source software.

https://github.com/ultimaweapon/porm

ORM for PostgreSQL that derive models from migration scripts
https://github.com/ultimaweapon/porm

orm postgresql rust

Last synced: about 3 hours ago
JSON representation

ORM for PostgreSQL that derive models from migration scripts

Awesome Lists containing this project

README

          

# Porm
[![Crates.io Version](https://img.shields.io/crates/v/porm?label=porm)](https://crates.io/crates/porm)
[![Crates.io Version](https://img.shields.io/crates/v/porm-parser?label=porm-parser)](https://crates.io/crates/porm-parser)
[![docs.rs](https://img.shields.io/docsrs/porm)](https://docs.rs/porm)

Porm is a new type of ORM for PostgreSQL. Instead of defining some models in Rust, Porm parse migration scripts and generate models from it.

> [!WARNING]
> Porm currently in a pre-1.0 so prepare for a lot of breaking changes!

## Features

- Lightweight.
- The generated models in a thin layer on top of [tokio-postgres](https://crates.io/crates/tokio-postgres) API.
- Database is a single source of truth.
- Built-in schema migration.
- Use actual parser from PostgreSQL.

## How it works

Suppose you have the following migration scripts:

```sql
-- 0.sql
CREATE TABLE post (
id serial NOT NULL,
title text NOT NULL,
body text NOT NULL,
PRIMARY KEY (id)
);
```

```sql
-- 1.sql
ALTER TABLE post ADD published boolean NOT NULL DEFAULT FALSE;

CREATE INDEX ON post (published);
```

Porm will generate a corresponding struct for you:

```rust
pub struct Post<'a> {
pub id: i32,
pub title: Cow<'a, str>,
pub body: Cow<'a, str>,
pub published: bool,
}
```

The generated struct will have methods to query PostgreSQL based on table indexes:

```rust
impl<'a> Post<'a> {
pub async fn find(client: &T, id: i32) -> Result, Error>;
pub async fn select_by_published(
client: &T,
published: bool,
) -> Result> + use<'a, T>>>, Error>;
}
```

Porm also generate a helper struct to insert a new row with default values:

```rust
pub struct PostBuilder<'a> { ... }

impl<'a> PostBuilder<'a> {
pub fn new(title: &'a str, body: &'a str) -> Self;
pub fn set_id(&mut self, v: i32) -> &mut Self;
pub fn set_title(&mut self, v: &'a str) -> &mut Self;
pub fn set_body(&mut self, v: &'a str) -> &mut Self;
pub fn set_published(&mut self, v: bool) -> &mut Self;
pub async fn create(&self, client: &T) -> Result, Error>;
}
```

Notice `PostBuilder::new` function that requires non-null columns without default value. The following code will insert a new row and construct `Post` value with `id` and `published` loaded from the database:

```rust
let post = PostBuilder::new("Foo", "Bar.").create(&pg).await.unwrap();

assert_eq!(post.id, 1); // Suppose this is the first row.
assert_eq!(post.title, "Foo");
assert_eq!(post.body, "Bar.");
assert!(!post.published);
```

## Non-goals

- Synchronous API.
- Supports downgrade migration.
- Supports other databases.

## Breaking changes in parser 0.3

- `ParseError` no longer have migration version on every variants.
- Migration version will be become a migration name if `Migration::name` return `None`.

## Breaking changes in 0.2

- `Migration::name` no longer optional.
- `Logger::run` has new signature.
- `Error::ExecuteMigration` and `Error::UpdateVersion` has been updated.

## License

This project is licensed under either of

- Apache License, Version 2.0
- MIT License

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in Porm by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.