mirror of
https://github.com/Phundrak/georm.git
synced 2025-11-30 19:03:59 +00:00
feat: enable transaction support via sqlx::Executor
This commit abstracts the database operations to use the generic `sqlx::Executor` trait instead of a concrete `&sqlx::PgPool`. This change allows all generated methods (find, create, update, delete, and relationships) to be executed within a `sqlx::Transaction`, in addition to a connection pool. This is a crucial feature for ensuring atomic operations and data consistency. The public-facing traits `Georm` and `Defaultable` have been updated to require `sqlx::Executor`, and the documentation has been updated to reflect this new capability.
This commit is contained in:
@@ -94,7 +94,10 @@ fn generate_defaultable_trait_impl(
|
||||
|
||||
quote! {
|
||||
impl ::georm::Defaultable<#id_type, #struct_name> for #defaultable_struct_name {
|
||||
async fn create(&self, pool: &::sqlx::PgPool) -> ::sqlx::Result<#struct_name> {
|
||||
async fn create<'e, E>(&self, mut executor: E) -> ::sqlx::Result<#struct_name>
|
||||
where
|
||||
E: ::sqlx::Executor<'e, Database = ::sqlx::Postgres>
|
||||
{
|
||||
let mut dynamic_fields = Vec::new();
|
||||
|
||||
#(#field_checks)*
|
||||
@@ -121,7 +124,7 @@ fn generate_defaultable_trait_impl(
|
||||
// Then bind defaultable fields that have values
|
||||
#(#bind_checks)*
|
||||
|
||||
query_builder.fetch_one(pool).await
|
||||
query_builder.fetch_one(executor).await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,8 +71,11 @@ WHERE local.{} = $1",
|
||||
value.local.id
|
||||
);
|
||||
quote! {
|
||||
pub async fn #function(&self, pool: &::sqlx::PgPool) -> ::sqlx::Result<Vec<#entity>> {
|
||||
::sqlx::query_as!(#entity, #query, self.get_id()).fetch_all(pool).await
|
||||
pub async fn #function<'e, E>(&self, mut executor: E) -> ::sqlx::Result<Vec<#entity>>
|
||||
where
|
||||
E: ::sqlx::Executor<'e, Database = ::sqlx::Postgres>
|
||||
{
|
||||
::sqlx::query_as!(#entity, #query, self.get_id()).fetch_all(executor).await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,8 +172,11 @@ impl From<&GeormField> for proc_macro2::TokenStream {
|
||||
quote! { fetch_one }
|
||||
};
|
||||
quote! {
|
||||
pub async fn #function(&self, pool: &::sqlx::PgPool) -> ::sqlx::Result<#return_type> {
|
||||
::sqlx::query_as!(#entity, #query, self.#local_ident).#fetch(pool).await
|
||||
pub async fn #function<'e, E>(&self, mut executor: E) -> ::sqlx::Result<#return_type>
|
||||
where
|
||||
E: ::sqlx::Executor<'e, Database = ::sqlx::Postgres>
|
||||
{
|
||||
::sqlx::query_as!(#entity, #query, self.#local_ident).#fetch(executor).await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,8 +45,11 @@ impl From<&SimpleRelationship<OneToOne>> for proc_macro2::TokenStream {
|
||||
let entity = &value.entity;
|
||||
let function = value.make_function_name();
|
||||
quote! {
|
||||
pub async fn #function(&self, pool: &::sqlx::PgPool) -> ::sqlx::Result<Option<#entity>> {
|
||||
::sqlx::query_as!(#entity, #query, self.get_id()).fetch_optional(pool).await
|
||||
pub async fn #function<'e, E>(&self, mut executor: E) -> ::sqlx::Result<Option<#entity>>
|
||||
where
|
||||
E: ::sqlx::Executor<'e, Database = ::sqlx::Postgres>
|
||||
{
|
||||
::sqlx::query_as!(#entity, #query, self.get_id()).fetch_optional(executor).await
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,8 +61,11 @@ impl From<&SimpleRelationship<OneToMany>> for proc_macro2::TokenStream {
|
||||
let entity = &value.entity;
|
||||
let function = value.make_function_name();
|
||||
quote! {
|
||||
pub async fn #function(&self, pool: &::sqlx::PgPool) -> ::sqlx::Result<Vec<#entity>> {
|
||||
::sqlx::query_as!(#entity, #query, self.get_id()).fetch_all(pool).await
|
||||
pub async fn #function<'e, E>(&self, mut executor: E) -> ::sqlx::Result<Vec<#entity>>
|
||||
where
|
||||
E: ::sqlx::Executor<'e, Database = ::sqlx::Postgres>
|
||||
{
|
||||
::sqlx::query_as!(#entity, #query, self.get_id()).fetch_all(executor).await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,13 +21,16 @@ pub fn generate_create_query(table_name: &str, fields: &[GeormField]) -> proc_ma
|
||||
placeholders.join(", ")
|
||||
);
|
||||
quote! {
|
||||
async fn create(&self, pool: &::sqlx::PgPool) -> ::sqlx::Result<Self> {
|
||||
async fn create<'e, E>(&self, mut executor: E) -> ::sqlx::Result<Self>
|
||||
where
|
||||
E: ::sqlx::Executor<'e, Database = ::sqlx::Postgres>
|
||||
{
|
||||
::sqlx::query_as!(
|
||||
Self,
|
||||
#query,
|
||||
#(self.#field_idents),*
|
||||
)
|
||||
.fetch_one(pool)
|
||||
.fetch_one(executor)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,16 +24,22 @@ pub fn generate_delete_query(table: &str, id: &IdType) -> proc_macro2::TokenStre
|
||||
};
|
||||
let delete_string = format!("DELETE FROM {table} WHERE {where_clause}");
|
||||
quote! {
|
||||
async fn delete_by_id(pool: &::sqlx::PgPool, id: &#id_type) -> ::sqlx::Result<u64> {
|
||||
async fn delete<'e, E>(&self, mut executor: E) -> ::sqlx::Result<u64>
|
||||
where
|
||||
E: ::sqlx::Executor<'e, Database = ::sqlx::Postgres>
|
||||
{
|
||||
Self::delete_by_id(executor, &self.get_id()).await
|
||||
}
|
||||
|
||||
async fn delete_by_id<'e, E>(mut executor: E, id: &#id_type) -> ::sqlx::Result<u64>
|
||||
where
|
||||
E: ::sqlx::Executor<'e, Database = ::sqlx::Postgres>
|
||||
{
|
||||
let rows_affected = ::sqlx::query!(#delete_string, #query_args)
|
||||
.execute(pool)
|
||||
.execute(executor)
|
||||
.await?
|
||||
.rows_affected();
|
||||
Ok(rows_affected)
|
||||
}
|
||||
|
||||
async fn delete(&self, pool: &::sqlx::PgPool) -> ::sqlx::Result<u64> {
|
||||
Self::delete_by_id(pool, &self.get_id()).await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,11 @@ use quote::quote;
|
||||
pub fn generate_find_all_query(table: &str) -> proc_macro2::TokenStream {
|
||||
let find_string = format!("SELECT * FROM {table}");
|
||||
quote! {
|
||||
async fn find_all(pool: &::sqlx::PgPool) -> ::sqlx::Result<Vec<Self>> {
|
||||
::sqlx::query_as!(Self, #find_string).fetch_all(pool).await
|
||||
async fn find_all<'e, E>(mut executor: E) -> ::sqlx::Result<Vec<Self>>
|
||||
where
|
||||
E: ::sqlx::Executor<'e, Database = ::sqlx::Postgres>
|
||||
{
|
||||
::sqlx::query_as!(Self, #find_string).fetch_all(executor).await
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,10 +21,13 @@ pub fn generate_find_query(table: &str, id: &IdType) -> proc_macro2::TokenStream
|
||||
} => {
|
||||
let find_string = format!("SELECT * FROM {table} WHERE {} = $1", field_name);
|
||||
quote! {
|
||||
async fn find(pool: &::sqlx::PgPool, id: &#field_type) -> ::sqlx::Result<Option<Self>> {
|
||||
async fn find<'e, E>(mut executor: E, id: &#field_type) -> ::sqlx::Result<Option<Self>>
|
||||
where
|
||||
E: ::sqlx::Executor<'e, Database = ::sqlx::Postgres>
|
||||
{
|
||||
::sqlx::query_as!(Self, #find_string, id)
|
||||
.fetch_optional(pool)
|
||||
.await
|
||||
.fetch_optional(executor)
|
||||
.await
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,10 +42,13 @@ pub fn generate_find_query(table: &str, id: &IdType) -> proc_macro2::TokenStream
|
||||
fields.iter().map(|field| field.name.clone()).collect();
|
||||
let find_string = format!("SELECT * FROM {table} WHERE {id_match_string}");
|
||||
quote! {
|
||||
async fn find(pool: &::sqlx::PgPool, id: &#field_type) -> ::sqlx::Result<Option<Self>> {
|
||||
async fn find<'e, E>(mut executor: E, id: &#field_type) -> ::sqlx::Result<Option<Self>>
|
||||
where
|
||||
E: ::sqlx::Executor<'e, Database = ::sqlx::Postgres>
|
||||
{
|
||||
::sqlx::query_as!(Self, #find_string, #(id.#id_members),*)
|
||||
.fetch_optional(pool)
|
||||
.await
|
||||
.fetch_optional(executor)
|
||||
.await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,14 +28,17 @@ pub fn generate_update_query(table_name: &str, fields: &[GeormField]) -> proc_ma
|
||||
where_clauses.join(" AND ")
|
||||
);
|
||||
quote! {
|
||||
async fn update(&self, pool: &::sqlx::PgPool) -> ::sqlx::Result<Self> {
|
||||
async fn update<'e, E>(&self, mut executor: E) -> ::sqlx::Result<Self>
|
||||
where
|
||||
E: ::sqlx::Executor<'e, Database = ::sqlx::Postgres>
|
||||
{
|
||||
::sqlx::query_as!(
|
||||
Self,
|
||||
#query,
|
||||
#(self.#update_idents),*,
|
||||
#(self.#id_idents),*
|
||||
)
|
||||
.fetch_one(pool)
|
||||
.fetch_one(executor)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,13 +44,16 @@ pub fn generate_upsert_query(
|
||||
let field_idents: Vec<syn::Ident> = fields.iter().map(|f| f.ident.clone()).collect();
|
||||
|
||||
quote! {
|
||||
async fn create_or_update(&self, pool: &::sqlx::PgPool) -> ::sqlx::Result<Self> {
|
||||
async fn create_or_update<'e, E>(&self, mut executor: E) -> ::sqlx::Result<Self>
|
||||
where
|
||||
E: ::sqlx::Executor<'e, Database = ::sqlx::Postgres>
|
||||
{
|
||||
::sqlx::query_as!(
|
||||
Self,
|
||||
#upsert_string,
|
||||
#(self.#field_idents),*
|
||||
)
|
||||
.fetch_one(pool)
|
||||
.fetch_one(executor)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user