├── next ├── .env ├── taitan-orm │ ├── src │ │ ├── api_macro │ │ │ ├── extractor.rs │ │ │ └── mod.rs │ │ ├── api │ │ │ └── mod.rs │ │ ├── database │ │ │ ├── mysql │ │ │ │ ├── commanders │ │ │ │ │ ├── mod.rs │ │ │ │ │ ├── template.rs │ │ │ │ │ ├── read.rs │ │ │ │ │ └── write.rs │ │ │ │ ├── mod.rs │ │ │ │ ├── database.rs │ │ │ │ ├── transaction.rs │ │ │ │ └── extractor.rs │ │ │ ├── postgres │ │ │ │ ├── commanders │ │ │ │ │ ├── mod.rs │ │ │ │ │ ├── template.rs │ │ │ │ │ ├── write.rs │ │ │ │ │ └── read.rs │ │ │ │ ├── mod.rs │ │ │ │ ├── database.rs │ │ │ │ └── transaction.rs │ │ │ ├── mod.rs │ │ │ └── sqlite │ │ │ │ ├── commanders │ │ │ │ └── mod.rs │ │ │ │ ├── mod.rs │ │ │ │ └── config.rs │ │ ├── dto │ │ │ ├── mod.rs │ │ │ └── count.rs │ │ ├── result.rs │ │ ├── sql_generator_container.rs │ │ ├── db.rs │ │ ├── error.rs │ │ ├── extractor.rs │ │ └── lib.rs │ ├── tests │ │ ├── entities │ │ │ └── mod.rs │ │ ├── integration_tests.rs │ │ ├── macros │ │ │ ├── mod.rs │ │ │ ├── entity_spec.rs │ │ │ └── template_spec.rs │ │ └── sqlite │ │ │ └── mod.rs │ └── Cargo.toml ├── test.sh ├── taitan-orm-macro │ ├── src │ │ ├── util │ │ │ ├── parser.rs │ │ │ ├── mod.rs │ │ │ ├── life_time_checker.rs │ │ │ └── copy_struct.rs │ │ ├── attrs │ │ │ └── mod.rs │ │ ├── types │ │ │ ├── mod.rs │ │ │ └── extractor.rs │ │ ├── fields │ │ │ ├── selected_parser.rs │ │ │ ├── selection_parser.rs │ │ │ ├── table_name_parser.rs │ │ │ ├── mappers │ │ │ │ ├── mod.rs │ │ │ │ ├── row_constructor.rs │ │ │ │ └── struct_constructor.rs │ │ │ ├── mod.rs │ │ │ ├── location_parser.rs │ │ │ ├── fields_mapper.rs │ │ │ ├── mutation_parser.rs │ │ │ └── unique_parser.rs │ │ ├── template.rs │ │ ├── lib.rs │ │ ├── expands │ │ │ ├── mod.rs │ │ │ ├── selection_expander.rs │ │ │ └── location_expander.rs │ │ └── schema.rs │ └── Cargo.toml ├── taitan-orm-trait │ ├── src │ │ ├── schema.rs │ │ ├── join │ │ │ ├── from_clause.rs │ │ │ ├── joined_query.rs │ │ │ ├── mod.rs │ │ │ ├── joined_condition_part.rs │ │ │ ├── joined_mode.rs │ │ │ ├── joined_condition_array.rs │ │ │ ├── joined_field.rs │ │ │ └── joined_condition.rs │ │ ├── page │ │ │ ├── mod.rs │ │ │ ├── count_sql.rs │ │ │ ├── paged_info.rs │ │ │ ├── paged_list.rs │ │ │ └── pagination.rs │ │ ├── template │ │ │ ├── mod.rs │ │ │ └── template_value.rs │ │ ├── location │ │ │ ├── located_query.rs │ │ │ ├── mod.rs │ │ │ ├── location_expr.rs │ │ │ ├── cmp_operator.rs │ │ │ └── location.rs │ │ ├── selection.rs │ │ ├── write_command.rs │ │ ├── error.rs │ │ ├── update_command.rs │ │ ├── lib.rs │ │ ├── entity.rs │ │ ├── field.rs │ │ ├── unique.rs │ │ ├── template_record.rs │ │ ├── selected.rs │ │ └── mutation.rs │ └── Cargo.toml ├── lines.sh ├── plan.md └── Cargo.toml ├── old ├── luna-types │ ├── src │ │ ├── sqlx │ │ │ ├── supported │ │ │ ├── supports │ │ │ │ ├── mod.rs │ │ │ │ └── integer.rs │ │ │ ├── mod.rs │ │ │ └── field.rs │ │ ├── field │ │ │ ├── supports │ │ │ │ ├── mod.rs │ │ │ │ ├── integer.rs │ │ │ │ └── string.rs │ │ │ ├── mod.rs │ │ │ ├── named.rs │ │ │ └── valid.rs │ │ ├── constraint │ │ │ ├── supports │ │ │ │ ├── mod.rs │ │ │ │ └── datetime.rs │ │ │ ├── mod.rs │ │ │ ├── common.rs │ │ │ └── error.rs │ │ ├── record │ │ │ ├── mod.rs │ │ │ ├── entity_record.rs │ │ │ └── record.rs │ │ ├── lib.rs │ │ └── schema.rs │ ├── tests │ │ ├── sqlx.rs │ │ ├── field.rs │ │ ├── constraint.rs │ │ ├── string.rs │ │ └── integer.rs │ ├── Cargo.toml │ └── README.md ├── luna-orm-trait │ ├── src │ │ ├── order.rs │ │ ├── request.rs │ │ ├── input_generator.rs │ │ ├── timer.rs │ │ ├── field_type.rs │ │ ├── field.rs │ │ └── utils.rs │ ├── tests │ │ └── trait_test.rs │ ├── Cargo.toml │ └── README.md ├── examples │ ├── crud │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ ├── sqlite │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ ├── transaction │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ ├── mysql │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ ├── template │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ └── input │ │ ├── Cargo.toml │ │ └── src │ │ └── main.rs ├── luna-orm-macro │ ├── src │ │ ├── into_arguments.rs │ │ ├── entity_trait.rs │ │ ├── timer.rs │ │ ├── type_extract.rs │ │ ├── order_by.rs │ │ ├── gen_arguments.rs │ │ ├── selected_entity.rs │ │ ├── auto_entity.rs │ │ ├── selection.rs │ │ ├── type_check.rs │ │ ├── primary.rs │ │ ├── mutation.rs │ │ ├── lib.rs │ │ └── field_mapper.rs │ └── Cargo.toml ├── luna-orm │ ├── src │ │ ├── main.rs │ │ ├── database │ │ │ ├── mod.rs │ │ │ ├── mysql │ │ │ │ └── MySqlInputGenerator.rs │ │ │ └── mysql.rs │ │ ├── error.rs │ │ ├── lib.rs │ │ └── command_executor2.rs │ ├── tests │ │ ├── common │ │ │ ├── mod.rs │ │ │ ├── mutex.rs │ │ │ ├── logger.rs │ │ │ ├── schema.rs │ │ │ └── setup_database.rs │ │ ├── timer.rs │ │ ├── insert.rs │ │ ├── entity.rs │ │ └── create.rs │ └── Cargo.toml ├── script │ └── lines.sh ├── luna-orm-dynamic │ ├── src │ │ ├── lib.rs │ │ ├── active_json.rs │ │ └── active_entity.rs │ ├── Cargo.toml │ └── tests │ │ ├── record.rs │ │ └── field.rs ├── luna-orm-axum │ ├── src │ │ ├── lib.rs │ │ ├── generator.rs │ │ ├── router.rs │ │ ├── schema.rs │ │ ├── response.rs │ │ └── field_type.rs │ ├── Cargo.toml │ └── tests │ │ ├── axum_router.rs │ │ └── schema.rs └── Cargo.toml ├── docs └── concept.png ├── .github └── workflows │ └── rust.yml └── .gitignore /next/.env: -------------------------------------------------------------------------------- 1 | TEST_THREADS=1 -------------------------------------------------------------------------------- /old/luna-types/src/sqlx/supported: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /old/luna-types/tests/sqlx.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /old/luna-orm-trait/src/order.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /next/taitan-orm/src/api_macro/extractor.rs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /next/test.sh: -------------------------------------------------------------------------------- 1 | cargo test -- --test-threads=1 -------------------------------------------------------------------------------- /old/examples/crud/.gitignore: -------------------------------------------------------------------------------- 1 | /workspace 2 | -------------------------------------------------------------------------------- /old/luna-orm-macro/src/into_arguments.rs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /next/taitan-orm-macro/src/util/parser.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /old/examples/sqlite/.gitignore: -------------------------------------------------------------------------------- 1 | /workspace 2 | -------------------------------------------------------------------------------- /old/examples/transaction/.gitignore: -------------------------------------------------------------------------------- 1 | /workspace 2 | -------------------------------------------------------------------------------- /old/luna-types/src/sqlx/supports/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod integer; -------------------------------------------------------------------------------- /next/taitan-orm-trait/src/schema.rs: -------------------------------------------------------------------------------- 1 | pub trait Schema {} 2 | -------------------------------------------------------------------------------- /old/luna-orm-macro/src/entity_trait.rs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /old/luna-types/src/sqlx/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod field; 2 | pub mod supports; 3 | -------------------------------------------------------------------------------- /next/lines.sh: -------------------------------------------------------------------------------- 1 | find . -name "*.rs" -not -path "./target/*" | xargs wc -l 2 | -------------------------------------------------------------------------------- /old/luna-types/src/field/supports/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod integer; 2 | pub mod string; -------------------------------------------------------------------------------- /old/luna-orm/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("Hello, world!"); 3 | } 4 | -------------------------------------------------------------------------------- /old/script/lines.sh: -------------------------------------------------------------------------------- 1 | find .. -name "*.rs" -not -path "../target/*" | xargs wc -l 2 | -------------------------------------------------------------------------------- /docs/concept.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thegenius/luna-orm/HEAD/docs/concept.png -------------------------------------------------------------------------------- /next/taitan-orm/src/api/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod writer; 2 | pub mod reader; 3 | pub mod template; -------------------------------------------------------------------------------- /next/taitan-orm/tests/entities/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod user; 2 | pub mod user2; 3 | pub mod user3; 4 | -------------------------------------------------------------------------------- /next/taitan-orm/tests/integration_tests.rs: -------------------------------------------------------------------------------- 1 | mod entities; 2 | mod macros; 3 | mod sqlite; 4 | -------------------------------------------------------------------------------- /next/taitan-orm/src/database/mysql/commanders/mod.rs: -------------------------------------------------------------------------------- 1 | mod write; 2 | mod read; 3 | mod template; -------------------------------------------------------------------------------- /next/taitan-orm/src/database/postgres/commanders/mod.rs: -------------------------------------------------------------------------------- 1 | mod write; 2 | mod read; 3 | mod template; -------------------------------------------------------------------------------- /next/taitan-orm/src/database/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod sqlite; 2 | 3 | pub mod mysql; 4 | pub mod postgres; 5 | -------------------------------------------------------------------------------- /old/luna-types/src/constraint/supports/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod string; 2 | pub mod integer; 3 | pub mod datetime; -------------------------------------------------------------------------------- /next/taitan-orm/tests/macros/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod entity_spec; 2 | mod template_spec; 3 | mod execute_loop; 4 | -------------------------------------------------------------------------------- /next/taitan-orm/src/database/sqlite/commanders/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod read; 2 | pub mod write; 3 | pub mod template; 4 | -------------------------------------------------------------------------------- /next/taitan-orm/src/database/mysql/mod.rs: -------------------------------------------------------------------------------- 1 | mod commanders; 2 | mod database; 3 | mod transaction; 4 | mod extractor; -------------------------------------------------------------------------------- /next/taitan-orm/src/database/postgres/mod.rs: -------------------------------------------------------------------------------- 1 | mod commanders; 2 | mod extractor; 3 | mod database; 4 | mod transaction; -------------------------------------------------------------------------------- /next/taitan-orm/src/dto/mod.rs: -------------------------------------------------------------------------------- 1 | mod count; 2 | 3 | pub use count::CountResult; 4 | pub use count::EmptySelection; 5 | -------------------------------------------------------------------------------- /next/taitan-orm/tests/sqlite/mod.rs: -------------------------------------------------------------------------------- 1 | mod sql_commander_spec; 2 | mod sql_executor_spec; 3 | mod transaction_spec; 4 | -------------------------------------------------------------------------------- /next/taitan-orm-trait/src/join/from_clause.rs: -------------------------------------------------------------------------------- 1 | pub trait FromClause { 2 | fn get_from_clause(&self) -> String; 3 | } 4 | -------------------------------------------------------------------------------- /next/taitan-orm/src/result.rs: -------------------------------------------------------------------------------- 1 | use crate::TaitanOrmError; 2 | 3 | pub type Result = std::result::Result; 4 | -------------------------------------------------------------------------------- /next/taitan-orm-trait/src/page/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod paged_info; 2 | pub mod paged_list; 3 | 4 | pub mod count_sql; 5 | pub mod pagination; 6 | -------------------------------------------------------------------------------- /next/taitan-orm/src/api_macro/mod.rs: -------------------------------------------------------------------------------- 1 | mod read; 2 | mod write; 3 | mod template; 4 | mod executor; 5 | mod transaction; 6 | mod extractor; -------------------------------------------------------------------------------- /next/taitan-orm-trait/src/page/count_sql.rs: -------------------------------------------------------------------------------- 1 | pub enum CountSql { 2 | Empty, 3 | PlainSql(String), 4 | VariableSql(String), 5 | } 6 | -------------------------------------------------------------------------------- /old/luna-orm-dynamic/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod active_entity; 2 | pub mod active_json; 3 | fn main() { 4 | println!("Hello, world!"); 5 | } 6 | -------------------------------------------------------------------------------- /old/luna-types/src/record/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod entity_record; 2 | mod record; 3 | 4 | pub use record::Record; 5 | pub use record::RecordConstraint; -------------------------------------------------------------------------------- /next/taitan-orm-macro/src/attrs/mod.rs: -------------------------------------------------------------------------------- 1 | mod attr_parser; 2 | 3 | pub use attr_parser::AttrParser; 4 | pub use attr_parser::DefaultAttrParser; 5 | -------------------------------------------------------------------------------- /old/luna-types/src/constraint/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod common; 2 | pub mod error; 3 | pub mod named; 4 | pub mod supports; 5 | pub mod supported; 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /old/luna-types/src/field/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | pub mod supports; 3 | pub mod supported; 4 | pub mod named; 5 | pub mod valid; 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /old/luna-orm/tests/common/mod.rs: -------------------------------------------------------------------------------- 1 | mod logger; 2 | pub mod mutex; 3 | pub mod schema; 4 | mod setup_database; 5 | 6 | pub use logger::setup_logger; 7 | pub use setup_database::*; 8 | -------------------------------------------------------------------------------- /next/taitan-orm-trait/src/template/mod.rs: -------------------------------------------------------------------------------- 1 | mod parser; 2 | mod template_value; 3 | mod parsed_template_sql; 4 | 5 | pub use parsed_template_sql::ParsedTemplateSql; 6 | pub use template_value::TemplateValue; -------------------------------------------------------------------------------- /next/taitan-orm-macro/src/types/mod.rs: -------------------------------------------------------------------------------- 1 | mod checker; 2 | mod extractor; 3 | 4 | pub use checker::DefaultTypeChecker; 5 | pub use checker::TypeChecker; 6 | pub use extractor::DefaultTypeExtractor; 7 | pub use extractor::TypeExtractor; 8 | -------------------------------------------------------------------------------- /old/luna-types/src/record/entity_record.rs: -------------------------------------------------------------------------------- 1 | use crate::constraint::supported::Constraint; 2 | use crate::schema::Schema; 3 | 4 | pub struct EntityRecord<'a> { 5 | fields: Vec>, 6 | constraints: &'a Schema<'a> 7 | } 8 | -------------------------------------------------------------------------------- /next/taitan-orm/src/sql_generator_container.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Debug; 2 | use crate::{SqlGenerator}; 3 | 4 | pub trait SqlGeneratorContainer { 5 | type G: SqlGenerator + Sync + Debug; 6 | 7 | fn get_generator(&mut self) -> &Self::G; 8 | } -------------------------------------------------------------------------------- /old/luna-orm/src/database/mod.rs: -------------------------------------------------------------------------------- 1 | mod lib; 2 | pub mod mysql; 3 | pub mod postgres; 4 | pub mod sqlite; 5 | pub mod sqlite2; 6 | pub mod lib2; 7 | 8 | pub use lib::*; 9 | pub use mysql::*; 10 | pub use postgres::*; 11 | pub use sqlite::*; 12 | -------------------------------------------------------------------------------- /old/luna-orm-axum/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod field_type; 2 | mod generator; 3 | pub mod handler; 4 | mod middleware; 5 | pub mod request; 6 | pub mod response; 7 | pub mod router; 8 | mod schema; 9 | 10 | pub use field_type::FieldType; 11 | pub use schema::*; 12 | -------------------------------------------------------------------------------- /next/taitan-orm-trait/src/location/located_query.rs: -------------------------------------------------------------------------------- 1 | use crate::{Location, Selection}; 2 | 3 | #[typetag::serde(tag = "table")] 4 | pub trait LocatedQuery { 5 | fn get_selection(&self) -> &dyn Selection; 6 | fn get_location(&self) -> &dyn Location; 7 | } 8 | -------------------------------------------------------------------------------- /old/luna-types/tests/field.rs: -------------------------------------------------------------------------------- 1 | use luna_types::field::supported::Field; 2 | use serde_json::Value; 3 | 4 | #[test] 5 | fn test_field() { 6 | let data_str = r#"{ }"#; 7 | let value: Value = serde_json::from_str(data_str).unwrap(); 8 | 9 | assert!(true); 10 | } 11 | -------------------------------------------------------------------------------- /next/taitan-orm-trait/src/location/mod.rs: -------------------------------------------------------------------------------- 1 | mod cmp_operator; 2 | mod located_query; 3 | mod location; 4 | mod location_expr; 5 | 6 | pub use cmp_operator::CmpOperator; 7 | pub use located_query::LocatedQuery; 8 | pub use location::Location; 9 | pub use location_expr::LocationExpr; 10 | pub use location_expr::LocationTrait; 11 | -------------------------------------------------------------------------------- /next/taitan-orm-macro/src/fields/selected_parser.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Debug; 2 | use proc_macro2::TokenStream; 3 | 4 | use crate::fields::FieldsContainer; 5 | 6 | 7 | pub trait SelectedParser: FieldsContainer { 8 | fn gen_from_row(&self) -> TokenStream; 9 | 10 | fn gen_from_row_full(&self) -> TokenStream; 11 | 12 | } -------------------------------------------------------------------------------- /old/luna-orm/tests/common/mutex.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | use std::sync::OnceLock; 3 | use tokio::sync::Mutex; 4 | 5 | static GLOBAL_TEST_MUTEX: OnceLock>> = OnceLock::new(); 6 | 7 | pub fn get_test_mutex() -> &'static Arc> { 8 | GLOBAL_TEST_MUTEX.get_or_init(|| Arc::new(Mutex::new(()))) 9 | } 10 | -------------------------------------------------------------------------------- /old/examples/crud/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "crud" 3 | edition = "2021" 4 | version.workspace = true 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | luna-orm = {path="../../luna-orm"} 10 | tokio = { version = "1.35.1", features = ["full"] } 11 | -------------------------------------------------------------------------------- /old/examples/mysql/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mysql" 3 | edition = "2021" 4 | version.workspace = true 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | luna-orm = {path="../../luna-orm"} 10 | tokio = { version = "1.35.1", features = ["full"] } 11 | -------------------------------------------------------------------------------- /old/examples/sqlite/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sqlite" 3 | edition = "2021" 4 | version.workspace = true 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | luna-orm = {path="../../luna-orm"} 10 | tokio = { version = "1.35.1", features = ["full"] } 11 | -------------------------------------------------------------------------------- /old/examples/template/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "template" 3 | edition = "2021" 4 | version.workspace = true 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | luna-orm = {path="../../luna-orm"} 10 | tokio = { version = "1.35.1", features = ["full"] } 11 | -------------------------------------------------------------------------------- /next/taitan-orm-trait/src/join/joined_query.rs: -------------------------------------------------------------------------------- 1 | use crate::join::joined_conditions::JoinedConditions; 2 | use crate::location::LocatedQuery; 3 | use serde::{Deserialize, Serialize}; 4 | 5 | #[derive(Serialize, Deserialize)] 6 | pub struct JoinedQuery { 7 | query_vec: Vec>, 8 | join_conditions: JoinedConditions, 9 | } 10 | -------------------------------------------------------------------------------- /old/examples/input/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "input" 3 | edition = "2021" 4 | version.workspace = true 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | luna-orm = {path="../../luna-orm"} 10 | tokio = { version = "1.35.1", features = ["full"] } 11 | sqlx = "0.8.2" -------------------------------------------------------------------------------- /old/examples/transaction/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "transaction" 3 | edition = "2021" 4 | version.workspace = true 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | luna-orm = {path="../../luna-orm"} 10 | tokio = { version = "1.35.1", features = ["full"] } 11 | -------------------------------------------------------------------------------- /old/luna-orm/tests/common/logger.rs: -------------------------------------------------------------------------------- 1 | use std::sync::OnceLock; 2 | 3 | static logger_setup: OnceLock = OnceLock::new(); 4 | 5 | pub fn setup_logger() { 6 | logger_setup.get_or_init(|| { 7 | tracing_subscriber::fmt() 8 | .with_max_level(tracing::Level::TRACE) 9 | .init(); 10 | true 11 | }); 12 | } 13 | -------------------------------------------------------------------------------- /old/luna-orm/tests/timer.rs: -------------------------------------------------------------------------------- 1 | use luna_orm::prelude::Timer; 2 | mod common; 3 | use common::setup_logger; 4 | 5 | #[test] 6 | pub fn test_timer() { 7 | setup_logger(); 8 | let timer = Timer::new("hello"); 9 | } 10 | 11 | #[test] 12 | pub fn test_timer_from_string() { 13 | setup_logger(); 14 | let timer = Timer::new("hello".to_string()); 15 | } 16 | -------------------------------------------------------------------------------- /next/plan.md: -------------------------------------------------------------------------------- 1 | 2 | # API设计,把API设计逐渐固定下来 3 | 1. transaction支持能够更加优雅 4 | 5 | # 多数据库支持 6 | 1. 参数生成的trait可能需要按照数据库拆分开来 7 | 2. generator 8 | 3. executor 9 | 4. api 10 | 分层的设计逻辑需要重新review 11 | 12 | sqlite: YES 13 | mysql: No 14 | postgres: No 15 | 16 | # 文档 17 | 18 | # 正确性测试 19 | 20 | # 性能测试 21 | 22 | 23 | # 额外优化 24 | 是否支持Cow<'a, str>作为entity的字符串字段,目前因为查询返回值一定不能用&str 25 | -------------------------------------------------------------------------------- /old/luna-orm-trait/tests/trait_test.rs: -------------------------------------------------------------------------------- 1 | use luna_orm_trait::Primary; 2 | use sqlx::any::AnyArguments; 3 | use sqlx::Any; 4 | use sqlx::Encode; 5 | use sqlx::{AnyExecutor, Arguments}; 6 | pub struct HelloPrimary { 7 | name: String, 8 | } 9 | use luna_orm_trait::luna_add_arg; 10 | 11 | #[test] 12 | pub fn test_primary_trait() { 13 | assert_eq!(true, true); 14 | } 15 | -------------------------------------------------------------------------------- /next/taitan-orm/src/database/sqlite/mod.rs: -------------------------------------------------------------------------------- 1 | mod config; 2 | mod database; 3 | pub mod executor; 4 | mod transaction; 5 | mod commanders; 6 | mod extractor; 7 | 8 | pub use commanders::write::SqliteWriteCommander; 9 | pub use commanders::read::SqliteReadCommander; 10 | pub use config::SqliteLocalConfig; 11 | pub use database::SqliteDatabase; 12 | pub use transaction::SqliteTransaction; 13 | -------------------------------------------------------------------------------- /next/taitan-orm-trait/src/selection.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Debug; 2 | 3 | pub trait Selection: Sync + Debug { 4 | fn get_table_name(&self) -> &'static str; 5 | 6 | fn get_selected_fields(&self) -> Vec; 7 | 8 | fn get_selected_bits(&self) -> bit_vec::BitVec { 9 | todo!() 10 | } 11 | 12 | fn full_fields() -> Self 13 | where 14 | Self: Sized; 15 | } 16 | -------------------------------------------------------------------------------- /next/taitan-orm-macro/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "taitan-orm-macro" 3 | edition = "2021" 4 | version.workspace = true 5 | rust-version.workspace = true 6 | 7 | 8 | [lib] 9 | proc-macro = true 10 | 11 | [dependencies] 12 | quote = "1.0" 13 | syn = { version = "2.0.90", features = ["full"] } 14 | proc-macro2 = "1.0" 15 | case = "1.0" 16 | darling = "0.20.10" 17 | 18 | taitan-orm-trait = { path = "../taitan-orm-trait" } -------------------------------------------------------------------------------- /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | - name: Build 20 | run: cargo build --verbose 21 | - name: Run tests 22 | run: cargo test --verbose 23 | -------------------------------------------------------------------------------- /old/luna-types/src/constraint/common.rs: -------------------------------------------------------------------------------- 1 | use serde::Serialize; 2 | use serde_json::Value; 3 | use std::fmt::Debug; 4 | 5 | pub trait ConstraintTrait: Debug + Serialize { 6 | type ValueType; 7 | 8 | fn is_option(&self) -> bool; 9 | 10 | // for dynamic json value 11 | fn is_valid_json(&self, value: &Value) -> bool; 12 | 13 | // for specific type fo value 14 | fn is_valid(&self, value: &Self::ValueType) -> bool; 15 | } 16 | -------------------------------------------------------------------------------- /next/taitan-orm-trait/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "taitan-orm-trait" 3 | edition = "2021" 4 | version.workspace = true 5 | rust-version.workspace = true 6 | 7 | [dependencies] 8 | sqlx = {workspace = true} 9 | serde = { version = "1.0.215", features = ["derive"] } 10 | time = "0.3.37" 11 | serde_with = {workspace = true} 12 | serde_json = {workspace = true} 13 | typetag = {workspace = true} 14 | nom = {workspace = true} 15 | rinja = "0.3.5" 16 | bit-vec ="0.8" -------------------------------------------------------------------------------- /next/taitan-orm-trait/src/page/paged_info.rs: -------------------------------------------------------------------------------- 1 | #[derive(Clone, Debug)] 2 | pub struct PagedInfo { 3 | pub page_size: u64, 4 | pub page_num: u64, 5 | pub page_total: u64, 6 | pub total: u64, 7 | } 8 | 9 | impl PagedInfo { 10 | pub fn empty(page_size: u64, page_num: u64) -> Self { 11 | Self { 12 | page_size, 13 | page_num, 14 | page_total: 0, 15 | total: 0, 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /next/taitan-orm/src/database/sqlite/config.rs: -------------------------------------------------------------------------------- 1 | use std::borrow::Cow; 2 | 3 | pub struct SqliteLocalConfig<'a> { 4 | pub work_dir: Cow<'a, str>, 5 | pub db_file: Cow<'a, str>, 6 | } 7 | 8 | impl<'a> SqliteLocalConfig<'a> { 9 | pub fn new(work_dir: S, db_file: S) -> Self 10 | where 11 | S: Into>, 12 | { 13 | Self { 14 | work_dir: work_dir.into(), 15 | db_file: db_file.into(), 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /next/taitan-orm-macro/src/util/mod.rs: -------------------------------------------------------------------------------- 1 | mod parser; 2 | mod utils; 3 | mod life_time_checker; 4 | mod copy_struct; 5 | 6 | pub use utils::extract_fields; 7 | pub use utils::create_path_from_str; 8 | pub use life_time_checker::check_field_lifetime; 9 | pub use life_time_checker::check_type_lifetime; 10 | pub use life_time_checker::extract_generic_lifetimes; 11 | pub use life_time_checker::build_struct_ident; 12 | pub use life_time_checker::build_impl_trait_token; 13 | pub use copy_struct::copy_to_template_struct; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | debug/ 4 | target/ 5 | 6 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 7 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 8 | Cargo.lock 9 | 10 | # These are backup files generated by rustfmt 11 | **/*.rs.bk 12 | 13 | # MSVC Windows builds of rustc generate these, which store debugging information 14 | *.pdb 15 | .idea 16 | 17 | /workspace 18 | **/workspace 19 | -------------------------------------------------------------------------------- /old/luna-orm-axum/src/generator.rs: -------------------------------------------------------------------------------- 1 | use crate::Schema; 2 | 3 | pub struct Generator { 4 | schema: Schema, 5 | } 6 | 7 | impl Generator { 8 | pub fn new(schema: Schema) -> Self { 9 | Self { schema } 10 | } 11 | 12 | pub fn from_yaml>(value: T) -> serde_yaml::Result { 13 | let schema = serde_yaml::from_str(value.as_ref())?; 14 | Ok(Generator::new(schema)) 15 | } 16 | 17 | pub fn generate_axum_router() -> String { 18 | "".to_string() 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /old/luna-types/src/field/named.rs: -------------------------------------------------------------------------------- 1 | 2 | use serde::{Serialize, Deserialize}; 3 | use std::borrow::Cow; 4 | use crate::field::supported::Field; 5 | 6 | #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] 7 | pub struct NamedField<'a> { 8 | pub name: Cow<'a, str>, 9 | pub field: Field<'a>, 10 | } 11 | 12 | impl<'a> NamedField<'a> { 13 | pub fn new(name: impl Into>, field: Field<'a>) -> Self { 14 | Self { 15 | name: name.into(), 16 | field, 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /next/taitan-orm-trait/src/join/mod.rs: -------------------------------------------------------------------------------- 1 | mod from_clause; 2 | mod joined_condition; 3 | mod joined_condition_array; 4 | mod joined_condition_part; 5 | mod joined_conditions; 6 | mod joined_field; 7 | mod joined_mode; 8 | mod joined_query; 9 | 10 | pub use from_clause::FromClause; 11 | pub use joined_field::JoinedField; 12 | pub use joined_field::JoinedFields; 13 | pub use joined_mode::JoinedMode; 14 | 15 | pub use joined_condition::get_on_clause; 16 | pub use joined_condition::JoinedCondition; 17 | pub use joined_conditions::JoinedConditions; 18 | pub use joined_query::JoinedQuery; 19 | -------------------------------------------------------------------------------- /next/taitan-orm-trait/src/write_command.rs: -------------------------------------------------------------------------------- 1 | use crate::{Entity, Location, Mutation, Unique}; 2 | 3 | #[derive(Debug)] 4 | pub enum WriteCommand { 5 | Insert { entity: Box }, 6 | Upsert { entity: Box }, 7 | // Update { 8 | // mutation: Box, 9 | // primary: Box, 10 | // }, 11 | // Change { 12 | // mutation: Box, 13 | // location: Box, 14 | // }, 15 | // Delete { primary: Box }, 16 | 17 | // Purify { location: Box }, 18 | } 19 | -------------------------------------------------------------------------------- /old/luna-types/src/constraint/error.rs: -------------------------------------------------------------------------------- 1 | use std::borrow::Cow; 2 | use std::error::Error; 3 | use std::fmt::Display; 4 | 5 | #[derive(Debug, Clone)] 6 | pub struct ConstraintError<'a> { 7 | msg: Cow<'a, str>, 8 | } 9 | 10 | impl<'a> ConstraintError<'a> { 11 | pub fn new(msg: impl Into>) -> Self { 12 | Self { msg: msg.into() } 13 | } 14 | } 15 | impl<'a> Display for ConstraintError<'a> { 16 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 17 | write!(f, "{}", self.msg) 18 | } 19 | } 20 | 21 | impl<'a> Error for ConstraintError<'a> {} 22 | -------------------------------------------------------------------------------- /next/taitan-orm-macro/src/template.rs: -------------------------------------------------------------------------------- 1 | use proc_macro::TokenStream; 2 | use syn::{parse_macro_input, DeriveInput}; 3 | use crate::expands::generate_template_struct_and_impl; 4 | use crate::util::{extract_fields}; 5 | 6 | 7 | pub fn impl_template_macro(input: TokenStream) -> TokenStream { 8 | let DeriveInput { 9 | attrs, ident, data, generics, .. 10 | } = parse_macro_input!(input); 11 | 12 | let fields = extract_fields(&data).unwrap(); 13 | let output = generate_template_struct_and_impl(&ident, &attrs, &data, &fields, &generics); 14 | // panic!("{}", output); 15 | output.into() 16 | } -------------------------------------------------------------------------------- /next/taitan-orm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "taitan-orm" 3 | edition = "2021" 4 | version.workspace = true 5 | rust-version.workspace = true 6 | 7 | [dependencies] 8 | taitan-orm-trait = { path = "../taitan-orm-trait" } 9 | taitan-orm-macro = { path = "../taitan-orm-macro" } 10 | sqlx = {workspace = true} 11 | serde = {workspace = true} 12 | time = {workspace = true} 13 | uuid = {workspace = true} 14 | tracing = {workspace = true} 15 | thiserror = {workspace = true} 16 | path-absolutize = {workspace = true} 17 | rinja = "0.3.5" 18 | bit-vec = "0.8.0" 19 | 20 | [dev-dependencies] 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /next/taitan-orm-macro/src/fields/selection_parser.rs: -------------------------------------------------------------------------------- 1 | use crate::fields::mappers::StructFieldConstructor; 2 | use crate::fields::{FieldsContainer, NamesAddConstructor, NamesConstructor, StructConstructor}; 3 | use proc_macro2::TokenStream; 4 | 5 | pub trait SelectionParser: 6 | FieldsContainer 7 | + NamesAddConstructor 8 | + NamesConstructor 9 | + StructFieldConstructor 10 | + StructConstructor 11 | { 12 | fn get_selected_fields(&self) -> TokenStream { 13 | self.of_bool_names_vec() 14 | } 15 | 16 | fn full_fields(&self) -> TokenStream { 17 | self.of_bool_true() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /old/luna-types/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "luna-types" 3 | edition = "2021" 4 | version.workspace = true 5 | rust-version.workspace = true 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | serde = {workspace = true} 11 | serde_json = {workspace = true} 12 | serde_regex = {workspace = true} 13 | regex = {workspace = true} 14 | derive_builder = {workspace = true} 15 | chrono = {workspace = true} 16 | 17 | num = {workspace = true} 18 | num-traits = {workspace = true} 19 | 20 | 21 | sqlx = {workspace = true} 22 | sqlx-core = {workspace = true} 23 | -------------------------------------------------------------------------------- /next/taitan-orm-trait/src/location/location_expr.rs: -------------------------------------------------------------------------------- 1 | use crate::CmpOperator; 2 | use serde::{Deserialize, Serialize}; 3 | 4 | #[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] 5 | pub struct LocationExpr { 6 | pub val: T, 7 | pub cmp: CmpOperator, 8 | } 9 | 10 | pub trait LocationTrait { 11 | fn get_cmp_sql(&self) -> &str; 12 | } 13 | impl LocationTrait for LocationExpr { 14 | fn get_cmp_sql(&self) -> &str { 15 | self.cmp.get_sql() 16 | } 17 | } 18 | 19 | impl LocationExpr { 20 | pub fn new(cmp: CmpOperator, val: T) -> Self { 21 | Self { cmp, val } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /next/taitan-orm-macro/src/fields/table_name_parser.rs: -------------------------------------------------------------------------------- 1 | use crate::attrs::{AttrParser, DefaultAttrParser}; 2 | use crate::fields::FieldsParser; 3 | use proc_macro2::{Ident, TokenStream}; 4 | use quote::quote; 5 | use syn::Attribute; 6 | 7 | pub trait TableNameParser { 8 | fn get_table_name(ident: &Ident, attrs: &Vec) -> TokenStream; 9 | } 10 | 11 | impl TableNameParser for FieldsParser { 12 | fn get_table_name(ident: &Ident, attrs: &Vec) -> TokenStream { 13 | let table_name = DefaultAttrParser::extract_table_name(ident, attrs); 14 | quote! { 15 | #table_name 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /old/examples/mysql/src/main.rs: -------------------------------------------------------------------------------- 1 | use luna_orm::prelude::*; 2 | use luna_orm::LunaOrmResult; 3 | 4 | #[tokio::main] 5 | async fn main() -> LunaOrmResult<()> { 6 | // 2. create a DB instance. 7 | let mut db: DB = MysqlDatabase::build("localhost/test", "user", "passwod") 8 | .await? 9 | .into(); 10 | 11 | // 3. optional: you may need to create the table for the first time. 12 | let result = db.execute_plain( 13 | "CREATE TABLE IF NOT EXISTS `user`(`id` INT PRIMARY KEY, `age` INT, `name` VARCHAR(64))", 14 | ).await?; 15 | 16 | println!("result: {}", result.rows_affected()); 17 | Ok(()) 18 | } 19 | -------------------------------------------------------------------------------- /old/luna-orm-macro/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "luna-orm-macro" 3 | version = {workspace = true} 4 | rust-version = {workspace = true} 5 | edition = "2021" 6 | license-file = "LICENSE" 7 | description = "ORM based on sqlx" 8 | homepage = "https://github.com/thegenius/luna-orm" 9 | 10 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 11 | 12 | [lib] 13 | proc-macro = true 14 | 15 | [dependencies] 16 | quote = "1.0" 17 | syn = { version = "1.0", features = ["full"] } 18 | proc-macro2 = "1.0" 19 | case = "1.0" 20 | 21 | luna-orm-trait = { path = "../luna-orm-trait", version = "0.3.6" } 22 | sqlx = { workspace = true } 23 | -------------------------------------------------------------------------------- /old/luna-orm-axum/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "luna-orm-axum" 3 | edition = "2021" 4 | version.workspace = true 5 | 6 | [dependencies] 7 | #sqlx = {workspace = true} 8 | axum = {workspace = true} 9 | tower = {workspace = true} 10 | axum-macros = {workspace = true} 11 | tokio = {workspace = true} 12 | serde = {workspace = true} 13 | serde_yaml = {workspace = true} 14 | serde_json = {workspace = true} 15 | case = {workspace = true} 16 | rust-format = {workspace = true} 17 | tera = {workspace = true} 18 | http-body-util = {workspace = true} 19 | 20 | sqlx = {version = "0.8.2", features = ["runtime-tokio", "mysql", "sqlite", "macros", "any"]} 21 | luna-orm = { path = "../luna-orm" } 22 | -------------------------------------------------------------------------------- /next/taitan-orm-trait/src/error.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | pub struct NotImplementError(pub String); 3 | impl std::error::Error for NotImplementError {} 4 | impl std::fmt::Display for NotImplementError { 5 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 6 | write!(f, "method {} is not implements", self.0) 7 | } 8 | } 9 | 10 | #[derive(Debug)] 11 | pub struct NotValidOrderByError(pub String); 12 | impl std::error::Error for NotValidOrderByError {} 13 | impl std::fmt::Display for NotValidOrderByError { 14 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 15 | write!(f, "order by fields: {} is not valid", self.0) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /old/examples/sqlite/src/main.rs: -------------------------------------------------------------------------------- 1 | use luna_orm::prelude::*; 2 | use luna_orm::LunaOrmResult; 3 | 4 | #[tokio::main] 5 | async fn main() -> LunaOrmResult<()> { 6 | let config = SqliteLocalConfig::new("./workspace", "test.db"); 7 | 8 | // 2. create a DB instance. 9 | let mut db: DB = SqliteDatabase::build(config).await.unwrap().into(); 10 | 11 | // 3. optional: you may need to create the table for the first time. 12 | let result = db.execute_plain( 13 | "CREATE TABLE IF NOT EXISTS `user`(`id` INT PRIMARY KEY, `age` INT, `name` VARCHAR(64))", 14 | ).await?; 15 | 16 | println!("result: {}", result.rows_affected()); 17 | Ok(()) 18 | } 19 | -------------------------------------------------------------------------------- /next/taitan-orm-trait/src/join/joined_condition_part.rs: -------------------------------------------------------------------------------- 1 | use crate::join::{get_on_clause, FromClause, JoinedFields, JoinedMode}; 2 | use serde::{Deserialize, Serialize}; 3 | 4 | #[derive(Serialize, Deserialize, PartialEq, Eq, Debug)] 5 | pub struct JoinedConditionPart { 6 | mode: JoinedMode, 7 | table: String, 8 | #[serde(alias = "fields")] 9 | joined_fields: Vec, 10 | } 11 | 12 | impl FromClause for JoinedConditionPart { 13 | fn get_from_clause(&self) -> String { 14 | let on_clause = get_on_clause(&self.joined_fields); 15 | let join_operator = self.mode.get_join_operator(); 16 | format!("{} {} ON {}", join_operator, self.table, on_clause) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /next/taitan-orm-macro/src/lib.rs: -------------------------------------------------------------------------------- 1 | use crate::schema::impl_schema_macro; 2 | use proc_macro::TokenStream; 3 | use crate::template::impl_template_macro; 4 | 5 | mod attrs; 6 | mod expands; 7 | mod fields; 8 | mod schema; 9 | mod types; 10 | mod util; 11 | mod template; 12 | 13 | #[proc_macro_derive( 14 | Schema, 15 | attributes(table_name, primary_key, unique_key, auto_increment, generated, field_name) 16 | )] 17 | pub fn expand_schema_macro(input: TokenStream) -> TokenStream { 18 | impl_schema_macro(input) 19 | } 20 | 21 | #[proc_macro_derive(TemplateRecord, attributes(sql, count_sql, limit_field))] 22 | pub fn expand_template_record(input: TokenStream) -> TokenStream { 23 | impl_template_macro(input) 24 | } 25 | -------------------------------------------------------------------------------- /next/taitan-orm-trait/src/join/joined_mode.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | #[derive(Serialize, Deserialize, PartialEq, Eq, Debug)] 4 | pub enum JoinedMode { 5 | #[serde(alias = "left")] 6 | Left, 7 | #[serde(alias = "right")] 8 | Right, 9 | #[serde(alias = "outer")] 10 | Outer, 11 | #[serde(alias = "inner")] 12 | Inner, 13 | } 14 | 15 | impl JoinedMode { 16 | pub fn get_join_operator(&self) -> &'static str { 17 | match self { 18 | JoinedMode::Left => "LEFT JOIN", 19 | JoinedMode::Right => "RIGHT JOIN", 20 | JoinedMode::Outer => "OUTER JOIN", 21 | JoinedMode::Inner => "INNER JOIN", 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /old/luna-orm-axum/src/router.rs: -------------------------------------------------------------------------------- 1 | use crate::handler; 2 | use crate::handler::PostHandler; 3 | use axum::routing::post; 4 | use axum::Router; 5 | use luna_orm::prelude::*; 6 | use serde::de::DeserializeOwned; 7 | use serde::Serialize; 8 | 9 | /* 10 | pub fn get_post_router(db: &DB, path: impl AsRef) -> Router 11 | where 12 | T: DeserializeOwned + Serialize + Entity + Send + Clone + 'static, 13 | D: Database + Clone + Send + Sync + 'static, 14 | { 15 | let post_handler = PostHandler::::new(db); 16 | //Router::new() 17 | // .route(path.as_ref(), post(post_handler)) 18 | // .with_state(db.clone()); 19 | Router::new().route(path.as_ref(), post(post_handler)) 20 | } 21 | */ 22 | -------------------------------------------------------------------------------- /old/luna-orm-trait/src/request.rs: -------------------------------------------------------------------------------- 1 | use crate::{Entity, Location, Mutation, Primary}; 2 | use serde::{Deserialize, Serialize}; 3 | 4 | //#[derive(Serialize, Deserialize)] 5 | //#[serde(untagged)] 6 | #[derive(Debug)] 7 | pub enum WriteCommand { 8 | Insert { 9 | entity: Box, 10 | }, 11 | Upsert { 12 | entity: Box, 13 | }, 14 | Update { 15 | mutation: Box, 16 | primary: Box, 17 | }, 18 | Change { 19 | mutation: Box, 20 | location: Box, 21 | }, 22 | Delete { 23 | primary: Box, 24 | }, 25 | 26 | Purify { 27 | location: Box, 28 | }, 29 | } 30 | -------------------------------------------------------------------------------- /next/taitan-orm-macro/src/expands/mod.rs: -------------------------------------------------------------------------------- 1 | mod entity_expander; 2 | mod unique_expander; 3 | mod mutation_expander; 4 | mod location_expander; 5 | mod selection_expander; 6 | mod selected_expander; 7 | mod ordering_expander; 8 | mod template_expander; 9 | 10 | pub use entity_expander::generate_entity_impl; 11 | pub use unique_expander::generate_unique_structs_and_impls; 12 | pub use location_expander::generate_location_struct_and_impl; 13 | pub use mutation_expander::generate_mutation_struct_and_impl; 14 | pub use selection_expander::generate_selection_struct_and_impl; 15 | pub use selected_expander::generate_selected_struct_and_impl; 16 | pub use ordering_expander::generate_ordering_struct_and_impl; 17 | pub use template_expander::generate_template_struct_and_impl; -------------------------------------------------------------------------------- /next/taitan-orm/tests/macros/entity_spec.rs: -------------------------------------------------------------------------------- 1 | 2 | use sqlx::sqlx_macros; 3 | use time::PrimitiveDateTime; 4 | use uuid::Uuid; 5 | use taitan_orm::Schema; 6 | use taitan_orm_trait::Optional; 7 | 8 | #[derive(Schema, Clone, Debug)] 9 | #[table_name = "user"] 10 | #[unique_key = "age"] 11 | #[unique_key = "name, birthday"] 12 | pub struct UserEntity { 13 | #[primary_key] 14 | #[auto_increment] 15 | pub id: Optional, 16 | 17 | #[field_name = "r_id"] 18 | pub request_id: Uuid, 19 | 20 | pub age: Optional, 21 | 22 | pub name: String, 23 | 24 | pub birthday: Optional, 25 | } 26 | 27 | #[sqlx_macros::test] 28 | pub async fn entity_macro_spec() -> taitan_orm::Result<()> { 29 | 30 | 31 | 32 | 33 | Ok(()) 34 | } 35 | -------------------------------------------------------------------------------- /next/taitan-orm-macro/src/fields/mappers/mod.rs: -------------------------------------------------------------------------------- 1 | mod args_add_constructor; 2 | mod struct_field_constructor; 3 | mod args_constructor; 4 | mod struct_constructor; 5 | mod names_constructor; 6 | mod names_add_constructor; 7 | mod row_get_constructor; 8 | mod row_constructor; 9 | 10 | 11 | pub use struct_field_constructor::StructFieldConstructor; 12 | pub use struct_constructor::StructConstructor; 13 | 14 | pub use names_constructor::NamesConstructor; 15 | pub use names_add_constructor::NamesAddConstructor; 16 | 17 | pub use args_add_constructor::ArgsAddConstructor; 18 | pub use args_constructor::ArgsConstructorMySql; 19 | pub use args_constructor::ArgsConstructorPostgres; 20 | pub use args_constructor::ArgsConstructorSqlite; 21 | 22 | pub use row_constructor::RowConstructor; 23 | pub use row_get_constructor::RowGetConstructor; -------------------------------------------------------------------------------- /old/luna-orm-axum/src/schema.rs: -------------------------------------------------------------------------------- 1 | use crate::FieldType; 2 | use case::CaseExt; 3 | use serde::{Deserialize, Serialize}; 4 | 5 | #[derive(Debug, Clone, Deserialize, Serialize)] 6 | pub struct Field { 7 | pub f_name: String, 8 | pub f_type: FieldType, 9 | pub f_constraint: String, 10 | } 11 | 12 | #[derive(Debug, Clone, Deserialize, Serialize)] 13 | #[serde(rename_all = "lowercase")] 14 | pub enum IndexType { 15 | Normal, 16 | Primary, 17 | Unique, 18 | } 19 | 20 | #[derive(Debug, Clone, Deserialize, Serialize)] 21 | pub struct Index { 22 | pub i_name: String, 23 | pub i_type: IndexType, 24 | pub f_names: Vec, 25 | } 26 | 27 | #[derive(Debug, Clone, Deserialize, Serialize)] 28 | pub struct Schema { 29 | pub name: String, 30 | pub fields: Vec, 31 | pub indexes: Vec, 32 | } 33 | -------------------------------------------------------------------------------- /old/luna-orm-trait/src/input_generator.rs: -------------------------------------------------------------------------------- 1 | use sqlx::{Arguments, Database}; 2 | use crate::{Entity, Location, Mutation, OrderBy, Primary}; 3 | 4 | pub trait InputGenerator { 5 | fn gen_insert_arguments(&self, entity: &dyn Entity) -> DB::Arguments<'_>; 6 | fn gen_upsert_arguments(&self, entity: &dyn Entity) -> ::Arguments<'_>; 7 | fn gen_update_arguments(&self, mutation: &dyn Mutation, primary: &dyn Primary) -> ::Arguments<'_>; 8 | fn gen_change_arguments(&self, mutation: &dyn Mutation, location: &dyn Location) -> ::Arguments<'_>; 9 | fn gen_primary_arguments(&self, primary: &dyn Primary) -> ::Arguments<'_>; 10 | fn gen_location_arguments(&self, location: &dyn Location, order_by_option: Option<&dyn OrderBy>) -> ::Arguments<'_>; 11 | } 12 | -------------------------------------------------------------------------------- /old/luna-orm/src/error.rs: -------------------------------------------------------------------------------- 1 | use thiserror::Error; 2 | 3 | #[derive(Error, Debug)] 4 | pub enum LunaOrmError { 5 | #[error("databse init fail with args: `{0}`")] 6 | DatabaseInitFail(String), 7 | 8 | #[error(transparent)] 9 | SqlxError(#[from] sqlx::Error), 10 | 11 | #[error(transparent)] 12 | BoxDynError(#[from] Box), 13 | 14 | #[error("deserialize entity from row error")] 15 | FromRowToEntityError, 16 | 17 | #[error("invalid order by fields")] 18 | OrderByFieldsError, 19 | 20 | #[error("method not implement error")] 21 | NotImplement, 22 | 23 | #[error("paged template sql can't execute with no count sql")] 24 | PagedTemplateHasNoCountSql, 25 | 26 | #[error("dynamic request parse error: {0}")] 27 | DynamicRequestParseError(String), 28 | } 29 | -------------------------------------------------------------------------------- /old/luna-types/src/field/supports/integer.rs: -------------------------------------------------------------------------------- 1 | use crate::constraint::error::ConstraintError; 2 | use crate::constraint::supports::integer::IntegerConstraint; 3 | use num_traits::PrimInt; 4 | use serde::{Deserialize, Serialize}; 5 | use std::fmt::Debug; 6 | use std::ops::{Deref, DerefMut}; 7 | 8 | #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] 9 | #[serde(transparent)] 10 | pub struct Integer(pub T); 11 | 12 | impl From for Integer { 13 | fn from(value: T) -> Self { 14 | Integer(value) 15 | } 16 | } 17 | 18 | impl Deref for Integer { 19 | type Target = T; 20 | fn deref(&self) -> &Self::Target { 21 | &self.0 22 | } 23 | } 24 | impl DerefMut for Integer { 25 | fn deref_mut(&mut self) -> &mut Self::Target { 26 | &mut self.0 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /old/luna-types/src/field/supports/string.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use std::borrow::Cow; 3 | use std::fmt::Debug; 4 | use std::ops::{Deref, DerefMut}; 5 | 6 | #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] 7 | pub struct Text<'a>(pub Cow<'a, str>); 8 | 9 | impl<'a> From<&'a str> for Text<'a> { 10 | fn from(value: &'a str) -> Text<'a> { 11 | Self(Cow::Borrowed(value)) 12 | } 13 | } 14 | 15 | impl From for Text<'_> { 16 | fn from(value: String) -> Self { 17 | Self(Cow::Owned(value)) 18 | } 19 | } 20 | 21 | impl<'a> Deref for Text<'a> { 22 | type Target = Cow<'a, str>; 23 | fn deref(&self) -> &Self::Target { 24 | &self.0 25 | } 26 | } 27 | impl<'a> DerefMut for Text<'a> { 28 | fn deref_mut(&mut self) -> &mut Self::Target { 29 | &mut self.0 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /old/luna-types/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::needless_return)] 2 | 3 | pub mod constraint; 4 | pub mod field; 5 | pub mod record; 6 | pub mod schema; 7 | pub mod sqlx; 8 | 9 | // pub use constraint::CachedConstraint; 10 | // pub use constraint::Constraint; 11 | // pub use constraint::ConstraintError; 12 | // pub use constraint::ConstraintType; 13 | // pub use constraint::IntegerConstraint; 14 | // pub use constraint::IntegerConstraintBuilder; 15 | // pub use constraint::NamedConstraint; 16 | // pub use constraint::NamedIntConstraint; 17 | // pub use constraint::StringConstraint; 18 | // pub use constraint::StringConstraintBuilder; 19 | 20 | // pub use field::try_from_json; 21 | // pub use field::FieldType; 22 | // pub use field::Integer; 23 | // pub use field::Text; 24 | //pub use field::ValidField; 25 | 26 | // pub use record::Record; 27 | // pub use record::RecordConstraint; 28 | -------------------------------------------------------------------------------- /next/taitan-orm-trait/src/location/cmp_operator.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | #[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] 4 | pub enum CmpOperator { 5 | #[serde(alias = "=")] 6 | Eq, 7 | #[serde(alias = "<")] 8 | LessThan, 9 | #[serde(alias = "<=")] 10 | LessOrEq, 11 | #[serde(alias = ">")] 12 | GreaterThan, 13 | #[serde(alias = ">=")] 14 | GreaterOrEq, 15 | #[serde(alias = "like")] 16 | Like, 17 | } 18 | 19 | impl CmpOperator { 20 | pub fn get_sql(&self) -> &'static str { 21 | match self { 22 | CmpOperator::Eq => "=", 23 | CmpOperator::LessThan => "<", 24 | CmpOperator::LessOrEq => "<=", 25 | CmpOperator::GreaterThan => ">", 26 | CmpOperator::GreaterOrEq => ">=", 27 | CmpOperator::Like => "LIKE", 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /next/taitan-orm/src/db.rs: -------------------------------------------------------------------------------- 1 | use std::ops::{Deref, DerefMut}; 2 | use crate::{ReaderApi, SqlExecutor, SqlGeneratorContainer, SqlGenericExecutor, TemplateApi}; 3 | use crate::extractor::Extractor; 4 | 5 | #[derive(Debug, Clone)] 6 | pub struct DB(pub T); 7 | 8 | impl Deref for DB 9 | where 10 | T: ReaderApi + ReaderApi + TemplateApi + Extractor + SqlExecutor + SqlGenericExecutor + SqlGeneratorContainer, 11 | { 12 | type Target = T; 13 | fn deref(&self) -> &Self::Target { 14 | &self.0 15 | } 16 | } 17 | 18 | impl DerefMut for DB 19 | where 20 | T: ReaderApi + ReaderApi + TemplateApi + Extractor + SqlExecutor + SqlGenericExecutor + SqlGeneratorContainer, 21 | { 22 | fn deref_mut(&mut self) -> &mut Self::Target { 23 | &mut self.0 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /old/luna-orm/tests/common/schema.rs: -------------------------------------------------------------------------------- 1 | /* 2 | use storage_generator::schema::schema_raw::SchemaRaw; 3 | 4 | pub fn get_test_schema() -> SchemaRaw { 5 | let content = r#" 6 | --- 7 | name: article 8 | 9 | fields: 10 | - name: id 11 | type: uuid 12 | - name: author_id 13 | type: uuid 14 | - name: title 15 | type: string 16 | - name: content 17 | type: string 18 | - name: last_update_time 19 | type: timestamp 20 | 21 | 22 | index_infos: 23 | primary: 24 | partition: 25 | - id 26 | clustering: 27 | - title 28 | secondary: 29 | - name: time_index 30 | fields: 31 | - last_update_time 32 | - name: author_id_title_index 33 | fields: 34 | - author_id 35 | - title 36 | method_infos: 37 | has_default_method: true 38 | methods: [] 39 | "#; 40 | let schema_raw: SchemaRaw = serde_yaml::from_str(content).unwrap(); 41 | return schema_raw; 42 | } 43 | */ 44 | -------------------------------------------------------------------------------- /old/luna-orm-trait/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "luna-orm-trait" 3 | version = {workspace = true } 4 | rust-version = {workspace = true} 5 | edition = "2021" 6 | license-file = "LICENSE" 7 | description = "ORM based on sqlx" 8 | homepage = "https://github.com/thegenius/luna-orm" 9 | 10 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 11 | 12 | [dependencies] 13 | tracing = {workspace = true} 14 | sqlx = { workspace = true } 15 | sqlx-core = {workspace = true} 16 | #async-trait = { workspace = true } 17 | serde = { workspace = true } 18 | serde_with = {workspace = true} 19 | serde_json = {workspace = true} 20 | regex = {workspace = true} 21 | typetag = {workspace = true} 22 | nom = {workspace = true} 23 | 24 | [dev-dependencies] 25 | tokio = {workspace = true} 26 | serde_json = {workspace = true} 27 | serde_yaml = {workspace = true} 28 | chrono = { workspace = true} 29 | -------------------------------------------------------------------------------- /old/luna-orm-trait/README.md: -------------------------------------------------------------------------------- 1 | ## entity 2 | | type | auto-increment | nullable | default |is option| 3 | |------|----------------|---------------|-----------|-| 4 | | 主键 | N | must not null | not allow |✗| 5 | | 主键 | Y | must not null | not allow |✓| 6 | | 唯一键 | not allow | must not null | Y |✓| 7 | | 唯一键 | not allow | must not null | N |✗| 8 | | 非键 | Y | - | - |✓| 9 | | 非键 | - | - | Y |✓| 10 | | 非键 | - | Y | - |✓| 11 | | 非键 | N | N | N |✗| 12 | 13 | ## 表结构主信息 14 | \#[TableName] 15 | \#[FieldName] 16 | 17 | ## 索引信息宏 18 | \#[PrimaryKey] 19 | \#[UniqueKey] 20 | \#[Index] 21 | 22 | ## input转化层 23 | 1. insert(entity):所有非空字段都应该转化到arguments里面 24 | 2. upsert(entity):所有非空字段都转化,非primary主键的部分需要转2遍用来 on duplicate update set 25 | 3. update(mutation, primary): 所有mutation的 -------------------------------------------------------------------------------- /next/taitan-orm-trait/src/join/joined_condition_array.rs: -------------------------------------------------------------------------------- 1 | use crate::join::joined_condition_part::JoinedConditionPart; 2 | use crate::join::{FromClause, JoinedCondition}; 3 | use serde::{Deserialize, Serialize}; 4 | use serde_with::serde_as; 5 | 6 | #[serde_as] 7 | #[derive(Serialize, Deserialize, PartialEq, Eq, Debug)] 8 | pub struct JoinedConditionArray { 9 | root: JoinedCondition, 10 | #[serde_as(as = "[_; N]")] 11 | next: [JoinedConditionPart; N], 12 | } 13 | 14 | impl JoinedConditionArray { 15 | pub fn get_from_clause(&self) -> String { 16 | let root_join = self.root.get_from_clause(); 17 | let mut part_clauses: Vec = Vec::new(); 18 | for part in &self.next { 19 | let part_clause = part.get_from_clause(); 20 | part_clauses.push(part_clause); 21 | } 22 | let part_clause = part_clauses.join(" "); 23 | format!("{} {}", root_join, part_clause) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /old/luna-orm-dynamic/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "luna-orm-dynamic" 3 | edition = "2021" 4 | version.workspace = true 5 | rust-version.workspace = true 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | axum = {workspace = true} 11 | axum-macros = {workspace = true} 12 | tokio = {workspace = true} 13 | serde = {workspace = true} 14 | serde_yaml = {workspace = true} 15 | serde_json = {workspace = true} 16 | case = {workspace = true} 17 | rust-format = {workspace = true} 18 | tera = {workspace = true} 19 | http-body-util = {workspace = true} 20 | 21 | sqlx = {workspace = true} 22 | 23 | luna-orm-trait = { path = "../luna-orm-trait", version = "0.3.6" } 24 | luna-orm = { path = "../luna-orm", version = "0.3.6" } 25 | luna-types = {path = "../luna-types", version = "0.3.6"} 26 | 27 | 28 | [dev-dependencies] 29 | sqlx = {version = "0.8.2", features = ["runtime-tokio", "mysql", "sqlite", "macros", "any"]} 30 | -------------------------------------------------------------------------------- /next/taitan-orm/src/database/mysql/commanders/template.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | execute_by_template_fn, fetch_all_by_template_fn, fetch_one_by_template_fn, 3 | fetch_option_by_template_fn, fetch_paged_by_template_fn 4 | }; 5 | use crate::{SqlExecutor, SqlGenerator, SqlGeneratorContainer}; 6 | 7 | 8 | pub trait MySqlTemplateCommander: SqlExecutor + SqlGeneratorContainer { 9 | execute_by_template_fn!(crate::traits::TemplateRecord::gen_template_arguments_mysql); 10 | 11 | fetch_one_by_template_fn!(crate::traits::TemplateRecord::gen_template_arguments_mysql); 12 | 13 | fetch_option_by_template_fn!(crate::traits::TemplateRecord::gen_template_arguments_mysql); 14 | 15 | fetch_all_by_template_fn!(crate::traits::TemplateRecord::gen_template_arguments_mysql); 16 | 17 | fetch_paged_by_template_fn!( 18 | crate::traits::TemplateRecord::gen_template_count_arguments_mysql, 19 | crate::traits::TemplateRecord::gen_template_arguments_mysql 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /next/taitan-orm-trait/src/join/joined_field.rs: -------------------------------------------------------------------------------- 1 | use serde::de::Deserialize; 2 | use serde::Serialize; 3 | 4 | pub type JoinedFields = (JoinedField, JoinedField); 5 | #[derive(Serialize, PartialEq, Eq, Debug)] 6 | pub struct JoinedField { 7 | pub(crate) table_name: String, 8 | pub(crate) field_name: String, 9 | } 10 | 11 | impl<'de> Deserialize<'de> for JoinedField { 12 | fn deserialize(deserializer: D) -> Result 13 | where 14 | D: serde::Deserializer<'de>, 15 | { 16 | let content = String::deserialize(deserializer)?; 17 | let pair: Vec<&str> = content.split('.').collect(); 18 | if pair.len() != 2 { 19 | return Err(serde::de::Error::custom( 20 | "join field must have table name, and seperate by '.' ", 21 | )); 22 | } 23 | Ok(Self { 24 | table_name: pair.first().unwrap().to_string(), 25 | field_name: pair.last().unwrap().to_string(), 26 | }) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /next/taitan-orm-trait/src/update_command.rs: -------------------------------------------------------------------------------- 1 | use crate::NotImplementError; 2 | use sqlx::error::BoxDynError; 3 | use sqlx::mysql::MySqlArguments; 4 | use sqlx::postgres::PgArguments; 5 | use sqlx::sqlite::SqliteArguments; 6 | use std::fmt::Debug; 7 | 8 | pub trait UpdateCommand: Sync + Debug { 9 | fn gen_update_arguments_sqlite(&self) -> Result, BoxDynError> { 10 | Err( 11 | NotImplementError("PrimaryMutationPair::gen_update_arguments_sqlite".to_string()) 12 | .into(), 13 | ) 14 | } 15 | fn gen_update_arguments_mysql(&self) -> Result { 16 | Err(NotImplementError("PrimaryMutationPair::gen_update_arguments_mysql".to_string()).into()) 17 | } 18 | fn gen_update_arguments_postgres(&self) -> Result { 19 | Err( 20 | NotImplementError("PrimaryMutationPair::gen_update_arguments_postgres".to_string()) 21 | .into(), 22 | ) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /old/luna-orm-macro/src/timer.rs: -------------------------------------------------------------------------------- 1 | use quote::quote; 2 | use syn::parse_macro_input; 3 | 4 | pub fn impl_timed_func( 5 | _metadata: proc_macro::TokenStream, 6 | input: proc_macro::TokenStream, 7 | ) -> proc_macro::TokenStream { 8 | let input_fn: syn::ItemFn = parse_macro_input!(input as syn::ItemFn); 9 | let attrs = input_fn.attrs; 10 | let visibility = input_fn.vis; 11 | let ident = input_fn.sig.ident; 12 | let asyncness = input_fn.sig.asyncness; 13 | let inputs = input_fn.sig.inputs; 14 | let output = input_fn.sig.output; 15 | let generics = &input_fn.sig.generics; 16 | let where_clause = &input_fn.sig.generics.where_clause; 17 | let block = input_fn.block; 18 | 19 | let timer_name = ident.to_string(); 20 | 21 | (quote!( 22 | #(#attrs)* #visibility #asyncness fn #ident #generics (#inputs) #output #where_clause { 23 | let _tmr = luna_orm_trait::Timer::new(#timer_name); 24 | #block 25 | } 26 | )) 27 | .into() 28 | } 29 | -------------------------------------------------------------------------------- /next/taitan-orm/src/database/postgres/commanders/template.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | execute_by_template_fn, fetch_all_by_template_fn, fetch_one_by_template_fn, 3 | fetch_option_by_template_fn, fetch_paged_by_template_fn 4 | }; 5 | use crate::{SqlExecutor, SqlGenerator, SqlGeneratorContainer}; 6 | 7 | pub trait PostgresTemplateCommander: 8 | SqlExecutor + SqlGeneratorContainer 9 | { 10 | execute_by_template_fn!(crate::traits::TemplateRecord::gen_template_arguments_postgres); 11 | 12 | fetch_one_by_template_fn!(crate::traits::TemplateRecord::gen_template_arguments_postgres); 13 | 14 | fetch_option_by_template_fn!(crate::traits::TemplateRecord::gen_template_arguments_postgres); 15 | 16 | fetch_all_by_template_fn!(crate::traits::TemplateRecord::gen_template_arguments_postgres); 17 | 18 | fetch_paged_by_template_fn!( 19 | crate::traits::TemplateRecord::gen_template_count_arguments_postgres, 20 | crate::traits::TemplateRecord::gen_template_arguments_postgres 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /old/luna-orm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "luna-orm" 3 | version = { workspace = true } 4 | edition = "2021" 5 | license-file = "LICENSE" 6 | description = "ORM based on sqlx" 7 | homepage = "https://github.com/thegenius/luna-orm" 8 | rust-version = {workspace = true} 9 | 10 | [dependencies] 11 | luna-orm-trait = { path = "../luna-orm-trait" } 12 | luna-orm-macro = { path = "../luna-orm-macro" } 13 | thiserror = {workspace = true} 14 | sqlx = {workspace = true} 15 | path-absolutize = {workspace = true} 16 | tracing = {workspace = true} 17 | 18 | [dev-dependencies] 19 | tracing-test = {workspace = true} 20 | tracing-subscriber = {workspace = true} 21 | tokio = {workspace = true} 22 | serde = {workspace = true} 23 | serde_json = {workspace = true} 24 | serde_yaml = {workspace = true} 25 | sqlx = {version = "0.8.2", features = ["runtime-tokio", "mysql", "sqlite", "macros", "any"]} 26 | time = { version = "0.3", features = ["macros", "serde"] } 27 | uuid = { version = "1.11.0", features = ["v4", "serde"] } 28 | 29 | [profile.test] 30 | test-threads = 1 31 | -------------------------------------------------------------------------------- /old/luna-types/src/schema.rs: -------------------------------------------------------------------------------- 1 | use crate::constraint::error::ConstraintError; 2 | use crate::record::Record; 3 | use crate::record::RecordConstraint; 4 | use crate::{constraint::supported::Constraint, constraint::named::NamedConstraint}; 5 | 6 | pub struct Schema<'a> { 7 | constraints: Vec>, 8 | } 9 | 10 | impl<'a> Schema<'a> { 11 | pub fn validate(&self, record: Record) -> Result<(), ConstraintError> { 12 | return Ok(()); 13 | } 14 | 15 | pub fn is_valid(&self, record: Record) -> bool { 16 | return true; 17 | } 18 | 19 | pub fn get_entity_schema(&self) -> Schema { 20 | unimplemented!() 21 | } 22 | 23 | pub fn get_selected_schema(&self) -> Schema { 24 | unimplemented!() 25 | } 26 | 27 | pub fn get_primary_schema(&self) -> Schema { 28 | unimplemented!() 29 | } 30 | 31 | pub fn get_location_schema(&self) -> Schema { 32 | unimplemented!() 33 | } 34 | 35 | pub fn get_mutation_schema(&self) -> Schema { 36 | unimplemented!() 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /next/taitan-orm/src/database/mysql/commanders/read.rs: -------------------------------------------------------------------------------- 1 | 2 | 3 | use crate::{count_all_fn, count_fn, devour_fn, devour_paged_fn, exists_fn, search_fn, search_paged_fn, select_fn}; 4 | use crate::{SqlExecutor, SqlGenerator, SqlGeneratorContainer}; 5 | 6 | 7 | use taitan_orm_trait::{ 8 | Entity, Location, Mutation, OrderBy, SelectedEntity, Selection, TemplateRecord, Unique, 9 | }; 10 | use crate::{CountResult, Result}; 11 | 12 | 13 | pub trait MySqlReadCommander: SqlExecutor + SqlGeneratorContainer { 14 | 15 | exists_fn!(MySqlArguments, Unique::gen_unique_arguments_mysql); 16 | 17 | count_fn!(MySqlArguments, Location::gen_location_arguments_mysql); 18 | 19 | count_all_fn!(MySqlArguments); 20 | 21 | select_fn!(Unique::gen_unique_arguments_mysql); 22 | 23 | search_fn!(Location::gen_location_arguments_mysql); 24 | 25 | search_paged_fn!(Location::gen_location_arguments_mysql); 26 | 27 | devour_fn!(crate::page::Pagination::gen_page_arguments_mysql); 28 | 29 | devour_paged_fn!(crate::page::Pagination::gen_page_arguments_mysql); 30 | } 31 | -------------------------------------------------------------------------------- /next/taitan-orm/src/database/mysql/commanders/write.rs: -------------------------------------------------------------------------------- 1 | 2 | use crate::{change_fn, delete_fn, insert_fn, purify_fn, update_fn, upsert_fn, CountResult, Result}; 3 | use crate::{SqlApi, SqlExecutor, SqlGenerator, TaitanOrmError}; 4 | 5 | use crate::sql_generator_container::SqlGeneratorContainer; 6 | use sqlx::{Database, MySql }; 7 | use std::marker::PhantomData; 8 | 9 | use sqlx::mysql::MySqlArguments; 10 | use taitan_orm_trait::{ 11 | Entity, Location, Mutation, OrderBy, SelectedEntity, Selection, TemplateRecord, Unique, 12 | }; 13 | 14 | pub trait MySqlWriteCommander: SqlExecutor + SqlGeneratorContainer { 15 | 16 | insert_fn!(MySqlArguments, Entity::gen_insert_arguments_mysql); 17 | 18 | upsert_fn!(MySqlArguments, Entity::gen_upsert_arguments_mysql); 19 | 20 | update_fn!(MySqlArguments, Unique::gen_update_arguments_mysql); 21 | 22 | change_fn!(MySqlArguments, Mutation::gen_change_arguments_mysql); 23 | 24 | delete_fn!(MySqlArguments, Unique::gen_unique_arguments_mysql); 25 | 26 | purify_fn!(MySqlArguments, Location::gen_location_arguments_mysql); 27 | } -------------------------------------------------------------------------------- /old/luna-orm-axum/src/response.rs: -------------------------------------------------------------------------------- 1 | use luna_orm::prelude::*; 2 | use serde::{Deserialize, Serialize}; 3 | 4 | #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] 5 | #[serde(untagged)] 6 | pub enum PostResponse 7 | where 8 | T: Serialize + Entity + Send + Sync, 9 | { 10 | #[serde(rename = "create")] 11 | Create { entity: T }, 12 | #[serde(rename = "insert")] 13 | Insert, 14 | #[serde(rename = "upsert")] 15 | Upsert, 16 | } 17 | #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] 18 | #[serde(untagged)] 19 | pub enum PutResponse { 20 | #[serde(rename = "update")] 21 | Update, 22 | #[serde(rename = "change")] 23 | Change { count: usize }, 24 | } 25 | 26 | #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] 27 | #[serde(untagged)] 28 | pub enum DeleteResponse 29 | where 30 | SE: Serialize + SelectedEntity, 31 | { 32 | #[serde(rename = "delete")] 33 | Delete, 34 | #[serde(rename = "remove")] 35 | Remove { entity: Option }, 36 | #[serde(rename = "purify")] 37 | Purify { count: usize }, 38 | } 39 | -------------------------------------------------------------------------------- /old/luna-orm-trait/src/timer.rs: -------------------------------------------------------------------------------- 1 | use std::marker::PhantomData; 2 | use std::{borrow::Cow, time::Instant}; 3 | use tracing::debug; 4 | 5 | #[cfg(debug_assertions)] 6 | pub struct Timer<'a> { 7 | func_name: Cow<'a, str>, 8 | start: Instant, 9 | } 10 | 11 | #[cfg(debug_assertions)] 12 | impl<'a> Timer<'a> { 13 | pub fn new(func_name: impl Into>) -> Self { 14 | Self { 15 | func_name: func_name.into(), 16 | start: Instant::now(), 17 | } 18 | } 19 | } 20 | 21 | #[cfg(debug_assertions)] 22 | impl<'a> Drop for Timer<'a> { 23 | fn drop(&mut self) { 24 | let elapsed = self.start.elapsed(); 25 | debug!(target: "luna_orm", fn_name= ?self.func_name, elapsed = ?elapsed); 26 | } 27 | } 28 | 29 | #[cfg(not(debug_assertions))] 30 | pub struct Timer<'a> { 31 | _phantom: PhantomData<&'a ()>, 32 | } 33 | 34 | #[cfg(not(debug_assertions))] 35 | impl<'a> Timer<'a> { 36 | pub fn new(func_name: impl Into>) -> Self { 37 | Self { 38 | _phantom: PhantomData, 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /next/taitan-orm/src/database/postgres/commanders/write.rs: -------------------------------------------------------------------------------- 1 | 2 | 3 | use crate::{change_fn, delete_fn, insert_fn, purify_fn, update_fn, upsert_fn, CountResult, Result}; 4 | use crate::{SqlApi, SqlExecutor, SqlGenerator, TaitanOrmError}; 5 | 6 | 7 | use crate::sql_generator_container::SqlGeneratorContainer; 8 | use sqlx::{Database, MySql, Postgres, Sqlite, SqlitePool}; 9 | 10 | use sqlx::postgres::PgArguments; 11 | use taitan_orm_trait::{ 12 | Entity, Location, Mutation, OrderBy, SelectedEntity, Selection, TemplateRecord, Unique, 13 | }; 14 | 15 | 16 | pub trait PostgresWriteCommander: SqlExecutor + SqlGeneratorContainer { 17 | 18 | insert_fn!(PgArguments, Entity::gen_insert_arguments_postgres); 19 | 20 | upsert_fn!(PgArguments, Entity::gen_upsert_arguments_postgres); 21 | 22 | update_fn!(PgArguments, Unique::gen_update_arguments_postgres); 23 | 24 | change_fn!(PgArguments, Mutation::gen_change_arguments_postgres); 25 | 26 | delete_fn!(PgArguments, Unique::gen_unique_arguments_postgres); 27 | 28 | purify_fn!(PgArguments, Location::gen_location_arguments_postgres); 29 | } -------------------------------------------------------------------------------- /next/taitan-orm-macro/src/fields/mod.rs: -------------------------------------------------------------------------------- 1 | mod entity_parser; 2 | mod fields_filter; 3 | mod field_mapper; 4 | mod parser; 5 | mod table_name_parser; 6 | mod unique_parser; 7 | mod fields_mapper; 8 | mod mutation_parser; 9 | mod location_parser; 10 | mod mappers; 11 | mod selection_parser; 12 | mod selected_parser; 13 | 14 | pub use entity_parser::EntityParser; 15 | pub use fields_filter::FieldsFilter; 16 | pub use table_name_parser::TableNameParser; 17 | pub use unique_parser::UniqueParser; 18 | pub use fields_mapper::FieldsMapper; 19 | 20 | pub use field_mapper::DefaultFieldMapper; 21 | pub use field_mapper::FieldMapType; 22 | pub use field_mapper::FieldMapper; 23 | pub use parser::FieldsContainer; 24 | pub use parser::FieldsParser; 25 | 26 | pub use mappers::RowConstructor; 27 | pub use mappers::RowGetConstructor; 28 | 29 | pub use mappers::NamesConstructor; 30 | pub use mappers::NamesAddConstructor; 31 | pub use mappers::StructConstructor; 32 | pub use mappers::ArgsConstructorPostgres; 33 | pub use mappers::ArgsConstructorMySql; 34 | pub use mappers::ArgsConstructorSqlite; 35 | pub use location_parser::LocationParser; 36 | -------------------------------------------------------------------------------- /next/taitan-orm-macro/src/fields/location_parser.rs: -------------------------------------------------------------------------------- 1 | use crate::fields::mappers::{ 2 | ArgsConstructorMySql, ArgsConstructorPostgres, ArgsConstructorSqlite, NamesAddConstructor, 3 | NamesConstructor, 4 | }; 5 | use crate::fields::{FieldsContainer, TableNameParser}; 6 | use proc_macro2::TokenStream; 7 | 8 | pub trait LocationParser: 9 | FieldsContainer 10 | + TableNameParser 11 | + NamesAddConstructor 12 | + NamesConstructor 13 | + ArgsConstructorPostgres 14 | + ArgsConstructorSqlite 15 | + ArgsConstructorMySql 16 | { 17 | fn get_location_fields_name(&self) -> TokenStream { 18 | self.of_option_names_vec() 19 | } 20 | 21 | fn get_where_clause(&self) -> TokenStream { 22 | self.of_where_clause() 23 | } 24 | 25 | fn gen_location_arguments_sqlite(&self) -> TokenStream { 26 | self.of_location_args_sqlite() 27 | } 28 | 29 | fn gen_location_arguments_mysql(&self) -> TokenStream { 30 | self.of_location_args_mysql() 31 | } 32 | 33 | fn gen_location_arguments_postgres(&self) -> TokenStream { 34 | self.of_location_args_postgres() 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /next/taitan-orm-trait/src/location/location.rs: -------------------------------------------------------------------------------- 1 | use crate::{FieldName, NotImplementError}; 2 | use sqlx::error::BoxDynError; 3 | use sqlx::mysql::MySqlArguments; 4 | use sqlx::postgres::PgArguments; 5 | use sqlx::sqlite::SqliteArguments; 6 | use std::fmt::Debug; 7 | 8 | pub trait Location: Sync + Debug { 9 | fn get_table_name(&self) -> &'static str; 10 | 11 | fn get_location_fields_name(&self) -> Vec; 12 | 13 | fn get_where_clause(&self, wrap_char: char, place_holder: char) -> String; 14 | 15 | // fn check_valid_order_by(&self, fields: &[&str]) -> bool; 16 | 17 | fn gen_location_arguments_sqlite(&self) -> Result, BoxDynError> { 18 | Err(NotImplementError("gen_primary_arguments_sqlite".to_string()).into()) 19 | } 20 | fn gen_location_arguments_mysql(&self) -> Result { 21 | Err(NotImplementError("gen_primary_arguments_mysql".to_string()).into()) 22 | } 23 | fn gen_location_arguments_postgres(&self) -> Result { 24 | Err(NotImplementError("gen_primary_arguments_postgres".to_string()).into()) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /next/taitan-orm/src/database/postgres/commanders/read.rs: -------------------------------------------------------------------------------- 1 | 2 | use crate::sql_generator::DefaultSqlGenerator; 3 | use crate::{count_all_fn, count_fn, devour_fn, devour_paged_fn, exists_fn, search_fn, search_paged_fn, select_fn}; 4 | use crate::{CountResult, Result}; 5 | use crate::{SqlApi, SqlExecutor, SqlGenerator, SqlGeneratorContainer}; 6 | use taitan_orm_trait::{ 7 | Entity, Location, Mutation, OrderBy, SelectedEntity, Selection, TemplateRecord, Unique, 8 | }; 9 | 10 | 11 | 12 | pub trait PostgresReadCommander: SqlExecutor + SqlGeneratorContainer { 13 | 14 | exists_fn!(PgArguments, Unique::gen_unique_arguments_postgres); 15 | 16 | count_fn!(PgArguments, Location::gen_location_arguments_postgres); 17 | 18 | count_all_fn!(PgArguments); 19 | 20 | select_fn!(Unique::gen_unique_arguments_postgres); 21 | 22 | search_fn!(Location::gen_location_arguments_postgres); 23 | 24 | search_paged_fn!(Location::gen_location_arguments_postgres); 25 | 26 | devour_fn!(crate::page::Pagination::gen_page_arguments_postgres); 27 | 28 | devour_paged_fn!(crate::page::Pagination::gen_page_arguments_postgres); 29 | } 30 | -------------------------------------------------------------------------------- /old/luna-orm/tests/common/setup_database.rs: -------------------------------------------------------------------------------- 1 | use luna_orm::prelude::*; 2 | use luna_orm::LunaOrmResult; 3 | 4 | pub async fn setup_database() -> LunaOrmResult> { 5 | let config = SqliteLocalConfig::new("./workspace", "test.db"); 6 | let db: SqliteDatabase = SqliteDatabase::build(config).await.unwrap(); 7 | let mut db: DB = DB(db); 8 | db.execute_plain("DROP TABLE IF EXISTS `article`") 9 | .await 10 | .unwrap(); 11 | db.execute_plain( 12 | "CREATE TABLE IF NOT EXISTS `article`(`id` INT PRIMARY KEY, `age` INT, `content` VARCHAR(64))", 13 | ).await?; 14 | Ok(db) 15 | } 16 | 17 | pub async fn create_table( 18 | db: &mut DB, 19 | table_name: &str, 20 | create_table_stmt: &str, 21 | ) -> LunaOrmResult 22 | where 23 | T: Database, 24 | { 25 | let drop_stmt = format!("DROP TABLE IF EXISTS `{}`", table_name); 26 | db.execute_plain(&drop_stmt).await?; 27 | db.execute_plain(create_table_stmt).await?; 28 | //let delete_stmt = format!("DELETE FROM `{}`", table_name); 29 | //db.execute_plain(&delete_stmt).await?; 30 | Ok(true) 31 | } 32 | -------------------------------------------------------------------------------- /next/taitan-orm-macro/src/fields/fields_mapper.rs: -------------------------------------------------------------------------------- 1 | use proc_macro2::TokenStream; 2 | use quote::quote; 3 | use syn::Field; 4 | use crate::fields::{DefaultFieldMapper, FieldMapType, FieldMapper, FieldsContainer, FieldsParser}; 5 | use crate::types::{DefaultTypeChecker, TypeChecker}; 6 | 7 | pub trait FieldsMapper: FieldsContainer { 8 | fn get_maybe_option_name_vec(&self) -> TokenStream; 9 | } 10 | 11 | impl FieldsMapper for FieldsParser { 12 | 13 | fn get_maybe_option_name_vec(&self) -> TokenStream { 14 | let tokens = 15 | DefaultFieldMapper::map_field_vec(self.get_fields(), &|field: Field| { 16 | let field_type = &field.ty; 17 | if DefaultTypeChecker::type_is_option(field_type) { 18 | DefaultFieldMapper::map_field( 19 | field, 20 | FieldMapType::OptionNamePush, 21 | ) 22 | } else { 23 | DefaultFieldMapper::map_field(field, FieldMapType::NamePush) 24 | } 25 | }); 26 | quote!( 27 | let mut fields = Vec::new(); 28 | #(#tokens;)* 29 | return fields; 30 | ) 31 | } 32 | } -------------------------------------------------------------------------------- /old/luna-types/tests/constraint.rs: -------------------------------------------------------------------------------- 1 | use luna_types::constraint::named:: NamedConstraint; 2 | use luna_types::constraint::supported::Constraint; 3 | use luna_types::constraint::supports::integer::IntegerConstraint; 4 | use luna_types::constraint::supports::integer::IntegerConstraintBuilder; 5 | 6 | #[test] 7 | fn test_constraint_serialize_deserialize() { 8 | let int_constraint: IntegerConstraint = IntegerConstraintBuilder::default() 9 | .min(23i16) 10 | .build() 11 | .unwrap(); 12 | 13 | let constraint_type = Constraint::SmallInt(int_constraint); 14 | let constraint_type_serde_str = serde_json::to_string(&constraint_type).unwrap(); 15 | let expect_str = "{\"type\":\"smallint\",\"is_option\":null,\"min\":23,\"max\":null}"; 16 | assert_eq!(constraint_type_serde_str, expect_str); 17 | 18 | let named_cons: NamedConstraint = NamedConstraint::from_named("hello".to_string(), constraint_type.clone()); 19 | let named_cons_str = serde_json::to_string(&named_cons).unwrap(); 20 | let named_cons_expect_str = "{\"name\":\"hello\",\"constraint\":{\"type\":\"smallint\",\"is_option\":null,\"min\":23,\"max\":null}}"; 21 | assert_eq!(named_cons_str, named_cons_expect_str); 22 | } 23 | -------------------------------------------------------------------------------- /old/luna-orm-macro/src/type_extract.rs: -------------------------------------------------------------------------------- 1 | use crate::type_check::type_is_option; 2 | use quote::quote; 3 | use syn::Path; 4 | use syn::Type; 5 | 6 | pub fn get_option_inner_type(ty: &syn::Type) -> Option<&syn::Type> { 7 | if !type_is_option(ty) { 8 | return None; 9 | } 10 | 11 | let syn::Type::Path(ty) = ty else { return None }; 12 | if ty.qself.is_some() { 13 | return None; 14 | } 15 | 16 | let last_segment = ty.path.segments.last().unwrap(); 17 | let syn::PathArguments::AngleBracketed(generics) = &last_segment.arguments else { 18 | return None; 19 | }; 20 | if generics.args.len() != 1 { 21 | return None; 22 | } 23 | let syn::GenericArgument::Type(inner_type) = &generics.args[0] else { 24 | return None; 25 | }; 26 | 27 | Some(inner_type) 28 | } 29 | 30 | pub fn extract_type_path(ty: &syn::Type) -> Option<&Path> { 31 | match *ty { 32 | syn::Type::Path(ref typepath) if typepath.qself.is_none() => Some(&typepath.path), 33 | _ => None, 34 | } 35 | } 36 | 37 | pub fn create_option_type(ty: &syn::Type) -> proc_macro2::TokenStream { 38 | let output = quote!( 39 | std::option::Option<#ty> 40 | ); 41 | output 42 | } 43 | -------------------------------------------------------------------------------- /next/taitan-orm/src/error.rs: -------------------------------------------------------------------------------- 1 | use thiserror::Error; 2 | 3 | #[derive(Error, Debug)] 4 | pub enum TaitanOrmError { 5 | #[error("databse init fail with args: `{0}`")] 6 | DatabaseInitFail(String), 7 | 8 | #[error(transparent)] 9 | SqlxError(#[from] sqlx::Error), 10 | 11 | #[error(transparent)] 12 | BoxDynError(#[from] Box), 13 | 14 | // #[error(transparent)] 15 | // BoxDynNoStaticError(#[from] Box), 16 | 17 | #[error(transparent)] 18 | BoxDynError2(#[from] Box), 19 | 20 | #[error("execute template paged search must has count sql")] 21 | TemplatePagedNotHasCountSql, 22 | 23 | #[error("execute template paged search must has page field")] 24 | TemplatePageFieldNotFound, 25 | 26 | #[error("deserialize entity from row error")] 27 | FromRowToEntityError, 28 | 29 | #[error("invalid order by fields")] 30 | OrderByFieldsError, 31 | 32 | #[error("method not implement error: {0}")] 33 | NotImplement(String), 34 | 35 | #[error("paged template sql can't execute with no count sql")] 36 | PagedTemplateHasNoCountSql, 37 | 38 | #[error("dynamic request parse error: {0}")] 39 | DynamicRequestParseError(String), 40 | } 41 | -------------------------------------------------------------------------------- /old/luna-orm-axum/tests/axum_router.rs: -------------------------------------------------------------------------------- 1 | use axum::http::StatusCode; 2 | use axum::routing::{get, post}; 3 | use axum::Json; 4 | use axum::Router; 5 | use luna_orm::prelude::*; 6 | use luna_orm_axum::handler::PostHandler; 7 | //use luna_orm_axum::router::get_post_router; 8 | use serde::{Deserialize, Serialize}; 9 | use sqlx::SqliteConnection; 10 | 11 | #[derive(Debug, Clone, Serialize, Deserialize, Entity)] 12 | struct User { 13 | #[PrimaryKey] 14 | id: i64, 15 | username: String, 16 | } 17 | async fn create_user(Json(payload): Json) -> (StatusCode, Json) { 18 | // insert your application logic here 19 | let user = User { 20 | id: 1337, 21 | username: payload.username, 22 | }; 23 | 24 | // this will be converted into a JSON response 25 | // with a status code of `201 Created` 26 | (StatusCode::CREATED, Json(user)) 27 | } 28 | 29 | // the input to our `create_user` handler 30 | #[derive(Deserialize)] 31 | struct CreateUser { 32 | username: String, 33 | } 34 | 35 | #[tokio::test] 36 | async fn test_router() { 37 | let config = SqliteLocalConfig::new("workspace", "test.db"); 38 | let database = SqliteDatabase::build(config).await.unwrap(); 39 | // let router = get_post_router::(&database, "/user"); 40 | } 41 | -------------------------------------------------------------------------------- /old/luna-orm-dynamic/src/active_json.rs: -------------------------------------------------------------------------------- 1 | use serde_json::{Number, Value}; 2 | 3 | #[derive(Debug, Clone)] 4 | pub struct ActiveJson { 5 | value: Value, 6 | } 7 | /* 8 | impl ActiveJson { 9 | pub fn as_str(&self) -> Option<&str> { 10 | match &self.value { 11 | Value::String(data) => Some(data), 12 | _ => None, 13 | } 14 | } 15 | pub fn as_bool(&self) -> Option { 16 | match &self.value { 17 | Value::Bool(data) => Some(*data), 18 | _ => None, 19 | } 20 | } 21 | pub fn as_null(&self) -> Option<()> { 22 | match &self.value { 23 | Value::Null => Some(()), 24 | _ => None, 25 | } 26 | } 27 | 28 | pub fn as_i64(&self) -> Option { 29 | match &self.value { 30 | Value::Number(data) => data.as_i64(), 31 | _ => None, 32 | } 33 | } 34 | 35 | pub fn as_u64(&self) -> Option { 36 | match &self.value { 37 | Value::Number(data) => data.as_u64(), 38 | _ => None, 39 | } 40 | } 41 | 42 | pub fn as_f64(&self) -> Option { 43 | match &self.value { 44 | Value::Number(data) => data.as_f64(), 45 | _ => None, 46 | } 47 | } 48 | } 49 | */ 50 | -------------------------------------------------------------------------------- /old/luna-types/src/constraint/supports/datetime.rs: -------------------------------------------------------------------------------- 1 | use crate::constraint::common::ConstraintTrait; 2 | use derive_builder::Builder; 3 | use regex::Regex; 4 | use serde::{Deserialize, Serialize}; 5 | use serde_json::Value; 6 | use std::borrow::Cow; 7 | use std::{fmt::Debug}; 8 | use chrono::{DateTime, Utc}; 9 | 10 | #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, Builder)] 11 | #[builder(setter(into))] 12 | pub struct DateTimeConstraint { 13 | #[builder(default = "None")] 14 | #[serde(default)] 15 | is_option: Option 16 | } 17 | 18 | 19 | impl ConstraintTrait for DateTimeConstraint { 20 | type ValueType = DateTime; 21 | 22 | fn is_option(&self) -> bool { 23 | return self.is_option.unwrap_or(false); 24 | } 25 | 26 | fn is_valid_json(&self, value: &Value) -> bool { 27 | let value = value.as_str(); 28 | if value.is_none() { 29 | return false; 30 | } 31 | let value = value.unwrap(); 32 | let datetime_value = serde_json::from_str(value); 33 | if let Err(_) = datetime_value { 34 | return false; 35 | } 36 | return self.is_valid(&datetime_value.unwrap()); 37 | } 38 | 39 | fn is_valid(&self, value: &DateTime) -> bool { 40 | return true; 41 | } 42 | } -------------------------------------------------------------------------------- /next/taitan-orm-trait/src/join/joined_condition.rs: -------------------------------------------------------------------------------- 1 | use crate::join::{FromClause, JoinedFields, JoinedMode}; 2 | use serde::{Deserialize, Serialize}; 3 | 4 | #[derive(Serialize, Deserialize, PartialEq, Eq, Debug)] 5 | pub struct JoinedCondition { 6 | pub(crate) mode: JoinedMode, 7 | #[serde(alias = "left")] 8 | pub(crate) left_table: String, 9 | #[serde(alias = "right")] 10 | pub(crate) right_table: String, 11 | #[serde(alias = "fields")] 12 | pub(crate) joined_fields: Vec, 13 | } 14 | 15 | pub fn get_on_clause(joined_fields: &Vec) -> String { 16 | let mut on_clause_vec: Vec = Vec::new(); 17 | for field in joined_fields { 18 | let on_seg = format!( 19 | "{}.{} = {}.{}", 20 | field.0.table_name, field.0.field_name, field.1.table_name, field.1.field_name 21 | ); 22 | on_clause_vec.push(on_seg); 23 | } 24 | on_clause_vec.join(",") 25 | } 26 | 27 | impl FromClause for JoinedCondition { 28 | fn get_from_clause(&self) -> String { 29 | let on_clause = get_on_clause(&self.joined_fields); 30 | let join_operator = self.mode.get_join_operator(); 31 | format!( 32 | "{} {} {} ON {}", 33 | self.left_table, join_operator, self.right_table, on_clause 34 | ) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /old/luna-types/tests/string.rs: -------------------------------------------------------------------------------- 1 | use luna_types::constraint::supported::Constraint; 2 | use luna_types::constraint::common::ConstraintTrait; 3 | use luna_types::constraint::supports::string::StringConstraint; 4 | use luna_types::constraint::supports::string::StringConstraintBuilder; 5 | use serde_json::{Number, Value}; 6 | 7 | #[test] 8 | pub fn test_min_max() { 9 | let mut builder = StringConstraintBuilder::default(); 10 | let constraint = builder.min_len(5).max_len(8).build().unwrap(); 11 | let value = Value::String("hello".to_string()); 12 | assert!(constraint.is_valid_json(&value)); 13 | let value = Value::String("hello world".to_string()); 14 | assert_eq!(false, constraint.is_valid_json(&value)); 15 | } 16 | 17 | #[test] 18 | pub fn test_regex() { 19 | let mut builder = StringConstraintBuilder::default(); 20 | let constraint = builder 21 | .min_len(5) 22 | .max_len(8) 23 | .regex("^hello") 24 | .build() 25 | .unwrap(); 26 | let value = Value::String("hello".to_string()); 27 | assert!(constraint.is_valid_json(&value)); 28 | let value = Value::String("hello world".to_string()); 29 | assert_eq!(false, constraint.is_valid_json(&value)); 30 | let value = Value::String("test".to_string()); 31 | assert_eq!(false, constraint.is_valid_json(&value)); 32 | } 33 | -------------------------------------------------------------------------------- /next/taitan-orm-trait/src/page/paged_list.rs: -------------------------------------------------------------------------------- 1 | use crate::paged_info::PagedInfo; 2 | use crate::SelectedEntity; 3 | use sqlx::Database; 4 | use std::marker::PhantomData; 5 | use crate::pagination::Pagination; 6 | 7 | #[derive(Clone, Debug)] 8 | pub struct PagedList 9 | where 10 | DB: Database, 11 | T: SelectedEntity, 12 | { 13 | pub data: Vec, 14 | pub page: PagedInfo, 15 | pub _phantom: PhantomData, 16 | } 17 | 18 | impl PagedList 19 | where 20 | DB: Database, 21 | T: SelectedEntity, 22 | { 23 | pub fn empty(page_size: u64, page_num: u64) -> Self { 24 | Self { 25 | page: PagedInfo::empty(page_size, page_num), 26 | data: Vec::new(), 27 | _phantom: PhantomData, 28 | } 29 | } 30 | } 31 | 32 | pub fn build_paged_list( 33 | data: Vec, 34 | record_count: u64, 35 | page: &Pagination, 36 | ) -> PagedList 37 | where 38 | SE: SelectedEntity + Send + Unpin, 39 | { 40 | let page_info = PagedInfo { 41 | page_size: page.page_size, 42 | page_num: page.page_num, 43 | page_total: (record_count + page.page_size - 1) / page.page_size, // ceil 44 | total: record_count, 45 | }; 46 | 47 | PagedList { 48 | data, 49 | page: page_info, 50 | _phantom: PhantomData, 51 | } 52 | } -------------------------------------------------------------------------------- /next/taitan-orm/src/database/mysql/database.rs: -------------------------------------------------------------------------------- 1 | use sqlx::{MySql, MySqlConnection, MySqlPool, Sqlite}; 2 | use crate::database::sqlite::{SqliteDatabase, SqliteReadCommander, SqliteWriteCommander}; 3 | use crate::sql_generator::MySqlGenerator; 4 | use crate::{executor_impl, CountResult, DefaultSqlGenerator, SqlExecutor, SqlGeneratorContainer, SqlGenericExecutor}; 5 | 6 | #[derive(Debug, Clone)] 7 | pub struct MySqlDatabase { 8 | generator: MySqlGenerator, 9 | pool: MySqlPool, 10 | } 11 | impl MySqlDatabase { 12 | pub fn get_pool(&mut self) -> crate::Result<&MySqlPool> { 13 | Ok(&self.pool) 14 | } 15 | 16 | async fn get_connection(&mut self) -> crate::Result> { 17 | Ok(self.get_pool()?.acquire().await?) 18 | } 19 | } 20 | impl SqlGenericExecutor for MySqlDatabase { 21 | type DB = MySql; 22 | type CountType = CountResult; 23 | 24 | fn get_affected_rows(query_result: &::QueryResult) -> u64 { 25 | query_result.rows_affected() 26 | } 27 | 28 | } 29 | // SqlExecutor + SqlGeneratorContainer + Extractor 30 | impl SqlGeneratorContainer for MySqlDatabase { 31 | type G = MySqlGenerator; 32 | 33 | fn get_generator(&mut self) -> &Self::G { 34 | &self.generator 35 | } 36 | } 37 | 38 | impl SqlExecutor for MySqlDatabase { 39 | executor_impl!(MySqlConnection); 40 | } 41 | 42 | 43 | -------------------------------------------------------------------------------- /old/luna-orm/src/database/mysql/MySqlInputGenerator.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Arguments; 2 | use sqlx::{Database, MySql}; 3 | use luna_orm_trait::{Entity, Location, Mutation, OrderBy, Primary}; 4 | use luna_orm_trait::input_generator::InputGenerator; 5 | 6 | // struct MysqlInputGenerator; 7 | // impl InputGenerator for MysqlInputGenerator { 8 | // fn gen_insert_arguments(&self, entity: &dyn Entity) -> DB::Arguments<'_> { 9 | // // let mut arguments: ::Arguments<'_> = ::Arguments::default(); 10 | // // return arguments; 11 | // todo!() 12 | // } 13 | // 14 | // fn gen_upsert_arguments(&self, entity: &dyn Entity) -> ::Arguments<'_> { 15 | // todo!() 16 | // } 17 | // 18 | // fn gen_update_arguments(&self, mutation: &dyn Mutation, primary: &dyn Primary) -> ::Arguments<'_> { 19 | // todo!() 20 | // } 21 | // 22 | // fn gen_change_arguments(&self, mutation: &dyn Mutation, location: &dyn Location) -> ::Arguments<'_> { 23 | // todo!() 24 | // } 25 | // 26 | // fn gen_primary_arguments(&self, primary: &dyn Primary) -> ::Arguments<'_> { 27 | // todo!() 28 | // } 29 | // 30 | // fn gen_location_arguments(&self, location: &dyn Location, order_by_option: Option<&dyn OrderBy>) -> ::Arguments<'_> { 31 | // todo!() 32 | // } 33 | // } -------------------------------------------------------------------------------- /next/taitan-orm-trait/src/template/template_value.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Display; 2 | 3 | #[derive(Debug, Clone, PartialEq, Eq)] 4 | pub enum TemplateValue { 5 | SingleQuoteString(String), 6 | DoubleQuoteString(String), 7 | BackQuoteString(String), 8 | Star(String), 9 | Segment(String), 10 | HashVariable(String), 11 | DollarVariable(String), 12 | } 13 | 14 | pub trait InnerString { 15 | fn inner_string(&self) -> String; 16 | } 17 | 18 | impl InnerString for TemplateValue { 19 | fn inner_string(&self) -> String { 20 | match &self { 21 | Self::SingleQuoteString(s) | Self::DoubleQuoteString(s) => s.clone(), 22 | Self::BackQuoteString(s) | Self::Star(s) => s.clone(), 23 | Self::HashVariable(v) | Self::DollarVariable(v) => v.clone(), 24 | Self::Segment(s) => s.clone(), 25 | } 26 | } 27 | } 28 | 29 | impl Display for TemplateValue { 30 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 31 | let str = match self { 32 | TemplateValue::SingleQuoteString(v) 33 | | TemplateValue::DoubleQuoteString(v) 34 | | TemplateValue::BackQuoteString(v) 35 | | TemplateValue::Star(v) 36 | | TemplateValue::Segment(v) 37 | | TemplateValue::HashVariable(v) => v.to_string(), 38 | | TemplateValue::DollarVariable(v) => v.to_string(), 39 | }; 40 | write!(f, "{}", str) 41 | } 42 | } -------------------------------------------------------------------------------- /next/taitan-orm/src/database/postgres/database.rs: -------------------------------------------------------------------------------- 1 | use sqlx::{MySql, MySqlConnection, MySqlPool, PgConnection, PgPool, Postgres, Sqlite}; 2 | use crate::database::sqlite::{SqliteDatabase, SqliteReadCommander, SqliteWriteCommander}; 3 | use crate::sql_generator::{MySqlGenerator, PostgresGenerator}; 4 | use crate::{executor_impl, CountResult, DefaultSqlGenerator, SqlExecutor, SqlGeneratorContainer, SqlGenericExecutor}; 5 | 6 | #[derive(Debug, Clone)] 7 | pub struct PostgresDatabase { 8 | generator: PostgresGenerator, 9 | pool: PgPool, 10 | } 11 | impl PostgresDatabase { 12 | pub fn get_pool(&mut self) -> crate::Result<&PgPool> { 13 | Ok(&self.pool) 14 | } 15 | 16 | async fn get_connection(&mut self) -> crate::Result> { 17 | Ok(self.get_pool()?.acquire().await?) 18 | } 19 | } 20 | impl SqlGenericExecutor for PostgresDatabase { 21 | type DB = Postgres; 22 | type CountType = CountResult; 23 | 24 | fn get_affected_rows(query_result: &::QueryResult) -> u64 { 25 | query_result.rows_affected() 26 | } 27 | 28 | } 29 | // SqlExecutor + SqlGeneratorContainer + Extractor 30 | impl SqlGeneratorContainer for PostgresDatabase { 31 | type G = PostgresGenerator; 32 | 33 | fn get_generator(&mut self) -> &Self::G { 34 | &self.generator 35 | } 36 | } 37 | 38 | impl SqlExecutor for PostgresDatabase { 39 | executor_impl!(PgConnection); 40 | } 41 | 42 | 43 | -------------------------------------------------------------------------------- /next/taitan-orm/src/database/mysql/transaction.rs: -------------------------------------------------------------------------------- 1 | use sqlx::{MySql, MySqlConnection}; 2 | use crate::{transaction_impl, CountResult, SqlExecutor, SqlGeneratorContainer, SqlGenericExecutor}; 3 | use crate::sql_generator::MySqlGenerator; 4 | 5 | #[derive(Debug)] 6 | pub struct MySqlTransaction<'a> { 7 | transaction: sqlx::Transaction<'a, MySql>, 8 | generator: &'a MySqlGenerator, 9 | } 10 | 11 | impl<'a> MySqlTransaction<'a> { 12 | pub fn new(trx: sqlx::Transaction<'a, MySql>, generator: &'a MySqlGenerator) -> Self { 13 | Self { 14 | transaction: trx, 15 | generator, 16 | } 17 | } 18 | 19 | #[inline] 20 | pub async fn commit(self) -> crate::Result<()> { 21 | Ok(self.transaction.commit().await?) 22 | } 23 | 24 | #[inline] 25 | pub async fn rollback(self) -> crate::Result<()> { 26 | Ok(self.transaction.rollback().await?) 27 | } 28 | } 29 | 30 | impl<'t> SqlGenericExecutor for MySqlTransaction<'t> { 31 | type DB = MySql; 32 | type CountType = CountResult; 33 | 34 | fn get_affected_rows(query_result: &::QueryResult) -> u64 { 35 | query_result.rows_affected() 36 | } 37 | } 38 | 39 | impl<'t> SqlExecutor for MySqlTransaction<'t> { 40 | transaction_impl!(MySqlConnection); 41 | } 42 | impl<'a> SqlGeneratorContainer for MySqlTransaction<'a> { 43 | type G = MySqlGenerator; 44 | 45 | fn get_generator(&mut self) -> &Self::G { 46 | &self.generator 47 | } 48 | } -------------------------------------------------------------------------------- /next/taitan-orm-trait/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports, unused_mut, unused_variables)] 2 | mod entity; 3 | mod error; 4 | mod join; 5 | mod location; 6 | mod mutation; 7 | mod order_by; 8 | mod page; 9 | mod schema; 10 | mod selected; 11 | mod selection; 12 | mod template_record; 13 | mod unique; 14 | mod update_command; 15 | mod write_command; 16 | mod template; 17 | mod optional; 18 | mod field; 19 | 20 | pub use schema::Schema; 21 | pub use optional::Optional; 22 | 23 | pub use error::NotImplementError; 24 | pub use error::NotValidOrderByError; 25 | 26 | pub use entity::Entity; 27 | 28 | pub use mutation::Mutation; 29 | pub use unique::Unique; 30 | pub use update_command::UpdateCommand; 31 | 32 | pub use selected::SelectedEntity; 33 | pub use selection::Selection; 34 | pub use selected::SelectedEntityNew; 35 | 36 | pub use join::FromClause; 37 | pub use location::CmpOperator; 38 | pub use location::Location; 39 | pub use location::LocationExpr; 40 | pub use location::LocationTrait; 41 | pub use order_by::validate_order_by; 42 | pub use order_by::OrderBy; 43 | 44 | pub use join::JoinedCondition; 45 | pub use join::JoinedConditions; 46 | 47 | pub use page::paged_info; 48 | pub use page::paged_list; 49 | pub use page::pagination; 50 | pub use page::count_sql::CountSql; 51 | 52 | pub use template_record::TemplateRecord; 53 | pub use template::ParsedTemplateSql; 54 | pub use template::TemplateValue; 55 | 56 | pub use write_command::WriteCommand; 57 | pub use page::paged_list::build_paged_list; 58 | pub use field::FieldName; -------------------------------------------------------------------------------- /next/taitan-orm/src/database/postgres/transaction.rs: -------------------------------------------------------------------------------- 1 | use sqlx::{PgConnection, Postgres}; 2 | use crate::{transaction_impl, CountResult, SqlExecutor, SqlGeneratorContainer, SqlGenericExecutor}; 3 | use crate::sql_generator::{PostgresGenerator}; 4 | 5 | #[derive(Debug)] 6 | pub struct PostgresTransaction<'a> { 7 | transaction: sqlx::Transaction<'a, Postgres>, 8 | generator: &'a PostgresGenerator, 9 | } 10 | 11 | impl<'a> PostgresTransaction<'a> { 12 | pub fn new(trx: sqlx::Transaction<'a, Postgres>, generator: &'a PostgresGenerator) -> Self { 13 | Self { 14 | transaction: trx, 15 | generator, 16 | } 17 | } 18 | 19 | #[inline] 20 | pub async fn commit(self) -> crate::Result<()> { 21 | Ok(self.transaction.commit().await?) 22 | } 23 | 24 | #[inline] 25 | pub async fn rollback(self) -> crate::Result<()> { 26 | Ok(self.transaction.rollback().await?) 27 | } 28 | } 29 | 30 | impl<'t> SqlGenericExecutor for PostgresTransaction<'t> { 31 | type DB = Postgres; 32 | type CountType = CountResult; 33 | 34 | fn get_affected_rows(query_result: &::QueryResult) -> u64 { 35 | query_result.rows_affected() 36 | } 37 | } 38 | 39 | impl<'t> SqlExecutor for PostgresTransaction<'t> { 40 | transaction_impl!(PgConnection); 41 | } 42 | impl<'a> SqlGeneratorContainer for PostgresTransaction<'a> { 43 | type G = PostgresGenerator; 44 | 45 | fn get_generator(&mut self) -> &Self::G { 46 | &self.generator 47 | } 48 | } -------------------------------------------------------------------------------- /old/luna-orm-macro/src/order_by.rs: -------------------------------------------------------------------------------- 1 | use proc_macro::{self, TokenStream}; 2 | use quote::quote; 3 | use quote::quote_spanned; 4 | 5 | use crate::utils::*; 6 | use case::CaseExt; 7 | use proc_macro2::{Ident, Span}; 8 | use syn::Attribute; 9 | use syn::Field; 10 | use syn::{ 11 | parse_macro_input, token, Data, DataEnum, DataStruct, DataUnion, DeriveInput, Error, Fields, 12 | FieldsNamed, LitStr, Path, Result, 13 | }; 14 | 15 | pub fn impl_order_by_macro(input: TokenStream) -> TokenStream { 16 | let DeriveInput { ident, data, .. } = parse_macro_input!(input); 17 | 18 | //let fields = extract_fields(&data).unwrap(); 19 | //let fields_name = extract_order_by_fields_name(&fields); 20 | let variant_list = extract_enum_variants(&data).unwrap(); 21 | let mut match_token_stream = quote!(); 22 | for variant_ident in &variant_list { 23 | let order_by_variant_string = variant_ident.to_string().to_snake(); 24 | let order_by_field_list: Vec<&str> = 25 | order_by_variant_string.split("_").collect::>(); 26 | 27 | let match_arm = quote!( 28 | #ident::#variant_ident => &[ #(#order_by_field_list,)* ], 29 | ); 30 | match_token_stream.extend(match_arm); 31 | } 32 | 33 | let output = quote! { 34 | impl OrderBy for #ident { 35 | fn get_order_by_fields(&self) -> &'static [&'static str] { 36 | match self { 37 | #match_token_stream 38 | } 39 | } 40 | } 41 | }; 42 | //panic!("{}", output) 43 | output.into() 44 | } 45 | -------------------------------------------------------------------------------- /old/luna-orm-axum/tests/schema.rs: -------------------------------------------------------------------------------- 1 | use luna_orm_axum::Field; 2 | use luna_orm_axum::FieldType; 3 | use luna_orm_axum::Index; 4 | use luna_orm_axum::IndexType; 5 | use luna_orm_axum::Schema; 6 | 7 | #[test] 8 | pub fn test_serailize_index() { 9 | let index_type = IndexType::Normal; 10 | let serailized = serde_yaml::to_string(&index_type).unwrap(); 11 | assert_eq!(serailized, "normal\n"); 12 | } 13 | 14 | #[test] 15 | pub fn test_serailize() { 16 | let schema = Schema { 17 | name: "article".to_string(), 18 | fields: vec![Field { 19 | f_name: "a".to_string(), 20 | f_type: FieldType::Cellphone, 21 | f_constraint: "".to_string(), 22 | }], 23 | indexes: vec![Index { 24 | i_name: "i_test".to_string(), 25 | i_type: IndexType::Normal, 26 | f_names: vec!["name".to_string()], 27 | }], 28 | }; 29 | let schema_str: String = serde_yaml::to_string(&schema).unwrap(); 30 | dbg!(&schema_str); 31 | assert_eq!( 32 | schema_str, 33 | r#"name: article 34 | fields: 35 | - f_name: a 36 | f_type: cellphone 37 | f_constraint: '' 38 | indexes: 39 | - i_name: i_test 40 | i_type: normal 41 | f_names: 42 | - name 43 | "# 44 | ); 45 | } 46 | 47 | #[test] 48 | pub fn test_deserialize() { 49 | let schema_str = r#" 50 | name: article 51 | fields: 52 | - f_name: a 53 | f_type: email 54 | f_constraint: '' 55 | indexes: [] 56 | "#; 57 | let schema: Schema = serde_yaml::from_str(&schema_str).unwrap(); 58 | 59 | assert!(true); 60 | } 61 | -------------------------------------------------------------------------------- /old/luna-orm-macro/src/gen_arguments.rs: -------------------------------------------------------------------------------- 1 | use crate::fields_parser::FieldsParser; 2 | use crate::utils::extract_fields; 3 | use proc_macro::TokenStream; 4 | use proc_macro2::Ident; 5 | use quote::quote; 6 | use syn::{parse_macro_input, Attribute, DeriveInput, FieldsNamed}; 7 | 8 | pub fn generate_entity_impl( 9 | ident: &Ident, 10 | attrs: &Vec, 11 | fields: &FieldsNamed, 12 | ) -> proc_macro2::TokenStream { 13 | let insert_args = FieldsParser::from_named(fields).get_insert_args(); 14 | let upsert_args = FieldsParser::from_named(fields).get_upsert_args(); 15 | 16 | let output = quote! { 17 | impl Entity for #ident { 18 | 19 | fn gen_mysql_arguments(&self) -> MySqlArguments { 20 | MySqlArguments::default() 21 | } 22 | 23 | fn gen_sqlite_arguments(&self) -> SqliteArguments<'_> { 24 | SqliteArguments::default() 25 | } 26 | 27 | fn any_arguments_of_insert(&self) -> AnyArguments<'_> { 28 | #insert_args 29 | } 30 | 31 | fn any_arguments_of_upsert(&self) -> AnyArguments<'_> { 32 | #upsert_args 33 | } 34 | } 35 | }; 36 | 37 | output 38 | } 39 | 40 | pub fn impl_gen_arguments_macro(input: TokenStream) -> TokenStream { 41 | let DeriveInput { 42 | attrs, ident, data, .. 43 | } = parse_macro_input!(input); 44 | 45 | let fields = extract_fields(&data).unwrap(); 46 | let output = generate_entity_impl(&ident, &attrs, &fields); 47 | //panic!("{}", output); 48 | output.into() 49 | } 50 | -------------------------------------------------------------------------------- /next/taitan-orm-macro/src/fields/mutation_parser.rs: -------------------------------------------------------------------------------- 1 | use crate::fields::mappers::{ArgsConstructorMySql, ArgsConstructorPostgres, ArgsConstructorSqlite, NamesAddConstructor, NamesConstructor}; 2 | use crate::fields::FieldsContainer; 3 | use proc_macro2::TokenStream; 4 | use std::fmt::Debug; 5 | use syn::Field; 6 | 7 | pub trait MutationParser: 8 | FieldsContainer 9 | + NamesAddConstructor 10 | + NamesConstructor 11 | + ArgsConstructorPostgres 12 | + ArgsConstructorSqlite 13 | + ArgsConstructorMySql 14 | { 15 | fn get_mutation_fields_name(&self) -> TokenStream { 16 | self.of_maybe_option_names_vec() 17 | } 18 | 19 | fn gen_update_arguments_sqlite(&self, primary_fields: &Vec) -> TokenStream { 20 | self.of_update_args_sqlite(primary_fields) 21 | } 22 | 23 | fn gen_update_arguments_mysql(&self, primary_fields: &Vec) -> TokenStream { 24 | self.of_update_args_mysql(primary_fields) 25 | } 26 | 27 | fn gen_update_arguments_postgres(&self, primary_fields: &Vec) -> TokenStream { 28 | self.of_update_args_postgres(primary_fields) 29 | } 30 | 31 | fn gen_change_arguments_sqlite(&self, location_fields: &Vec) -> TokenStream { 32 | self.of_change_args_sqlite(location_fields) 33 | } 34 | 35 | fn gen_change_arguments_mysql(&self, location_fields: &Vec) -> TokenStream { 36 | self.of_change_args_mysql(location_fields) 37 | } 38 | 39 | fn gen_change_arguments_postgres(&self, location_fields: &Vec) -> TokenStream { 40 | self.of_change_args_postgres(location_fields) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /next/taitan-orm-macro/src/schema.rs: -------------------------------------------------------------------------------- 1 | use crate::expands::{generate_entity_impl, generate_location_struct_and_impl, generate_mutation_struct_and_impl, generate_ordering_struct_and_impl, generate_selected_struct_and_impl, generate_selection_struct_and_impl, generate_unique_structs_and_impls}; 2 | use crate::util::extract_fields; 3 | use proc_macro::TokenStream; 4 | use syn::{parse_macro_input, DeriveInput}; 5 | 6 | pub fn impl_schema_macro(input: TokenStream) -> TokenStream { 7 | let DeriveInput { 8 | attrs, ident, data, .. 9 | } = parse_macro_input!(input); 10 | 11 | let fields = extract_fields(&data).unwrap(); 12 | 13 | let mut output = generate_entity_impl(&ident, &attrs, &fields); 14 | let primary_struct_stream = generate_unique_structs_and_impls(&ident, &attrs, &fields); 15 | let location_struct_stream = generate_location_struct_and_impl(&ident, &attrs, &fields); 16 | let mutation_struct_stream = generate_mutation_struct_and_impl(&ident, &attrs, &fields); 17 | let selection_struct_stream = generate_selection_struct_and_impl(&ident, &attrs, &fields); 18 | let selected_struct_stream = generate_selected_struct_and_impl(&ident, &attrs, &fields); 19 | let ordering_struct_stream = generate_ordering_struct_and_impl(&ident, &attrs, &fields); 20 | 21 | output.extend(primary_struct_stream); 22 | output.extend(location_struct_stream); 23 | output.extend(mutation_struct_stream); 24 | output.extend(selection_struct_stream); 25 | output.extend(selected_struct_stream); 26 | output.extend(ordering_struct_stream); 27 | // panic!("{}", output); 28 | output.into() 29 | } 30 | -------------------------------------------------------------------------------- /next/taitan-orm/src/extractor.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Debug; 2 | use sqlx::Database; 3 | 4 | use taitan_orm_trait::{Entity, Location, Mutation, TemplateRecord, Unique}; 5 | use taitan_orm_trait::pagination::Pagination; 6 | use crate::SqlGenericExecutor; 7 | use crate::Result; 8 | 9 | pub trait Extractor: SqlGenericExecutor { 10 | fn extract_pagination_arguments(page: &Pagination)-> Result<::Arguments<'_>>; 11 | fn extract_unique_arguments(unique: &dyn Unique) -> Result<::Arguments<'_>>; 12 | fn extract_location_arguments(location: &dyn Location) -> Result<::Arguments<'_>>; 13 | fn extract_insert_arguments(entity: &dyn Entity) -> Result<::Arguments<'_>>; 14 | fn extract_upsert_arguments(entity: &dyn Entity) -> Result<::Arguments<'_>>; 15 | fn extract_update_arguments<'a, M: Mutation>(mutation: &'a M, unique: &'a dyn Unique) -> Result<::Arguments<'a>>; 16 | fn extract_change_arguments<'a, M: Mutation>(mutation: &'a M, location: &'a M::Location) -> Result<::Arguments<'a>>; 17 | fn extract_delete_arguments(unique: &dyn Unique) -> Result<::Arguments<'_>>; 18 | fn extract_purify_arguments(location: &dyn Location) -> Result<::Arguments<'_>>; 19 | fn extract_template_arguments(template: &dyn TemplateRecord) -> Result<::Arguments<'_>>; 20 | fn extract_template_count_arguments(template: &dyn TemplateRecord) -> Result<::Arguments<'_>>; 21 | } -------------------------------------------------------------------------------- /old/luna-types/tests/integer.rs: -------------------------------------------------------------------------------- 1 | use luna_types::constraint::supported::Constraint; 2 | use luna_types::constraint::common::ConstraintTrait; 3 | use luna_types::constraint::supports::integer:: IntegerConstraint; 4 | use luna_types::constraint::supports::integer::IntegerConstraintBuilder; 5 | use serde_json::{Number, Value}; 6 | 7 | #[test] 8 | pub fn test_min_max() { 9 | let mut builder = IntegerConstraintBuilder::default(); 10 | let constraint = builder.min(10).max(20).build().unwrap(); 11 | let value = Value::Number(Number::from(15)); 12 | assert!(constraint.is_valid_json(&value)); 13 | let value = Value::Number(Number::from(22)); 14 | assert_eq!(false, constraint.is_valid_json(&value)); 15 | } 16 | 17 | #[test] 18 | pub fn test_deserialize_min() { 19 | let mut builder = IntegerConstraintBuilder::default(); 20 | let constraint_a = builder.min(10).build().unwrap(); 21 | let constraint_b = serde_json::from_str(r#" {"min": 10} "#).unwrap(); 22 | assert_eq!(constraint_a, constraint_b); 23 | } 24 | 25 | #[test] 26 | pub fn test_deserialize_max() { 27 | let mut builder = IntegerConstraintBuilder::default(); 28 | let constraint_a = builder.max(20).build().unwrap(); 29 | let constraint_b = serde_json::from_str(r#" {"max": 20} "#).unwrap(); 30 | assert_eq!(constraint_a, constraint_b); 31 | } 32 | 33 | #[test] 34 | pub fn test_deserialize_min_max() { 35 | let mut builder = IntegerConstraintBuilder::default(); 36 | let constraint_a = builder.min(10).max(20).build().unwrap(); 37 | let constraint_b = serde_json::from_str(r#" {"min": 10, "max": 20} "#).unwrap(); 38 | assert_eq!(constraint_a, constraint_b); 39 | } 40 | -------------------------------------------------------------------------------- /old/luna-types/src/field/valid.rs: -------------------------------------------------------------------------------- 1 | 2 | use crate::constraint; 3 | use crate::constraint::common::ConstraintTrait; 4 | use crate::constraint::error::ConstraintError; 5 | use crate::constraint::supported::Constraint; 6 | use crate::field::named::NamedField; 7 | use crate::field::supported::Field; 8 | 9 | pub struct ValidField<'a> { 10 | field: Field<'a>, 11 | constraint: Constraint<'a>, 12 | } 13 | 14 | impl<'a> ValidField<'a> { 15 | pub fn get_field(&'a self)-> &Field<'a> { 16 | return &self.field; 17 | } 18 | pub fn get_constraint(&'a self) -> &Constraint<'a> { 19 | return &self.constraint; 20 | } 21 | 22 | pub fn from_valid(field: Field<'a>, constraint: Constraint<'a>) -> Result, ConstraintError<'a>> { 23 | if !constraint.is_valid(&field) { 24 | return Err(ConstraintError::new("not valid")); 25 | } 26 | return Ok(ValidField { field, constraint }); 27 | } 28 | } 29 | 30 | 31 | pub struct ValidNamedField<'a> { 32 | field: NamedField<'a>, 33 | constraint: Constraint<'a>, 34 | } 35 | 36 | impl<'a> ValidNamedField<'a> { 37 | pub fn get_named_field(&'a self)-> &NamedField<'a> { 38 | return &self.field; 39 | } 40 | pub fn get_constraint(&'a self) -> &Constraint<'a> { 41 | return &self.constraint; 42 | } 43 | 44 | pub fn from_valid(field: NamedField<'a>, constraint: Constraint<'a>) -> Result, ConstraintError<'a>> { 45 | if !constraint.is_valid(&field.field) { 46 | return Err(ConstraintError::new("not valid")); 47 | } 48 | return Ok(ValidNamedField { field, constraint }); 49 | } 50 | } -------------------------------------------------------------------------------- /old/luna-orm-axum/src/field_type.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] 4 | #[serde(rename_all = "lowercase")] 5 | pub enum NumericType { 6 | #[serde(alias = "short")] 7 | Short, 8 | #[serde(alias = "int")] 9 | Integer, 10 | #[serde(alias = "long")] 11 | Long, 12 | 13 | #[serde(alias = "ushort")] 14 | UShort, 15 | #[serde(alias = "uint")] 16 | UInteger, 17 | #[serde(alias = "ulong")] 18 | ULong, 19 | 20 | #[serde(alias = "float")] 21 | Float, 22 | #[serde(alias = "double")] 23 | Double, 24 | #[serde(alias = "decimal")] 25 | Decimal, 26 | } 27 | 28 | #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] 29 | #[serde(rename_all = "lowercase")] 30 | pub enum FieldType { 31 | #[serde(alias = "boolean")] 32 | Boolean, 33 | 34 | #[serde(alias = "timestamp")] 35 | Timestamp, 36 | 37 | #[serde(alias = "datetime")] 38 | DateTime, 39 | 40 | #[serde(alias = "uuid")] 41 | Uuid, 42 | 43 | #[serde(alias = "id")] 44 | Id, 45 | 46 | #[serde(alias = "string")] 47 | String, 48 | 49 | #[serde(alias = "cellphone")] 50 | Cellphone, 51 | 52 | #[serde(alias = "email")] 53 | Email, 54 | 55 | #[serde(untagged)] 56 | NumericType(NumericType), 57 | } 58 | 59 | #[cfg(test)] 60 | mod test { 61 | use super::*; 62 | #[test] 63 | fn test_deserialize() { 64 | let field_type: FieldType = serde_yaml::from_str("ushort").unwrap(); 65 | let expect_type: FieldType = FieldType::NumericType(NumericType::UShort); 66 | assert_eq!(field_type, expect_type); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /old/luna-orm-trait/src/field_type.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] 4 | #[serde(rename_all = "lowercase")] 5 | pub enum NumericType { 6 | #[serde(alias = "short")] 7 | Short, 8 | #[serde(alias = "int")] 9 | Integer, 10 | #[serde(alias = "long")] 11 | Long, 12 | 13 | #[serde(alias = "ushort")] 14 | UShort, 15 | #[serde(alias = "uint")] 16 | UInteger, 17 | #[serde(alias = "ulong")] 18 | ULong, 19 | 20 | #[serde(alias = "float")] 21 | Float, 22 | #[serde(alias = "double")] 23 | Double, 24 | #[serde(alias = "decimal")] 25 | Decimal, 26 | } 27 | 28 | #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] 29 | #[serde(rename_all = "lowercase")] 30 | pub enum FieldType { 31 | #[serde(alias = "boolean")] 32 | Boolean, 33 | 34 | #[serde(alias = "timestamp")] 35 | Timestamp, 36 | 37 | #[serde(alias = "datetime")] 38 | DateTime, 39 | 40 | #[serde(alias = "uuid")] 41 | Uuid, 42 | 43 | #[serde(alias = "id")] 44 | Id, 45 | 46 | #[serde(alias = "string")] 47 | String, 48 | 49 | #[serde(alias = "cellphone")] 50 | Cellphone, 51 | 52 | #[serde(alias = "email")] 53 | Email, 54 | 55 | #[serde(untagged)] 56 | NumericType(NumericType), 57 | } 58 | 59 | #[cfg(test)] 60 | mod test { 61 | use super::*; 62 | #[test] 63 | fn test_deserialize() { 64 | let field_type: FieldType = serde_yaml::from_str("ushort").unwrap(); 65 | let expect_type: FieldType = FieldType::NumericType(NumericType::UShort); 66 | assert_eq!(field_type, expect_type); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /next/taitan-orm-macro/src/expands/selection_expander.rs: -------------------------------------------------------------------------------- 1 | use crate::attrs::{AttrParser, DefaultAttrParser}; 2 | use crate::fields::{FieldsParser, NamesConstructor, StructConstructor}; 3 | use case::CaseExt; 4 | use proc_macro2::{Ident, Span, TokenStream}; 5 | use quote::quote; 6 | use syn::{Attribute, FieldsNamed}; 7 | 8 | pub fn generate_selection_struct_and_impl( 9 | ident: &Ident, 10 | attrs: &Vec, 11 | fields: &FieldsNamed, 12 | ) -> TokenStream { 13 | let parser = FieldsParser::from_named(fields); 14 | 15 | let bool_names_vec = parser.of_bool_names_vec(); 16 | let bool_names_bits = parser.of_bool_bits_vec(); 17 | let full_fields_stream = parser.of_bool_true(); 18 | 19 | let table_name = DefaultAttrParser::extract_table_name(ident, attrs); 20 | let struct_name = format!("{}Selection", table_name.to_camel()); 21 | let struct_ident = Ident::new(&struct_name, Span::call_site()); 22 | let struct_stream = FieldsParser::from_named(fields).of_bool(&struct_name); 23 | 24 | let output = quote! { 25 | 26 | #struct_stream 27 | 28 | impl taitan_orm::traits::Selection for #struct_ident { 29 | 30 | fn get_table_name(&self) -> &'static str { 31 | #table_name 32 | } 33 | 34 | fn get_selected_bits(&self) -> bit_vec::BitVec { 35 | #bool_names_bits 36 | } 37 | 38 | fn get_selected_fields(&self) -> Vec { 39 | #bool_names_vec 40 | } 41 | 42 | fn full_fields() -> Self 43 | where Self: Sized, 44 | { 45 | #full_fields_stream 46 | } 47 | } 48 | }; 49 | 50 | output 51 | } 52 | -------------------------------------------------------------------------------- /next/taitan-orm-trait/src/entity.rs: -------------------------------------------------------------------------------- 1 | use crate::error::NotImplementError; 2 | use sqlx::error::BoxDynError; 3 | use sqlx::mysql::MySqlArguments; 4 | use sqlx::postgres::PgArguments; 5 | use sqlx::sqlite::SqliteArguments; 6 | use std::fmt::Debug; 7 | use crate::FieldName; 8 | 9 | pub trait Entity: Sync + Debug { 10 | fn get_table_name(&self) -> &str; 11 | 12 | fn get_insert_fields(&self) -> Vec; 13 | 14 | fn get_upsert_set_fields(&self) -> Vec; 15 | 16 | fn get_auto_increment_field(&self) -> Option<&str>; 17 | 18 | fn set_auto_increment_field(&mut self, value: Option) -> bool; 19 | 20 | fn gen_insert_arguments_sqlite(&self) -> Result, BoxDynError> { 21 | Err(NotImplementError("gen_insert_arguments_sqlite".to_string()).into()) 22 | } 23 | fn gen_upsert_arguments_sqlite(&self) -> Result, BoxDynError> { 24 | Err(NotImplementError("gen_upsert_arguments_sqlite".to_string()).into()) 25 | } 26 | fn gen_insert_arguments_mysql(&self) -> Result { 27 | Err(NotImplementError("gen_insert_arguments_mysql".to_string()).into()) 28 | } 29 | fn gen_upsert_arguments_mysql(&self) -> Result { 30 | Err(NotImplementError("gen_upsert_arguments_mysql".to_string()).into()) 31 | } 32 | 33 | fn gen_insert_arguments_postgres(&self) -> Result { 34 | Err(NotImplementError("gen_insert_arguments_postgres".to_string()).into()) 35 | } 36 | fn gen_upsert_arguments_postgres(&self) -> Result { 37 | Err(NotImplementError("gen_upsert_arguments_postgres".to_string()).into()) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /next/taitan-orm-macro/src/types/extractor.rs: -------------------------------------------------------------------------------- 1 | use super::{DefaultTypeChecker, TypeChecker}; 2 | use quote::quote; 3 | use syn::Path; 4 | 5 | pub trait TypeExtractor { 6 | fn get_option_inner_type(ty: &syn::Type) -> Option<&syn::Type>; 7 | 8 | fn extract_type_path(ty: &syn::Type) -> Option<&Path>; 9 | 10 | fn create_option_type(ty: &syn::Type) -> proc_macro2::TokenStream; 11 | } 12 | 13 | pub struct DefaultTypeExtractor {} 14 | 15 | impl TypeExtractor for DefaultTypeExtractor { 16 | fn get_option_inner_type(ty: &syn::Type) -> Option<&syn::Type> { 17 | if !::type_is_option(ty) { 18 | return None; 19 | } 20 | 21 | let syn::Type::Path(ty) = ty else { return None }; 22 | if ty.qself.is_some() { 23 | return None; 24 | } 25 | 26 | let last_segment = ty.path.segments.last().unwrap(); 27 | let syn::PathArguments::AngleBracketed(generics) = &last_segment.arguments else { 28 | return None; 29 | }; 30 | if generics.args.len() != 1 { 31 | return None; 32 | } 33 | let syn::GenericArgument::Type(inner_type) = &generics.args[0] else { 34 | return None; 35 | }; 36 | 37 | Some(inner_type) 38 | } 39 | 40 | fn extract_type_path(ty: &syn::Type) -> Option<&Path> { 41 | match *ty { 42 | syn::Type::Path(ref type_path) if type_path.qself.is_none() => Some(&type_path.path), 43 | _ => None, 44 | } 45 | } 46 | 47 | fn create_option_type(ty: &syn::Type) -> proc_macro2::TokenStream { 48 | let output = quote!( 49 | std::option::Option<#ty> 50 | ); 51 | output 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /next/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "taitan-orm", 4 | "taitan-orm-macro", 5 | "taitan-orm-trait", 6 | ] 7 | resolver = "2" 8 | 9 | default-members = [ 10 | "taitan-orm" 11 | ] 12 | 13 | [workspace.package] 14 | version = "0.1.0" 15 | rust-version = "1.83" 16 | 17 | 18 | [workspace.dependencies] 19 | sqlx = {version = "0.8.2", features = ["runtime-tokio", "mysql", "sqlite", "postgres", "bigdecimal", "time", "uuid"]} 20 | 21 | time = {version = "0.3.37", features = ["macros", "serde"]} 22 | bigdecimal = { version = "0.4.6", features = ["serde"] } 23 | uuid = { version = "1.11.0", features = ["v4", "serde"] } 24 | 25 | tokio = {version = "1.34.0", features = ["full"]} 26 | 27 | tracing = {version = "0.1", features = ["max_level_trace", "release_max_level_info"] } 28 | tracing-test = {version = "0.2"} 29 | tracing-subscriber = {version ="0.3.18"} 30 | derive_builder = "0.13.0" 31 | 32 | serde = {version = "1.0", features = ["derive"]} 33 | serde_with = { version = "3.4.0" } 34 | serde_regex = "1.1.0" 35 | serde_json = "1.0" 36 | serde_yaml = "0.9.27" 37 | regex = "1.10.3" 38 | 39 | axum = {version = "0.7.4"} 40 | axum-macros = {version = "0.4.1"} 41 | http-body-util = {version = "0.1.0"} 42 | chrono = { version = "0.4.38", features = ["serde"]} 43 | 44 | tower = { version = "0.4.13", default-features = false, features = ["util"] } 45 | tower-layer = "0.3.2" 46 | tower-service = "0.3" 47 | 48 | case = {version = "1.0"} 49 | rust-format = {version = "0.3.4"} 50 | tera = {version = "1.19"} 51 | 52 | num = "0.4.1" 53 | num-traits = "0.2.17" 54 | 55 | 56 | thiserror = {version = "2.0.4"} 57 | path-absolutize = { version = "3.1.1"} 58 | typetag = { version= "0.2"} 59 | nom = { version = "7.0.0" } 60 | runtime-fmt = { version = "0.4.1"} 61 | 62 | -------------------------------------------------------------------------------- /next/taitan-orm-trait/src/field.rs: -------------------------------------------------------------------------------- 1 | use std::borrow::Cow; 2 | 3 | #[derive(Debug, PartialEq, Clone)] 4 | pub struct FieldName { 5 | pub name: Cow<'static, str>, 6 | pub is_null: bool, 7 | database_field_alias: Option>, 8 | } 9 | 10 | impl FieldName { 11 | pub fn new(name: Cow<'static, str>, is_null: bool) -> Self { 12 | Self { name, is_null, database_field_alias: None } 13 | } 14 | 15 | pub fn from_str(name: &'static str, is_null: bool) -> Self { 16 | Self { 17 | name: Cow::Borrowed(name), 18 | is_null, 19 | database_field_alias: None, 20 | } 21 | } 22 | 23 | pub fn with_alias(name: Cow<'static, str>, is_null: bool, database_field_alias: Option<&'static str>) -> Self { 24 | match database_field_alias { 25 | Some(database_field_alias) => { 26 | Self { 27 | name, 28 | is_null, 29 | database_field_alias: Some(Cow::Borrowed(database_field_alias)), 30 | } 31 | } 32 | None => { 33 | Self { 34 | name, 35 | is_null, 36 | database_field_alias: None 37 | } 38 | } 39 | } 40 | } 41 | 42 | pub fn database_field_name(&self) -> &str { 43 | match &self.database_field_alias { 44 | Some(database_field_name) => database_field_name, 45 | None => &self.name, 46 | } 47 | } 48 | } 49 | 50 | #[cfg(test)] 51 | mod test { 52 | use crate::field::FieldName; 53 | 54 | #[test] 55 | pub fn test_field_name() { 56 | let field_name = FieldName::from_str("foo", true); 57 | } 58 | } -------------------------------------------------------------------------------- /next/taitan-orm-trait/src/unique.rs: -------------------------------------------------------------------------------- 1 | use crate::{Mutation, NotImplementError}; 2 | use sqlx::error::BoxDynError; 3 | use sqlx::mysql::MySqlArguments; 4 | use sqlx::postgres::PgArguments; 5 | use sqlx::sqlite::SqliteArguments; 6 | use std::fmt::Debug; 7 | 8 | pub trait Unique: Sync + Debug { 9 | type Mutation: Mutation; 10 | fn get_table_name(&self) -> &'static str; 11 | 12 | fn get_unique_field_names(&self) -> &'static [&'static str]; 13 | 14 | 15 | fn gen_update_arguments_sqlite<'a>( 16 | &'a self, 17 | mutation: &'a Self::Mutation, 18 | ) -> Result, BoxDynError> { 19 | Err(NotImplementError("gen_update_arguments_sqlite".to_string()).into()) 20 | } 21 | fn gen_update_arguments_mysql<'a>( 22 | &'a self, 23 | mutation: &'a Self::Mutation, 24 | ) -> Result { 25 | Err(NotImplementError("gen_update_arguments_mysql".to_string()).into()) 26 | } 27 | fn gen_update_arguments_postgres<'a>( 28 | &'a self, 29 | mutation: &'a Self::Mutation, 30 | ) -> Result { 31 | Err(NotImplementError("gen_update_arguments_postgres".to_string()).into()) 32 | } 33 | 34 | fn gen_unique_arguments_sqlite(&self) -> Result, BoxDynError> { 35 | Err(NotImplementError("gen_primary_arguments_sqlite".to_string()).into()) 36 | } 37 | fn gen_unique_arguments_mysql(&self) -> Result { 38 | Err(NotImplementError("gen_primary_arguments_mysql".to_string()).into()) 39 | } 40 | fn gen_unique_arguments_postgres(&self) -> Result { 41 | Err(NotImplementError("gen_primary_arguments_postgres".to_string()).into()) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /old/luna-orm-macro/src/selected_entity.rs: -------------------------------------------------------------------------------- 1 | use proc_macro::{self, TokenStream}; 2 | use quote::quote; 3 | 4 | use crate::fields_parser::FieldsParser; 5 | use crate::utils::*; 6 | use case::CaseExt; 7 | use proc_macro2::{Ident, Span}; 8 | use syn::Field; 9 | use syn::{parse_macro_input, DeriveInput}; 10 | 11 | pub fn impl_selected_entity_macro(input: TokenStream) -> TokenStream { 12 | let DeriveInput { ident, data, .. } = parse_macro_input!(input); 13 | 14 | let fields = extract_fields(&data).unwrap(); 15 | let row_construct = FieldsParser::from_named(&fields).get_row_construct(); 16 | 17 | let output = quote! { 18 | impl SelectedEntity for #ident { 19 | fn from_any_row(row: AnyRow) -> Result where Self: Sized { 20 | #row_construct 21 | } 22 | } 23 | }; 24 | // panic!("{}", output); 25 | output.into() 26 | } 27 | 28 | pub fn generate_selected_entity(table_name: &str, fields: &Vec) -> proc_macro2::TokenStream { 29 | let selected_name = format!("{}SelectedEntity", table_name.to_camel()); 30 | let selected_ident = Ident::new(&selected_name, Span::call_site()); 31 | 32 | let parser = FieldsParser::from_vec(fields); 33 | let option_fields = parser.get_option_fields(); 34 | let row_construct = parser.get_row_construct(); 35 | 36 | let output = quote!( 37 | #[derive(Default, Debug, Clone, PartialEq, Eq)] 38 | pub struct #selected_ident { 39 | #option_fields 40 | } 41 | 42 | impl SelectedEntity for #selected_ident { 43 | fn from_any_row(row: AnyRow) -> Result where Self: Sized { 44 | #row_construct 45 | } 46 | } 47 | ); 48 | 49 | //panic!("{}", output); 50 | output 51 | } 52 | -------------------------------------------------------------------------------- /next/taitan-orm-macro/src/fields/unique_parser.rs: -------------------------------------------------------------------------------- 1 | use crate::fields::mappers::{ArgsConstructorMySql, ArgsConstructorPostgres, ArgsConstructorSqlite, NamesAddConstructor, NamesConstructor}; 2 | use crate::fields::table_name_parser::TableNameParser; 3 | use crate::fields::{FieldsContainer}; 4 | use proc_macro2::TokenStream; 5 | use std::fmt::Debug; 6 | use syn::Field; 7 | 8 | // 1. Unique中不包含option的field 9 | // 2. 因为涉及为多个Unique生成类,所以parser里面应该传入正确的fields 10 | pub trait UniqueParser: 11 | FieldsContainer 12 | + NamesConstructor 13 | + NamesAddConstructor 14 | + TableNameParser 15 | + ArgsConstructorPostgres 16 | + ArgsConstructorSqlite 17 | + ArgsConstructorMySql 18 | { 19 | fn get_unique_field_names(&self) -> TokenStream { 20 | self.of_names_array() 21 | } 22 | 23 | fn gen_update_arguments_sqlite<'a>( 24 | &'a self, 25 | mutation_fields: &'a Vec, 26 | ) -> TokenStream { 27 | self.of_unique_update_args_sqlite(mutation_fields) 28 | } 29 | fn gen_update_arguments_mysql<'a>( 30 | &'a self, 31 | mutation_fields: &'a Vec, 32 | ) -> TokenStream { 33 | self.of_unique_update_args_mysql(mutation_fields) 34 | } 35 | fn gen_update_arguments_postgres<'a>( 36 | &'a self, 37 | mutation_fields: &'a Vec, 38 | ) -> TokenStream { 39 | self.of_unique_update_args_postgres(mutation_fields) 40 | } 41 | 42 | fn gen_unique_arguments_sqlite(&self) -> TokenStream { 43 | self.of_not_option_args_sqlite() 44 | } 45 | 46 | fn gen_unique_arguments_mysql(&self) -> TokenStream { 47 | self.of_not_option_args_mysql() 48 | } 49 | 50 | fn gen_unique_arguments_postgres(&self) -> TokenStream { 51 | self.of_not_option_args_postgres() 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /old/luna-orm-macro/src/auto_entity.rs: -------------------------------------------------------------------------------- 1 | use crate::entity::generate_entity_impl; 2 | use crate::fields_parser::FieldsParser; 3 | use crate::location::generate_location; 4 | use crate::mutation::generate_mutation; 5 | use crate::primary::generate_primary; 6 | use crate::selected_entity::generate_selected_entity; 7 | use crate::selection::generate_selection; 8 | use crate::utils::*; 9 | use proc_macro::{self, TokenStream}; 10 | use syn::{parse_macro_input, DeriveInput}; 11 | 12 | pub fn impl_auto_entity_macro(input: TokenStream) -> TokenStream { 13 | let DeriveInput { 14 | attrs, ident, data, .. 15 | } = parse_macro_input!(input); 16 | 17 | let fields = extract_fields(&data).unwrap(); 18 | let mut output = generate_entity_impl(&ident, &attrs, &fields); 19 | 20 | let primary_fields = FieldsParser::from_named(&fields).filter_annotated_fields("PrimaryKey"); 21 | let body_fields = FieldsParser::from_named(&fields).filter_not_annotated_fields("PrimaryKey"); 22 | let full_fields = FieldsParser::from_named(&fields).get_sorted_fields(); 23 | 24 | let table_name = extract_table_name(&ident, &attrs); 25 | let generated_primary = generate_primary(&table_name, &primary_fields); 26 | let generated_mutation = generate_mutation(&table_name, &body_fields); 27 | let generated_selection = generate_selection(&table_name, &full_fields); 28 | let generated_selected_entity = generate_selected_entity(&table_name, &full_fields); 29 | let generated_location = generate_location(&table_name, &full_fields, &attrs); 30 | 31 | output.extend(generated_primary); 32 | output.extend(generated_selection); 33 | output.extend(generated_selected_entity); 34 | output.extend(generated_mutation); 35 | output.extend(generated_location); 36 | //panic!("{}", output); 37 | output.into() 38 | } 39 | -------------------------------------------------------------------------------- /old/luna-orm/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! 2 | //! # LUNA-ORM 3 | //! luna-orm is build for time saving 4 | //! 5 | //! **LUNA-ORM** is an async orm framework based on SQLx. Built with :heart: 6 | //! - **Intuitive** : Simple API, the most simple orm in this world. 7 | //! - **Time Saving** : Most useful API is implemented by default, no need to waste your life. 8 | //! - **Smooth Transaction** : Transaction is almost same as normal. 9 | //! - **Template SQL** : You can execute your own sql with no pain. 10 | //! - **Dynamic Parameters** : Handle complex dynamic sql with default. 11 | //! - **Truly Asynchronous** : Based on SQLx, luna-orm is fully async. 12 | //! - **Error Soundly** : Every error has its meaning. 13 | //! 14 | //! 15 | 16 | #![allow(dead_code)] 17 | #![allow(async_fn_in_trait)] 18 | #![forbid(unsafe_code)] 19 | //#![feature(trait_upcasting)] 20 | //#![allow(incomplete_features)] 21 | 22 | mod command_executor; 23 | mod command_executor2; 24 | 25 | mod database; 26 | mod error; 27 | mod mapper; 28 | mod sql_executor; 29 | mod sql_generator; 30 | 31 | mod sql_generator2; 32 | 33 | mod transaction; 34 | mod sql_executor2; 35 | 36 | pub type LunaOrmResult = std::result::Result; 37 | 38 | pub mod prelude { 39 | pub use luna_orm_trait::input_generator::InputGenerator; 40 | pub use crate::sql_executor2::SqlExecutorNew; 41 | pub use crate::command_executor::CommandExecutor; 42 | pub use crate::database::*; 43 | pub use crate::error::*; 44 | pub use crate::sql_executor::*; 45 | pub use crate::sql_generator::*; 46 | pub use crate::transaction::Transaction; 47 | pub use luna_orm_macro::*; 48 | pub use luna_orm_trait::*; 49 | pub use sqlx::any::AnyArguments; 50 | pub use sqlx::any::AnyRow; 51 | pub use sqlx::Arguments; 52 | pub use sqlx::Row; 53 | } 54 | -------------------------------------------------------------------------------- /next/taitan-orm-trait/src/template_record.rs: -------------------------------------------------------------------------------- 1 | use crate::CountSql; 2 | use crate::pagination::Pagination; 3 | use crate::NotImplementError; 4 | use sqlx::any::AnyArguments; 5 | use sqlx::error::BoxDynError; 6 | use sqlx::mysql::MySqlArguments; 7 | use sqlx::postgres::PgArguments; 8 | use sqlx::sqlite::SqliteArguments; 9 | use std::fmt::Debug; 10 | 11 | pub trait TemplateRecord: Sync + Debug { 12 | 13 | fn get_sql(&self, page: Option<&Pagination>) -> String; 14 | 15 | fn get_count_sql(&self) -> Option; 16 | 17 | fn get_pagination(&self) -> Option<&Pagination> { 18 | None 19 | } 20 | 21 | fn get_variables(&self) -> Vec; 22 | 23 | fn gen_template_count_arguments_sqlite(&self) -> Result, BoxDynError> { 24 | Err(NotImplementError("gen_template_count_arguments_sqlite".to_string()).into()) 25 | } 26 | fn gen_template_count_arguments_mysql(&self) -> Result { 27 | Err(NotImplementError("gen_template_count_arguments_mysql".to_string()).into()) 28 | } 29 | fn gen_template_count_arguments_postgres(&self) -> Result { 30 | Err(NotImplementError("gen_template_count_arguments_postgres".to_string()).into()) 31 | } 32 | 33 | fn gen_template_arguments_sqlite(&self) -> Result, BoxDynError> { 34 | Err(NotImplementError("gen_template_arguments_sqlite".to_string()).into()) 35 | } 36 | fn gen_template_arguments_mysql(&self) -> Result { 37 | Err(NotImplementError("gen_template_arguments_mysql".to_string()).into()) 38 | } 39 | fn gen_template_arguments_postgres(&self) -> Result { 40 | Err(NotImplementError("gen_template_arguments_postgres".to_string()).into()) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /old/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "luna-types", 4 | "luna-orm", 5 | "luna-orm-trait", 6 | "luna-orm-macro", 7 | "luna-orm-dynamic", 8 | "luna-orm-axum", 9 | "examples/*" 10 | ] 11 | 12 | default-members = [ 13 | "luna-orm" 14 | ] 15 | workspace.resolver = 2 16 | [workspace.package] 17 | version = "0.3.7" 18 | rust-version = "1.56" 19 | 20 | 21 | [workspace.dependencies] 22 | sqlx = {version = "0.8.2", features = ["mysql", "sqlite", "postgres", "any", "bigdecimal", "time", "uuid"]} 23 | sqlx-core = {version = "0.8.2"} 24 | 25 | time = {version = "0.3.37"} 26 | bigdecimal = { version = "0.4.6" } 27 | uuid = { version = "1.11.0", features = ["v4"] } 28 | 29 | tokio = {version = "1.34.0", features = ["full"]} 30 | 31 | tracing = {version = "0.1", features = ["max_level_trace", "release_max_level_info"] } 32 | tracing-test = {version = "0.2"} 33 | tracing-subscriber = {version ="0.3.18"} 34 | derive_builder = "0.13.0" 35 | 36 | serde = {version = "1.0", features = ["derive"]} 37 | serde_with = { version = "3.4.0" } 38 | serde_regex = "1.1.0" 39 | serde_json = "1.0" 40 | serde_yaml = "0.9.27" 41 | regex = "1.10.3" 42 | 43 | axum = {version = "0.7.4"} 44 | axum-macros = {version = "0.4.1"} 45 | http-body-util = {version = "0.1.0"} 46 | chrono = { version = "0.4.38", features = ["serde"]} 47 | 48 | tower = { version = "0.4.13", default-features = false, features = ["util"] } 49 | tower-layer = "0.3.2" 50 | tower-service = "0.3" 51 | 52 | case = {version = "1.0"} 53 | rust-format = {version = "0.3.4"} 54 | tera = {version = "1.19"} 55 | 56 | num = "0.4.1" 57 | num-traits = "0.2.17" 58 | 59 | 60 | thiserror = {version = "1.0"} 61 | path-absolutize = { version = "3.1.1"} 62 | typetag = { version= "0.2"} 63 | nom = { version = "7.1.3" } 64 | runtime-fmt = { version = "0.4.1"} 65 | 66 | [profile.test] 67 | test-threads = 1 68 | -------------------------------------------------------------------------------- /next/taitan-orm/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(async_fn_in_trait)] 2 | #![allow(dead_code)] 3 | #![forbid(unsafe_code)] 4 | mod error; 5 | mod result; 6 | 7 | pub mod database; 8 | mod sql_api; 9 | 10 | mod db; 11 | mod dto; 12 | mod sql_executor; 13 | mod sql_generator; 14 | pub mod sql_generator_container; 15 | 16 | #[macro_use] 17 | mod api_macro; 18 | mod sql_generic_executor; 19 | mod extractor; 20 | mod api; 21 | 22 | 23 | pub use taitan_orm_trait::Optional; 24 | 25 | // pub use db::DB; 26 | pub use dto::CountResult; 27 | pub use error::TaitanOrmError; 28 | pub use result::Result; 29 | pub use sql_api::SqlApi; 30 | pub use sql_executor::SqlExecutor; 31 | pub use sql_generic_executor::SqlGenericExecutor; 32 | pub use sql_generator_container::SqlGeneratorContainer; 33 | pub use sql_generator::DefaultSqlGenerator; 34 | pub use sql_generator::SqlGenerator; 35 | 36 | pub use taitan_orm_macro::Schema; 37 | pub use taitan_orm_trait::FieldName; 38 | pub use api::reader::ReaderApi; 39 | pub use api::writer::WriterApi; 40 | pub use api::template::TemplateApi; 41 | pub use db::DB; 42 | 43 | pub mod page { 44 | pub use taitan_orm_trait::pagination::Pagination; 45 | pub use taitan_orm_trait::paged_info::PagedInfo; 46 | pub use taitan_orm_trait::paged_list::PagedList; 47 | pub use taitan_orm_trait::build_paged_list; 48 | } 49 | 50 | pub mod traits { 51 | pub use taitan_orm_trait::{CountSql, Entity, Location, LocationExpr, Mutation, OrderBy, Schema, SelectedEntity, Selection, Unique}; 52 | pub use taitan_orm_trait::validate_order_by; 53 | pub use taitan_orm_trait::pagination::Pagination; 54 | pub use taitan_orm_trait::paged_info::PagedInfo; 55 | pub use taitan_orm_trait::paged_list::PagedList; 56 | pub use taitan_orm_trait::ParsedTemplateSql; 57 | pub use taitan_orm_trait::TemplateValue; 58 | pub use taitan_orm_trait::TemplateRecord; 59 | } -------------------------------------------------------------------------------- /old/luna-orm-dynamic/src/active_entity.rs: -------------------------------------------------------------------------------- 1 | use luna_orm_trait::Entity; 2 | use luna_orm_trait::ParsedSchema; 3 | use serde_json::Value; 4 | use sqlx::any::AnyArguments; 5 | 6 | #[derive(Debug, Clone)] 7 | pub struct ActiveEntity { 8 | value: Value, 9 | schema: ParsedSchema, 10 | } 11 | 12 | impl Entity for ActiveEntity { 13 | fn get_table_name(&self) -> &str { 14 | &self.schema.name 15 | } 16 | 17 | fn get_insert_fields(&self) -> Vec { 18 | self.schema.fields.names.clone() 19 | } 20 | 21 | fn get_upsert_set_fields(&self) -> Vec { 22 | self.schema.fields.non_primary_names.clone() 23 | } 24 | 25 | fn get_auto_increment_field(&self) -> Option<&str> { 26 | self.schema.fields.auto_increment_field.as_deref() 27 | } 28 | fn set_auto_increment_field(&mut self, value: Option) -> bool { 29 | if value.is_none() { 30 | return false; 31 | } 32 | 33 | let name = self.get_auto_increment_field(); 34 | if name.is_none() { 35 | return false; 36 | } 37 | let name = name.unwrap().to_string(); 38 | 39 | match &mut self.value { 40 | Value::Object(record) => { 41 | record.insert(name, Value::Number(value.unwrap().into())); 42 | true 43 | } 44 | _ => false, 45 | } 46 | } 47 | fn any_arguments_of_insert(&self) -> sqlx::any::AnyArguments<'_> { 48 | let record = self.value.as_object().unwrap(); 49 | let arg = AnyArguments::default(); 50 | for name in &self.schema.fields.names { 51 | let value = record.get(name); 52 | } 53 | return arg; 54 | } 55 | fn any_arguments_of_upsert(&self) -> sqlx::any::AnyArguments<'_> { 56 | let arg = AnyArguments::default(); 57 | return arg; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /old/luna-orm/src/command_executor2.rs: -------------------------------------------------------------------------------- 1 | use crate::sql_executor2::SqlExecutorNew; 2 | use crate::sql_generator2::SqlGenerator; 3 | 4 | use crate::LunaOrmResult; 5 | use luna_orm_trait::schema_trait::{ 6 | EntityNew, LocationNew, MutationNew, PrimaryNew, SelectedEntityNew, UpdateCommand, 7 | }; 8 | use sqlx::error::BoxDynError; 9 | use sqlx::Database; 10 | use std::fmt::Debug; 11 | 12 | pub trait CommandExecutorNew: SqlExecutorNew + Debug { 13 | type G: SqlGenerator + Sync + Debug; 14 | 15 | fn get_generator(&self) -> &Self::G; 16 | 17 | // fn gen_insert_arguments<'a>( 18 | // &'a self, 19 | // entity: &'a dyn EntityNew, 20 | // ) -> Result<::Arguments<'_>, BoxDynError>; 21 | // fn gen_upsert_arguments<'a>( 22 | // &'a self, 23 | // entity: &'a dyn EntityNew, 24 | // ) -> Result<::Arguments<'a>, BoxDynError>; 25 | // fn gen_update_arguments<'a>( 26 | // &'a self, 27 | // update_command: &'a dyn UpdateCommand, 28 | // ) -> Result<::Arguments<'a>, BoxDynError>; 29 | // 30 | // fn gen_primary_arguments<'a>( 31 | // &'a self, 32 | // primary: &'a dyn PrimaryNew, 33 | // ) -> Result<::Arguments<'a>, BoxDynError>; 34 | // fn gen_location_arguments<'a>( 35 | // &'a self, 36 | // location: &'a dyn LocationNew, 37 | // ) -> Result<::Arguments<'a>, BoxDynError>; 38 | // fn gen_selected_entity>( 39 | // &self, 40 | // selection: &SL, 41 | // row: Self::DB::Row, 42 | // ) -> Result; 43 | 44 | async fn select( 45 | &self, 46 | primary: &dyn PrimaryNew, 47 | selection: &SE::Selection, 48 | ) -> LunaOrmResult> 49 | where 50 | SE: SelectedEntityNew + Send + Unpin; 51 | } 52 | -------------------------------------------------------------------------------- /old/luna-types/src/sqlx/field.rs: -------------------------------------------------------------------------------- 1 | use crate::{field::supported::Field, field::supports::integer::Integer}; 2 | use num_traits::PrimInt; 3 | use sqlx::any::AnyValue; 4 | use sqlx::database::HasArguments; 5 | use sqlx::encode::IsNull; 6 | use sqlx::sqlite::SqliteArgumentValue; 7 | use sqlx::Database; 8 | use sqlx::{Any, Sqlite}; 9 | use sqlx::{Encode, Type}; 10 | use sqlx_core::any::AnyTypeInfo; 11 | use sqlx_core::any::AnyTypeInfoKind; 12 | use sqlx_core::any::AnyValueKind; 13 | 14 | /******************************************/ 15 | impl<'a> Encode<'a, Any> for Field<'a> { 16 | fn encode_by_ref( 17 | &self, 18 | buf: &mut >::ArgumentBuffer, 19 | ) -> sqlx::encode::IsNull { 20 | match self { 21 | Self::SmallInt(val) => { 22 | buf.0.push(AnyValueKind::SmallInt(val.0)); 23 | } 24 | Self::Int(val) => { 25 | buf.0.push(AnyValueKind::Integer(val.0)); 26 | } 27 | Self::BigInt(val) => { 28 | buf.0.push(AnyValueKind::BigInt(val.0)); 29 | } 30 | Self::SmallUInt(val) => { 31 | buf.0.push(AnyValueKind::SmallInt(val.0 as i16)); 32 | } 33 | Self::UInt(val) => { 34 | buf.0.push(AnyValueKind::Integer(val.0 as i32)); 35 | } 36 | Self::BigUInt(val) => { 37 | buf.0.push(AnyValueKind::BigInt(val.0 as i64)); 38 | } 39 | Self::Text(val) => { 40 | buf.0.push(AnyValueKind::Text(val.0.clone())); 41 | } 42 | Self::DateTime(val) => { 43 | // buf.0.push(&val.naive_utc()); 44 | } 45 | } 46 | return IsNull::No; 47 | } 48 | } 49 | 50 | impl<'a> Type for Field<'a> { 51 | fn type_info() -> ::TypeInfo { 52 | AnyTypeInfo { 53 | kind: AnyTypeInfoKind::Blob 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /old/examples/crud/src/main.rs: -------------------------------------------------------------------------------- 1 | use luna_orm::prelude::*; 2 | use luna_orm::LunaOrmResult; 3 | 4 | #[derive(Schema, Clone, Debug)] 5 | #[TableName = "user"] 6 | pub struct UserEntity { 7 | #[PrimaryKey] 8 | id: i32, 9 | name: String, 10 | age: Option, 11 | } 12 | 13 | #[tokio::main] 14 | async fn main() -> LunaOrmResult<()> { 15 | let config = SqliteLocalConfig { 16 | work_dir: "./workspace".to_string(), 17 | db_file: "test.db".to_string(), 18 | }; 19 | 20 | let mut db: DB = SqliteDatabase::build(config).await.unwrap().into(); 21 | 22 | let result = db.execute_plain("DROP TABLE IF EXISTS `user`").await?; 23 | let result = db.execute_plain( 24 | "CREATE TABLE IF NOT EXISTS `user`(`id` INT PRIMARY KEY, `age` INT, `name` VARCHAR(64))", 25 | ).await?; 26 | 27 | // 1. insert entity 28 | let entity = UserEntity { 29 | id: 1, 30 | name: "Allen".to_string(), 31 | age: Some(23), 32 | }; 33 | let result = db.insert(&entity).await?; 34 | 35 | // 2. update 36 | let mutation = UserMutation { 37 | name: None, 38 | age: Some(24), 39 | }; 40 | let primary = UserPrimary { id: 1 }; 41 | let result = db.update(&mutation, &primary).await?; 42 | 43 | // 3. select 44 | let selection = UserSelection { 45 | id: false, 46 | name: true, 47 | age: true, 48 | }; 49 | let entity: Option = db.select(&primary, &selection).await?; 50 | let expect_entity = UserSelectedEntity { 51 | id: None, 52 | name: Some("Allen".to_string()), 53 | age: Some(24), 54 | }; 55 | assert_eq!(entity, Some(expect_entity)); 56 | 57 | // 4. delete 58 | let _ = db.delete(&primary).await?; 59 | let entity: Option = db.select(&primary, &selection).await?; 60 | assert_eq!(entity, None); 61 | 62 | println!("result: {}", result); 63 | Ok(()) 64 | } 65 | -------------------------------------------------------------------------------- /next/taitan-orm-trait/src/selected.rs: -------------------------------------------------------------------------------- 1 | use crate::selection::Selection; 2 | use crate::NotImplementError; 3 | use sqlx::types::Uuid; 4 | use sqlx::{ColumnIndex, Database, Decode, Type}; 5 | use std::fmt::Debug; 6 | use time::PrimitiveDateTime; 7 | 8 | pub trait SelectedEntity: Debug + Default { 9 | type Selection: Selection; 10 | fn from_row(selection: &Self::Selection, row: DB::Row) -> Result 11 | where 12 | Self: Sized; 13 | 14 | fn from_row_bits(bits: &bit_vec::BitVec, row: DB::Row) -> Result 15 | where 16 | Self: Sized, 17 | { 18 | todo!() 19 | } 20 | 21 | fn select_from_row(selection: &Self, row: DB::Row) -> Result 22 | where 23 | Self: Sized, 24 | { 25 | todo!() 26 | } 27 | 28 | fn from_row_full(row: DB::Row) -> Result 29 | where 30 | Self: Sized, 31 | { 32 | Err(sqlx::Error::Decode( 33 | NotImplementError("".to_string()).into(), 34 | )) 35 | } 36 | } 37 | 38 | pub trait SelectedEntityNew: Debug + Default { 39 | type Selection: Selection; 40 | fn from_row( 41 | selection: &Self::Selection, 42 | row: DB::Row, 43 | ) -> Result 44 | where 45 | Self: Sized, 46 | for<'a> PrimitiveDateTime: Type + Decode<'a, DB>, 47 | for<'a> i32: Type + Decode<'a, DB>, 48 | for<'a> String: Type + Decode<'a, DB>, 49 | for<'a> Uuid: Type + Decode<'a, DB>, 50 | for<'a> u64: Type + Decode<'a, DB>, 51 | for<'a> &'a str: ColumnIndex, 52 | usize: ColumnIndex; 53 | 54 | fn from_row_full(row: DB::Row) -> Result 55 | where 56 | Self: Sized, 57 | { 58 | Err(sqlx::Error::Decode( 59 | NotImplementError("".to_string()).into(), 60 | )) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /next/taitan-orm-trait/src/mutation.rs: -------------------------------------------------------------------------------- 1 | use crate::{FieldName, Location, NotImplementError, Unique}; 2 | use sqlx::error::BoxDynError; 3 | use sqlx::mysql::MySqlArguments; 4 | use sqlx::postgres::PgArguments; 5 | use sqlx::sqlite::SqliteArguments; 6 | use std::fmt::Debug; 7 | 8 | pub trait Mutation: Sync + Debug { 9 | 10 | type Location: Location; 11 | 12 | fn get_mutation_fields_name(&self) -> Vec; 13 | 14 | // fn gen_update_arguments_sqlite<'a>( 15 | // &'a self, 16 | // primary: &'a Self::Primary, 17 | // ) -> Result, BoxDynError> { 18 | // Err(NotImplementError("gen_update_arguments_sqlite".to_string()).into()) 19 | // } 20 | // fn gen_update_arguments_mysql<'a>( 21 | // &'a self, 22 | // primary: &'a Self::Primary, 23 | // ) -> Result { 24 | // Err(NotImplementError("gen_update_arguments_mysql".to_string()).into()) 25 | // } 26 | // fn gen_update_arguments_postgres<'a>( 27 | // &'a self, 28 | // primary: &'a Self::Primary, 29 | // ) -> Result { 30 | // Err(NotImplementError("gen_update_arguments_postgres".to_string()).into()) 31 | // } 32 | 33 | fn gen_change_arguments_sqlite<'a>( 34 | &'a self, 35 | location: &'a Self::Location, 36 | ) -> Result, BoxDynError> { 37 | Err(NotImplementError("gen_change_arguments_sqlite".to_string()).into()) 38 | } 39 | fn gen_change_arguments_mysql<'a>( 40 | &'a self, 41 | location: &'a Self::Location, 42 | ) -> Result { 43 | Err(NotImplementError("gen_change_arguments_mysql".to_string()).into()) 44 | } 45 | fn gen_change_arguments_postgres<'a>( 46 | &'a self, 47 | location: &'a Self::Location, 48 | ) -> Result { 49 | Err(NotImplementError("gen_change_arguments_postgres".to_string()).into()) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /old/luna-orm/tests/insert.rs: -------------------------------------------------------------------------------- 1 | use luna_orm::prelude::*; 2 | use luna_orm::LunaOrmResult; 3 | mod common; 4 | use common::create_table; 5 | use common::mutex::get_test_mutex; 6 | use common::setup_database; 7 | use common::setup_logger; 8 | use sqlx::sqlx_macros; 9 | use tracing::debug; 10 | 11 | #[derive(Schema, Clone, Debug)] 12 | #[TableName = "user"] 13 | pub struct UserEntity { 14 | #[PrimaryKey] 15 | #[AutoIncrement] 16 | id: Option, 17 | age: Option, 18 | name: String, 19 | } 20 | 21 | #[sqlx_macros::test] 22 | pub async fn test_insert_normal() -> LunaOrmResult<()> { 23 | let test_mutex = get_test_mutex(); 24 | let test_lock = test_mutex.lock(); 25 | setup_logger(); 26 | let mut db = setup_database().await?; 27 | create_table(&mut db, "user" , 28 | "create table if not exists `user`(`id` integer primary key autoincrement, `age` INT, `name` VARCHAR(60), create_time DATETIME default current_timestamp)" ).await?; 29 | let entity = UserEntity { 30 | id: None, 31 | age: Some(23), 32 | name: "test".to_string(), 33 | }; 34 | 35 | let result = db.insert(&entity).await?; 36 | assert_eq!(result, true); 37 | 38 | let selection = UserSelection { 39 | id: true, 40 | age: true, 41 | name: true, 42 | }; 43 | let entities: Vec = db.search_all(&selection).await?; 44 | dbg!(&entities); 45 | 46 | let location = UserLocation { 47 | id: None, 48 | age: Some(LocationExpr { 49 | val: 23, 50 | cmp: CmpOperator::Eq, 51 | }), 52 | name: None, 53 | }; 54 | let selected: Vec = db.search(&location, None, &selection).await?; 55 | assert_eq!(selected.len(), 1); 56 | let selected_one = selected.first().unwrap(); 57 | assert_eq!(selected_one.id, Some(1)); 58 | assert_eq!(selected_one.age, Some(23)); 59 | assert_eq!(selected_one.name, Some("test".to_string())); 60 | 61 | Ok(()) 62 | } 63 | -------------------------------------------------------------------------------- /old/luna-orm-dynamic/tests/record.rs: -------------------------------------------------------------------------------- 1 | use luna_orm::prelude::*; 2 | use luna_orm::LunaOrmResult; 3 | use luna_types::constraint::named::NamedConstraint; 4 | use luna_types::field::supports::integer::Integer; 5 | use luna_types::constraint::supports::integer::IntegerConstraint; 6 | use luna_types::constraint::supports::integer::IntegerConstraintBuilder; 7 | use luna_types::field::valid::ValidField; 8 | use luna_types::{constraint::supported::Constraint, record::Record, record::RecordConstraint}; 9 | use serde_json::Value; 10 | use sqlx::sqlx_macros; 11 | 12 | #[sqlx_macros::test] 13 | async fn test_insert_record() { 14 | let config = SqliteLocalConfig::new("./workspace", "test.db"); 15 | let mut db: SqliteDatabase = SqliteDatabase::build(config).await.unwrap(); 16 | let mut db: DB = DB(db); 17 | db.execute_plain("DROP TABLE IF EXISTS `article`") 18 | .await 19 | .unwrap(); 20 | db.execute_plain( 21 | "CREATE TABLE IF NOT EXISTS `article`(`id` INT PRIMARY KEY, `age` INT, `content` VARCHAR(64))", 22 | ) 23 | .await 24 | .unwrap(); 25 | 26 | let json_str = r#"{"age":21,"id":20}"#; 27 | let json_value: Value = serde_json::from_str(json_str).unwrap(); 28 | 29 | let constraint_str = r#"[ 30 | { "name": "id", "constraint": {"type": "smallint", "min": 10, "max": 20 } }, 31 | { "name": "age", "constraint": { "type": "smallint", "min": 10, "max": 30 } } ]"#; 32 | let constraint: RecordConstraint = serde_json::from_str(constraint_str).unwrap(); 33 | dbg!(&constraint); 34 | 35 | let record: Record = Record::from_json(&json_value, &constraint).unwrap(); 36 | dbg!(&record); 37 | let args = record.into_any_arguments(); 38 | 39 | let result = db 40 | .execute("insert into `article`(`id`, `age`) values(?, ?)", args) 41 | .await; 42 | let row: JsonResult = db 43 | .fetch_one_plain("select id, age from article") 44 | .await 45 | .unwrap(); 46 | assert_eq!(r#"{"age":21,"id":20}"#, row.data); 47 | } 48 | -------------------------------------------------------------------------------- /old/luna-orm-macro/src/selection.rs: -------------------------------------------------------------------------------- 1 | use proc_macro::{self, TokenStream}; 2 | use quote::quote; 3 | 4 | use crate::fields_parser::FieldsParser; 5 | use crate::utils::*; 6 | use case::CaseExt; 7 | use proc_macro2::{Ident, Span}; 8 | use syn::Field; 9 | use syn::{parse_macro_input, DeriveInput}; 10 | 11 | pub fn generate_impl(ident: &Ident, fields: &Vec) -> proc_macro2::TokenStream { 12 | let ident_name = ident.to_string(); 13 | let entity_name = ident_name.strip_suffix("Selection").unwrap_or(&ident_name); 14 | let table_name = entity_name.to_lowercase(); 15 | 16 | let parser = FieldsParser::from_vec(fields); 17 | let fields_name = parser.get_bool_name_vec(); 18 | quote! { 19 | impl Selection for #ident { 20 | fn get_table_name(&self) -> &'static str { 21 | #table_name 22 | } 23 | fn get_selected_fields(&self) -> Vec { 24 | #fields_name 25 | } 26 | } 27 | } 28 | } 29 | 30 | pub fn impl_selection_macro(input: TokenStream) -> TokenStream { 31 | let DeriveInput { ident, data, .. } = parse_macro_input!(input); 32 | let fields = extract_fields(&data).unwrap(); 33 | let fields = fields.named.into_iter().collect(); 34 | let output = generate_impl(&ident, &fields).into(); 35 | //panic!("{}", output); 36 | output 37 | } 38 | 39 | pub fn generate_selection(table_name: &str, fields: &Vec) -> proc_macro2::TokenStream { 40 | let selection_name = format!("{}Selection", table_name.to_camel()); 41 | let selection_ident = Ident::new(&selection_name, Span::call_site()); 42 | 43 | let fields_tokens = FieldsParser::from_vec(fields).get_bool_fields(); 44 | let generated_impl = generate_impl(&selection_ident, fields); 45 | 46 | let output = quote!( 47 | #[derive(Default, Debug, Clone)] 48 | pub struct #selection_ident { 49 | #fields_tokens 50 | } 51 | 52 | #generated_impl 53 | ); 54 | 55 | //panic!("{}", output); 56 | output 57 | } 58 | -------------------------------------------------------------------------------- /old/luna-orm-trait/src/field.rs: -------------------------------------------------------------------------------- 1 | use sqlx::database::Database; 2 | use sqlx::error::BoxDynError; 3 | use sqlx::Any; 4 | use sqlx::ColumnIndex; 5 | use sqlx::Decode; 6 | use sqlx::Error; 7 | use sqlx::Type; 8 | use sqlx::ValueRef; 9 | 10 | pub trait Decodable<'r, DB: Database>: Decode<'r, DB> + Type {} 11 | impl<'r, T, DB: Database> Decodable<'r, DB> for T where T: Decode<'r, DB> + Type {} 12 | 13 | pub enum Field 14 | where 15 | for<'r> T: Decodable<'r, Any>, 16 | { 17 | Selected(Option), 18 | Value(Option), 19 | } 20 | 21 | impl Decode<'_, Any> for Field 22 | where 23 | for <'r> T: Decodable<'r, Any>, 24 | { 25 | #[inline] 26 | fn decode(value: ::ValueRef<'_>) -> Result { 27 | let val = T::decode(value)?; 28 | Ok(Self::Value(Some(val))) 29 | } 30 | } 31 | 32 | impl Field 33 | where 34 | for<'r> T: Decode<'r, Any> + Type, 35 | { 36 | pub fn value(val: T) -> Self { 37 | Self::Value(Some(val)) 38 | } 39 | 40 | pub fn selected() -> Self { 41 | Self::Selected(Some(true)) 42 | } 43 | 44 | pub fn is_selected(&self) -> bool { 45 | match &self { 46 | Self::Selected(s) => s.unwrap_or(false), 47 | Self::Value(v) => v.is_some(), 48 | } 49 | } 50 | 51 | pub fn unbox(self) -> Option { 52 | match self { 53 | Self::Selected(_) => None, 54 | Self::Value(v) => v, 55 | } 56 | } 57 | 58 | pub fn get(&self) -> Option<&T> { 59 | match &self { 60 | Self::Selected(_) => None, 61 | Self::Value(v) => v.as_ref(), 62 | } 63 | } 64 | 65 | /* 66 | pub fn try_get<'r, I>(&'r self, index: I) -> Result 67 | where 68 | I: ColumnIndex, 69 | { 70 | todo!() 71 | } 72 | */ 73 | } 74 | 75 | #[cfg(test)] 76 | mod test { 77 | use super::Field; 78 | use sqlx::Any; 79 | 80 | struct User { 81 | name: Field, 82 | age: Field, 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /old/examples/template/src/main.rs: -------------------------------------------------------------------------------- 1 | use luna_orm::prelude::*; 2 | use luna_orm::LunaOrmResult; 3 | 4 | #[derive(Schema, Clone, Debug)] 5 | #[TableName = "user"] 6 | pub struct UserEntity { 7 | #[PrimaryKey] 8 | id: i32, 9 | name: String, 10 | age: Option, 11 | } 12 | 13 | #[derive(TemplateRecord, Debug)] 14 | #[TemplateSql = "select id, name, age FROM `user` where id > #{id}"] 15 | #[TemplateCountSql = "select count(*) as count FROM `user` where id > #{id}"] 16 | pub struct HelloSelectTemplate { 17 | id: i32, 18 | } 19 | 20 | #[tokio::main] 21 | async fn main() -> LunaOrmResult<()> { 22 | let config = SqliteLocalConfig { 23 | work_dir: "./workspace".to_string(), 24 | db_file: "test.db".to_string(), 25 | }; 26 | 27 | let mut db: DB = SqliteDatabase::build(config).await.unwrap().into(); 28 | 29 | let result = db.execute_plain("DROP TABLE IF EXISTS `user`").await?; 30 | let result = db.execute_plain( 31 | "CREATE TABLE IF NOT EXISTS `user`(`id` INT PRIMARY KEY, `age` INT, `name` VARCHAR(64))", 32 | ).await?; 33 | 34 | // 1. insert entity 35 | let entity1 = UserEntity { 36 | id: 1, 37 | name: "Allen".to_string(), 38 | age: Some(23), 39 | }; 40 | 41 | let entity2 = UserEntity { 42 | id: 2, 43 | name: "Bob".to_string(), 44 | age: Some(23), 45 | }; 46 | 47 | let entity3 = UserEntity { 48 | id: 3, 49 | name: "Carter".to_string(), 50 | age: Some(23), 51 | }; 52 | let _ = db.insert(&entity1).await?; 53 | let _ = db.insert(&entity2).await?; 54 | let _ = db.insert(&entity3).await?; 55 | 56 | let template = HelloSelectTemplate { id: 0 }; 57 | let page = Pagination { 58 | page_size: 1, 59 | page_num: 1, 60 | }; 61 | let entities: PagedList = 62 | db.search_paged_by_template(&template, &page).await?; 63 | assert_eq!(entities.page.total, 3); 64 | assert_eq!(entities.data.get(0).unwrap().name, Some("Bob".to_string())); 65 | 66 | Ok(()) 67 | } 68 | -------------------------------------------------------------------------------- /old/luna-types/src/record/record.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | constraint::error::ConstraintError, field::named::NamedField, field::supported::try_from_json, constraint::supported::Constraint, 3 | constraint::named::NamedConstraint 4 | }; 5 | use serde::{Deserialize, Serialize}; 6 | use serde_json::{Map, Value}; 7 | use sqlx::{any::AnyArguments, AnyPool, Arguments, Encode}; 8 | use std::collections::HashMap; 9 | 10 | /* must not be hashmap, because it will mess the field order*/ 11 | #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] 12 | #[serde(transparent)] 13 | pub struct Record<'a>(Vec>); 14 | 15 | #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] 16 | #[serde(transparent)] 17 | pub struct RecordConstraint<'a>(Vec>); 18 | 19 | impl<'a> Record<'a> { 20 | pub fn from_json( 21 | value: &'a Value, 22 | constraints: &'a RecordConstraint, 23 | ) -> Result> { 24 | let mut fields: Vec> = Vec::new(); 25 | let value_map: &Map = value.as_object().ok_or(ConstraintError::new( 26 | "only json object can transfer to record.", 27 | ))?; 28 | for constraint in &constraints.0 { 29 | let name = constraint.name(); 30 | let value: Option<&Value> = value_map.get(name); 31 | if let Some(value) = value { 32 | let data = try_from_json(value, constraint)?; 33 | let field = NamedField::new(name, data); 34 | fields.push(field); 35 | } else { 36 | return Err(ConstraintError::new(format!("{} not found", name))); 37 | } 38 | } 39 | return Ok(Record(fields)); 40 | } 41 | 42 | pub fn into_any_arguments(&self) -> AnyArguments<'_> { 43 | let mut args = AnyArguments::default(); 44 | for val in &self.0 { 45 | let _ = val.field.encode_by_ref(&mut args.values); 46 | } 47 | return args; 48 | } 49 | } 50 | 51 | pub struct EntityRecord<'a>(Vec>); 52 | -------------------------------------------------------------------------------- /next/taitan-orm-trait/src/page/pagination.rs: -------------------------------------------------------------------------------- 1 | use sqlx::Arguments; 2 | use sqlx::error::BoxDynError; 3 | use sqlx::mysql::MySqlArguments; 4 | use sqlx::postgres::PgArguments; 5 | use sqlx::sqlite::SqliteArguments; 6 | use crate::NotImplementError; 7 | 8 | #[derive(Clone, Debug, Default)] 9 | pub struct Pagination { 10 | pub page_size: u64, 11 | pub page_num: u64, 12 | pub offset: i64, // sqlx pg and mysql does not support u64, use i64 instead 13 | pub count: i64, // sqlx pg and mysql does not support u64, use i64 instead 14 | } 15 | 16 | impl Pagination { 17 | 18 | pub fn new(page_size: u64, page_num: u64) -> Self { 19 | Self { 20 | page_size, 21 | page_num, 22 | offset: (page_size * page_num) as i64, 23 | count: page_size as i64, 24 | } 25 | } 26 | 27 | // #[inline(always)] 28 | // pub fn get_offset(&self) -> u64 { 29 | // self.page_num * self.page_size 30 | // } 31 | // 32 | // #[inline(always)] 33 | // pub fn get_count(&self) -> u64 { 34 | // self.page_size 35 | // } 36 | 37 | pub fn gen_page_arguments_sqlite(&self) -> Result, BoxDynError> { 38 | let offset: i64 = self.offset as i64; 39 | let count: i64 = self.count as i64; 40 | let mut arguments = SqliteArguments::default(); 41 | arguments.add(offset)?; 42 | arguments.add(count)?; 43 | Ok(arguments) 44 | } 45 | pub fn gen_page_arguments_mysql(&self) -> Result { 46 | let offset = self.offset; 47 | let count = self.count; 48 | let mut arguments = MySqlArguments::default(); 49 | arguments.add(offset)?; 50 | arguments.add(count)?; 51 | Ok(arguments) 52 | } 53 | pub fn gen_page_arguments_postgres(&self) -> Result { 54 | let offset: i64 = self.offset as i64; 55 | let count: i64 = self.count as i64; 56 | let mut arguments = PgArguments::default(); 57 | arguments.add(offset)?; 58 | arguments.add(count)?; 59 | Ok(arguments) 60 | } 61 | } -------------------------------------------------------------------------------- /old/luna-orm/tests/entity.rs: -------------------------------------------------------------------------------- 1 | use luna_orm::prelude::*; 2 | 3 | #[derive(Schema, Clone, Debug)] 4 | #[TableName = "user"] 5 | pub struct UserEntity { 6 | age: Option, 7 | 8 | #[PrimaryKey] 9 | #[AutoIncrement] 10 | id: Option, 11 | 12 | name: String, 13 | } 14 | 15 | #[test] 16 | pub fn test_entity_with_auto() { 17 | let entity = UserEntity { 18 | id: None, 19 | age: Some(23), 20 | name: "test".to_string(), 21 | }; 22 | 23 | let table_name = entity.get_table_name(); 24 | assert_eq!(table_name, "user"); 25 | 26 | let insert_field_names = entity.get_insert_fields(); 27 | assert_eq!(insert_field_names, ["age", "name"]); 28 | 29 | let body_names = entity.get_upsert_set_fields(); 30 | assert_eq!(body_names, ["age", "name"]); 31 | 32 | let arguments: AnyArguments = entity.any_arguments_of_insert(); 33 | let len = arguments.values.0.len(); 34 | assert_eq!(len, 2); 35 | 36 | let arguments: AnyArguments = entity.any_arguments_of_upsert(); 37 | let len = arguments.values.0.len(); 38 | assert_eq!(len, 4); 39 | } 40 | 41 | #[derive(Schema, Clone, Debug)] 42 | #[TableName = "user2"] 43 | pub struct UserEntity2 { 44 | age: Option, 45 | 46 | #[PrimaryKey] 47 | id: i32, 48 | 49 | name: String, 50 | } 51 | 52 | #[test] 53 | pub fn test_entity_with_primary() { 54 | let entity = UserEntity2 { 55 | id: 1, 56 | age: Some(23), 57 | name: "test".to_string(), 58 | }; 59 | 60 | let table_name = entity.get_table_name(); 61 | assert_eq!(table_name, "user2"); 62 | 63 | let insert_field_names = entity.get_insert_fields(); 64 | assert_eq!(insert_field_names, ["id", "age", "name"]); 65 | 66 | let body_names = entity.get_upsert_set_fields(); 67 | assert_eq!(body_names, ["age", "name"]); 68 | 69 | let arguments: AnyArguments = entity.any_arguments_of_insert(); 70 | let len = arguments.values.0.len(); 71 | assert_eq!(len, 3); 72 | 73 | let arguments: AnyArguments = entity.any_arguments_of_upsert(); 74 | let len = arguments.values.0.len(); 75 | assert_eq!(len, 5); 76 | } 77 | -------------------------------------------------------------------------------- /old/luna-orm-dynamic/tests/field.rs: -------------------------------------------------------------------------------- 1 | use luna_orm::prelude::*; 2 | use luna_orm::LunaOrmResult; 3 | use luna_types::constraint::supported::Constraint; 4 | use luna_types::constraint::named::NamedConstraint; 5 | use luna_types::field::supports::integer::Integer; 6 | use luna_types::constraint::supports::integer::IntegerConstraint; 7 | use luna_types::constraint::supports::integer::IntegerConstraintBuilder; 8 | use luna_types::field::valid::ValidField; 9 | use luna_types::field::supported::Field; 10 | use sqlx::sqlx_macros; 11 | 12 | #[sqlx_macros::test] 13 | async fn test_insert_field() { 14 | let config = SqliteLocalConfig::new("./workspace", "test.db"); 15 | let mut db: SqliteDatabase = SqliteDatabase::build(config).await.unwrap(); 16 | let mut db: DB = DB(db); 17 | db.execute_plain("DROP TABLE IF EXISTS `article`") 18 | .await 19 | .unwrap(); 20 | db.execute_plain( 21 | "CREATE TABLE IF NOT EXISTS `article`(`id` INT PRIMARY KEY, `age` INT, `content` VARCHAR(64))", 22 | ) 23 | .await 24 | .unwrap(); 25 | 26 | let int_constraint: IntegerConstraint = 27 | IntegerConstraintBuilder::default() 28 | .min(10) 29 | .max(30) 30 | .build() 31 | .unwrap() 32 | .into(); 33 | let int_cons = Constraint::Int(int_constraint); 34 | 35 | let val_id: Field = Field::Int( Integer::::from(20i32)); 36 | let val_age: Field = Field::Int(Integer::::from(21i32)); 37 | // let valid_id: ValidField<'_> = ValidField::from_valid(val_id, int_cons.clone()).unwrap(); 38 | // let valid_age: ValidField<'_> = ValidField::from_valid(val_age, int_cons).unwrap(); 39 | 40 | let mut args: AnyArguments = AnyArguments::default(); 41 | luna_add_arg(&mut args, &val_id); 42 | luna_add_arg(&mut args, &val_age); 43 | 44 | let result = db 45 | .execute("insert into `article`(`id`, `age`) values(?, ?)", args) 46 | .await; 47 | let row: JsonResult = db 48 | .fetch_one_plain("select id, age from article") 49 | .await 50 | .unwrap(); 51 | assert_eq!(r#"{"age":21,"id":20}"#, row.data); 52 | } 53 | -------------------------------------------------------------------------------- /old/examples/transaction/src/main.rs: -------------------------------------------------------------------------------- 1 | use luna_orm::prelude::*; 2 | use luna_orm::LunaOrmResult; 3 | 4 | #[derive(Schema, Clone, Debug)] 5 | #[TableName = "user"] 6 | pub struct UserEntity { 7 | #[PrimaryKey] 8 | id: i32, 9 | name: String, 10 | cash: Option, 11 | } 12 | 13 | #[tokio::main] 14 | async fn main() -> LunaOrmResult<()> { 15 | let config = SqliteLocalConfig { 16 | work_dir: "./workspace".to_string(), 17 | db_file: "test.db".to_string(), 18 | }; 19 | 20 | let mut db: DB = SqliteDatabase::build(config).await.unwrap().into(); 21 | 22 | let result = db.execute_plain("DROP TABLE IF EXISTS `user`").await?; 23 | let result = db.execute_plain( 24 | "CREATE TABLE IF NOT EXISTS `user`(`id` INT PRIMARY KEY, `cash` INT, `name` VARCHAR(64))", 25 | ).await?; 26 | 27 | // 1. insert entity 28 | let entity = UserEntity { 29 | id: 1, 30 | name: "Allen".to_string(), 31 | cash: Some(100), 32 | }; 33 | db.insert(&entity).await?; 34 | let entity = UserEntity { 35 | id: 2, 36 | name: "Bob".to_string(), 37 | cash: Some(0), 38 | }; 39 | db.insert(&entity).await?; 40 | 41 | // 2. execute transaction commands 42 | let mut trx = db.transaction().await?; 43 | let mutation1 = UserMutation { 44 | name: None, 45 | cash: Some(50), 46 | }; 47 | let primary1 = UserPrimary { id: 1 }; 48 | let mutation2 = UserMutation { 49 | name: None, 50 | cash: Some(50), 51 | }; 52 | let primary2 = UserPrimary { id: 2 }; 53 | trx.update(&mutation1, &primary1).await?; 54 | trx.update(&mutation2, &primary2).await?; 55 | trx.commit().await?; 56 | 57 | // 3. check 58 | let selection = UserSelection { 59 | id: false, 60 | name: true, 61 | cash: true, 62 | }; 63 | let entity1: Option = db.select(&primary1, &selection).await?; 64 | let entity2: Option = db.select(&primary2, &selection).await?; 65 | assert_eq!(entity1.unwrap().cash, Some(50)); 66 | assert_eq!(entity2.unwrap().cash, Some(50)); 67 | 68 | Ok(()) 69 | } 70 | -------------------------------------------------------------------------------- /old/luna-types/README.md: -------------------------------------------------------------------------------- 1 | # This lib will build the extend type for daily development 2 | 3 | 1. Extend the basic type 4 | 2. Make validation the default part of data-type 5 | 3. Make serialize and store to Database smoothly 6 | 7 | ## 1. extend the basic type 8 | 1. Big Integer 9 | 2. Big Decimal 10 | 3. DateTime 11 | 4. ZonedDataTime 12 | 5. Birthday 13 | 6. Email 14 | 7. Cellphone 15 | 8. LongId 16 | 9. Uuid 17 | 10. JsonRecord 18 | 19 | ## 2. Make validation default 20 | 21 | ## 3. Serialize and deserialize 22 | ### 3.1 From/To Serde 23 | ### 3.2 From/To Sqlx 24 | 25 | 26 | 27 | 28 | 29 | ## Global Structure 30 | trait Contraint -> struct {Xxx}Constraint-> enum SupportedConstraint -> struct NamedConstraint 31 | trait Field -> struct {Xxx}Field -> enum FieldType -> struct ValidField -> struct NamedField 32 | Constraint array -> Schema 33 | Field array -> Record 34 | 35 | ## trait Constraint 36 | fn is_option(&self) -> bool 37 | fn is_valid(&self, value) -> bool 38 | fn is_valid_json(&self, json) -> bool 39 | fn validate(&self, value) -> Result<(), ConstraintError> 40 | fn validate_json(&self, value) -> Result<(), ConstraintError> 41 | 42 | ## trait Field 43 | validate 44 | From/To Serde 45 | From/To Sqlx 46 | Deref 47 | DerefMut 48 | 49 | ## struct Schema(Constraint Array) 50 | fn validate(&self, record) -> Result<(), ConstraintError> 51 | fn is_valid(&self, record) -> bool 52 | fn get_entity_schema(&self) 53 | fn get_selected_schema(&self) 54 | fn get_primary_schema(&self) 55 | fn get_location_schema(&self) 56 | fn get_mutation_schema(&self) 57 | 58 | ## struct Record(Fields Array) 59 | struct EntityRecord : Entity 60 | struct SelectedRecord : SelectedEntity 61 | struct PrimaryRecord : Primary 62 | struct LocationRecord : Location 63 | struct MutationRecord : Mutation 64 | fn into_entity_record(&self, entity_schema) -> Result 65 | fn into_selected_record(&self, selected_schema) -> Result 66 | fn into_primary_record(&self, primary_schema) -> Result 67 | fn into_location_record(&self, location_schema) -> Result 68 | fn into_mutation_record(&self, mutation_schema) -> Result 69 | 70 | -------------------------------------------------------------------------------- /old/luna-orm-macro/src/type_check.rs: -------------------------------------------------------------------------------- 1 | use proc_macro2::{self, Ident, Span, TokenStream}; 2 | use quote::quote_spanned; 3 | use syn::{ 4 | punctuated::Punctuated, 5 | token::{self, Comma}, 6 | Attribute, Data, DataEnum, DataStruct, DataUnion, Error, Field, Fields, FieldsNamed, LitStr, 7 | Path, Result, Type, Variant, 8 | }; 9 | 10 | pub fn type_has_prefix(ty: &Type, name: &str) -> bool { 11 | match ty { 12 | Type::Path(type_path) => { 13 | let idents_of_path = 14 | type_path 15 | .path 16 | .segments 17 | .iter() 18 | .fold(String::new(), |mut acc, v| { 19 | acc.push_str(&v.ident.to_string()); 20 | acc.push_str("::"); 21 | acc 22 | }); 23 | idents_of_path.starts_with(name) 24 | } 25 | _ => false, 26 | } 27 | } 28 | 29 | pub fn get_field_type_name(field: &Field) -> String { 30 | let ty = &field.ty; 31 | match ty { 32 | Type::Path(type_path) => { 33 | let idents_of_path = 34 | type_path 35 | .path 36 | .segments 37 | .iter() 38 | .fold(String::new(), |mut acc, v| { 39 | acc.push_str(&v.ident.to_string()); 40 | acc.push_str("::"); 41 | acc 42 | }); 43 | idents_of_path 44 | } 45 | _ => "".to_string(), 46 | } 47 | } 48 | 49 | pub fn type_has_one_of_names(ty: &Type, names: &[&str]) -> bool { 50 | names.iter().any(|name| type_has_prefix(ty, name)) 51 | } 52 | 53 | pub fn type_is_option(ty: &Type) -> bool { 54 | type_has_one_of_names( 55 | ty, 56 | &[ 57 | "Option::", 58 | "std::option::Option::", 59 | "core::option::Option::", 60 | ], 61 | ) 62 | } 63 | pub fn field_is_option(field: &Field) -> bool { 64 | type_is_option(&field.ty) 65 | } 66 | 67 | pub fn field_is_type_of(field: &Field, type_name: &str) -> bool { 68 | let ty: &Type = &field.ty; 69 | type_has_prefix(ty, type_name) 70 | } 71 | -------------------------------------------------------------------------------- /next/taitan-orm-macro/src/fields/mappers/row_constructor.rs: -------------------------------------------------------------------------------- 1 | use proc_macro2::TokenStream; 2 | use quote::quote; 3 | use crate::fields::{FieldsContainer}; 4 | use crate::fields::mappers::row_get_constructor::RowGetConstructor; 5 | 6 | pub trait RowConstructor : FieldsContainer + RowGetConstructor { 7 | fn gen_selected_named_row(&self) -> TokenStream { 8 | let tokens =self.map_field_vec(&::of_selected_row); 9 | quote!( 10 | let mut selected = Self::default(); 11 | #(#tokens;)* 12 | Ok(selected) 13 | ) 14 | } 15 | 16 | fn gen_selected_row(&self) -> TokenStream { 17 | let tokens =self.map_field_vec(&::of_selected_row_i); 18 | quote!( 19 | let mut selected = Self::default(); 20 | let mut i = 0; 21 | #(#tokens;)* 22 | Ok(selected) 23 | ) 24 | } 25 | 26 | fn gen_selected_bits_row(&self) -> TokenStream { 27 | let tokens = self.map_field_vec_with_index(&::of_selected_bits_index_row_i); 28 | quote!( 29 | let mut selected = Self::default(); 30 | let mut i = 0; 31 | #(#tokens;)* 32 | Ok(selected) 33 | ) 34 | } 35 | 36 | fn gen_selected_self_row(&self) -> TokenStream { 37 | let tokens = self.map_field_vec(&::of_selected_self_row_i); 38 | quote!( 39 | let mut selected = Self::default(); 40 | let mut i = 0; 41 | #(#tokens;)* 42 | Ok(selected) 43 | ) 44 | } 45 | 46 | fn gen_full_named_row(&self) -> TokenStream { 47 | let tokens =self.map_field_vec(&::of_row); 48 | quote!( 49 | let mut selected = Self::default(); 50 | #(#tokens;)* 51 | Ok(selected) 52 | ) 53 | } 54 | 55 | fn gen_full_row(&self) -> TokenStream { 56 | let tokens =self.map_field_vec(&::of_row_i); 57 | quote!( 58 | let mut selected = Self::default(); 59 | let mut i = 0; 60 | #(#tokens;)* 61 | Ok(selected) 62 | ) 63 | } 64 | } -------------------------------------------------------------------------------- /old/luna-orm-macro/src/primary.rs: -------------------------------------------------------------------------------- 1 | use case::CaseExt; 2 | use proc_macro::{self, TokenStream}; 3 | use quote::quote; 4 | 5 | use crate::fields_parser::FieldsParser; 6 | use crate::utils::*; 7 | 8 | use proc_macro2::{Ident, Span}; 9 | use syn::Field; 10 | use syn::{parse_macro_input, DeriveInput}; 11 | 12 | pub fn impl_primary_macro(input: TokenStream) -> TokenStream { 13 | let DeriveInput { 14 | attrs, ident, data, .. 15 | } = parse_macro_input!(input); 16 | let fields = extract_fields(&data).unwrap(); 17 | let fields = fields.named.into_iter().collect::>(); 18 | let table_name = extract_table_name(&ident, &attrs); 19 | let impl_token = generate_impl(&table_name, &fields); 20 | 21 | let output = quote! { 22 | 23 | impl Primary for #ident { 24 | #impl_token 25 | } 26 | }; 27 | 28 | //panic!("{}", output); 29 | output.into() 30 | } 31 | 32 | pub fn generate_primary(table_name: &str, fields: &Vec) -> proc_macro2::TokenStream { 33 | let primary_name = format!("{}Primary", table_name.to_camel()); 34 | let primary_ident = Ident::new(&primary_name, Span::call_site()); 35 | let fields_tokens = FieldsParser::from_vec(fields).get_not_option_fields(); 36 | let impl_token = generate_impl(table_name, fields); 37 | 38 | let output = quote!( 39 | #[derive(Default, Debug, Clone)] 40 | pub struct #primary_ident { 41 | #fields_tokens 42 | } 43 | 44 | impl Primary for #primary_ident { 45 | #impl_token 46 | } 47 | ); 48 | 49 | //panic!("{}", output); 50 | output 51 | } 52 | 53 | fn generate_impl(table_name: &str, fields: &Vec) -> proc_macro2::TokenStream { 54 | let parser = FieldsParser::from_vec(fields); 55 | let fields_name = parser.get_name_array(); 56 | let args_add_stmt = parser.get_args(); 57 | let output = quote!( 58 | fn get_table_name(&self) -> &'static str { 59 | #table_name 60 | } 61 | 62 | fn get_primary_field_names(&self) -> &'static [&'static str] { 63 | #fields_name 64 | } 65 | 66 | fn any_arguments(&self) -> sqlx::any::AnyArguments<'_> { 67 | #args_add_stmt 68 | } 69 | ); 70 | output 71 | } 72 | -------------------------------------------------------------------------------- /next/taitan-orm-macro/src/util/life_time_checker.rs: -------------------------------------------------------------------------------- 1 | 2 | use proc_macro2::{Ident, Span, TokenStream}; 3 | use quote::quote; 4 | use syn::{parse_macro_input, DeriveInput, Data, Fields, Field, Type, GenericParam, Generics, Lifetime}; 5 | 6 | use syn::visit::Visit; 7 | use crate::util::create_path_from_str; 8 | 9 | // 自定义访问器用于查找生命周期 10 | struct LifetimeFinder { 11 | has_lifetime: bool, 12 | } 13 | 14 | impl<'ast> Visit<'ast> for LifetimeFinder { 15 | fn visit_lifetime(&mut self, _: &'ast syn::Lifetime) { 16 | self.has_lifetime = true; 17 | } 18 | } 19 | 20 | pub fn build_impl_trait_token(struct_ident: &Ident, generics: &Generics, trait_name: &str) -> TokenStream { 21 | let mut lifetimes: Vec = Vec::new(); 22 | for param in generics.params.iter() { 23 | if let GenericParam::Lifetime(lifetime_def) = param { 24 | lifetimes.push(lifetime_def.lifetime.clone()); 25 | } 26 | } 27 | 28 | let trait_name = create_path_from_str(trait_name); 29 | if !lifetimes.is_empty() { 30 | quote! { 31 | impl <#(#lifetimes),*> #trait_name for #struct_ident<#(#lifetimes),*> 32 | } 33 | } else { 34 | quote! { 35 | impl #trait_name for #struct_ident 36 | } 37 | } 38 | } 39 | 40 | pub fn build_struct_ident(ident: &Ident, lifetimes: &Vec) -> TokenStream { 41 | if lifetimes.is_empty() { 42 | quote! { 43 | #ident 44 | } 45 | } else { 46 | quote! { 47 | #ident<#(#lifetimes),*> 48 | } 49 | } 50 | } 51 | 52 | pub fn extract_generic_lifetimes(generics: &Generics) -> Vec { 53 | let mut lifetimes: Vec = Vec::new(); 54 | for param in generics.params.iter() { 55 | if let GenericParam::Lifetime(lifetime_def) = param { 56 | lifetimes.push(lifetime_def.lifetime.clone()); 57 | } 58 | } 59 | lifetimes 60 | } 61 | 62 | 63 | pub fn check_type_lifetime(ty: &Type) -> bool { 64 | let mut finder = LifetimeFinder { has_lifetime: false }; 65 | finder.visit_type(ty); 66 | finder.has_lifetime 67 | } 68 | pub fn check_field_lifetime(field: &Field) -> bool { 69 | let mut finder = LifetimeFinder { has_lifetime: false }; 70 | finder.visit_field(field); 71 | finder.has_lifetime 72 | } 73 | 74 | -------------------------------------------------------------------------------- /old/luna-types/src/sqlx/supports/integer.rs: -------------------------------------------------------------------------------- 1 | use crate::field::supports::integer::Integer; 2 | use num_traits::PrimInt; 3 | use sqlx::any::AnyValue; 4 | use sqlx::database::HasArguments; 5 | use sqlx::encode::IsNull; 6 | use sqlx::sqlite::SqliteArgumentValue; 7 | use sqlx::Database; 8 | use sqlx::{Any, Sqlite}; 9 | use sqlx::{Encode, Type}; 10 | use sqlx_core::any::AnyTypeInfo; 11 | use sqlx_core::any::AnyValueKind; 12 | 13 | impl<'a> Encode<'a, Sqlite> for Integer { 14 | fn encode_by_ref( 15 | &self, 16 | buf: &mut >::ArgumentBuffer, 17 | ) -> sqlx::encode::IsNull { 18 | buf.push(SqliteArgumentValue::Int(self.0)); 19 | return IsNull::No; 20 | } 21 | } 22 | impl<'a> Encode<'a, Sqlite> for Integer { 23 | fn encode_by_ref( 24 | &self, 25 | buf: &mut >::ArgumentBuffer, 26 | ) -> sqlx::encode::IsNull { 27 | buf.push(SqliteArgumentValue::Int64(self.0)); 28 | return IsNull::No; 29 | } 30 | } 31 | 32 | impl Type for Integer { 33 | fn type_info() -> ::TypeInfo { 34 | >::type_info() 35 | } 36 | } 37 | 38 | impl Type for Integer { 39 | fn type_info() -> ::TypeInfo { 40 | >::type_info() 41 | } 42 | } 43 | 44 | /******************************************/ 45 | impl<'a> Encode<'a, Any> for Integer { 46 | fn encode_by_ref( 47 | &self, 48 | buf: &mut >::ArgumentBuffer, 49 | ) -> sqlx::encode::IsNull { 50 | buf.0.push(AnyValueKind::Integer(self.0)); 51 | return IsNull::No; 52 | } 53 | } 54 | impl<'a> Encode<'a, Any> for Integer { 55 | fn encode_by_ref( 56 | &self, 57 | buf: &mut >::ArgumentBuffer, 58 | ) -> sqlx::encode::IsNull { 59 | buf.0.push(AnyValueKind::BigInt(self.0)); 60 | return IsNull::No; 61 | } 62 | } 63 | 64 | impl Type for Integer { 65 | fn type_info() -> ::TypeInfo { 66 | >::type_info() 67 | } 68 | } 69 | 70 | impl Type for Integer { 71 | fn type_info() -> ::TypeInfo { 72 | >::type_info() 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /old/luna-orm/tests/create.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::{Debug, Formatter}; 2 | use luna_orm::prelude::*; 3 | use luna_orm::LunaOrmResult; 4 | mod common; 5 | use common::create_table; 6 | use common::mutex::get_test_mutex; 7 | use common::setup_database; 8 | use common::setup_logger; 9 | use sqlx::sqlx_macros; 10 | 11 | #[derive(Schema, Clone, Debug)] 12 | #[TableName = "user"] 13 | pub struct UserEntity { 14 | #[PrimaryKey] 15 | #[AutoIncrement] 16 | id: Option, 17 | age: Option, 18 | name: String, 19 | } 20 | 21 | #[sqlx_macros::test] 22 | pub async fn test_create() -> LunaOrmResult<()> { 23 | let test_mutex = get_test_mutex(); 24 | let test_lock = test_mutex.lock(); 25 | setup_logger(); 26 | let mut db = setup_database().await?; 27 | create_table(&mut db, "user" , 28 | "create table if not exists `user`(`id` integer primary key autoincrement, `age` INT, `name` VARCHAR(60), create_time DATETIME default current_timestamp)" ).await?; 29 | let mut entity = UserEntity { 30 | id: None, 31 | age: Some(23), 32 | name: "test".to_string(), 33 | }; 34 | 35 | let result = db.create(&mut entity).await?; 36 | assert_eq!(entity.id, Some(1)); 37 | 38 | // sqlx sqlite has bug #2099, it does not actually commit insert returning stmt 39 | /* 40 | let db_clone = db.clone(); 41 | let mut trx = db_clone.transaction().await?; 42 | let selection = UserSelection { 43 | id: true, 44 | age: true, 45 | name: true, 46 | }; 47 | let entities: Vec = trx.search_all(&selection).await?; 48 | 49 | let location = UserLocation { 50 | id: None, 51 | age: Some(LocationExpr { 52 | val: 23, 53 | cmp: CmpOperator::Eq, 54 | }), 55 | name: None, 56 | }; 57 | let selected: Vec = db.search(&location, None, &selection).await?; 58 | let sql = db 59 | .get_generator() 60 | .get_search_sql(&selection, &location, None); 61 | dbg!(&sql); 62 | assert_eq!(selected.len(), 1); 63 | let selected_one = selected.first().unwrap(); 64 | assert_eq!(selected_one.id, Some(1)); 65 | assert_eq!(selected_one.age, Some(23)); 66 | assert_eq!(selected_one.name, Some("test".to_string())); 67 | 68 | trx.commit().await?; 69 | */ 70 | 71 | Ok(()) 72 | } -------------------------------------------------------------------------------- /old/luna-orm-trait/src/utils.rs: -------------------------------------------------------------------------------- 1 | use sqlx::any::AnyArguments; 2 | use sqlx::mysql::MySqlArguments; 3 | use sqlx::sqlite::SqliteArguments; 4 | use sqlx::Arguments; 5 | use sqlx::{Any, MySql, Sqlite}; 6 | use sqlx::{Encode, Type}; 7 | use sqlx_core::error::BoxDynError; 8 | 9 | pub fn add_val_to_any_arguments<'q, T>(args: &mut AnyArguments<'q>, value: &T) 10 | where 11 | T: 'q + Send + Encode<'q, Any> + Type, 12 | { 13 | let _ = value.encode_by_ref(&mut args.values); 14 | } 15 | 16 | pub fn add_val_to_mysql_arguments<'q, T>( 17 | args: &mut MySqlArguments, 18 | value: &'q T, 19 | ) -> Result<(), BoxDynError> 20 | where 21 | T: 'q + Sync + Encode<'q, MySql> + Type, 22 | { 23 | args.add(value) 24 | } 25 | 26 | pub fn add_val_to_sqlite_arguments<'q, T>(args: &'q mut SqliteArguments<'q>, value: &'q T) 27 | -> Result<(), BoxDynError> 28 | where 29 | T: 'q + Sync + Encode<'q, Sqlite> + Type, 30 | { 31 | args.add(value) 32 | } 33 | 34 | pub trait ArrayStrEqual { 35 | fn equal(&self, arr: &[S]) -> bool 36 | where 37 | S: AsRef; 38 | } 39 | 40 | impl ArrayStrEqual for [&str; N] { 41 | fn equal(&self, arr: &[S]) -> bool 42 | where 43 | S: AsRef, 44 | { 45 | let n = self.len(); 46 | if n != arr.len() { 47 | return false; 48 | } 49 | for i in 0..n { 50 | let a = self[i]; 51 | let b = &arr[i]; 52 | if a != b.as_ref() { 53 | return false; 54 | } 55 | } 56 | true 57 | } 58 | } 59 | 60 | pub trait ArrayEqual 61 | where 62 | T: PartialEq, 63 | { 64 | fn equal(&self, arr: &[S]) -> bool 65 | where 66 | S: AsRef; 67 | } 68 | 69 | impl ArrayEqual for [T; N] { 70 | fn equal(&self, arr: &[S]) -> bool 71 | where 72 | S: AsRef, 73 | { 74 | let n = self.len(); 75 | if n != arr.len() { 76 | return false; 77 | } 78 | for i in 0..n { 79 | let a = &self[i]; 80 | let b = arr[i].as_ref(); 81 | if a != b { 82 | return false; 83 | } 84 | } 85 | true 86 | } 87 | } 88 | 89 | pub fn array_str_equal(arr_str: &[&str], arr_string: &[&str]) -> bool { 90 | arr_str.iter().all(|e| arr_string.contains(e)) 91 | } 92 | -------------------------------------------------------------------------------- /next/taitan-orm/tests/macros/template_spec.rs: -------------------------------------------------------------------------------- 1 | use sqlx::sqlx_macros; 2 | use std::borrow::Cow; 3 | use taitan_orm::Schema; 4 | use taitan_orm_macro::TemplateRecord; 5 | use taitan_orm_trait::TemplateRecord; 6 | use time::PrimitiveDateTime; 7 | use uuid::Uuid; 8 | use taitan_orm_trait::pagination::Pagination; 9 | #[derive(TemplateRecord, Clone, Debug)] 10 | #[sql = "select * from ${name}"] 11 | pub struct TestTemplate1<'a> { 12 | name: Cow<'a, str>, 13 | } 14 | 15 | #[derive(TemplateRecord, Clone, Debug)] 16 | #[sql = "select * from #{name}"] 17 | pub struct TestTemplate2 { 18 | name: String, 19 | } 20 | 21 | #[derive(TemplateRecord, Clone, Debug)] 22 | #[sql = "select * from ${name} #{age}"] 23 | pub struct TestTemplate3<'a> { 24 | name: Cow<'a, str>, 25 | age: i32, 26 | } 27 | 28 | #[derive(TemplateRecord, Clone, Debug)] 29 | #[sql = "select * from ${name} #{age} 'hello' "] 30 | pub struct TestTemplate4<'a> { 31 | name: Cow<'a, str>, 32 | age: i32, 33 | } 34 | 35 | #[derive(TemplateRecord, Clone, Debug)] 36 | #[sql = "select * from ${name} #{age} \"hello ${name}\" #{age} LIMIT #{page.offset} #{page.count}"] 37 | #[count_sql = "select count(*) from ${name} #{age} \"hello ${name}\""] 38 | pub struct TestTemplate5<'a> { 39 | name: Cow<'a, str>, 40 | 41 | age: i32, 42 | 43 | #[limit_field] 44 | page: Pagination, 45 | } 46 | 47 | 48 | #[sqlx_macros::test] 49 | pub async fn template_macro_spec() -> taitan_orm::Result<()> { 50 | let template = TestTemplate1 { 51 | name: Cow::Borrowed("wang"), 52 | }; 53 | let sql = template.get_sql(None); 54 | assert_eq!(sql, "select * from wang"); 55 | 56 | let template = TestTemplate2 { 57 | name: String::from("wang"), 58 | }; 59 | let sql = template.get_sql(None); 60 | assert_eq!(sql, "select * from ?"); 61 | 62 | let template = TestTemplate3 { 63 | name: Cow::Borrowed("wang"), 64 | age: 23, 65 | }; 66 | let sql = template.get_sql(None); 67 | assert_eq!(sql, "select * from wang ?"); 68 | 69 | let template = TestTemplate4 { 70 | name: Cow::Borrowed("wang"), 71 | age: 23, 72 | }; 73 | let sql = template.get_sql(None); 74 | assert_eq!(sql, "select * from wang ? 'hello'"); 75 | 76 | let template = TestTemplate5 { 77 | name: Cow::Borrowed("wang"), 78 | age: 23, 79 | page: Pagination::new(100, 200) 80 | }; 81 | let sql = template.get_sql(None); 82 | assert_eq!(sql, "select * from wang ? \"hello ${name}\" ? LIMIT ? ?"); 83 | 84 | Ok(()) 85 | } 86 | -------------------------------------------------------------------------------- /next/taitan-orm-macro/src/expands/location_expander.rs: -------------------------------------------------------------------------------- 1 | use case::CaseExt; 2 | use proc_macro2::{Ident, Span, TokenStream}; 3 | use quote::quote; 4 | use syn::{Attribute, FieldsNamed}; 5 | use crate::attrs::{AttrParser, DefaultAttrParser}; 6 | use crate::fields::{FieldsFilter, FieldsParser, UniqueParser}; 7 | use crate::fields::StructConstructor; 8 | use crate::fields::LocationParser; 9 | 10 | 11 | pub fn generate_location_struct_and_impl( 12 | ident: &Ident, 13 | attrs: &Vec, 14 | fields: &FieldsNamed, 15 | ) -> TokenStream { 16 | 17 | let parser = FieldsParser::from_named(fields); 18 | 19 | let where_clause = FieldsParser::from_named(fields).get_where_clause(); 20 | let location_fields_name = parser.get_location_fields_name(); 21 | let location_arguments_sqlite = FieldsParser::from_named(fields).gen_location_arguments_sqlite(); 22 | let location_arguments_mysql = FieldsParser::from_named(fields).gen_location_arguments_mysql(); 23 | let location_arguments_postgres = FieldsParser::from_named(fields).gen_location_arguments_postgres(); 24 | 25 | let table_name = DefaultAttrParser::extract_table_name(ident, attrs); 26 | let struct_name = format!("{}Location", table_name.to_camel()); 27 | let struct_ident = Ident::new(&struct_name, Span::call_site()); 28 | let struct_stream = FieldsParser::from_named(fields).of_location(&struct_name); 29 | 30 | let output = quote! { 31 | 32 | #struct_stream 33 | 34 | impl taitan_orm::traits::Location for #struct_ident { 35 | 36 | fn get_table_name(&self) -> &'static str { 37 | #table_name 38 | } 39 | 40 | fn get_location_fields_name(&self) -> Vec { 41 | #location_fields_name 42 | } 43 | 44 | fn get_where_clause(&self, wrap_char: char, place_holder: char) -> String { 45 | #where_clause 46 | } 47 | 48 | fn gen_location_arguments_sqlite(&self) -> Result, sqlx::error::BoxDynError> { 49 | #location_arguments_sqlite 50 | } 51 | 52 | fn gen_location_arguments_mysql(&self) -> Result { 53 | #location_arguments_mysql 54 | } 55 | 56 | fn gen_location_arguments_postgres(&self) -> Result { 57 | #location_arguments_postgres 58 | } 59 | } 60 | }; 61 | 62 | output 63 | } -------------------------------------------------------------------------------- /old/examples/input/src/main.rs: -------------------------------------------------------------------------------- 1 | use luna_orm::LunaOrmResult; 2 | use luna_orm::prelude::{Entity, InputGenerator, Location, Mutation, OrderBy, Primary}; 3 | use luna_orm::prelude::{CommandExecutor, SqlExecutor, SqliteDatabase, SqliteLocalConfig, DB}; 4 | use sqlx::{Arguments, Database, Sqlite}; 5 | use sqlx::sqlite::SqliteArguments; 6 | use sqlx::error::BoxDynError; 7 | pub struct UserEntity { 8 | id: i32, 9 | name: String, 10 | age: Option, 11 | } 12 | 13 | 14 | 15 | impl InputGenerator for UserEntity { 16 | fn gen_insert_arguments(&self, entity: &dyn Entity) -> Result, BoxDynError> { 17 | let mut arguments: ::Arguments<'_> = SqliteArguments::default(); 18 | arguments.add(&self.name)?; 19 | if let Some(age) = self.age { 20 | arguments.add(age)?; 21 | } 22 | Ok(arguments) 23 | } 24 | 25 | fn gen_upsert_arguments(&self, entity: &dyn Entity) -> ::Arguments<'_> { 26 | todo!() 27 | } 28 | 29 | fn gen_update_arguments(&self, mutation: &dyn Mutation, primary: &dyn Primary) -> ::Arguments<'_> { 30 | todo!() 31 | } 32 | 33 | fn gen_change_arguments(&self, mutation: &dyn Mutation, location: &dyn Location) -> ::Arguments<'_> { 34 | todo!() 35 | } 36 | 37 | fn gen_primary_arguments(&self, primary: &dyn Primary) -> ::Arguments<'_> { 38 | todo!() 39 | } 40 | 41 | fn gen_location_arguments(&self, location: &dyn Location, order_by_option: Option<&dyn OrderBy>) -> ::Arguments<'_> { 42 | todo!() 43 | } 44 | } 45 | 46 | 47 | #[tokio::main] 48 | async fn main() -> LunaOrmResult<()> { 49 | let config = SqliteLocalConfig { 50 | work_dir: "./workspace".to_string(), 51 | db_file: "test.db".to_string(), 52 | }; 53 | 54 | let mut db: DB = SqliteDatabase::build(config).await.unwrap().into(); 55 | 56 | let result = db.execute_plain("DROP TABLE IF EXISTS `user`").await?; 57 | let result = db.execute_plain( 58 | "CREATE TABLE IF NOT EXISTS `user`(`id` INT PRIMARY KEY, `age` INT, `name` VARCHAR(64))", 59 | ).await?; 60 | 61 | // 1. insert entity 62 | let entity = UserEntity { 63 | id: 1, 64 | name: "Allen".to_string(), 65 | age: Some(23), 66 | }; 67 | 68 | let insert_stmt: &str = ""; 69 | let args = entity.gen_insert_arguments(&entity).unwrap(); 70 | let result = db.execute_with_db(insert_stmt, args).await?; 71 | 72 | 73 | Ok(()) 74 | } -------------------------------------------------------------------------------- /next/taitan-orm/src/dto/count.rs: -------------------------------------------------------------------------------- 1 | use bit_vec::BitVec; 2 | use sqlx::mysql::MySqlRow; 3 | use sqlx::postgres::PgRow; 4 | use sqlx::sqlite::SqliteRow; 5 | use sqlx::{Error, MySql, Postgres, Row, Sqlite}; 6 | use taitan_orm_trait::{SelectedEntity, Selection}; 7 | 8 | #[derive(Clone, Debug, Default)] 9 | pub struct EmptySelection {} 10 | 11 | impl Selection for EmptySelection { 12 | fn get_table_name(&self) -> &'static str { 13 | todo!() 14 | } 15 | 16 | fn get_selected_fields(&self) -> Vec { 17 | todo!() 18 | } 19 | 20 | fn get_selected_bits(&self) -> BitVec { 21 | todo!() 22 | } 23 | 24 | 25 | fn full_fields() -> Self { 26 | todo!() 27 | } 28 | } 29 | 30 | #[derive(Clone, Debug, Default)] 31 | pub struct CountResult { 32 | pub count: u64, 33 | } 34 | 35 | impl SelectedEntity for CountResult { 36 | type Selection = EmptySelection; 37 | 38 | fn from_row(_selection: &Self::Selection, row: SqliteRow) -> Result 39 | where 40 | Self: Sized, 41 | { 42 | // TODO: 有可能使用try_get(0)更好 43 | let count: i64 = row.try_get("count")?; 44 | Ok(Self { 45 | count: count as u64, 46 | }) 47 | } 48 | 49 | fn from_row_full(row: SqliteRow) -> Result 50 | where 51 | Self: Sized, 52 | { 53 | let count: i64 = row.try_get("count")?; 54 | Ok(Self { 55 | count: count as u64, 56 | }) 57 | } 58 | } 59 | 60 | impl SelectedEntity for CountResult { 61 | type Selection = EmptySelection; 62 | 63 | fn from_row(_selection: &Self::Selection, row: MySqlRow) -> Result 64 | where 65 | Self: Sized, 66 | { 67 | let count: i64 = row.try_get("count")?; 68 | Ok(Self { 69 | count: count as u64, 70 | }) 71 | } 72 | fn from_row_full(row: MySqlRow) -> Result { 73 | let count: i64 = row.try_get("count")?; 74 | Ok(Self { 75 | count: count as u64, 76 | }) 77 | } 78 | } 79 | 80 | impl SelectedEntity for CountResult { 81 | type Selection = EmptySelection; 82 | 83 | fn from_row(_selection: &Self::Selection, row: PgRow) -> Result 84 | where 85 | Self: Sized, 86 | { 87 | let count: i64 = row.try_get("count")?; 88 | Ok(Self { 89 | count: count as u64, 90 | }) 91 | } 92 | fn from_row_full(row: PgRow) -> Result { 93 | let count: i64 = row.try_get("count")?; 94 | Ok(Self { 95 | count: count as u64, 96 | }) 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /old/luna-orm/src/database/mysql.rs: -------------------------------------------------------------------------------- 1 | mod MySqlInputGenerator; 2 | 3 | use crate::database::lib::Database; 4 | use crate::database::lib::DatabaseType; 5 | use crate::database::DB; 6 | use crate::{error::LunaOrmError, LunaOrmResult}; 7 | 8 | use sqlx::any::AnyConnectOptions; 9 | use sqlx::AnyPool; 10 | 11 | use crate::command_executor::CommandExecutor; 12 | use crate::sql_executor::SqlExecutor; 13 | use crate::sql_generator::MySqlGenerator; 14 | use crate::sql_generator::SqlGenerator; 15 | use luna_orm_trait::Entity; 16 | use std::str::FromStr; 17 | use tracing::debug; 18 | 19 | #[derive(Debug)] 20 | pub struct MysqlDatabase { 21 | database_type: DatabaseType, 22 | pool: AnyPool, 23 | sql_generator: MySqlGenerator, 24 | } 25 | 26 | impl SqlExecutor for MysqlDatabase { 27 | fn get_pool(&self) -> LunaOrmResult<&AnyPool> { 28 | Ok(&self.pool) 29 | } 30 | } 31 | 32 | impl CommandExecutor for MysqlDatabase { 33 | type G = MySqlGenerator; 34 | 35 | fn get_generator(&self) -> &Self::G { 36 | &self.sql_generator 37 | } 38 | 39 | async fn create<'a>(&mut self, entity: &'a mut dyn Entity) -> LunaOrmResult { 40 | debug!(target: "luna_orm", command = "create", entity = ?entity); 41 | let sql = self.get_generator().get_insert_sql(entity); 42 | debug!(target: "luna_orm", command = "create", sql = sql); 43 | let args = entity.any_arguments_of_insert(); 44 | let result = self.execute(&sql, args).await?; 45 | entity.set_auto_increment_field(result.last_insert_id()); 46 | debug!(target: "luna_orm", command = "create", result = ?entity); 47 | return Ok(result.rows_affected() > 0); 48 | } 49 | } 50 | 51 | impl Database for MysqlDatabase { 52 | fn get_type(&self) -> &DatabaseType { 53 | &self.database_type 54 | } 55 | } 56 | 57 | impl From for DB { 58 | fn from(value: MysqlDatabase) -> Self { 59 | Self(value) 60 | } 61 | } 62 | 63 | impl MysqlDatabase { 64 | pub async fn build(url: &str, user: &str, password: &str) -> LunaOrmResult { 65 | let url = format!("mysql://{}:{}@{}", user, password, url); 66 | 67 | let any_options = AnyConnectOptions::from_str(&url).unwrap(); 68 | let pool = AnyPool::connect_with(any_options) 69 | .await 70 | .map_err(|_e| LunaOrmError::DatabaseInitFail("init pool fail".to_string()))?; 71 | 72 | let generator = MySqlGenerator::new(); 73 | let database = MysqlDatabase { 74 | database_type: DatabaseType::MySql, 75 | pool, 76 | sql_generator: generator, 77 | }; 78 | return Ok(database); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /old/luna-orm-macro/src/mutation.rs: -------------------------------------------------------------------------------- 1 | use proc_macro::{self, TokenStream}; 2 | use quote::quote; 3 | use quote::quote_spanned; 4 | 5 | use crate::field_utils::map_field; 6 | use crate::field_utils::map_field_vec; 7 | use crate::field_utils::map_fields; 8 | use crate::field_utils::FieldMapType; 9 | use crate::fields_parser::FieldsParser; 10 | use crate::type_check::field_is_option; 11 | use crate::type_check::type_is_option; 12 | use crate::utils::*; 13 | use case::CaseExt; 14 | use proc_macro2::{Ident, Span}; 15 | use syn::Attribute; 16 | use syn::Field; 17 | use syn::{ 18 | parse_macro_input, token, Data, DataEnum, DataStruct, DataUnion, DeriveInput, Error, Fields, 19 | FieldsNamed, LitStr, Path, Result, 20 | }; 21 | 22 | pub fn impl_mutation_macro(input: TokenStream) -> TokenStream { 23 | let DeriveInput { ident, data, .. } = parse_macro_input!(input); 24 | 25 | let fields = extract_fields(&data).unwrap(); 26 | //let args_push_clause = build_args_push_clause(&fields); 27 | //let args_push_ref_clause = build_args_add_option_ref_clause(&fields); 28 | //let fields_name = extract_fields_name(&fields); 29 | let parser = FieldsParser::from_named(&fields); 30 | let fields_tokens = parser.get_option_fields(); 31 | let fields_name = parser.get_option_name_vec(); 32 | let option_args_stmt = parser.get_option_args(); 33 | 34 | let output = quote! { 35 | impl Mutation for #ident { 36 | fn get_fields_name(&self) -> Vec { 37 | #fields_name 38 | } 39 | 40 | fn any_arguments(&self) -> AnyArguments<'_> { 41 | #option_args_stmt 42 | } 43 | } 44 | }; 45 | 46 | output.into() 47 | } 48 | 49 | pub fn generate_mutation(table_name: &str, fields: &Vec) -> proc_macro2::TokenStream { 50 | let mutation_name = format!("{}Mutation", table_name.to_camel()); 51 | let mutation_ident = Ident::new(&mutation_name, Span::call_site()); 52 | 53 | let parser = FieldsParser::from_vec(fields); 54 | let fields_tokens = parser.get_option_fields(); 55 | let fields_name = parser.get_option_name_vec(); 56 | let option_args_stmt = parser.get_option_args(); 57 | 58 | let output = quote!( 59 | #[derive(Default, Debug, Clone, PartialEq, Eq)] 60 | pub struct #mutation_ident { 61 | #fields_tokens 62 | } 63 | 64 | impl Mutation for #mutation_ident { 65 | fn get_fields_name(&self) -> Vec { 66 | #fields_name 67 | } 68 | 69 | fn any_arguments(&self) -> AnyArguments<'_> { 70 | #option_args_stmt 71 | } 72 | } 73 | ); 74 | 75 | //panic!("{}", output); 76 | output 77 | } 78 | -------------------------------------------------------------------------------- /next/taitan-orm-macro/src/fields/mappers/struct_constructor.rs: -------------------------------------------------------------------------------- 1 | use proc_macro2::{Ident, Span, TokenStream}; 2 | use quote::quote; 3 | use crate::fields::FieldsContainer; 4 | use crate::fields::mappers::{StructFieldConstructor}; 5 | 6 | pub trait StructConstructor: FieldsContainer + StructFieldConstructor { 7 | fn of_not_option(&self, struct_name: &str) -> TokenStream { 8 | let struct_ident = Ident::new(&struct_name, Span::call_site()); 9 | let fields_tokens = self.map_field_vec(&::get_not_option_field); 10 | quote! { 11 | #[derive(Default, Debug, Clone)] 12 | pub struct #struct_ident { 13 | #(#fields_tokens,)* 14 | } 15 | } 16 | } 17 | 18 | fn of_option(&self, struct_name: &str) -> TokenStream { 19 | let struct_ident = Ident::new(&struct_name, Span::call_site()); 20 | let fields_tokens = self.map_field_vec(&::get_option_field); 21 | quote! { 22 | #[derive(Default, Debug, Clone)] 23 | pub struct #struct_ident { 24 | #(#fields_tokens,)* 25 | } 26 | } 27 | } 28 | 29 | // field_name: Option> 30 | fn of_location(&self, struct_name: &str) -> TokenStream { 31 | let struct_ident = Ident::new(&struct_name, Span::call_site()); 32 | let fields_tokens = self.map_field_vec(&::get_location_field); 33 | quote! { 34 | #[derive(Default, Debug, Clone)] 35 | pub struct #struct_ident { 36 | #(#fields_tokens,)* 37 | } 38 | } 39 | } 40 | 41 | // field_name: bool 42 | fn of_bool(&self, struct_name: &str) -> TokenStream { 43 | let struct_ident = Ident::new(&struct_name, Span::call_site()); 44 | let fields_tokens = self.map_field_vec(&::get_bool_field); 45 | quote! { 46 | #[derive(Default, Debug, Clone)] 47 | pub struct #struct_ident { 48 | #(#fields_tokens,)* 49 | } 50 | } 51 | } 52 | 53 | fn of_bool_true(&self) -> TokenStream { 54 | let fields_tokens = self.map_field_vec(&::get_bool_true_field); 55 | quote! { 56 | Self { 57 | #(#fields_tokens,)* 58 | } 59 | } 60 | } 61 | 62 | fn of_optional_selected(&self) -> TokenStream { 63 | let fields_tokens = self.map_field_vec(&::get_optional_selected_field); 64 | quote! { 65 | Self { 66 | #(#fields_tokens,)* 67 | } 68 | } 69 | } 70 | } -------------------------------------------------------------------------------- /old/luna-orm-macro/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | use proc_macro::TokenStream; 3 | 4 | mod auto_entity; 5 | mod entity; 6 | mod field_utils; 7 | mod fields_parser; 8 | mod location; 9 | mod mutation; 10 | mod order_by; 11 | mod primary; 12 | mod selected_entity; 13 | mod selection; 14 | mod template_record; 15 | mod timer; 16 | mod type_check; 17 | mod type_extract; 18 | mod utils; 19 | mod into_arguments; 20 | mod gen_arguments; 21 | mod field_mapper; 22 | mod entity_trait; 23 | 24 | use auto_entity::impl_auto_entity_macro; 25 | use entity::impl_entity_macro; 26 | use location::impl_location_macro; 27 | use mutation::impl_mutation_macro; 28 | use order_by::impl_order_by_macro; 29 | use primary::impl_primary_macro; 30 | use selected_entity::impl_selected_entity_macro; 31 | use selection::impl_selection_macro; 32 | use template_record::impl_template_record_by_macro; 33 | use timer::impl_timed_func; 34 | 35 | #[proc_macro_derive(Primary, attributes(TableName))] 36 | pub fn expand_primary_macro(input: TokenStream) -> TokenStream { 37 | impl_primary_macro(input) 38 | } 39 | 40 | #[proc_macro_derive(Location, attributes(TableName, UniqueIndex))] 41 | pub fn expand_location_macro(input: TokenStream) -> TokenStream { 42 | impl_location_macro(input) 43 | } 44 | 45 | #[proc_macro_derive(Mutation)] 46 | pub fn expand_mutation_macro(input: TokenStream) -> TokenStream { 47 | impl_mutation_macro(input) 48 | } 49 | 50 | #[proc_macro_derive(SelectedEntity)] 51 | pub fn expand_selected_entity_macro(input: TokenStream) -> TokenStream { 52 | impl_selected_entity_macro(input) 53 | } 54 | 55 | #[proc_macro_derive(Selection)] 56 | pub fn expand_selection_macro(input: TokenStream) -> TokenStream { 57 | impl_selection_macro(input) 58 | } 59 | 60 | #[proc_macro_derive(Entity, attributes(TableName, PrimaryKey))] 61 | pub fn expand_entity_macro(input: TokenStream) -> TokenStream { 62 | impl_entity_macro(input) 63 | } 64 | 65 | #[proc_macro_derive(OrderBy)] 66 | pub fn expand_order_by_macro(input: TokenStream) -> TokenStream { 67 | impl_order_by_macro(input) 68 | } 69 | 70 | #[proc_macro_derive(TemplateRecord, attributes(TemplateSql, TemplateCountSql))] 71 | pub fn expand_template_record_by_macro(input: TokenStream) -> TokenStream { 72 | impl_template_record_by_macro(input) 73 | } 74 | 75 | #[proc_macro_derive( 76 | Schema, 77 | attributes(TableName, PrimaryKey, UniqueIndex, AutoIncrement, Generated) 78 | )] 79 | pub fn expand_auto_entity_macro(input: TokenStream) -> TokenStream { 80 | impl_auto_entity_macro(input) 81 | } 82 | 83 | #[proc_macro_attribute] 84 | pub fn timed( 85 | metadata: proc_macro::TokenStream, 86 | input: proc_macro::TokenStream, 87 | ) -> proc_macro::TokenStream { 88 | impl_timed_func(metadata, input) 89 | } 90 | -------------------------------------------------------------------------------- /next/taitan-orm-macro/src/util/copy_struct.rs: -------------------------------------------------------------------------------- 1 | use proc_macro2::Ident; 2 | use proc_macro2::TokenStream; 3 | use quote::{format_ident, quote}; 4 | use syn::{parse_macro_input, Data, DeriveInput, Fields, GenericParam, Generics, Lifetime}; 5 | use crate::util::extract_generic_lifetimes; 6 | 7 | pub fn copy_to_template_struct(struct_ident: &Ident, data: &Data, generics: &Generics, sql: &str, struct_suffix: &str) -> TokenStream { 8 | let mut lifetimes: Vec = extract_generic_lifetimes(generics); 9 | let struct_name = struct_ident; 10 | let template_struct_ident = format_ident!("{}{}", struct_name, struct_suffix); 11 | 12 | // 获取字段信息 13 | let fields = match data { 14 | Data::Struct(data) => match &data.fields { 15 | Fields::Named(fields) => &fields.named, 16 | _ => panic!("Only structs with named fields are supported"), 17 | }, 18 | _ => panic!("This macro only works on structs"), 19 | }; 20 | 21 | // 生成新的结构体名称 22 | 23 | 24 | // 生成字段定义 25 | let field_defs: Vec<_> = fields 26 | .iter() 27 | .map(|f| { 28 | let field_name = &f.ident; 29 | let field_type = &f.ty; 30 | quote! { #field_name: #field_type } 31 | }) 32 | .collect(); 33 | 34 | // 生成字段初始化 35 | let field_inits: Vec<_> = fields 36 | .iter() 37 | .map(|f| { 38 | let field_name = f.ident.as_ref().unwrap(); 39 | quote! { #field_name: orig.#field_name.clone() } 40 | }) 41 | .collect(); 42 | 43 | if lifetimes.is_empty() { 44 | quote! { 45 | #[derive(Clone, rinja::Template)] 46 | #[template(source = #sql, ext="txt")] 47 | pub struct #template_struct_ident { 48 | #(#field_defs),* 49 | } 50 | 51 | impl From<&#struct_name> for #template_struct_ident { 52 | fn from(orig: &#struct_name) -> Self { 53 | Self { 54 | #(#field_inits),* 55 | } 56 | } 57 | } 58 | } 59 | } else { 60 | quote! { 61 | #[derive(Clone, rinja::Template)] 62 | #[template(source = #sql, ext="txt")] 63 | pub struct #template_struct_ident <#(#lifetimes),*> { 64 | #(#field_defs),* 65 | } 66 | 67 | impl <#(#lifetimes),*> From<&#struct_name<#(#lifetimes),*>> for #template_struct_ident<#(#lifetimes),*> { 68 | fn from(orig: &#struct_name<#(#lifetimes),*>) -> #template_struct_ident<#(#lifetimes),*> { 69 | Self { 70 | #(#field_inits),* 71 | } 72 | } 73 | } 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /old/luna-orm-macro/src/field_mapper.rs: -------------------------------------------------------------------------------- 1 | use proc_macro2::TokenStream; 2 | use syn::Field; 3 | 4 | use crate::type_check::type_is_option; 5 | use quote::{quote, quote_spanned}; 6 | 7 | use syn::LitStr; 8 | 9 | pub struct FieldMapper {} 10 | 11 | impl FieldMapper { 12 | pub fn map_to_any_args_add(field: Field) -> TokenStream { 13 | let field_name = field.ident.unwrap(); 14 | let span = field_name.span(); 15 | let field_type = field.ty; 16 | if type_is_option(&field_type) { 17 | quote_spanned! { span => 18 | if let Some(#field_name) = &self.#field_name { 19 | luna_add_arg(&mut arguments, &#field_name); 20 | } 21 | } 22 | } else { 23 | quote_spanned! { span => 24 | luna_add_arg(&mut arguments, &self.#field_name); 25 | } 26 | } 27 | } 28 | 29 | pub fn map_to_args_add(field: Field) -> TokenStream { 30 | let field_name = field.ident.unwrap(); 31 | let span = field_name.span(); 32 | let field_type = field.ty; 33 | if type_is_option(&field_type) { 34 | quote_spanned! { span => 35 | if let Some(#field_name) = &self.#field_name { 36 | arguments.add(&self.#field_name); 37 | } 38 | } 39 | } else { 40 | quote_spanned! { span => 41 | arguments.add(&self.#field_name); 42 | } 43 | } 44 | } 45 | 46 | 47 | pub fn map_to_selected_field(field: Field) -> TokenStream { 48 | let field_name = field.ident.unwrap(); 49 | let span = field_name.span(); 50 | let field_name_lit = LitStr::new(&field_name.to_string(), span); 51 | let field_type = field.ty; 52 | if type_is_option(&field_type) { 53 | quote_spanned! { span => 54 | let #field_name: #field_type = row.try_get(#field_name_lit).ok(); 55 | } 56 | } else { 57 | quote_spanned! { span => 58 | let #field_name: Option<#field_type> = row.try_get(#field_name_lit).ok(); 59 | } 60 | } 61 | } 62 | 63 | pub fn map_to_where_field(field: Field) -> TokenStream { 64 | let field_name = field.ident.unwrap(); 65 | let span = field_name.span(); 66 | let field_name_lit = LitStr::new(&field_name.to_string(), span); 67 | quote_spanned! { span => 68 | if let Some(#field_name) = &self.#field_name { 69 | sql.push(wrap_char); 70 | sql.push_str(#field_name_lit); 71 | sql.push(wrap_char); 72 | sql.push_str(#field_name.cmp.get_sql()); 73 | sql.push(place_holder); 74 | } 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /next/taitan-orm/src/database/mysql/extractor.rs: -------------------------------------------------------------------------------- 1 | use sqlx::Database; 2 | use taitan_orm_trait::{Entity, Location, Mutation, TemplateRecord, Unique}; 3 | use taitan_orm_trait::pagination::Pagination; 4 | use crate::database::mysql::database::MySqlDatabase; 5 | use crate::extractor::Extractor; 6 | 7 | impl Extractor for MySqlDatabase { 8 | 9 | #[inline(always)] 10 | fn extract_pagination_arguments(page: &Pagination) -> crate::Result<::Arguments<'_>> { 11 | Ok(page.gen_page_arguments_mysql()?) 12 | } 13 | 14 | #[inline(always)] 15 | fn extract_unique_arguments(unique: &dyn Unique) -> crate::Result<::Arguments<'_>> { 16 | Ok(unique.gen_unique_arguments_mysql()?) 17 | } 18 | 19 | #[inline(always)] 20 | fn extract_location_arguments(location: &dyn Location) -> crate::Result<::Arguments<'_>> { 21 | Ok(location.gen_location_arguments_mysql()?) 22 | } 23 | 24 | #[inline(always)] 25 | fn extract_insert_arguments(entity: &dyn Entity) -> crate::Result<::Arguments<'_>> { 26 | Ok(entity.gen_insert_arguments_mysql()?) 27 | } 28 | 29 | #[inline(always)] 30 | fn extract_upsert_arguments(entity: &dyn Entity) -> crate::Result<::Arguments<'_>> { 31 | Ok(entity.gen_upsert_arguments_mysql()?) 32 | } 33 | 34 | #[inline(always)] 35 | fn extract_update_arguments<'a, M: Mutation>(mutation: &'a M, unique: &'a dyn Unique) -> crate::Result<::Arguments<'a>> { 36 | Ok(unique.gen_update_arguments_mysql(mutation)?) 37 | } 38 | 39 | #[inline(always)] 40 | fn extract_change_arguments<'a, M: Mutation>(mutation: &'a M, location: &'a M::Location) -> crate::Result<::Arguments<'a>> { 41 | Ok(mutation.gen_change_arguments_mysql(location)?) 42 | } 43 | 44 | #[inline(always)] 45 | fn extract_delete_arguments(unique: &dyn Unique) -> crate::Result<::Arguments<'_>> { 46 | Ok(unique.gen_unique_arguments_mysql()?) 47 | } 48 | 49 | #[inline(always)] 50 | fn extract_purify_arguments(location: &dyn Location) -> crate::Result<::Arguments<'_>> { 51 | Ok(location.gen_location_arguments_mysql()?) 52 | } 53 | 54 | #[inline(always)] 55 | fn extract_template_arguments(template: &dyn TemplateRecord) -> crate::Result<::Arguments<'_>> { 56 | Ok(template.gen_template_arguments_mysql()?) 57 | } 58 | 59 | #[inline(always)] 60 | fn extract_template_count_arguments(template: &dyn TemplateRecord) -> crate::Result<::Arguments<'_>> { 61 | Ok(template.gen_template_count_arguments_mysql()?) 62 | } 63 | } --------------------------------------------------------------------------------