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 theModel
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
- Required method:
insert_query
- Defines how a model is translated into an INSERT statement - Provided methods:
insert_with_executor
- Inserts a single model using anyExecutor
insert
- Inserts a single modelinsert_many
- Inserts multiple models using the default batch sizeinsert_batch
- Inserts multiple models with a custom batch size
- All batch operations use transactions to ensure data consistency
- Performance is optimized through batching and connection pooling
Required Methods§
Sourcefn insert_query(model: &M) -> Query<'_>
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:
- Handle all model fields appropriately
- Use proper SQL parameter binding for safety
- Return an appropriate error if the model is invalid
Provided Methods§
Sourcefn insert_with_executor<'c, 'life0, 'async_trait, E>(
&'life0 self,
tx: E,
model: M,
) -> Pin<Box<dyn Future<Output = Result<M>> + Send + 'async_trait>>
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>>
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 querymodel
- 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
Sourcefn 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>>
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>>
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 querymodel
- 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
Sourcefn 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<'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
Sourcefn 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_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
Sourcefn 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_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
}
Sourcefn 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,
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:
- Chunks the input into batches of size N
- Processes each batch in a transactions
- Uses the
insert_query
query for each model - 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.