use awa::adapter::postgres::{prepare_job_insert, prepare_raw_job_insert, PreparedJobInsert};
use awa::{map_sqlx_error, AwaError, Client, ClientBuilder, InsertOpts, JobArgs, JobRow};
use sea_orm::{ConnectionTrait, DatabaseConnection, DbErr, Statement};
use sqlx::FromRow;
use sqlx::PgPool;
use std::sync::Arc;
pub trait SeaOrmAwaExt {
fn awa_pool(&self) -> &PgPool;
fn awa_client_builder(&self) -> ClientBuilder;
}
impl SeaOrmAwaExt for DatabaseConnection {
fn awa_pool(&self) -> &PgPool {
self.get_postgres_connection_pool()
}
fn awa_client_builder(&self) -> ClientBuilder {
Client::builder(self.awa_pool().clone())
}
}
pub fn pool(connection: &DatabaseConnection) -> &PgPool {
connection.awa_pool()
}
pub fn client_builder(connection: &DatabaseConnection) -> ClientBuilder {
connection.awa_client_builder()
}
pub async fn migrate(connection: &DatabaseConnection) -> Result<(), AwaError> {
awa::migrations::run(connection.awa_pool()).await
}
pub async fn insert<C>(connection: &C, args: &impl JobArgs) -> Result<JobRow, AwaError>
where
C: ConnectionTrait,
{
insert_with(connection, args, InsertOpts::default()).await
}
pub async fn insert_with<C>(
connection: &C,
args: &impl JobArgs,
opts: InsertOpts,
) -> Result<JobRow, AwaError>
where
C: ConnectionTrait,
{
let prepared = prepare_job_insert(args, opts)?;
insert_prepared(connection, &prepared).await
}
pub async fn insert_raw<C>(
connection: &C,
kind: impl Into<String>,
args: impl Into<serde_json::Value>,
opts: InsertOpts,
) -> Result<JobRow, AwaError>
where
C: ConnectionTrait,
{
let prepared = prepare_raw_job_insert(kind, args, opts)?;
insert_prepared(connection, &prepared).await
}
async fn insert_prepared<C>(
connection: &C,
prepared: &PreparedJobInsert,
) -> Result<JobRow, AwaError>
where
C: ConnectionTrait,
{
let unique_key = prepared.unique_key().map(<[u8]>::to_vec);
let unique_states = prepared.unique_states_bit_string().map(ToOwned::to_owned);
let ordering_key = prepared.ordering_key().map(<[u8]>::to_vec);
let statement = Statement::from_sql_and_values(
connection.get_database_backend(),
awa::adapter::postgres::INSERT_JOB_SQL,
vec![
prepared.kind().into(),
prepared.queue().into(),
prepared.args().clone().into(),
prepared.state_db_str().into(),
prepared.priority().into(),
prepared.max_attempts().into(),
prepared.run_at().into(),
prepared.metadata().clone().into(),
prepared.tags().to_vec().into(),
unique_key.into(),
unique_states.into(),
ordering_key.into(),
],
);
let result = connection
.query_one_raw(statement)
.await
.map_err(map_db_err)?
.ok_or_else(|| {
AwaError::Database(sqlx::Error::Protocol(
"insert_job_compat returned no row".to_string(),
))
})?;
let row = result.try_as_pg_row().ok_or_else(|| {
AwaError::Database(sqlx::Error::Protocol(
"expected a PostgreSQL row from the insert".to_string(),
))
})?;
JobRow::from_row(row).map_err(AwaError::from)
}
fn map_db_err(err: DbErr) -> AwaError {
match err {
DbErr::Exec(sea_orm::RuntimeErr::SqlxError(err))
| DbErr::Query(sea_orm::RuntimeErr::SqlxError(err))
| DbErr::Conn(sea_orm::RuntimeErr::SqlxError(err)) => match Arc::try_unwrap(err) {
Ok(err) => map_sqlx_error(err),
Err(err) => AwaError::Database(sqlx::Error::Protocol(err.to_string())),
},
other => AwaError::Database(sqlx::Error::Protocol(other.to_string())),
}
}