SeaQL / SeaQL/sea-orm

should `DatabaseConnectionType::MockDatabaseConnection` use `Arc<dyn MockDatabaseTrait>`

Open
#3,013 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
9.9k
Forks
734
Avg merge
6h 36m
Merged PRs (30d)
8

Description

Motivation

Currently, mocking only allows for explicitly defining list of events ahead of time. While this provides enough utility to get some basic testing accomplished, it limits the ability to assert the state of the database after a test has completed.

For example

struct SomeDbWrapper(DatabaseConnection);


impl SomeDbWrapper {
    pub fn new(conn: DatabaseConnection) -> Self {
        Self(conn)
    }

    pub async fn do_something_complicated(&self, other_data: Vec<(u32, u32, u32)>) -> Result<(), DbErr> {
        let tx = self.0.begin().await?;
        // This table has a composite key, that represents the only potential conflict
        // if that is violated, we want to update the data column
        let mut conflict_policy = OnConflict::new();
        conflict_policy.update_columns(
            Column::Data
        );
        // we want to clean up any data that isn't in the `other_data` provided so we will collect
        // a filter here of the composite keys
        let mut missing_items_filter = None;
        for (ida, idb, data) in other_data {
            if let Some(expr) = missing_items_filter {
                missing_items_filter = Some(expr.or(
                    Column::IdA.eq(ida).and(
                        Column::IdB.eq(idb)
                    ).not()
                ))
            } else {
                missing_items_filter = Some(
                    Column::IdA.eq(ida).and(
                        Column::IdB.eq(idb)
                    ).not()
                );
            }
            Insert(ActiveModel {
                ida: Set(ida),
                idb: Set(idb),
                data: Set(data),
            })
            .on_conflict(on_conflict.clone())
            .exec(&tx).await?;
        }
        let del = Entity::delete_many();

        if let Some(expr) = missing_items_filter {
            del = del.filter(expr);
        }
        del.exec(&tx).await?;
        
        tx.commit().await?;
        Ok(())
    }
}

The above would be very difficult to test with the current MockConnection since we cannot assert which operations have occurred, only what sql statements were executed. If we wanted to test that stale data is cleaned up after calling do_something_complicated we would need to attach to an actual database which can be a cumbersome process.

Proposed Solutions

While the work to build a fully functional in memory database from for testing is likely not something that is in the scope of this project, there is an escape hatch already provided and that is the MockDatabaseTrait,
by updating DatabaseConnectionType::MockDatabaseConnection(Arc<crate::MockDatabaseConnection>) to DatabaseConnectionType::MockDatabaseConnection(Arc<dyn MockDatabaseTrait>) (potentially with + Send + Sync + 'static in any combination) it would allow users to provide their own implementations w/o the maintenance burden.

Additional Information

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by locating DatabaseConnectionType::MockDatabaseConnection and the MockDatabaseTrait definition, then inspect their uses and the existing mock connection tests. Determine the required trait bounds and compatibility impact; done means users can provide custom MockDatabaseTrait implementations while existing mock behavior continues to work.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
databases
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.