# akita
**Repository Path**: mrpann/akita
## Basic Information
- **Project Name**: akita
- **Description**: 更好的一个数据库操作框架
- **Primary Language**: Rust
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 0
- **Created**: 2022-06-20
- **Last Updated**: 2026-03-06
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Akita
A lightweight, fast and easy-to-use ORM framework for Rust
## 🎯 Features
- **🚀 High Performance**: Pure Rust implementation, zero runtime overhead
- **🎯 Easy to Use**: Intuitive API, quick to learn
- **🔧 Flexible Query**: Powerful query builder with type safety
- **📦 Multi-Database**: Native support for MySQL, PostgreSQL, SQLite, and any MySQL-compatible databases (TiDB, MariaDB, etc.)
- **🔌 Dual Runtime**: Both synchronous and asynchronous operation modes
- **🛡️ Type Safe**: Full Rust type system support with compile-time checking
- **🔄 Transaction**: Complete ACID transaction management with savepoint support
- **⚡ Connection Pool**: Built-in high-performance connection pooling
- **🎨 Annotation Driven**: Simplify entity definition with derive macros
- **🔌 Interceptors**: Extensible interceptor system for AOP (Aspect-Oriented Programming)
- **📊 Pagination**: Built-in smart pagination with total count
- **🔍 Complex Query**: Support for joins, subqueries, and complex SQL operations
- **🛠️ Raw SQL**: Direct SQL execution when needed
## 📦 Installation
Add this to your `Cargo.toml`:
### For MySQL (Synchronous)
```toml
[dependencies]
akita = { version = "0.6", features = ["mysql-sync"] }
```
### For MySQL (Asynchronous)
```toml
[dependencies]
akita = { version = "0.6", features = ["mysql-async"] }
```
### For PostgreSQL:
```toml
[dependencies]
akita = { version = "0.6", features = ["postgres-sync"] }
```
### For Oracle:
```toml
[dependencies]
akita = { version = "0.6", features = ["oracle-sync"] }
```
### SqlServer:
```toml
[dependencies]
akita = { version = "0.6", features = ["mssql-sync"] }
```
### For SQLite:
```toml
[dependencies]
akita = { version = "0.6", features = ["sqlite-sync"] }
```
### For TiDB and MySQL-compatible Databases:
TiDB, MariaDB, and other MySQL-compatible databases can use the MySQL features:
```toml
[dependencies]
akita = { version = "0.6", features = ["mysql-sync"] } # or "mysql-async"
chrono = "0.4"
```
## 🚀 Quick Start
### 1. Define Your Entity
```rust
use akita::*;
use chrono::{NaiveDate, NaiveDateTime};
use serde_json::Value;
#[derive(Entity, Clone, Default, Debug)]
#[table(name = "users")]
pub struct User {
#[id(name = "id")]
pub id: i64,
#[field(name = "user_name")]
pub username: String,
pub email: String,
pub age: Option,
#[field(name = "is_active")]
pub active: bool,
pub level: u8,
pub metadata: Option,
pub birthday: Option,
pub created_at: Option,
#[field(exist = "false")]
pub full_name: String,
}
```
### 2. Initialize Akita
#### Synchronous Mode
```rust
use akita::prelude::*;
use std::time::Duration;
fn main() -> Result<()> {
// Configuration for MySQL
let cfg = AkitaConfig::new()
.url("mysql://root:password@localhost:3306/mydb")
.max_size(10) // Connection pool size
.connection_timeout(Duration::from_secs(5));
// Create Akita instance
let akita = Akita::new(cfg)?;
// For TiDB (uses MySQL protocol)
let tidb_cfg = AkitaConfig::new()
.url("mysql://root:@tidb-host:4000/mydb")
.max_size(20);
Ok(())
}
```
#### Asynchronous Mode
```rust
use akita::*;
use std::time::Duration;
#[tokio::main]
async fn main() -> Result<()> {
// Async configuration
let cfg = AkitaConfig::new()
.url("mysql://root:password@localhost:3306/mydb")
.max_size(10)
.connection_timeout(Duration::from_secs(5));
// Create async Akita instance
let akita = Akita::new(cfg).await?;
Ok(())
}
```
### 3. Basic Operations
#### Synchronous Operations
```rust
fn main() {
// Create
let user = User {
username: "john_doe".to_string(),
email: "john@example.com".to_string(),
active: true,
level: 1,
..Default::default()
};
let user_id: Option = akita.save(&user)?;
// Read
let user: Option = akita.select_by_id(user_id.unwrap())?;
// Update
let mut user = user.unwrap();
user.level = 2;
akita.update_by_id(&user)?;
// Delete
akita.remove_by_id::(user_id.unwrap())?;
}
```
#### Asynchronous Operations
```rust
fn main() {
// Create
let user = User {
username: "jane_doe".to_string(),
email: "jane@example.com".to_string(),
active: true,
level: 1,
..Default::default()
};
let user_id: Option = akita.save(&user).await?;
// Read
let user: Option = akita.select_by_id(user_id.unwrap()).await?;
// Update
let mut user = user.unwrap();
user.level = 2;
akita.update_by_id(&user).await?;
// Delete
akita.remove_by_id::(user_id.unwrap()).await?;
}
```
## ⬆️Database Compatibility Matrix
| Database | Sync Feature | Async Feature | Protocol | Sync Implementation | Async Implementation | Status | Notes |
|----------|--------------|---------------|----------|---------------------|----------------------|--------|-------|
| MySQL | `mysql-sync` | `mysql-async` | MySQL | `mysql` crate | `mysql_async` crate | ✅ Production Ready | Native Rust implementations |
| PostgreSQL | `postgres-sync` | `postgres-async` | PostgreSQL | `tokio-postgres` (blocking) | `tokio-postgres` (async) | ✅ Production Ready | Both use tokio-postgres under the hood |
| SQLite | `sqlite-sync` | `sqlite-async` | SQLite | `rusqlite` crate | `sqlx` with async runtime | ✅ Production Ready | Different implementation strategies |
| Oracle | `oracle-sync` | `oracle-async` | Oracle | `oracle` crate (blocking) | `oracle` crate + async runtime | ✅ Production Ready | Oracle driver with async wrapper |
| SQL Server | `sqlserver-sync` | `sqlserver-async` | TDS | `tiberius` (blocking) | `tiberius` (async) | ✅ Production Ready | Tiberius driver support |
| TiDB | `mysql-sync` | `mysql-async` | MySQL | Same as MySQL | Same as MySQL | ✅ Production Ready | 100% MySQL compatible |
| MariaDB | `mysql-sync` | `mysql-async` | MySQL | Same as MySQL | Same as MySQL | ✅ Production Ready | 100% MySQL compatible |
| OceanBase | `mysql-sync` | `mysql-async` | MySQL | Same as MySQL | Same as MySQL | ✅ Production Ready | MySQL compatible mode |
## Implementation Details Summary
### PostgreSQL Implementation
- **Sync**: Uses `tokio-postgres` with blocking wrapper
- **Async**: Direct `tokio-postgres` async client
- **Both share same underlying library**
### Oracle Implementation
- **Sync**: Native `oracle` crate (synchronous driver)
- **Async**: `oracle` crate wrapped with async runtime
- **Same driver, different execution model**
### SQLite Implementation
- **Sync**: `rusqlite` crate (synchronous SQLite)
- **Async**: `sqlx` with async SQLite support
- **Different libraries, same protocol**
### SQL Server Implementation
- **Sync**: `tiberius` with blocking API
- **Async**: `tiberius` native async API
- **Same library, different APIs**
## Feature Comparison
| Feature | MySQL/TiDB | PostgreSQL | SQLite | Oracle | SQL Server |
|---------|-----------|------------|--------|--------|------------|
| ACID Transactions | ✅ | ✅ | ✅ | ✅ | ✅ |
| Connection Pool | ✅ | ✅ | ✅ | ✅ | ✅ |
| Native Async | ✅ | ✅ | ⚠️ (via sqlx) | ⚠️ (wrapped) | ✅ |
| Sync via Async Runtime | ❌ | ✅ (blocking) | ❌ | ❌ | ✅ (blocking) |
| JSON Support | ✅ (JSON) | ✅ (JSONB) | ✅ (JSON1) | ✅ | ⚠️ (limited) |
| Full-text Search | ✅ | ✅ | ✅ (FTS5) | ✅ | ✅ |
| Spatial Data | ✅ | ✅ | ✅ (R*Tree) | ✅ | ✅ |
| Stored Procedures | ✅ | ✅ | ❌ | ✅ | ✅ |
| Replication | ✅ | ✅ | ❌ | ✅ | ✅ |
| Distributed | TiDB ✅ | ❌ | ❌ | ❌ | ❌ |
| Protocol | MySQL | PostgreSQL | SQLite | Oracle | TDS |
## Key Implementation Notes
1. **PostgreSQL**: Both sync and async use `tokio-postgres`, sync is just a blocking wrapper
2. **Oracle**: Sync is native driver, async is wrapper around same driver
3. **SQLite**: Different libraries for sync (`rusqlite`) and async (`sqlx`)
4. **SQL Server**: `tiberius` provides both sync (blocking) and async APIs
5. **MySQL**: Separate sync (`mysql`) and async (`mysql_async`) crates
6. **TiDB/MariaDB/OceanBase**: Use MySQL drivers with full compatibility
## 📚 Detailed Usage
### Query Builder
Akita provides a powerful, type-safe query builder that works across all supported databases:
```rust
fn main() {
use akita::*;
// Database-agnostic query builder
let wrapper = Wrapper::new()
// Select specific columns
.select(vec!["id", "username", "email"])
// Universal conditions (works on all databases)
.eq("status", 1)
.ne("deleted", true)
.gt("age", 18)
.ge("score", 60)
.lt("age", 65)
.le("level", 10)
// String operations
.like("username", "%john%")
.not_like("email", "%test%")
// List operations
.r#in("role", vec!["admin", "user"])
.not_in("status", vec![0, 9])
// Null checks
.is_null("deleted_at")
.is_not_null("created_at")
// Between
.between("age", 18, 65)
.not_between("score", 0, 60)
// Logical operations
.and(|w| {
w.eq("status", 1).or_direct().eq("status", 2)
})
.or(|w| {
w.like("username", "%admin%").like("email", "%admin%")
})
// Ordering
.order_by_asc(vec!["created_at"])
.order_by_desc(vec!["id", "level"])
// Grouping
.group_by(vec!["department", "level"])
// Having clause (database-specific optimizations)
.having("COUNT(*)", SqlOperator::Gt, 1)
// Pagination (optimized for each database)
.limit(10)
.offset(20);
}
```
### Complex Queries with Database Optimizations
```rust
fn main() {
// Join queries with database-specific optimizations
let users: Vec = akita.list(
Wrapper::new()
.eq("u.status", 1)
.inner_join("departments d", "u.department_id = d.id")
.select(vec!["u.*", "d.name as department_name"])
)?;
// Subqueries (automatically optimized for target database)
let active_users: Vec = akita.list(
Wrapper::new()
.r#in("id", |w| {
w.select(vec!["user_id"])
.from("user_logs")
.eq("action", "login")
.gt("created_at", "2023-01-01")
})
)?;
// Database-specific optimizations
let query = Wrapper::new()
.eq("status", 1)
.order_by_desc(vec!["created_at"]);
// For MySQL/TiDB: Uses LIMIT optimization
// For PostgreSQL: Uses LIMIT OFFSET
// For SQLite: Uses LIMIT OFFSET
let result = akita.list::(query.limit(100))?;
}
```
### Database-Specific Features
#### MySQL/TiDB Specific Features
```rust
fn main() {
// MySQL JSON functions
let users: Vec = akita.exec_raw(
"SELECT * FROM users WHERE JSON_EXTRACT(metadata, '$.premium') = true",
()
)?;
// MySQL full-text search
let users: Vec = akita.list(
Wrapper::new()
.raw("MATCH(username, email) AGAINST(:search IN BOOLEAN MODE)")
.set_param("search", "john*")
)?;
}
```
#### PostgreSQL Specific Features
```rust
fn main() {
// PostgreSQL JSONB operations
let users: Vec = akita.exec_raw(
"SELECT * FROM users WHERE metadata @> '{\"premium\": true}'",
()
)?;
// PostgreSQL array operations
let users: Vec = akita.exec_raw(
"SELECT * FROM users WHERE 'admin' = ANY(roles)",
()
)?;
}
```
#### SQLite Specific Features
```rust
fn main() {
// SQLite JSON1 extension
let users: Vec = akita.exec_raw(
"SELECT * FROM users WHERE json_extract(metadata, '$.premium') = 1",
()
)?;
// SQLite full-text search (FTS5)
let users: Vec = akita.exec_raw(
"SELECT * FROM users_fts WHERE users_fts MATCH 'john'",
()
)?;
}
```
### Raw SQL Queries with Database Portability
```rust
fn main() {
// Parameterized queries
let users: Vec = akita.exec_raw(
"SELECT * FROM users WHERE status = ? AND level > ?",
(1, 0)
)?;
// Named parameters
let user: Option = akita.exec_first(
"SELECT * FROM users WHERE username = :name AND email = :email",
params! {
"name" => "john",
"email" => "john@example.com"
}
)?;
// Executing DDL
akita.exec_drop(
"CREATE TABLE IF NOT EXISTS users (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
email VARCHAR(100) NOT NULL
)",
()
)?;
}
```
### Transactions with Database-Specific Features
```rust
fn main() {
// Simple transaction
akita.start_transaction().and_then(|mut tx| {
tx.save(&user1)?;
tx.save(&user2)?;
tx.update(&user3, wrapper)?;
tx.commit()
})?;
// Nested transactions (savepoints)
akita.start_transaction().and_then(|mut tx| {
tx.save(&user1)?;
match tx.save(&user2) {
Ok(_) => {
tx.commit()
}
Err(e) => {
// Continue with other operations or rollback
tx.rollback()
}
}
})?;
}
```
### Interceptors with Database Awareness
Akita supports powerful interceptor system that can adapt to different databases:
```rust
use akita::*;
use std::sync::Arc;
use std::time::Duration;
fn main() {
// Create interceptor-enabled Akita
let akita = Akita::new(config).unwrap()
.with_interceptor_builder(
InterceptorBuilder::new()
.register(tenant_interceptor)
.register(performance_interceptor)
.register(logging_interceptor)
.enable("trackable_tenant").unwrap()
.enable("trackable_performance").unwrap()
.enable("trackable_logging").unwrap()
)?;
}
// Custom interceptor
#[derive(Debug)]
struct AuditInterceptor {
user_id: String,
}
impl AkitaInterceptor for AuditInterceptor {
fn name(&self) -> &'static str {
"audit"
}
fn interceptor_type(&self) -> InterceptorType {
InterceptorType::Audit
}
fn order(&self) -> i32 {
50
}
fn before_execute(&self, ctx: &mut ExecuteContext) -> Result<()> {
// Add audit information to query
ctx.set_metadata("audit_user", self.user_id.clone());
ctx.set_metadata("audit_time", chrono::Utc::now().to_rfc3339());
Ok(())
}
}
```
### Entity Methods with Database Portability
Entities can have their own methods:
```rust
impl User {
// Custom finder methods
pub fn find_active(akita: &Akita) -> Result> {
akita.list(Wrapper::new().eq("status", 1))
}
pub fn find_by_email(akita: &Akita, email: &str) -> Result