Compare commits
4 commits
2da8721778
...
e3ce642226
| Author | SHA1 | Date | |
|---|---|---|---|
| e3ce642226 | |||
| 5f45671b74 | |||
| 32ef1f7b33 | |||
| d8624a762d |
6 changed files with 55 additions and 49 deletions
|
|
@ -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 2025 Matthieu Bessat
|
||||
Copyright 2020 LaunchBadge, LLC
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2025 Matthieu Bessat
|
||||
Copyright (c) 2020 LaunchBadge, LLC
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
|
|
|
|||
2
TODO.md
2
TODO.md
|
|
@ -14,7 +14,7 @@
|
|||
- insert
|
||||
- update
|
||||
- delete_by_id
|
||||
- [ ] delete_many
|
||||
- custom queries
|
||||
|
||||
- [ ] Config file for project
|
||||
- configure models path
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use quote::{format_ident, quote};
|
|||
use syn::File;
|
||||
use heck::ToSnakeCase;
|
||||
|
||||
use crate::{generators::repositories::relations::gen_get_many_of_related_entity_method, models::{Field, FieldForeignMode, Model}};
|
||||
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::{SourceNode, SourceNodeContainer};
|
||||
|
||||
|
||||
|
|
@ -242,42 +242,6 @@ 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::<Vec<String>>()
|
||||
.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<SourceNodeContainer> {
|
||||
let resource_name = model.name.clone();
|
||||
|
|
@ -304,7 +268,6 @@ pub fn generate_repository_file(all_models: &[Model], model: &Model) -> Result<S
|
|||
let insert_many_method_code = gen_insert_many_method(model);
|
||||
let update_by_id_method_code = gen_update_by_id_method(model);
|
||||
let delete_by_id_method_code = gen_delete_by_id_method(model);
|
||||
let delete_many_by_id_method_code = gen_delete_many_by_id_method(model);
|
||||
|
||||
|
||||
let query_by_field_methods: Vec<TokenStream> =
|
||||
|
|
@ -332,7 +295,10 @@ pub fn generate_repository_file(all_models: &[Model], model: &Model) -> Result<S
|
|||
match f.foreign_mode { FieldForeignMode::ForeignRef(_) => true, FieldForeignMode::NotRef => false }
|
||||
).collect();
|
||||
let related_entity_methods_codes: Vec<TokenStream> = fields_with_foreign_refs.iter().map(|field|
|
||||
gen_get_many_of_related_entity_method(model, &field)
|
||||
gen_get_many_by_related_entity_method(model, &field)
|
||||
).collect();
|
||||
let related_entities_methods_codes: Vec<TokenStream> = fields_with_foreign_refs.iter().map(|field|
|
||||
gen_get_many_by_related_entities_method(all_models, model, &field)
|
||||
).collect();
|
||||
|
||||
// TODO: add import line
|
||||
|
|
@ -365,13 +331,13 @@ pub fn generate_repository_file(all_models: &[Model], model: &Model) -> Result<S
|
|||
|
||||
#delete_by_id_method_code
|
||||
|
||||
#delete_many_by_id_method_code
|
||||
|
||||
#(#query_by_field_methods)*
|
||||
|
||||
#(#query_many_by_field_methods)*
|
||||
|
||||
#(#related_entity_methods_codes)*
|
||||
|
||||
#(#related_entities_methods_codes)*
|
||||
}
|
||||
};
|
||||
// convert TokenStream into rust code as string
|
||||
|
|
|
|||
|
|
@ -3,9 +3,7 @@ use quote::{format_ident, quote};
|
|||
|
||||
use crate::models::{Field, FieldForeignMode, Model};
|
||||
|
||||
/// 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 {
|
||||
pub fn gen_get_many_by_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 {
|
||||
|
|
@ -17,7 +15,7 @@ pub fn gen_get_many_of_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_of_{}", foreign_ref_params.target_resource_name);
|
||||
let func_name_ident = format_ident!("get_many_{}_by_{}", foreign_ref_params.reverse_relation_name, foreign_ref_params.target_resource_name);
|
||||
|
||||
quote! {
|
||||
pub async fn #func_name_ident(&self, item_id: &str) -> Result<Vec<#resource_ident>, sqlx::Error> {
|
||||
|
|
@ -29,3 +27,45 @@ pub fn gen_get_many_of_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<String>) -> Result<Vec<#resource_ident>, sqlx::Error> {
|
||||
if items_ids.is_empty() {
|
||||
return Ok(vec![])
|
||||
}
|
||||
let placeholder_params: String = (1..=(items_ids.len()))
|
||||
.map(|i| format!("${i}"))
|
||||
.collect::<Vec<String>>()
|
||||
.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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -248,7 +248,7 @@ pub fn parse_models(source_code_path: &Path) -> Result<Vec<Model>> {
|
|||
output_field.foreign_mode = FieldForeignMode::ForeignRef(
|
||||
ForeignRefParams {
|
||||
reverse_relation_name: rrn,
|
||||
target_resource_name: target_type_name.to_case(Case::Snake)
|
||||
target_resource_name: target_type_name.to_lowercase()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue