rust-ef 1.8.0

Rust Entity Framework - An EFCore-inspired ORM for Rust
Documentation
#[cfg(test)]
mod navigation_tests {
    use rust_ef::db_context::{DbContext, DbContextOptionsBuilder};
    use rust_ef::linq;
    use rust_ef::prelude::*;
    use rust_ef_sqlite::DbContextOptionsBuilderExt as _;

    #[derive(Debug, Clone, EntityType)]
    #[table("nav_blogs")]
    struct NavBlog {
        #[primary_key]
        #[auto_increment]
        blog_id: i32,
        #[required]
        url: String,
        #[navigation]
        posts: HasMany<NavPost>,
    }

    #[derive(Debug, Clone, EntityType)]
    #[table("nav_posts")]
    struct NavPost {
        #[primary_key]
        #[auto_increment]
        post_id: i32,
        #[required]
        title: String,
        #[foreign_key(NavBlog)]
        blog_id: i32,
        #[navigation]
        blog: BelongsTo<NavBlog>,
        #[navigation]
        comments: HasMany<NavComment>,
    }

    #[derive(Debug, Clone, EntityType)]
    #[table("nav_comments")]
    struct NavComment {
        #[primary_key]
        #[auto_increment]
        comment_id: i32,
        #[required]
        text: String,
        #[foreign_key(NavPost)]
        post_id: i32,
    }

    #[tokio::test]
    async fn test_include_has_many_and_belongs_to() {
        let mut builder = DbContextOptionsBuilder::new();
        builder.use_sqlite_in_memory();
        let options = builder.build();
        let mut ctx = DbContext::from_options(&options).unwrap();

        ctx.set::<NavBlog>();
        ctx.set::<NavPost>();
        ctx.ensure_created().await.unwrap();

        ctx.add::<NavBlog>(NavBlog {
            blog_id: 0,
            url: "https://test.example".into(),
            posts: HasMany::new(),
        });
        ctx.save_changes().await.unwrap();

        let blogs = ctx.set::<NavBlog>().query().to_list().await.unwrap();
        let blog_id = blogs[0].blog_id;

        ctx.add::<NavPost>(NavPost {
            post_id: 0,
            title: "First".into(),
            blog_id,
            blog: BelongsTo::new(),
            comments: HasMany::new(),
        });
        ctx.add::<NavPost>(NavPost {
            post_id: 0,
            title: "Second".into(),
            blog_id,
            blog: BelongsTo::new(),
            comments: HasMany::new(),
        });
        ctx.save_changes().await.unwrap();

        let blogs = linq!(ctx.set::<NavBlog>(); include b.posts)
            .to_list()
            .await
            .unwrap();
        assert_eq!(blogs.len(), 1);
        assert_eq!(blogs[0].posts.len(), 2);

        let posts = linq!(ctx.set::<NavPost>(); include b.blog)
            .to_list()
            .await
            .unwrap();
        assert_eq!(posts.len(), 2);
        assert!(posts[0].blog.get().is_some());
        assert_eq!(posts[0].blog.get().unwrap().url, "https://test.example");
    }

    #[tokio::test]
    async fn test_then_include_nested() {
        let mut builder = DbContextOptionsBuilder::new();
        builder.use_sqlite_in_memory();
        let options = builder.build();
        let mut ctx = DbContext::from_options(&options).unwrap();

        ctx.set::<NavBlog>();
        ctx.set::<NavPost>();
        ctx.set::<NavComment>();
        ctx.ensure_created().await.unwrap();

        ctx.add::<NavBlog>(NavBlog {
            blog_id: 0,
            url: "https://nested.example".into(),
            posts: HasMany::new(),
        });
        ctx.save_changes().await.unwrap();
        let blog_id = ctx.set::<NavBlog>().query().to_list().await.unwrap()[0].blog_id;

        ctx.add::<NavPost>(NavPost {
            post_id: 0,
            title: "Post A".into(),
            blog_id,
            blog: BelongsTo::new(),
            comments: HasMany::new(),
        });
        ctx.save_changes().await.unwrap();
        let post_id = ctx.set::<NavPost>().query().to_list().await.unwrap()[0].post_id;

        ctx.add::<NavComment>(NavComment {
            comment_id: 0,
            text: "Great post".into(),
            post_id,
        });
        ctx.add::<NavComment>(NavComment {
            comment_id: 0,
            text: "Thanks".into(),
            post_id,
        });
        ctx.save_changes().await.unwrap();

        let blogs = linq!(ctx.set::<NavBlog>(); include b.posts then b.comments)
            .to_list()
            .await
            .unwrap();

        assert_eq!(blogs.len(), 1);
        assert_eq!(blogs[0].posts.len(), 1);
        assert_eq!(blogs[0].posts.items()[0].comments.len(), 2);
        assert_eq!(
            blogs[0].posts.items()[0].comments.items()[0].text,
            "Great post"
        );
    }
}