Trait InsertableRepository

Source
pub trait InsertableRepository<M: Model>: Repository<M> {
    // Required method
    fn insert_query(model: &M) -> Query<'_>;

    // Provided methods
    fn insert_with_executor<'c, 'life0, 'async_trait, E>(
        &'life0 self,
        tx: E,
        model: M,
    ) -> Pin<Box<dyn Future<Output = Result<M>> + Send + 'async_trait>>
       where M: 'async_trait,
             E: Executor<'c, Database = Database> + Send + 'async_trait,
             Self: Sync + 'async_trait,
             'c: 'async_trait,
             'life0: 'async_trait { ... }
    fn insert_ref_with_executor<'c, 'life0, 'life1, 'async_trait, E>(
        &'life0 self,
        tx: E,
        model: &'life1 M,
    ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
       where E: Executor<'c, Database = Database> + Send + 'async_trait,
             Self: Sync + 'async_trait,
             'c: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait { ... }
    fn insert<'life0, 'async_trait>(
        &'life0 self,
        model: M,
    ) -> Pin<Box<dyn Future<Output = Result<M>> + Send + 'async_trait>>
       where M: 'async_trait,
             Self: Sync + 'async_trait,
             'life0: 'async_trait { ... }
    fn insert_ref<'life0, 'life1, 'async_trait>(
        &'life0 self,
        model: &'life1 M,
    ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
       where M: 'async_trait,
             Self: Sync + 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait { ... }
    fn insert_many<'life0, 'async_trait, I>(
        &'life0 self,
        models: I,
    ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
       where I: IntoIterator<Item = M> + Send + 'async_trait,
             I::IntoIter: Send,
             Self: Sync + 'async_trait,
             'life0: 'async_trait { ... }
    fn insert_batch<'life0, 'async_trait, const N: usize, I>(
        &'life0 self,
        models: I,
    ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
       where I: IntoIterator<Item = M> + Send + 'async_trait,
             I::IntoIter: Send,
             Self: Sync + 'async_trait,
             'life0: 'async_trait { ... }
}
Expand description

Trait for repositories that can insert new records into the database.

The InsertableRepository trait extends the base Repository trait with methods for inserting new records. It provides standardized ways to insert both individual models and batches of models, optimizing database interactions for performance while maintaining data integrity.

§Type Parameters

  • M - The model type that this repository inserts. Must implement the Model trait.

§Examples

Basic implementation:


impl InsertableRepository<User> for UserRepository {
    fn insert_query(user: &User) -> Query<'_> {
        sqlx::query("INSERT INTO users (name) VALUES ($1)")
            .bind(&user.name)
    }
}

// Usage
// Insert a single user via a reference
repo.insert_ref(user).await?;

// Insert multiple users
let users = vec![
    User { id: 1, name: String::from("Alice") },
    User { id: 2, name: String::from("Bob") }
];
repo.insert_many(users).await?;

Using the macro for simpler implementation:


repository! {
    UserRepository<User>;

    // if you need to override any method other than `Repository::pool` they will go here
}

repository_insert! {
    UserRepository<User>;

    insert_query(user) {
        sqlx::query("INSERT INTO users (name) VALUES ($1)")
            .bind(&user.name)
    }
}

§Implementation Notes

  1. Required method: insert_query - Defines how a model is translated into an INSERT statement
  2. Provided methods:
  3. All batch operations use transactions to ensure data consistency
  4. Performance is optimized through batching and connection pooling

Required Methods§

Source

fn insert_query(model: &M) -> Query<'_>

Creates a SQL query to insert a single model instance into the database.

This method defines how a model should be persisted in the database as a new record. It constructs a parameterized query that maps the model’s fields to database columns. The query is returned without being executed, allowing for transactions management and error handling at a higher level.

§Parameters
  • model - A reference to the model instance to be inserted
§Returns
  • Query - A prepared SQL query ready for execution
§Implementation Notes

The implementing repository should:

  1. Handle all model fields appropriately
  2. Use proper SQL parameter binding for safety
  3. Return an appropriate error if the model is invalid

Provided Methods§

Source

fn insert_with_executor<'c, 'life0, 'async_trait, E>( &'life0 self, tx: E, model: M, ) -> Pin<Box<dyn Future<Output = Result<M>> + Send + 'async_trait>>
where M: 'async_trait, E: Executor<'c, Database = Database> + Send + 'async_trait, Self: Sync + 'async_trait, 'c: 'async_trait, 'life0: 'async_trait,

Persists a new model instance to the database.

This method executes the insertion query generated by insert_query with the Executor tx. It handles the actual database interaction and provides a simple interface for creating new records.

§Parameters
  • tx - The executor to use for the query
  • model - The model instance to insert
§Returns
  • crate::Result<M> - Success if the insertion was executed, or an error if the operation failed
§Example
async fn create_user(repo: &UserRepository, user: &User) -> crate::Result<()> {
    repo.insert_with_executor(repo.pool(), user).await
}
§Panics

The method will panic if an ID is present, but it will only do so in debug mode to avoid performance issues. This is so that we don’t insert a duplicate key, if this is the desired behavior you want you can enable the feature insert_duplicate

Source

fn insert_ref_with_executor<'c, 'life0, 'life1, 'async_trait, E>( &'life0 self, tx: E, model: &'life1 M, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where E: Executor<'c, Database = Database> + Send + 'async_trait, Self: Sync + 'async_trait, 'c: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Persists a new model instance to the database.

This method executes the insertion query generated by insert_query with the Executor tx. It handles the actual database interaction and provides a simple interface for creating new records.

§Parameters
  • tx - The executor to use for the query
  • model - A reference to the model instance to insert
§Returns
  • crate::Result<()> - Success if the insertion was executed, or an error if the operation failed
§Example
async fn create_user(repo: &UserRepository, user: &User) -> crate::Result<()> {
    repo.insert_with_executor(repo.pool(), user).await
}
§Panics

The method will panic if an ID is present, but it will only do so in debug mode to avoid performance issues. This is so that we don’t insert a duplicate key, if this is the desired behavior you want you can enable the feature insert_duplicate

Source

fn insert<'life0, 'async_trait>( &'life0 self, model: M, ) -> Pin<Box<dyn Future<Output = Result<M>> + Send + 'async_trait>>
where M: 'async_trait, Self: Sync + 'async_trait, 'life0: 'async_trait,

Persists a new model instance to the database.

This method executes the insertion query generated by insert_query. It handles the actual database interaction and provides a simple interface for creating new records.

§Parameters
  • model - A reference to the model instance to insert
§Returns
  • crate::Result<()> - Success if the insertion was executed, or an error if the operation failed
§Example
async fn create_user(repo: &UserRepository, user: &User) -> crate::Result<()> {
    repo.insert(user).await
}
§Panics

The method will panic if an ID is present, but it will only do so in debug mode to avoid performance issues. This is so that we don’t insert a duplicate key, if this is the desired behavior you want you can enable the feature insert_duplicate

Source

fn insert_ref<'life0, 'life1, 'async_trait>( &'life0 self, model: &'life1 M, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where M: 'async_trait, Self: Sync + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Persists a new model instance to the database.

This method executes the insertion query generated by insert_query. It handles the actual database interaction and provides a simple interface for creating new records.

§Parameters
  • model - A reference to the model instance to insert
§Returns
  • crate::Result<()> - Success if the insertion was executed, or an error if the operation failed
§Example
async fn create_user(repo: &UserRepository, user: &User) -> crate::Result<()> {
    repo.insert(user).await
}
§Panics

The method will panic if an ID is present, but it will only do so in debug mode to avoid performance issues. This is so that we don’t insert a duplicate key, if this is the desired behavior you want you can enable the feature insert_duplicate

Source

fn insert_many<'life0, 'async_trait, I>( &'life0 self, models: I, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where I: IntoIterator<Item = M> + Send + 'async_trait, I::IntoIter: Send, Self: Sync + 'async_trait, 'life0: 'async_trait,

Inserts multiple models using the default batch size.

This is a convenience wrapper around insert_batch that uses DEFAULT_BATCH_SIZE. It provides a simpler interface for bulk insertions when the default batch size is appropriate for the use case.

§Parameters
  • models - An iterator yielding model instances to insert
§Returns
  • crate::Result<()> - Success if all insertions were executed, or an error if any operation failed
§Example
async fn create_users(repo: &UserRepository, users: Vec<User>) -> crate::Result<()> {
    repo.insert_many(users).await
}
Source

fn insert_batch<'life0, 'async_trait, const N: usize, I>( &'life0 self, models: I, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where I: IntoIterator<Item = M> + Send + 'async_trait, I::IntoIter: Send, Self: Sync + 'async_trait, 'life0: 'async_trait,

Performs a batched insertion operation with a specified batch size.

This method uses BatchOperator to efficiently process large numbers of insertions in chunks. It helps prevent memory overflow and maintains optimal database performance by limiting the number of records processed at once.

§Type Parameters
  • N - The size of each batch to process
§Parameters
  • models - An iterator yielding model instances to insert
§Returns
  • crate::Result<()> - Success if all batches were processed, or an error if any operation failed
§Implementation Details

The method:

  1. Chunks the input into batches of size N
  2. Processes each batch in a transactions
  3. Uses the insert_query query for each model
  4. Maintains ACID properties within each batch
§Performance Considerations

Consider batch size carefully:

  • Too small: More overhead from multiple transactions
  • Too large: Higher memory usage and longer transactions times

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementors§