ormer 0.2.3

A minimalist ORM framework that supports SQLite, PostgreSQL, MySQL, and SqlServer
Documentation
#![cfg(feature = "sqlite")]

use ormer::{Database, Model, RelationKind};

#[derive(Debug, Clone, ormer::Model)]
#[table = "relation_users"]
struct RelationUser {
    #[primary(auto)]
    id: i32,
    name: String,
    #[has_one(RelationProfile.user_id)]
    profile: Option<RelationProfile>,
    #[has_many(RelationPost.user_id)]
    posts: Vec<RelationPost>,
    #[has_many(RelationUserRole.user_id)]
    user_roles: Vec<RelationUserRole>,
    #[through(user_roles.role)]
    roles: Vec<RelationRole>,
}

#[derive(Debug, Clone, ormer::Model)]
#[table = "relation_profiles"]
struct RelationProfile {
    #[primary(auto)]
    id: i32,
    #[foreign(RelationUser.id)]
    user_id: i32,
    bio: String,
}

#[derive(Debug, Clone, ormer::Model)]
#[table = "relation_posts"]
struct RelationPost {
    #[primary(auto)]
    id: i32,
    #[foreign(RelationUser.id)]
    user_id: i32,
    #[belongs_to(user_id)]
    user: Option<RelationUser>,
    title: String,
}

#[derive(Debug, Clone, ormer::Model)]
#[table = "relation_roles"]
struct RelationRole {
    #[primary(auto)]
    id: i32,
    name: String,
    enabled: bool,
}

#[derive(Debug, Clone, ormer::Model)]
#[table = "relation_user_roles"]
struct RelationUserRole {
    #[primary]
    #[foreign(RelationUser.id)]
    user_id: i32,
    #[primary]
    #[foreign(RelationRole.id)]
    role_id: i32,
    #[belongs_to(role_id)]
    role: Option<RelationRole>,
}

#[tokio::test]
async fn relations_support_metadata_find_related_preload_and_include() -> ormer::Result<()> {
    assert_eq!(RelationUser::COLUMNS, &["id", "name"]);
    assert_eq!(RelationPost::COLUMNS, &["id", "user_id", "title"]);
    assert!(
        RelationUser::RELATIONS
            .iter()
            .any(|relation| relation.kind == RelationKind::HasMany)
    );
    assert!(
        RelationUser::RELATIONS
            .iter()
            .any(|relation| relation.kind == RelationKind::HasOne)
    );
    assert!(
        RelationUser::RELATIONS
            .iter()
            .any(|relation| relation.kind == RelationKind::Through)
    );
    assert_eq!(RelationPost::RELATIONS[0].kind, RelationKind::BelongsTo);

    let db = Database::connect(ormer::DbType::Sqlite, ":memory:").await?;
    db.create_table::<RelationUser>().execute().await?;
    db.create_table::<RelationProfile>().execute().await?;
    db.create_table::<RelationPost>().execute().await?;
    db.create_table::<RelationRole>().execute().await?;
    db.create_table::<RelationUserRole>().execute().await?;

    db.insert(&RelationUser {
        id: 1,
        name: "Alice".to_string(),
        profile: None,
        posts: Vec::new(),
        user_roles: Vec::new(),
        roles: Vec::new(),
    })
    .execute()
    .await?;
    db.insert(&RelationUser {
        id: 2,
        name: "Bob".to_string(),
        profile: None,
        posts: Vec::new(),
        user_roles: Vec::new(),
        roles: Vec::new(),
    })
    .execute()
    .await?;
    db.insert(&RelationProfile {
        id: 1,
        user_id: 1,
        bio: "Alice bio".to_string(),
    })
    .execute()
    .await?;
    db.insert(&RelationPost {
        id: 1,
        user_id: 1,
        user: None,
        title: "One".to_string(),
    })
    .execute()
    .await?;
    db.insert(&RelationPost {
        id: 2,
        user_id: 1,
        user: None,
        title: "Two".to_string(),
    })
    .execute()
    .await?;
    db.insert(&RelationPost {
        id: 3,
        user_id: 2,
        user: None,
        title: "Three".to_string(),
    })
    .execute()
    .await?;
    db.insert(&RelationRole {
        id: 1,
        name: "admin".to_string(),
        enabled: true,
    })
    .execute()
    .await?;
    db.insert(&RelationRole {
        id: 2,
        name: "viewer".to_string(),
        enabled: true,
    })
    .execute()
    .await?;
    db.insert(&RelationRole {
        id: 3,
        name: "disabled".to_string(),
        enabled: false,
    })
    .execute()
    .await?;
    db.insert(&RelationUserRole {
        user_id: 1,
        role_id: 1,
        role: None,
    })
    .execute()
    .await?;
    db.insert(&RelationUserRole {
        user_id: 1,
        role_id: 2,
        role: None,
    })
    .execute()
    .await?;
    db.insert(&RelationUserRole {
        user_id: 2,
        role_id: 3,
        role: None,
    })
    .execute()
    .await?;

    let user = db.find_by_id::<RelationUser>(1).await?.unwrap();
    let posts = db
        .find_related(&user, RelationUserWhere::default().posts)
        .await?;
    assert_eq!(posts.len(), 2);
    let roles = db
        .find_related(&user, RelationUserWhere::default().roles)
        .await?;
    assert_eq!(roles.len(), 2);

    let mut users = db.select::<RelationUser>().collect::<Vec<_>>().await?;
    db.preload(&mut users, RelationUserWhere::default().posts)
        .await?;
    assert_eq!(
        users.iter().find(|user| user.id == 1).unwrap().posts.len(),
        2
    );
    assert_eq!(
        users.iter().find(|user| user.id == 2).unwrap().posts.len(),
        1
    );

    let users = db
        .select::<RelationUser>()
        .filter(|user| {
            user.roles
                .any(|role| role.name.eq("admin").and(role.enabled.eq(true)))
        })
        .include(|user| user.roles.order_by(|role| role.name.asc()).range(..20))
        .collect::<Vec<_>>()
        .await?;
    assert_eq!(users.len(), 1);
    assert_eq!(users[0].roles.len(), 2);

    let users = db
        .select::<RelationUser>()
        .order_by(|user| user.id.asc())
        .include(|user| user.profile)
        .collect::<Vec<_>>()
        .await?;
    assert_eq!(users[0].profile.as_ref().unwrap().bio, "Alice bio");
    assert!(users[1].profile.is_none());

    let users = db
        .select::<RelationUser>()
        .filter(|user| user.id.eq(1))
        .include(|user| user.roles.order_by(|role| role.name.asc()).range(..20))
        .include(|user| user.user_roles.include(|user_role| user_role.role))
        .collect::<Vec<_>>()
        .await?;
    assert_eq!(users[0].roles.len(), 2);
    assert_eq!(users[0].user_roles.len(), 2);
    assert!(
        users[0]
            .user_roles
            .iter()
            .any(|user_role| user_role.role.as_ref().unwrap().name == "admin")
    );

    let posts = db
        .select::<RelationPost>()
        .include(|post| post.user)
        .collect::<Vec<_>>()
        .await?;
    assert_eq!(posts[0].user.as_ref().unwrap().id, 1);
    assert_eq!(posts[2].user.as_ref().unwrap().id, 2);

    db.drop_table::<RelationUserRole>().execute().await?;
    db.drop_table::<RelationRole>().execute().await?;
    db.drop_table::<RelationPost>().execute().await?;
    db.drop_table::<RelationProfile>().execute().await?;
    db.drop_table::<RelationUser>().execute().await?;
    Ok(())
}