Skip to content

Commit 1bf7ba1

Browse files
committed
WIP - Bringing back canyon_manager as canyon_entities
1 parent af89640 commit 1bf7ba1

22 files changed

Lines changed: 318 additions & 430 deletions

File tree

Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ description.workspace = true
1313
members = [
1414
"canyon_connection",
1515
"canyon_crud",
16+
"canyon_entities",
1617
"canyon_migrations",
1718
"canyon_macros",
1819

@@ -23,6 +24,7 @@ members = [
2324
# Project crates
2425
canyon_connection = { workspace = true, path = "canyon_connection" }
2526
canyon_crud = { workspace = true, path = "canyon_crud" }
27+
canyon_entities = { workspace = true, path = "canyon_entities" }
2628
canyon_migrations = { workspace = true, path = "canyon_migrations", optional = true }
2729
canyon_macros = { workspace = true, path = "canyon_macros" }
2830

@@ -33,6 +35,7 @@ tiberius = { workspace = true, optional = true }
3335
[workspace.dependencies]
3436
canyon_crud = { version = "0.3.1", path = "canyon_crud" }
3537
canyon_connection = { version = "0.3.1", path = "canyon_connection" }
38+
canyon_entities = { version = "0.3.1", path = "canyon_entities" }
3639
canyon_migrations = { version = "0.3.1", path = "canyon_migrations"}
3740
canyon_macros = { version = "0.3.1", path = "canyon_macros" }
3841

@@ -52,6 +55,7 @@ toml = "0.7.3"
5255
async-trait = "0.1.68"
5356
walkdir = "2.3.3"
5457
regex = "1.5"
58+
partialdebug = "0.2.0"
5559

5660
quote = "1.0.9"
5761
proc-macro2 = "1.0.27"
@@ -69,4 +73,4 @@ description = "A Rust ORM and QueryBuilder"
6973
[features]
7074
postgres = ["tokio-postgres", "canyon_connection/postgres", "canyon_crud/postgres", "canyon_migrations/postgres", "canyon_macros/postgres"]
7175
mssql = ["tiberius", "canyon_connection/mssql", "canyon_crud/mssql", "canyon_migrations/mssql", "canyon_macros/mssql"]
72-
migrations = ["canyon_migrations"]
76+
migrations = ["canyon_migrations", "canyon_macros/migrations"]
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use syn::{
1010
use super::entity_fields::EntityField;
1111

1212
/// Provides a convenient way of handling the data on any
13-
/// `CanyonEntity` struct anntotaded with the macro `#[canyon_entity]`
13+
/// `CanyonEntity` struct annotated with the macro `#[canyon_entity]`
1414
#[derive(PartialDebug, Clone)]
1515
pub struct CanyonEntity {
1616
pub struct_name: Ident,
File renamed without changes.
File renamed without changes.
File renamed without changes.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/// This file contains `Rust` types that represents an entry on the `CanyonRegister`
2+
/// where `Canyon` tracks the user types that has to manage
3+
4+
pub const NUMERIC_PK_DATATYPE: [&str; 6] = ["i16", "u16", "i32", "u32", "i64", "u64"];
5+
6+
/// Gets the necessary identifiers of a CanyonEntity to make it the comparative
7+
/// against the database schemas
8+
#[derive(Debug, Clone, Default)]
9+
pub struct CanyonRegisterEntity<'a> {
10+
pub entity_name: &'a str,
11+
pub entity_db_table_name: &'a str,
12+
pub user_schema_name: Option<&'a str>,
13+
pub entity_fields: Vec<CanyonRegisterEntityField>,
14+
}
15+
16+
/// Complementary type for a field that represents a struct field that maps
17+
/// some real database column data
18+
#[derive(Debug, Clone, Default)]
19+
pub struct CanyonRegisterEntityField {
20+
pub field_name: String,
21+
pub field_type: String,
22+
pub annotations: Vec<String>,
23+
}
24+
25+
impl CanyonRegisterEntityField {
26+
/// Return if the field is autoincremental
27+
pub fn is_autoincremental(&self) -> bool {
28+
let has_pk_annotation = self
29+
.annotations
30+
.iter()
31+
.find(|a| a.starts_with("Annotation: PrimaryKey"));
32+
33+
let pk_is_autoincremental = match has_pk_annotation {
34+
Some(annotation) => annotation.contains("true"),
35+
None => false,
36+
};
37+
38+
NUMERIC_PK_DATATYPE.contains(&self.field_type.as_str()) && pk_is_autoincremental
39+
}
40+
41+
/// Return the nullability of a the field
42+
pub fn is_nullable(&self) -> bool {
43+
self.field_type.to_uppercase().starts_with("OPTION")
44+
}
45+
}

canyon_macros/Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@ proc-macro2 = { workspace = true }
1919
futures = { workspace = true }
2020
tokio = { workspace = true }
2121

22-
canyon_migrations = { workspace = true, optional = true }
23-
canyon_crud = { workspace = true }
2422
canyon_connection = { workspace = true }
23+
canyon_crud = { workspace = true }
24+
canyon_entities = { workspace = true }
25+
canyon_migrations = { workspace = true, optional = true }
2526

2627
[features]
2728
postgres = ["canyon_connection/postgres", "canyon_crud/postgres", "canyon_migrations/postgres"]

canyon_macros/src/canyon_macro.rs

Lines changed: 17 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,112 +1,32 @@
11
//! Provides helpers to build the `#[canyon_macros::canyon]` procedural like attribute macro
22
3-
use proc_macro::TokenStream as TokenStream1;
4-
use proc_macro2::{Ident, TokenStream};
5-
3+
use proc_macro2::TokenStream;
64
use quote::quote;
7-
5+
use canyon_connection::CANYON_TOKIO_RUNTIME;
86
use canyon_migrations::{CM_QUERIES_TO_EXECUTE, QUERIES_TO_EXECUTE};
9-
use syn::{Lit, NestedMeta};
10-
11-
#[derive(Debug)]
12-
/// Utilery struct for wrapping the content and result of parsing the attributes on the `canyon` macro
13-
pub struct CanyonMacroAttributes {
14-
pub allowed_migrations: bool,
15-
pub error: Option<TokenStream1>,
16-
}
17-
18-
/// Parses the [`syn::NestedMeta::Meta`] or [`syn::NestedMeta::Lit`] attached to the `canyon` macro
19-
pub fn parse_canyon_macro_attributes(_meta: &Vec<NestedMeta>) -> CanyonMacroAttributes {
20-
let mut res = CanyonMacroAttributes {
21-
allowed_migrations: false,
22-
error: None,
23-
};
24-
25-
for nested_meta in _meta {
26-
match nested_meta {
27-
syn::NestedMeta::Meta(m) => determine_allowed_attributes(m, &mut res),
28-
syn::NestedMeta::Lit(lit) => match lit {
29-
syn::Lit::Str(ref l) => {
30-
res.error = Some(report_literals_not_allowed(&l.value(), lit))
31-
}
32-
syn::Lit::ByteStr(ref l) => {
33-
res.error = Some(report_literals_not_allowed(
34-
&String::from_utf8_lossy(&l.value()),
35-
lit,
36-
))
37-
}
38-
syn::Lit::Byte(ref l) => {
39-
res.error = Some(report_literals_not_allowed(&l.value().to_string(), lit))
40-
}
41-
syn::Lit::Char(ref l) => {
42-
res.error = Some(report_literals_not_allowed(&l.value().to_string(), lit))
43-
}
44-
syn::Lit::Int(ref l) => {
45-
res.error = Some(report_literals_not_allowed(&l.to_string(), lit))
46-
}
47-
syn::Lit::Float(ref l) => {
48-
res.error = Some(report_literals_not_allowed(&l.to_string(), lit))
49-
}
50-
syn::Lit::Bool(ref l) => {
51-
res.error = Some(report_literals_not_allowed(&l.value().to_string(), lit))
52-
}
53-
syn::Lit::Verbatim(ref l) => {
54-
res.error = Some(report_literals_not_allowed(&l.to_string(), lit))
55-
}
56-
},
57-
}
58-
}
7+
use canyon_migrations::migrations::handler::Migrations;
598

60-
res
61-
}
62-
63-
/// Determines whenever a [`syn::NestedMeta::Meta`] it's classified as a valid argument of the `canyon` macro
64-
fn determine_allowed_attributes(meta: &syn::Meta, cma: &mut CanyonMacroAttributes) {
65-
const ALLOWED_ATTRS: [&str; 1] = ["enable_migrations"];
66-
67-
let attr_ident = meta.path().get_ident().unwrap();
68-
let attr_ident_str = attr_ident.to_string();
69-
70-
if attr_ident_str.as_str() == "enable_migrations" {
71-
cma.allowed_migrations = true;
72-
} else {
73-
let error = syn::Error::new_spanned(
74-
Ident::new(&attr_ident_str, attr_ident.span()),
75-
format!(
76-
"No `{attr_ident_str}` arguments allowed in the `Canyon` macro attributes.\n\
77-
Allowed ones are: {ALLOWED_ATTRS:?}"
78-
),
79-
)
80-
.into_compile_error();
81-
cma.error = Some(
82-
quote! {
83-
#error
84-
fn main() {}
85-
}
86-
.into(),
87-
)
88-
}
89-
}
90-
91-
/// Creates a custom error for report not allowed literals on the attribute
92-
/// args of the `canyon` proc macro
93-
fn report_literals_not_allowed(ident: &str, s: &Lit) -> TokenStream1 {
94-
let error = syn::Error::new_spanned(
95-
Ident::new(ident, s.span()),
96-
"No literals allowed in the `Canyon` macro",
97-
)
98-
.into_compile_error();
9+
#[cfg(feature = "migrations")]
10+
pub fn main_with_queries() -> TokenStream {
11+
CANYON_TOKIO_RUNTIME.block_on(async {
12+
canyon_connection::init_connections_cache().await;
13+
Migrations::migrate().await;
14+
});
9915

16+
// The queries to execute at runtime in the managed state
17+
let mut queries_tokens: Vec<TokenStream> = Vec::new();
18+
wire_queries_to_execute(&mut queries_tokens);
10019
quote! {
101-
#error
102-
fn main() {}
20+
{
21+
#(#queries_tokens)*
22+
}
10323
}
104-
.into()
10524
}
10625

10726
/// Creates a TokenScream that is used to load the data generated at compile-time
10827
/// by the `CanyonManaged` macros again on the queries register
109-
pub fn wire_queries_to_execute(canyon_manager_tokens: &mut Vec<TokenStream>) {
28+
#[cfg(feature = "migrations")]
29+
fn wire_queries_to_execute(canyon_manager_tokens: &mut Vec<TokenStream>) {
11030
let cm_data = CM_QUERIES_TO_EXECUTE.lock().unwrap();
11131
let data = QUERIES_TO_EXECUTE.lock().unwrap();
11232

canyon_macros/src/lib.rs

Lines changed: 26 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
extern crate proc_macro;
22

3-
mod canyon_entity_macro;
4-
mod canyon_macro;
5-
mod query_operations;
63
mod utils;
4+
mod query_operations;
5+
mod canyon_entity_macro;
6+
#[cfg(feature = "migrations")] mod canyon_macro;
77

8-
use canyon_connection::CANYON_TOKIO_RUNTIME;
98
use canyon_entity_macro::parse_canyon_entity_proc_macro_attr;
109
use proc_macro::TokenStream as CompilerTokenStream;
1110
use proc_macro2::{Ident, TokenStream};
1211
use quote::{quote, ToTokens};
1312
use syn::{DeriveInput, Fields, Type, Visibility};
1413

14+
#[cfg(feature = "migrations")] use canyon_macro::main_with_queries;
15+
1516
use query_operations::{
1617
delete::{generate_delete_query_tokens, generate_delete_tokens},
1718
insert::{generate_insert_tokens, generate_multiple_insert_tokens},
@@ -22,24 +23,17 @@ use query_operations::{
2223
},
2324
update::{generate_update_query_tokens, generate_update_tokens},
2425
};
25-
26-
use canyon_macro::{parse_canyon_macro_attributes, wire_queries_to_execute};
2726
use utils::{function_parser::FunctionParser, helpers, macro_tokens::MacroTokens};
2827

29-
use canyon_migrations::{
30-
manager::{
31-
entity::CanyonEntity,
32-
manager_builder::{
33-
generate_enum_with_fields, generate_enum_with_fields_values, generate_user_struct,
34-
},
28+
use canyon_entities::{
29+
CANYON_REGISTER_ENTITIES,
30+
entity::CanyonEntity,
31+
manager_builder::{
32+
generate_enum_with_fields, generate_enum_with_fields_values, generate_user_struct,
3533
},
36-
migrations::handler::Migrations,
34+
register_types::{CanyonRegisterEntity, CanyonRegisterEntityField}
3735
};
3836

39-
use canyon_migrations::{
40-
migrations::register_types::{CanyonRegisterEntity, CanyonRegisterEntityField},
41-
CANYON_REGISTER_ENTITIES,
42-
};
4337

4438
/// Macro for handling the entry point to the program.
4539
///
@@ -51,15 +45,6 @@ use canyon_migrations::{
5145
/// the necessary operations for the migrations
5246
#[proc_macro_attribute]
5347
pub fn main(_meta: CompilerTokenStream, input: CompilerTokenStream) -> CompilerTokenStream {
54-
let attrs = syn::parse_macro_input!(_meta as syn::AttributeArgs);
55-
56-
// Parses the attributes declared in the arguments of this proc macro
57-
let attrs_parse_result = parse_canyon_macro_attributes(&attrs);
58-
if attrs_parse_result.error.is_some() {
59-
return attrs_parse_result.error.unwrap();
60-
}
61-
62-
// Parses the function items that this attribute is attached to
6348
let func_res = syn::parse::<FunctionParser>(input);
6449
if func_res.is_err() {
6550
return quote! { fn main() {} }.into();
@@ -70,46 +55,26 @@ pub fn main(_meta: CompilerTokenStream, input: CompilerTokenStream) -> CompilerT
7055
let sign = func.sig;
7156
let body = func.block.stmts;
7257

73-
if attrs_parse_result.allowed_migrations {
74-
CANYON_TOKIO_RUNTIME.block_on(async {
75-
canyon_connection::init_connections_cache().await;
76-
Migrations::migrate().await;
77-
});
78-
79-
// The queries to execute at runtime in the managed state
80-
let mut queries_tokens: Vec<TokenStream> = Vec::new();
81-
wire_queries_to_execute(&mut queries_tokens);
58+
#[allow(unused_mut, unused_assignments)]
59+
let mut migrations_tokens = quote! {};
60+
#[cfg(feature = "migrations")] {
61+
migrations_tokens = main_with_queries();
62+
}
8263

83-
// The final code wired in main()
84-
quote! {
85-
#sign {
86-
canyon_sql::runtime::CANYON_TOKIO_RUNTIME
87-
.handle()
88-
.block_on( async {
89-
canyon_sql::runtime::init_connections_cache().await;
90-
{
91-
#(#queries_tokens)*
92-
}
93-
#(#body)*
94-
}
95-
)
96-
}
97-
}
98-
.into()
99-
} else {
100-
quote! {
101-
#sign {
102-
canyon_sql::runtime::CANYON_TOKIO_RUNTIME
64+
// The final code wired in main()
65+
quote! {
66+
#sign {
67+
canyon_sql::runtime::CANYON_TOKIO_RUNTIME
10368
.handle()
10469
.block_on( async {
105-
canyon_sql::runtime::init_connections_cache().await;
106-
#(#body)*
107-
}
108-
)
109-
}
70+
canyon_sql::runtime::init_connections_cache().await;
71+
#migrations_tokens
72+
#(#body)*
73+
}
74+
)
11075
}
111-
.into()
11276
}
77+
.into()
11378
}
11479

11580
#[proc_macro_attribute]

canyon_macros/src/query_operations/select.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use canyon_migrations::manager::field_annotation::EntityFieldAnnotation;
1+
use canyon_entities::field_annotation::EntityFieldAnnotation;
22

33
use proc_macro2::TokenStream;
44
use quote::quote;

0 commit comments

Comments
 (0)