{"id":23959710,"url":"https://github.com/thegenius/taitan-orm","last_synced_at":"2025-10-03T14:28:53.283Z","repository":{"id":270534869,"uuid":"910680758","full_name":"thegenius/taitan-orm","owner":"thegenius","description":"The State of Art ORM for Rust","archived":false,"fork":false,"pushed_at":"2025-04-02T01:16:30.000Z","size":3430,"stargazers_count":73,"open_issues_count":3,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-02T02:25:08.955Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/thegenius.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-01-01T03:39:24.000Z","updated_at":"2025-04-02T01:16:34.000Z","dependencies_parsed_at":"2025-01-01T04:25:34.949Z","dependency_job_id":"e13f2b0b-908b-430e-b8f3-afe4bf1e72b5","html_url":"https://github.com/thegenius/taitan-orm","commit_stats":null,"previous_names":["thegenius/taitan-orm"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thegenius%2Ftaitan-orm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thegenius%2Ftaitan-orm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thegenius%2Ftaitan-orm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thegenius%2Ftaitan-orm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thegenius","download_url":"https://codeload.github.com/thegenius/taitan-orm/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246743133,"owners_count":20826476,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-01-06T18:51:38.688Z","updated_at":"2025-10-03T14:28:53.274Z","avatar_url":"https://github.com/thegenius.png","language":"Rust","funding_links":[],"categories":["Libraries"],"sub_categories":["Database"],"readme":"\u003ch1 align=\"center\"\u003e Great Art Stretches Taste. \u003c/h1\u003e  \n\n![Building](https://github.com/thegenius/taitan-orm/actions/workflows/rust-ci.yml/badge.svg)\n[![Version](https://img.shields.io/badge/crates-0.1.12-green)](https://crates.io/crates/taitan-orm)\n[![Version](https://img.shields.io/badge/Lines-32k-yellow)](https://crates.io/crates/taitan-orm)\n# I'm back\n\n# Features\n\u003cdiv style=\"margin-left: 20px; font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace;\"\u003e\n  \u003cdiv\u003e\u003cstrong\u003eSQL-First\u003c/strong\u003e\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;: SQL with template syntax and extremely performance.\u003c/div\u003e\n  \u003cdiv\u003e\u003cstrong\u003eErgonomics\u003c/strong\u003e\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;: Ergonomics API design and error handling.\u003c/div\u003e\n  \u003cdiv\u003e\u003cstrong\u003eCompile-Time\u003c/strong\u003e\u0026nbsp;\u0026nbsp;: Maximizing compile-time processing.\u003c/div\u003e\n  \u003cdiv\u003e\u003cstrong\u003eTransactional\u003c/strong\u003e\u0026nbsp: Beautiful transaction, as if not a transaction.\u003c/div\u003e\n  \u003cdiv\u003e\u003cstrong\u003eAsynchronous\u003c/strong\u003e\u0026nbsp;\u0026nbsp;: Fully async from day one.\u003c/div\u003e\n\u003c/div\u003e\n\n\n# Why Another ORM\n🔗[Why Another ORM](https://github.com/thegenius/taitan-orm/blob/main/docs/why_another_orm_en.md)\n\n# Deep Wiki\n🔗[wiki](https://deepwiki.com/thegenius/taitan-orm)\n\n# Quick Taste\n```\ngit clone https://github.com/thegenius/taitan-orm.git\ncd taitan-orm/examples/crud\ncargo run\n```\n# API Doc\n🔗[API Doc](https://github.com/thegenius/taitan-orm/blob/main/docs/API.md)\n\n\n# Examples\nAt present, the documentation for this newly-born project is limited. You can refer to the examples project for more details.\n\n| example     | description                 |\n|-------------|-----------------------------|\n| crud        | basic crud example          |\n| template    | template with paged example |\n| transaction | basic transaction example   |\n| search      | multi search features       |\n| axum_crud   | integrate with axum         |\n\n# Quick Start\n```shell\ncargo add taitan-orm\n```\n\n```rust\nuse std::borrow::Cow;\nuse sqlx::types::time::PrimitiveDateTime;\nuse time::macros::datetime;\n\nuse taitan_orm::database::sqlite::prelude::*;\nuse taitan_orm::prelude::*;\n\n#[derive(Debug, Schema, Clone)]\n#[table(user)]\n#[unique(uk_name=(name))]\n#[index(idx_hello=(age, birthday))]\n#[primary(id)]\npub struct User {\n id: i32,\n name: String,\n age: Option\u003ci32\u003e,\n birthday: Option\u003cPrimitiveDateTime\u003e,\n}\n\n#[tokio::main]\nasync fn main() -\u003e taitan_orm::result::Result\u003c()\u003e {\n    tracing_subscriber::fmt()\n            .with_max_level(tracing::Level::TRACE)\n            .init();\n \n    // setup database\n    // refer to docs/setup.md for database setup\n    let db = ...;\n    db.execute_plain(\"DROP TABLE IF EXISTS `user`\").await?;\n    db.execute_plain(\n     \"CREATE TABLE IF NOT EXISTS `user`(`id` INT PRIMARY KEY, `age` INT, `name` VARCHAR(64), `birthday` DATETIME)\",\n    )\n            .await?;\n    db.execute_plain(\"CREATE UNIQUE INDEX `uk_name` ON `user` (`name`);\")\n            .await?;\n    db.execute_plain(\"CREATE INDEX `idx_age_birthday` ON `user` (`age`, `birthday`);\")\n            .await?;\n   \n    // 1. insert entity\n    let entity = User {\n     id: 1,\n     name: \"Allen\".to_string(),\n     age: Option::Some(23),\n     birthday: Option::Some(datetime!(2019-01-01 0:00)),\n    };\n    let result = db.insert(\u0026entity).await?;\n   \n    // 2. update\n    let mutation = UserMutation {\n     name: None,\n     age: Some(Some(24)),\n     birthday: None,\n    };\n    let primary = UserPrimary { id: 1 };\n    let result = db.update(\u0026mutation, \u0026primary).await?;\n    assert_eq!(result, true);\n   \n    // 3. select\n    let selection = UserSelected::default();\n    let entity: Option\u003cUserSelected\u003e = db.select(\u0026selection, \u0026primary).await?;\n    assert!(entity.is_some());\n   \n    // 4. select by unique\n    let uk = UserUniqueUkName {\n     name: \"Allen\".to_string(),\n    };\n    let unique_entity: Option\u003cUserSelected\u003e = db.select(\u0026selection, \u0026uk).await?;\n    assert!(unique_entity.is_some());\n   \n    // 5. search by index\n    let index = UserIndexIdxHello::AgeBirthday {\n     age: Expr::from(\"=\", 24)?,\n     birthday: Expr::from(\"=\", datetime!(2019-01-01 0:00))?,\n    };\n    let pagination = Pagination::new(10, 0);\n    let order_by = UserOrderBy::build(vec![\"id\"]).unwrap();\n    let index_entities: Vec\u003cUserSelected\u003e = db\n            .search::\u003cUserSelected\u003e(\u0026selection, \u0026index, \u0026order_by, \u0026pagination)\n            .await?;\n    assert_eq!(index_entities.len(), 1);\n   \n    // 6. search\n    let selection = UserSelected::default();\n    let location = UserLocation::Id(Expr {\n     val: Some(1),\n     cmp: Cmp::Eq,\n    });\n    let entities: Vec\u003cUserSelected\u003e = db\n            .search(\u0026selection, \u0026location, \u0026order_by, \u0026pagination)\n            .await?;\n    assert_eq!(entities.len(), 1);\n   \n    // 7. delete\n    let result = db.delete(\u0026primary).await?;\n    assert_eq!(result, true);\n   \n    let entity: Option\u003cUserSelected\u003e = db.select(\u0026selection, \u0026primary).await?;\n    assert!(entity.is_none());\n   \n    println!(\"crud success!\");\n    Ok(())\n}\n```\n* you can run the crud example in examples/crud directory.\n\n\n# Documents\n1. 🔗[Setup](https://github.com/thegenius/taitan-orm/blob/main/docs/usages/setup.md)\n2. 🔗[Schema Definition](https://github.com/thegenius/taitan-orm/blob/main/docs/usages/schema_definition.md)\n3. 🔗[Write API](https://github.com/thegenius/taitan-orm/blob/main/docs/write_en.md)\n\n# Usage\n## Compile Time Generation  \nWhen derive(Schema), TaiTan-ORM will generate helper struct for you.\n\n```rust\n#[derive(Debug, Schema, Clone)]\n#[table(user)]\n#[unique(uk_name=(name))]\n#[index(idx_hello=(age, birthday))]\n#[primary(id)]\npub struct User {\n    id: i32,\n    name: String,\n    age: Option\u003ci32\u003e,\n    birthday: Option\u003cPrimitiveDateTime\u003e,\n}\n\n// struct for primary key \npub struct UserPrimary {\n    id: i32\n}\n\n// struct for update\n// None: skip this field\n// Some(None): null\n// Some(Some(23)): actual set value\n// before 0.1.9, there is a special enum Optional to support null expression\n// 0.1.10 remove Optional, use Option\u003cOption\u003cT\u003e\u003e instead.\npub struct UserMutation {\n    name: Option\u003cOption\u003cString\u003e\u003e,\n    age: Option\u003cOption\u003ci32\u003e\u003e,\n    birthday: Option\u003cOption\u003cPrimitiveDateTime\u003e\u003e\n}\n\n// struct for unique key\npub struct UserNameUnique { \n    name: String \n}\n\n// struct for index_hello, designed for index prefix matching\n// age is allowed,\n// age, birthday is allowed\n// birthday is not allowed\npub enum UserIndexIdxHello {\n    Age { \n        age: LocationExpr\u003ci32\u003e \n    },\n    AgeBirthday{ \n        age: LocationExpr\u003ci32\u003e, \n        birthday: LocationExpr\u003cPrimitiveDateTime\u003e \n    }\n}\n\n// struct to generate where condition \npub enum UserLocation {\n    Id(LocationExpr\u003ci32\u003e),\n    Name(LocationExpr\u003cString\u003e),\n    Age(LocationExpr\u003ci32\u003e),\n    Birthday(LocationExpr\u003cPrimitiveDateTime\u003e)\n}\n\n// struct to select field and recv result from database \npub struct UserSelected {\n    id: Option\u003cOption\u003ci32\u003e\u003e,\n    name: Option\u003cOption\u003cString\u003e\u003e,\n    age: Option\u003cOption\u003ci32\u003e\u003e,\n    birthday: Option\u003cOption\u003cPrimitiveDateTime\u003e\u003e\n}\n```\n\n\n## Template   \nTaiTan-ORM: The Most Powerful ORM Template Engine You'll Ever Meet\n\n| syntax                                   | description                |\n|------------------------------------------|----------------------------|\n| \u003cspan style=\"color: red;\"\u003e:{}\u003c/span\u003e     | placeholder binding syntax |\n| \u003cspan style=\"color: white;\"\u003e{{ }}\u003c/span\u003e | Askama variable syntax     |\n| \u003cspan style=\"color: green;\"\u003e{% %}\u003c/span\u003e | Askame template syntax     |\n\n```rust\n#[derive(Template, Debug)]\n#[template(\n source = \"UPDATE `user` SET name = :{name} WHERE `id` = :{id}\",\n ext = \"txt\"\n)]\npub struct UserUpdateTemplate {\n id: i32,\n name: String,\n}\n\n#[derive(Template, Debug)]\n#[template(\n source = \"select `id`, `name`, `age` FROM `user` where `id` \u003e= :{id}\",\n ext = \"txt\"\n)]\npub struct UserSelectTemplate {\n id: i32,\n}\n\n#[derive(Template, Debug)]\n#[template(\n source = \"select `id`, `name`, `age` FROM `user` where {% if age.is_some() %} age \u003e= :{age} AND {% endif %} `name` = :{name}\",\n ext = \"txt\"\n)]\npub struct UserCustomTemplate {\n name: String,\n age: Option\u003ci32\u003e,\n}\n\n```\n* you can run the template example in examples/template directory.\n\n## Transaction\nSeamless transaction handling\n```rust\nasync fn trx_insert_user(\n    db: \u0026mut SqliteDatabase,\n    user1: \u0026User,\n    user2: \u0026User,\n) -\u003e taitan_orm::result::Result\u003c()\u003e {\n    let mut trx = db.transaction().await?; // create a transaction, trx\n    trx.insert(user1).await?;              // same api as database\n    trx.insert(user2).await?;              // rollback if there is any error\n    trx.commit().await?;                   // commit it\n    Ok(())                                 // when trx drop, if not commit, rollback \n}\n```\n\n\n# Concepts\n![](https://github.com/thegenius/taitan-orm/blob/main/docs/concept.png)\n\n\n\n\n \n# Supported Database\n MySql  \n Postgres   \n Sqlite  \nPlease refer to 🔗[Setup](https://github.com/thegenius/taitan-orm/blob/main/docs/usages/setup.md) for details\n\n# Performance\nBench Environment:\n```\nCPU: Apple M4\nMEM: 16G\nSSD: 256G\nOS : Mac Sequoia 15.1.1 \nDB : Sqlite Memory Mode\n```\n\n| ORM        | Insert        | select        |\n|------------|---------------|---------------|\n| sqlx       | 18.676 us/ops | -             |\n| TaiTan-ORM | 17.831 us/ops | 15.942 us/ops |\n| Rbatis     | 19.360 us/ops | 18.248 us/ops |\n| Sea-ORM    | 28.116 us/ops | 25.818 us/ops |\n\nThanks to the maximum usage of compile time processing, TaiTan-ORM even faster than sqlx binding style!!\n\n**You can run benchmarks on your own machine in directory of `./benchmarks` with `cargo bench`**\n\n# Release Notes\n## 0.1.12\ninclude the askama template, simplify the template definition\nnow you can write template without add askama::Template\n```\n#[derive(Template, Debug)]\n#[template(\n source = \"UPDATE `user` SET name = :{name} WHERE `id` = :{id}\",\n ext = \"txt\"\n)]\npub struct UserUpdateTemplate {\n id: i32,\n name: String,\n}\n```\n\n## 0.1.11\ncompile time tracing dependency\n## 0.1.10\n[1] Database support is more accurate: if you only need mysql, there will be no sqlite/postgres code generation  \n[2] Template engine has the full power of Askama Engine  \n[3] API has been polished  \n[4] Location now can be combined with Logic Operator  \n\n\n\n# ROADMAP\n- **0.1 API** 🔧  \n**⚠️API may change, so just have a taste!**  \nWhat is being polished?\n- 1. write api: to support postgres insert returning syntax and batch insert/batch upsert\n- 2. search api: support index and more\n- 3. error\n\n- **0.2 Correctness**: specification and code coverage and fuzz  📎  \n🙏Help is wanted, maybe a long-running mysql instance and a postgres instance  \nnow there is a rough coverage report: 🪧[report](https://github.com/thegenius/taitan-orm/blob/main/docs/coverage.md)\n\n- **0.3 Documentation**: doc the usage and implementation  📎  \n🖊️Starting from version 0.3, I will focus my efforts on documentation.\n\n- **0.4 Performance**: benchmark and optimize  📎   \n🚀The ultimate speed originates from maximizing compile-time processing. But we need to exhibit it.\n\n- **1.0 Stable**: stabilize the api, macro and error  📎\n\n\n\n# LICENSE\nApache License","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthegenius%2Ftaitan-orm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthegenius%2Ftaitan-orm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthegenius%2Ftaitan-orm/lists"}