diff --git a/LICENSE-APACHE b/LICENSE-APACHE index 9703b5e..33b21f4 100644 --- a/LICENSE-APACHE +++ b/LICENSE-APACHE @@ -186,7 +186,7 @@ file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. -Copyright 2020 LaunchBadge, LLC +Copyright 2025 Matthieu Bessat Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/LICENSE-MIT b/LICENSE-MIT index 861bf60..3f18273 100644 --- a/LICENSE-MIT +++ b/LICENSE-MIT @@ -1,4 +1,4 @@ -Copyright (c) 2020 LaunchBadge, LLC +Copyright (c) 2025 Matthieu Bessat Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated diff --git a/TODO.md b/TODO.md index c00fc17..5339cc5 100644 --- a/TODO.md +++ b/TODO.md @@ -14,7 +14,7 @@ - insert - update - delete_by_id - - custom queries +- [ ] delete_many - [ ] Config file for project - configure models path diff --git a/lib/sqlxgentools_cli/src/generators/repositories/base.rs b/lib/sqlxgentools_cli/src/generators/repositories/base.rs index 340229d..d2f3609 100644 --- a/lib/sqlxgentools_cli/src/generators/repositories/base.rs +++ b/lib/sqlxgentools_cli/src/generators/repositories/base.rs @@ -4,7 +4,7 @@ use quote::{format_ident, quote}; use syn::File; use heck::ToSnakeCase; -use crate::{generators::repositories::relations::{gen_get_many_by_related_entities_method, gen_get_many_by_related_entity_method}, models::{Field, FieldForeignMode, Model}}; +use crate::{generators::repositories::relations::gen_get_many_of_related_entity_method, models::{Field, FieldForeignMode, Model}}; use crate::generators::{SourceNode, SourceNodeContainer}; @@ -242,6 +242,42 @@ fn gen_delete_by_id_method(model: &Model) -> TokenStream { } } +fn gen_delete_many_by_id_method(model: &Model) -> TokenStream { + let primary_key = &model.fields.iter() + .find(|f| f.is_primary) + .expect("A model must have at least one primary key") + .name; + + let func_name_ident = format_ident!("delete_many_by_{}", primary_key); + let delete_query_tmpl = format!( + "DELETE FROM {} WHERE {} IN ({{}})", + model.table_name, + primary_key + ); + + quote! { + pub async fn #func_name_ident(&self, ids: &[&str]) -> Result<(), sqlx::Error> { + if ids.is_empty() { + return Ok(()) + } + let placeholder_params: String = (1..=(ids.len())) + .map(|i| format!("${}", i)) + .collect::>() + .join(","); + let query_sql = format!(#delete_query_tmpl, placeholder_params); + let mut query = sqlx::query(&query_sql); + for item_id in ids { + query = query.bind(item_id) + } + query + .execute(&self.db.0) + .await?; + + Ok(()) + } + } +} + pub fn generate_repository_file(all_models: &[Model], model: &Model) -> Result { let resource_name = model.name.clone(); @@ -268,6 +304,7 @@ pub fn generate_repository_file(all_models: &[Model], model: &Model) -> Result = @@ -295,10 +332,7 @@ pub fn generate_repository_file(all_models: &[Model], model: &Model) -> Result true, FieldForeignMode::NotRef => false } ).collect(); let related_entity_methods_codes: Vec = fields_with_foreign_refs.iter().map(|field| - gen_get_many_by_related_entity_method(model, &field) - ).collect(); - let related_entities_methods_codes: Vec = fields_with_foreign_refs.iter().map(|field| - gen_get_many_by_related_entities_method(all_models, model, &field) + gen_get_many_of_related_entity_method(model, &field) ).collect(); // TODO: add import line @@ -331,13 +365,13 @@ pub fn generate_repository_file(all_models: &[Model], model: &Model) -> Result TokenStream { +/// method that can be used to retreive a list of entities of type X that are the children of a parent type Y +/// ex: get all comments of a post +pub fn gen_get_many_of_related_entity_method(model: &Model, foreign_key_field: &Field) -> TokenStream { let resource_ident = format_ident!("{}", &model.name); let foreign_ref_params = match &foreign_key_field.foreign_mode { @@ -15,7 +17,7 @@ pub fn gen_get_many_by_related_entity_method(model: &Model, foreign_key_field: & let select_query = format!("SELECT * FROM {} WHERE {} = $1", model.table_name, foreign_key_field.name); - let func_name_ident = format_ident!("get_many_{}_by_{}", foreign_ref_params.reverse_relation_name, foreign_ref_params.target_resource_name); + let func_name_ident = format_ident!("get_many_of_{}", foreign_ref_params.target_resource_name); quote! { pub async fn #func_name_ident(&self, item_id: &str) -> Result, sqlx::Error> { @@ -27,45 +29,3 @@ pub fn gen_get_many_by_related_entity_method(model: &Model, foreign_key_field: & } } -pub fn gen_get_many_by_related_entities_method(all_models: &[Model], model: &Model, foreign_key_field: &Field) -> TokenStream { - let resource_ident = format_ident!("{}", &model.name); - - let foreign_ref_params = match &foreign_key_field.foreign_mode { - FieldForeignMode::ForeignRef(params) => params, - FieldForeignMode::NotRef => { - panic!("Expected foreign key"); - } - }; - - let select_query = format!("SELECT * FROM {} WHERE {} IN ({{}})", model.table_name, foreign_key_field.name); - - let target_resource = all_models.iter() - .find(|m| m.name.to_lowercase() == foreign_ref_params.target_resource_name.to_lowercase()) - .expect("Could not find foreign ref target type associated resource"); - - let func_name_ident = format_ident!("get_many_{}_by_{}", foreign_ref_params.reverse_relation_name, target_resource.table_name); - - quote! { - pub async fn #func_name_ident(&self, items_ids: Vec) -> Result, sqlx::Error> { - if items_ids.is_empty() { - return Ok(vec![]) - } - let placeholder_params: String = (1..=(items_ids.len())) - .map(|i| format!("${i}")) - .collect::>() - .join(","); - let query_tmpl = format!( - #select_query, - placeholder_params - ); - let mut query = sqlx::query_as::<_, #resource_ident>(&query_tmpl); - for id in items_ids { - query = query.bind(id) - } - - query - .fetch_all(&self.db.0) - .await - } - } -} diff --git a/lib/sqlxgentools_cli/src/parse_models.rs b/lib/sqlxgentools_cli/src/parse_models.rs index 396bbb7..bea7a43 100644 --- a/lib/sqlxgentools_cli/src/parse_models.rs +++ b/lib/sqlxgentools_cli/src/parse_models.rs @@ -248,7 +248,7 @@ pub fn parse_models(source_code_path: &Path) -> Result> { output_field.foreign_mode = FieldForeignMode::ForeignRef( ForeignRefParams { reverse_relation_name: rrn, - target_resource_name: target_type_name.to_lowercase() + target_resource_name: target_type_name.to_case(Case::Snake) } ); }