Oxidizer
A simple orm based on tokio-postgres and refinery
#[async_trait]
pub trait Entity: Sized {
async fn save(&mut self, db: &DB) -> DBResult<bool>;
async fn delete(&mut self, db: &DB) -> DBResult<bool>;
fn from_row(row: &Row) -> Self;
fn create_migration() -> DBResult<Migration>;
fn get_table_name() -> String;
async fn find(db: &DB, query: &str, params: &'_ [&'_ (dyn ToSql + Sync)]) -> DBResult<Vec<Self>>;
async fn first(db: &DB, query: &str, params: &'_ [&'_ (dyn ToSql + Sync)]) -> DBResult<Option<Self>>;
}
use oxidizer::*;
use chrono::{DateTime, Utc};
#[derive(Entity)]
#[derive(Default)]
pub struct MyEntity {
#[primary_key]
id: i32,
name: String,
#[indexed]
integer: i32,
integer64: i64,
float: f32,
double: f64,
boolean: bool,
datetime: Option<DateTime<Utc>>,
}
#[tokio::test]
async fn test_my_entity() {
let uri = "postgres://postgres:alkje2lkaj2e@db/postgres";
let max_open = 50; // mobc
let ca_file: Option<&str> = None;
let db = DB::connect(&uri, max_open, ca_file).await.unwrap();
db.migrate_tables(&[MyEntity::create_migration().unwrap()]).await.unwrap();
let mut entity = MyEntity::default();
let creating = entity.save(&db).await.unwrap();
assert_eq!(creating, true);
}
Attributes
Derive attributes can be used to create indexes, change the default table name and create reverse relation accessors
#[primary_key]
Required Field attribute used to mark the field as the primary key, this will make the field autoincrement
use oxidizer::*;
#[derive(Entity)]
struct Entity {
#[primary_key]
id: i32
}
#[indexed]
Make the specified field indexed in the db
use oxidizer::*;
#[derive(Entity)]
struct Entity {
#[primary_key]
id: i32,
#[indexed]
name: String,
}
#[relation]
See Relations
#[has_many]
See Relations
#[entity]
General settings for the entity struct
table_name: String;
Allows one to change the table name of the entity
use oxidizer::*;
#[derive(Entity)]
#[entity(table_name="custom_table_name")]
struct Entity {
#[primary_key]
id: i32
}
#[index]
Creates a custom index/constraint on one or more column
use oxidizer::*;
#[derive(Default, Entity)]
#[index(name="myindex", columns="name, email", unique)]
struct MyEntity {
#[primary_key]
id: i32,
name: String,
email: String,
}
#[field_ignore]
Ignores the specified field. The field type must implement the Default
trait.
use oxidizer::*;
#[derive(Default, Entity)]
struct MyEntity {
#[primary_key]
id: i32,
name: String,
#[field_ignore]
email: String,
}
#[custom_type]
The custom type attribute lets you override the default type provided by oxidizer.
use oxidizer::*;
pub enum MyEnum {
Item1,
Item2,
}
impl std::convert::From<&MyEnum> for i32 {
fn from(v: &MyEnum) -> Self {
match v {
MyEnum::Item1 => 0,
MyEnum::Item2 => 1,
}
}
}
impl std::convert::From<i32> for MyEnum {
fn from(v: i32) -> Self {
match v {
0 => MyEnum::Item1,
1 => MyEnum::Item2,
_ => unimplemented!(),
}
}
}
#[derive(Entity)]
pub struct TestCustomType {
#[primary_key]
id: i32,
#[custom_type(ty = "i32")]
my_enum: MyEnum,
}
The custom type requires you to explicity implement the related From
functions to convert between the actual type and the overriden type
Relations
#[relation]
Relations can be created using the relation
attribute as in the example:
use oxidizer::*;
#[derive(Entity)]
struct Entity {
#[primary_key]
id: i32,
}
#[derive(Entity)]
struct TestRelation {
#[primary_key]
id: i32,
device_id: String,
#[relation(model="Entity", key="id")]
entity_id: i32,
}
This will implement for TestRelation
the following generated trait:
#[oxidizer::async_trait]
pub trait __AccessorTestRelationToEntity {
async fn get_test_entity(&self, db: &oxidizer::db::DB) -> oxidizer::db::DBResult<Entity>;
async fn set_test_entity(&mut self, db: &oxidizer::db::DB, v: &Entity) -> oxidizer::db::DBResult<()>;
}
#[has_many]
1-to-many or many-to-many relations can be achieved using the has_many
attribute
basic (1-to-many)
use oxidizer::*;
#[derive(Entity)]
#[derive(Default)]
#[has_many(model="TargetEntity", field="entity_id")]
pub struct Entity {
#[primary_key]
id: i32,
name: String
}
#[derive(Default, Entity)]
pub struct TargetEntity {
#[primary_key]
id: i32,
#[relation(model="Entity", key="id")]
entity_id: i32
}
This will create helper functions to access all the TargetEntity
that Entity has.
This is what the generated trait and implementation looks like (implementaion is also generated).
#[oxidizer::async_trait]
pub trait __AccessorHasManyTargetEntityToEntity {
async fn get_all_test_entity(&self, db: &oxidizer::db::DB) -> oxidizer::db::DBResult<Vec<Entity>>;
}
With a through table (many-to-many)
use oxidizer::*;
#[derive(Entity)]
#[derive(Default)]
pub struct Entity {
#[primary_key]
id: i32,
name: String
}
#[derive(Default, Entity)]
#[has_many(model="Entity", field="entity_id", through="TestManyToMany")]
pub struct TargetEntity {
#[primary_key]
id: i32,
}
#[derive(Default, Entity)]
pub struct TestManyToMany {
#[primary_key]
id: i32,
#[relation(model="TargetEntity", key="id")]
target_id: i32,
#[relation(model="Entity", key="id")]
entity_id: i32,
}
This will create helper functions to access the related entities. This is what the generated trait looks like (implementaion is also generated):
#[oxidizer::async_trait]
pub trait __AccessorHasManyTargetEntityToEntity {
async fn get_all_test_entity(&self, db: &oxidizer::db::DB) -> oxidizer::db::DBResult<Vec<TestManyToMany>>;
}