An open API service indexing awesome lists of open source software.

https://github.com/tabular-id/tabular

Your Query Client, Forged with Rust: Fast, Safe, Efficient.
https://github.com/tabular-id/tabular

client database database-management rust sql

Last synced: 2 months ago
JSON representation

Your Query Client, Forged with Rust: Fast, Safe, Efficient.

Awesome Lists containing this project

README

          

# Tabular

Your fast, native, cross‑platform SQL & NoSQL database client (Desktop, with early groundwork for iPadOS) — built in Rust.

![Main Window](screenshots/halaman-utama.jpg)

## 1. About Tabular
Tabular is a lightweight, native database client built with the `eframe`/`egui` stack. It focuses on instant startup, responsive UI, safe concurrency, and a distraction‑free workflow for developers, data engineers, and DBAs. Unlike web/electron apps, Tabular ships as a single native binary with a small memory footprint while still offering rich features like autocomplete, multiple drivers, query history, export tools, and self‑update.

## 2. Key Features
- Unified UI for multiple relational & non‑relational databases
- Drivers: PostgreSQL, MySQL/MariaDB, SQLite, SQL Server (TDS), Redis, MongoDB
- Async runtime (Tokio) for non‑blocking execution
- Multiple query tabs & saved query library (`queries/` folder)
- Query history panel with search & filtering
- Result grid with copy cell / row / full result set
- Export to CSV & XLSX
- Rich value formatting (dates, decimals, JSON, BSON, HEX)
- Connection caching & quick reconnect
- Self‑update (GitHub Releases) with semantic version check
- Configurable data directory (env `TABULAR_DATA_DIR`)
- Native file dialogs (`rfd`)
- Cross‑platform theming via egui
- Sandboxing & notarization ready for macOS

### Query Editor (New, In Progress)
The legacy `egui::TextEdit` editor is being replaced with a custom widget backed by a rope buffer. Current capabilities:
- Multi‑caret editing
- Per‑line syntax highlighting cache (SQL focus first)
- Basic scroll‑to‑caret
- Undo/Redo
- Multi‑line/column selection

Planned next: full autocomplete integration, diff‑based edits, revision tracking, and removal of the legacy path after feature parity.

## 3. Supported Databases
| Category | Engines / Protocols |
|------------|----------------------|
| Relational | PostgreSQL, MySQL/MariaDB, SQLite, Microsoft SQL Server |
| Document | MongoDB (BSON & compression) |
| Key/Value | Redis (async connection manager) |

Notes:
- Microsoft SQL Server uses `tiberius` (TDS over TLS)
- Redis uses pooled async managers
- SQLite runs in‑process (file mode) — ensure write permissions

## 4. Installation

### Option A: Download Prebuilt Release (Recommended)
1. Visit: https://github.com/tabular-id/tabular/releases
2. Download the bundle for your platform:
- macOS: `.dmg` (notarized) or `.pkg` (if available)
- Linux: `.tar.gz` (extract, then place the binary in `$HOME/.local/bin` or `/usr/local/bin`)
- Windows: portable package is planned
3. (macOS) Drag `Tabular.app` into `/Applications`.
4. Run Tabular.

### Option B: Build From Source
General requirements:
- Rust (stable; https://rustup.rs)
- Cargo (bundled with rustup)
- Clang/LLVM (for bindgen / some native crates)
- libclang headers (Linux)
- (Linux) pkg-config, OpenSSL dev packages may be required depending on environment

#### Arch Linux
```bash
sudo pacman -Syu --needed base-devel clang llvm pkgconf
export LIBCLANG_PATH=/usr/lib
git clone https://github.com/tabular-id/tabular.git
cd tabular
cargo build --release
```

#### Ubuntu / Debian
```bash
sudo apt update
sudo apt install -y build-essential clang libclang-dev pkg-config
git clone https://github.com/tabular-id/tabular.git
cd tabular
cargo build --release
```

#### macOS
```bash
xcode-select --install # Command Line Tools
brew install llvm # (opsional) clang lebih baru
git clone https://github.com/tabular-id/tabular.git
cd tabular
cargo build --release
```
Jika memakai LLVM dari Homebrew:
```bash
export LIBCLANG_PATH="$(brew --prefix llvm)/lib"
```

#### Windows (MSVC) – planned
Install the MSVC toolchain, then build with `cargo build --release`.

#### Multi‑Arsitektur / Cross Compilation (Desktop + Eksperimental iOS)
```bash
cargo install cross
cross build --target aarch64-apple-darwin --release

# Eksperimental iPadOS (butuh wrapper Xcode/iOS)
rustup target add aarch64-apple-ios
cargo build --target aarch64-apple-ios --release
```

### Run
```bash
./target/release/tabular
```

### Optional Environment Variables
| Variable | Purpose | Example |
|------------------|-------------------------------------|------------------------------|
| TABULAR_DATA_DIR | Override data directory location | /data/tabular |
| RUST_LOG | Enable logging | RUST_LOG=info ./tabular |

## 5. macOS Notarized / Signed Builds
For distributing outside the Mac App Store:
```bash
export APPLE_ID="your-apple-id@example.com"
export APPLE_PASSWORD="app-specific-password"
export APPLE_TEAM_ID="TEAMID"
export APPLE_BUNDLE_ID="id.tabular.database"
export APPLE_IDENTITY="Developer ID Application: Your Name (TEAMID)"
export NOTARIZE=1
./build.sh macos --deps
```
Staple & verify:
```bash
xcrun stapler staple dist/macos/Tabular-.dmg
spctl -a -vv dist/macos/Tabular.app
codesign --verify --deep --strict --verbose=2 dist/macos/Tabular.app
```
See `macos/Tabular.entitlements` for sandbox/network/file access settings. For App Store distribution use a distribution identity and provisioning profile:
```bash
export APPLE_IDENTITY="Apple Distribution: Your Name (TEAMID)"
export PROVISIONING_PROFILE="/path/Tabular_AppStore.provisionprofile"
make pkg-macos-store
```

## 6. Data Directory (Configurable)
Default location:
- macOS / Linux: `~/.tabular`

Change it via Preferences (native folder picker) or force it with:
```bash
export TABULAR_DATA_DIR="/absolute/custom/path"
./tabular
```
Manual migration: copy the old folder to the new location before switching & restarting.

Contents of the data directory:
- `preferences.*` — UI & app settings
- `cache.*` — metadata & driver caches
- `queries/` — saved queries
- `history/` — executed query history

## 7. Development Guide
### Project Layout (selected)
```
src/
main.rs # Entry point
window_egui.rs # UI / egui integration
editor.rs # Logika editor query
editor_autocomplete.rs
sidebar_*.rs # Panel samping (database, history, queries)
driver_*.rs # Abstraksi driver database
export.rs # Ekspor CSV / XLSX
self_update.rs # Cek & aplikasi update
config.rs # Preferensi & direktori data
models/ # Struktur data & enum
query_ast/ # Lapisan AST kueri (eksperimental, default aktif)
```

### Quick Start (Dev)
```bash
git clone https://github.com/tabular-id/tabular.git
cd tabular
cargo run
```

### Common Tasks
| Action | Command |
|---------------|----------------------------------|
| Build debug | `cargo build` |
| Run | `cargo run` |
| Test | `cargo test` |
| Lint (clippy) | `cargo clippy -- -D warnings` |
| Format | `cargo fmt` |
| Release build | `cargo build --release` |

### Logging
```bash
RUST_LOG=info cargo run
```

### Adding a New Driver (short)
1) Create `driver_.rs` 2) Implement connection & execution 3) Add feature flag if optional 4) Register in `modules.rs`/factory 5) Update README.

## 8. Core Dependencies (Crates)
| Purpose | Crate |
|----------------|-------|
| UI & App Shell | eframe, egui_extras |
| Async Runtime | tokio, futures, futures-util, tokio-util |
| Relational DB | sqlx (postgres, mysql, sqlite) |
| SQL Server | tiberius |
| Redis | redis |
| MongoDB | mongodb, bson |
| Data Formats | serde, serde_json, chrono, rust_decimal, hex, csv, xlsxwriter |
| File Dialog | rfd |
| Update | reqwest, self_update, semver |
| Logging | log, env_logger, dotenv |
| Utilities | dirs, regex, colorful |

See `Cargo.toml` for exact versions (current package version: 0.5.18).

## 9. Contributing
Contributions are welcome (bug fixes, new drivers, UI, performance). Suggested workflow:
1. Fork & create a feature branch.
2. Run `cargo fmt && cargo clippy` before committing.
3. Ensure release build compiles: `cargo build --release`.
4. Open a PR with a concise description & screenshots (for UI changes).

## 10. Troubleshooting
| Issue | Hint |
|---------------------------------|----------------------------------------------------|
| Build fails: clang not found | Install clang / set `LIBCLANG_PATH` |
| TLS errors on connect | Verify certificates & network reachability |
| SQLite file locked | Close other processes; check file permissions |
| UI freeze on long queries | Use server pagination; streaming improvements WIP |

## 11. Roadmap (High level)
- Windows build & signing
- iPadOS adaptive layout
- Query formatter / beautifier
- Result pagination for large datasets
- Connection grouping & tags
- Scripting/extension layer
- Secure secrets storage (Keychain/KWallet/Credential Manager)

## 12. License
This project is dual‑licensed:

1) GNU Affero General Public License v3 (AGPL‑3.0) — see `LICENSE-AGPL`
2) Commercial License — contact PT. Vneu Teknologi Indonesia (see `LICENSE`)

In short: use AGPL for OSS/non‑commercial; obtain a commercial license for closed‑source/commercial integration.

## 13. Acknowledgements
Built with the Rust ecosystem. egui & sqlx projects are especially instrumental.

---
Made with Rust 🦀 for people who love fast, native tools.

## 14. Agnostic AST Architecture (Advanced)

## 📋 Overview

Tabular uses a **database‑agnostic AST (Abstract Syntax Tree)** to separate query logic from database‑specific implementations. Benefits:

- ✅ **Performa Optimal**: Plan caching, rewrite optimization
- ✅ **Kemudahan Extensibility**: Tambah database baru tanpa ubah core logic
- ✅ **Type Safety**: Compile-time checking dengan Rust
- ✅ **Maintainability**: Clear separation of concerns

## 🏗️ Architecture Layers

### Layer 1: Parser (Database‑agnostic)
```
Raw SQL → sqlparser → AST (generic) → Logical Plan
```
- Uses the `sqlparser` crate for universal SQL parsing
- Not aware of any specific database
- Output: `LogicalQueryPlan` (database‑agnostic IR)

**File**: `src/query_ast/parser.rs`

### Layer 2: Logical Plan (Agnostik DB)
```rust
pub enum LogicalQueryPlan {
Projection { exprs: Vec, input: Box },
Filter { predicate: Expr, input: Box },
Sort { items: Vec, input: Box },
Limit { limit: u64, offset: u64, input: Box },
Join { left, right, on, kind },
TableScan { table, alias },
// ... etc
}
```

**File**: `src/query_ast/logical.rs`

**Benefits**:
- All databases share the same structure
- Optimizations apply to all databases
- Easy to visualize and debug

### Layer 3: Rewrite/Optimizer (Database‑agnostic)
```
Logical Plan → Apply Rules → Optimized Logical Plan
```

**Rules** (apply to all databases):
- Filter pushdown
- Projection pruning
- CTE inlining
- Predicate merging
- Auto‑limit injection
- Pagination rewrite

**File**: `src/query_ast/rewrite.rs`

**Example**:
```rust
// Before rewrite:
Projection -> Filter -> Filter -> TableScan
// After rewrite:
Projection -> Filter(merged) -> TableScan
```

### Layer 4: Emitter (Database‑specific)
```
Optimized Plan → Dialect → SQL for Target DB
```

**Trait-based**:
```rust
pub trait SqlDialect {
fn quote_ident(&self, ident: &str) -> String;
fn emit_limit(&self, limit: u64, offset: u64) -> String;
fn supports_window_functions(&self) -> bool;
// ... etc
}
```

**Implementations**:
- `MySqlDialect`: Backticks, `LIMIT n OFFSET m`
- `PostgresDialect`: Double quotes, window functions
- `MssqlDialect`: Square brackets, `TOP n`, `OFFSET FETCH`
- `SqliteDialect`: Backticks, limited window support
- `MongoDialect`: Minimal SQL, mostly native operations
- `RedisDialect`: Very limited SQL

**Files**:
- `src/query_ast/emitter/mod.rs` (core emitter)
- `src/query_ast/emitter/dialect.rs` (dialect trait + implementations)

### Layer 5: Executor (Database‑specific)
```
Emitted SQL → Connection Pool → Execute → Results
```

**Trait-based**:
```rust
#[async_trait]
pub trait DatabaseExecutor {
fn database_type(&self) -> DatabaseType;
async fn execute_query(&self, sql: &str, ...) -> Result;
fn supports_feature(&self, feature: SqlFeature) -> bool;
}
```

**File**: `src/query_ast/executor.rs`

## 📊 Performance Optimizations

### 1. Multi-Level Caching

```rust
// Level 1: Structural fingerprint (quick pre-check)
let fp = structural_fingerprint(sql); // hash without parsing

// Level 2: Logical plan hash (after parsing)
let plan = parse(sql);
let plan_hash = hash_plan(&plan);

// Cache key includes: plan_hash + db_type + pagination + options
let cache_key = format!("{}::{:?}::{:?}", plan_hash, db_type, pagination);
```

**Cache Stats Available**:
```rust
let (hits, misses) = query_ast::cache_stats();
println!("Cache hit rate: {:.1}%", hits as f64 / (hits + misses) as f64 * 100.0);
```

### 2. Plan Reuse

Same logical plan works for different databases:
```
Parse once → Rewrite once → Emit N times (one per DB type)
```

### 3. Zero-Copy Where Possible

- Use `Arc` untuk sharing plans
- String interning untuk column/table names
- COW (Copy-on-Write) untuk rewrites

## 🔧 Implementation Status

### ✅ Completed

| Feature | Status | Notes |
|---------|--------|-------|
| Basic SELECT parsing | ✅ | Includes JOIN, GROUP BY, HAVING, LIMIT |
| Filter/WHERE | ✅ | AND/OR/NOT, comparison ops |
| Projection/SELECT list | ✅ | Columns, aliases, * |
| Sorting/ORDER BY | ✅ | Multiple columns, ASC/DESC |
| Pagination/LIMIT | ✅ | Rewritten per database |
| JOINs | ✅ | INNER, LEFT, RIGHT, FULL |
| GROUP BY | ✅ | Multiple expressions |
| HAVING | ✅ | Post-aggregation filters |
| DISTINCT | ✅ | Deduplication |
| CTEs/WITH | ✅ | Single-use CTE inlining |
| UNION/UNION ALL | ✅ | Set operations |
| Window Functions | ✅ | ROW_NUMBER, RANK, etc |
| Subqueries | ✅ | Scalar, correlated detection |
| Plan Caching | ✅ | Multi-level with fingerprinting |
| Rewrite Rules | ✅ | 9 rules implemented |
| MySQL Dialect | ✅ | Full support |
| PostgreSQL Dialect | ✅ | Full support |
| SQLite Dialect | ✅ | Full support |
| MS SQL Dialect | ✅ | TOP/OFFSET FETCH syntax |
| MongoDB Dialect | 🟡 | Limited SQL, prefer native |
| Redis Dialect | 🟡 | Very limited |

### 🚧 In Progress / TODO

| Feature | Priority | Effort |
|---------|----------|--------|
| Executor trait implementation | HIGH | Medium |
| Database-specific executors | HIGH | Medium |
| Multi-statement support | MEDIUM | High |
| DDL parsing (CREATE/ALTER/DROP) | MEDIUM | High |
| Advanced subquery optimizations | LOW | High |
| Correlated subquery rewrite | LOW | High |
| Cost-based optimization | LOW | Very High |

## 📈 Benchmarks (indicative)

### Query Compilation Time

```
Simple SELECT: < 1ms (cache hit: < 0.1ms)
With JOIN: < 5ms (cache hit: < 0.1ms)
Complex (3+ JOINs): < 20ms (cache hit: < 0.1ms)
```

### Cache Hit Rates

```
Repeated queries: 95%+ hit rate
Pagination queries: 90%+ hit rate
Ad-hoc queries: 40%+ hit rate (fingerprint matching)
```

### Memory Usage

```
Per cached plan: ~5KB (typical)
Cache size limit: 1000 plans (configurable)
Total overhead: ~5MB for 1000 plans
```

## 🎯 Best Practices

### Untuk Penulis Driver

1. **Use the AST pipeline** instead of raw SQL where possible
2. **Implement SqlDialect** for your database
3. **Implement DatabaseExecutor** for execution
4. **Test with real queries** from your database
5. **Measure performance** before/after AST integration

### Untuk Penulis Query

1. **Use standard SQL** for best cross-database compatibility
2. **Avoid database-specific features** in shared code
3. **Let the AST handle optimization** (don't manually optimize)
4. **Check cache stats** to verify query reuse

### Untuk Maintainer

1. **Keep layers separate** (don't mix concerns)
2. **Add tests for new rewrites** (prevent regressions)
3. **Document dialect differences** in code comments
4. **Profile regularly** to catch performance regressions

## 🐛 Debugging Tools

### 1. Debug Plan Visualization

```rust
let debug_str = query_ast::debug_plan(&sql, &db_type)?;
println!("{}", debug_str);
// Output:
// -- debug plan for PostgreSQL
// Projection 3
// Filter "id > 10"
// TableScan(users alias=None)
```

### 2. Rewrite Rule Tracking

```rust
let rules = query_ast::last_rewrite_rules();
println!("Applied rules: {:?}", rules);
// Output: ["auto_limit", "filter_pushdown", "projection_prune"]
```

### 3. Plan Metrics

```rust
let (nodes, depth, subqueries, correlated, windows) = query_ast::plan_metrics(&sql)?;
println!("Plan complexity: {} nodes, depth {}", nodes, depth);
```

### 4. Structural Fingerprint

```rust
let (hash, cache_key) = query_ast::plan_structural_hash(&sql, &db_type, pagination, auto_limit)?;
println!("Plan hash: {:x}", hash);
```

## 📚 Referensi

### Key Files

```
src/query_ast/
├── mod.rs # Public API & main compilation pipeline
├── ast.rs # Raw AST wrapper (thin layer over sqlparser)
├── logical.rs # Logical plan IR (database-agnostic)
├── parser.rs # SQL → Logical plan conversion
├── emitter/
│ ├── mod.rs # Plan → SQL emission
│ └── dialect.rs # Database-specific SQL generation
├── rewrite.rs # Optimization rules
├── executor.rs # Execution trait & registry
├── plan_cache.rs # Multi-level caching
└── errors.rs # Error types

src/driver_*.rs # Database-specific drivers (legacy + AST integration)
src/connection.rs # Connection pool management
src/cache_data.rs # Metadata caching (tables, columns, etc)
```

### External Dependencies

- **sqlparser**: SQL parsing (universal)
- **tokio**: Async runtime
- **sqlx**: Database drivers (MySQL, PostgreSQL, SQLite)
- **tiberius**: MS SQL driver
- **mongodb**: MongoDB native driver
- **redis**: Redis client

## 🔮 Future Enhancements

### Phase 2: Advanced Features

1. **Cost-Based Optimizer**: Choose optimal join order
2. **Materialized Views**: Cache intermediate results
3. **Parallel Execution**: Split queries across cores
4. **Query Federation**: JOIN across different databases

### Phase 3: Code Generation

1. **Compile to native code**: LLVM backend for hot queries
2. **SIMD optimizations**: Vectorize filters and aggregations
3. **GPU acceleration**: Offload heavy computations

### Phase 4: AI Integration

1. **Query suggestions**: Based on schema and data
2. **Auto-indexing**: Recommend indexes based on query patterns
3. **Query rewrite hints**: AI-powered optimization suggestions

## 🤝 Contributing

See `Adding a New Database to Tabular` for step-by-step guide to adding new database support.

### Code Review Checklist

- [ ] Logical plan changes don't break existing databases
- [ ] New rewrites have tests for correctness
- [ ] Dialect changes respect database feature sets
- [ ] Performance benchmarks show no regressions
- [ ] Documentation updated for new features

## 📞 Support

- **Issues**: GitHub issues for bugs
- **Discussions**: GitHub discussions for questions
- **Docs**: This file + inline code documentation
- **Examples**: See `tests/query_ast_tests.rs`

---

**Last Updated**: 2025-11-11
**Version**: 0.5.18
**Maintainer**: Tabular Team

# Adding a New Database to Tabular

This guide explains how to add support for a new database type using the Agnostic AST architecture.

## Overview

Tabular uses a layered architecture with clear separation of concerns:

```
Raw SQL → Parser → Logical Plan → Optimizer/Rewriter → Emitter → Executor
↓ ↓ ↓ ↓
DB-Agnostic DB-Agnostic DB-Specific DB-Specific
```

## Steps to Add a New Database

### 1. Define Database Type

Add your database to `src/models/enums.rs`:

```rust
#[derive(Clone, PartialEq, Serialize, Deserialize, Debug)]
pub enum DatabaseType {
MySQL,
PostgreSQL,
SQLite,
Redis,
MsSQL,
MongoDB,
YourNewDB, // <- Add here
}

pub enum DatabasePool {
MySQL(Arc),
PostgreSQL(Arc),
SQLite(Arc),
Redis(Arc),
MsSQL(Arc),
MongoDB(Arc),
YourNewDB(Arc), // <- Add here
}
```

### 2. Implement SQL Dialect

Create `src/query_ast/emitter/your_db_dialect.rs`:

```rust
use super::dialect::SqlDialect;
use crate::models::enums::DatabaseType;

pub struct YourDbDialect;

impl SqlDialect for YourDbDialect {
fn db_type(&self) -> DatabaseType {
DatabaseType::YourNewDB
}

fn quote_ident(&self, ident: &str) -> String {
// Your database's identifier quoting
format!("\"{}\"", ident.replace('"', "\"\""))
}

fn emit_limit(&self, limit: u64, offset: u64) -> String {
// Your database's LIMIT syntax
if offset > 0 {
format!(" LIMIT {} OFFSET {}", limit, offset)
} else {
format!(" LIMIT {}", limit)
}
}

fn supports_window_functions(&self) -> bool {
true // or false, depending on your DB
}

fn supports_cte(&self) -> bool {
true // or false
}

fn supports_full_join(&self) -> bool {
true // or false
}

// Override other methods as needed for your database
}
```

Update `src/query_ast/emitter/dialect.rs`:

```rust
pub fn get_dialect(db_type: &DatabaseType) -> Box {
match db_type {
DatabaseType::MySQL => Box::new(MySqlDialect),
DatabaseType::PostgreSQL => Box::new(PostgresDialect),
// ... other databases ...
DatabaseType::YourNewDB => Box::new(YourDbDialect), // <- Add here
}
}
```

### 3. Implement Database Executor

Create `src/query_ast/executors/your_db_executor.rs`:

```rust
use async_trait::async_trait;
use crate::query_ast::executor::{DatabaseExecutor, QueryResult};
use crate::query_ast::errors::QueryAstError;
use crate::models::enums::DatabaseType;

pub struct YourDbExecutor {
// Connection pool or client reference
}

impl YourDbExecutor {
pub fn new() -> Self {
Self {}
}
}

#[async_trait]
impl DatabaseExecutor for YourDbExecutor {
fn database_type(&self) -> DatabaseType {
DatabaseType::YourNewDB
}

async fn execute_query(
&self,
sql: &str,
database_name: Option<&str>,
connection_id: i64,
) -> Result {
// 1. Get connection from pool using connection_id
// 2. Switch database if database_name is provided
// 3. Execute SQL query
// 4. Convert results to (Vec, Vec>)
// 5. Return results

todo!("Implement query execution for your database")
}

fn validate_query(&self, sql: &str) -> Result<(), QueryAstError> {
// Optional: Add database-specific validation
Ok(())
}
}
```

Register in `src/query_ast/executor.rs`:

```rust
impl ExecutorRegistry {
pub fn with_defaults() -> Self {
let mut registry = Self::new();

// ... existing executors ...

#[cfg(feature = "your_db")]
registry.register(Box::new(super::executors::YourDbExecutor::new()));

registry
}
}
```

### 4. Create Driver Module

Create `src/driver_your_db.rs`:

```rust
use crate::models::enums::DatabaseType;
use crate::window_egui::Tabular;

/// Create connection pool for your database
pub async fn create_connection_pool(
host: &str,
port: u16,
username: &str,
password: &str,
database: Option<&str>,
) -> Result> {
// Implement connection creation
todo!()
}

/// Fetch tables from your database
pub async fn fetch_tables_from_connection(
tabular: &Tabular,
connection_id: i64,
database_name: Option,
) -> Result, Box> {
// Implement table listing
todo!()
}

/// Fetch columns from a table
pub async fn fetch_columns_from_table(
tabular: &Tabular,
connection_id: i64,
database_name: Option,
table_name: &str,
) -> Result, Box> {
// Implement column listing (name, type)
todo!()
}
```

### 5. Update Connection Module

In `src/connection.rs`, add your database to the connection creation logic:

```rust
pub async fn get_or_create_connection_pool(
tabular: &mut Tabular,
connection_id: i64,
) -> Result> {
// ... existing code ...

match connection.connection_type {
models::enums::DatabaseType::MySQL => { /* ... */ }
models::enums::DatabaseType::PostgreSQL => { /* ... */ }
// ... other databases ...
models::enums::DatabaseType::YourNewDB => {
let client = driver_your_db::create_connection_pool(
&connection.host,
connection.port,
&connection.username,
&connection.password,
connection.database.as_deref(),
).await?;

let pool = models::enums::DatabasePool::YourNewDB(Arc::new(client));
tabular.connection_pools.insert(connection_id, pool.clone());
Ok(pool)
}
}
}
```

### 6. Add UI Support

In `src/sidebar_database.rs`, add folder icon and logic:

```rust
pub fn create_database_folders_from_connections(connections: &[models::structs::Connection]) -> Vec {
// ... existing code ...

models::enums::DatabaseType::YourNewDB => {
let mut node = models::structs::TreeNode {
name: format!("Your DB Connections ({})", count),
node_type: models::enums::NodeType::YourNewDBFolder,
// ... rest of initialization ...
};
node
}
}
```

Add to `src/models/enums.rs`:

```rust
pub enum NodeType {
// ... existing types ...
YourNewDBFolder, // <- Add here
}
```

## Testing Your Integration

### Unit Tests

```rust
#[cfg(test)]
mod tests {
use super::*;

#[tokio::test]
async fn test_your_db_query() {
let executor = YourDbExecutor::new();
let result = executor.execute_query(
"SELECT * FROM users LIMIT 10",
None,
1,
).await;

assert!(result.is_ok());
}

#[test]
fn test_your_db_dialect() {
let dialect = YourDbDialect;
assert_eq!(dialect.quote_ident("table"), "\"table\"");
}
}
```

### Integration Testing

1. Create a test connection in the UI
2. Test basic operations: connect, list tables, query data
3. Test AST features: filtering, sorting, pagination
4. Test error handling: invalid queries, connection failures

## Performance Considerations

### Connection Pooling

- Use connection pools for better performance
- Configure appropriate pool size (5-20 connections typically)
- Implement connection health checks

### Query Optimization

- The rewrite layer applies database-agnostic optimizations
- Add database-specific optimizations in your executor
- Consider query result caching for expensive queries

### Plan Caching

The AST layer automatically caches compiled plans. Ensure your SQL emission is deterministic for cache hits.

## Feature Flags

Add a feature flag for optional compilation:

In `Cargo.toml`:

```toml
[features]
default = ["mysql", "postgres", "sqlite"]
mysql = ["sqlx/mysql"]
postgres = ["sqlx/postgres"]
sqlite = ["sqlx/sqlite"]
your_db = ["your_db_driver"] # <- Add here
```

## Common Pitfalls

1. **Quote Identifiers**: Always use `dialect.quote_ident()`, never hardcode quotes
2. **NULL Handling**: Different databases handle NULL differently
3. **Type Mapping**: Map SQL types to your database's native types
4. **Transaction Support**: Implement proper transaction handling
5. **Error Messages**: Provide clear, actionable error messages

## Example: Adding CockroachDB

Here's a minimal example of adding CockroachDB (which is PostgreSQL-compatible):

```rust
// 1. Add to DatabaseType enum
pub enum DatabaseType {
// ... existing ...
CockroachDB,
}

// 2. Reuse PostgreSQL dialect (it's compatible!)
pub fn get_dialect(db_type: &DatabaseType) -> Box {
match db_type {
// ... existing ...
DatabaseType::CockroachDB => Box::new(PostgresDialect), // Reuse!
}
}

// 3. Create executor (can extend PostgreSQL executor)
pub struct CockroachExecutor {
pg_executor: PostgresExecutor, // Composition over inheritance!
}

#[async_trait]
impl DatabaseExecutor for CockroachExecutor {
fn database_type(&self) -> DatabaseType {
DatabaseType::CockroachDB
}

async fn execute_query(&self, sql: &str, db: Option<&str>, conn_id: i64)
-> Result
{
// Delegate to PostgreSQL executor since CockroachDB is wire-compatible
self.pg_executor.execute_query(sql, db, conn_id).await
}
}
```

## Performance Metrics

After adding your database, measure:

- Query compilation time (should be < 1ms for simple queries)
- Cache hit rate (should be > 80% for repeated queries)
- Execution overhead (AST layer adds < 5% overhead)

## Need Help?

- Check existing drivers (`driver_mysql.rs`, `driver_postgres.rs`)
- Review the executor trait in `query_ast/executor.rs`
- Look at dialect implementations in `query_ast/emitter/dialect.rs`
- See rewrite rules in `query_ast/rewrite.rs` for optimization ideas

## Benefits of This Architecture

✅ **Separation of Concerns**: Logic layer independent of database specifics
✅ **Reusability**: Share optimizations across all databases
✅ **Testability**: Mock executors for unit testing
✅ **Extensibility**: Add new databases without touching core logic
✅ **Performance**: Aggressive caching at every layer
✅ **Type Safety**: Rust's type system catches errors at compile time

# 🛠️ Build System Documentation

This document explains how to build Tabular for different platforms using the provided build scripts.

## 📋 Prerequisites

### Required Tools
- **Rust** (latest stable version)
- **Make** (for Unix-like systems)
- **Git** (for version control)

### Platform-Specific Requirements

#### macOS
- **Xcode Command Line Tools**: `xcode-select --install`
- **lipo**: Usually included with Xcode (for universal binaries)
- **hdiutil**: For creating DMG files (included with macOS)

#### Linux
- **GCC/Clang**: For native compilation
- **Cross**: For cross-compilation (`cargo install cross`)
- **Docker**: Required by cross for cross-compilation

#### Windows
- **MSVC**: Visual Studio Build Tools or Visual Studio
- **PowerShell**: For packaging scripts

## 🚀 Quick Start

### Using the Build Script (Recommended)

The easiest way to build Tabular is using the provided build script:

```bash
# Build for current platform only
./build.sh

# Build for specific platform
./build.sh macos
./build.sh linux
./build.sh windows

# Build for all platforms
./build.sh all

# Install dependencies and build
./build.sh all --deps

# Clean and build
./build.sh macos --clean
```

### Using Make Directly

If you prefer using Make directly:

```bash
# Show available targets
make help

# Install build dependencies
make install-deps

# Build for specific platforms
make bundle-macos
make bundle-linux
make bundle-windows

# Build everything
make release

# Clean build artifacts
make clean
```

## 📦 Build Targets

### macOS Universal Binary
Creates a universal binary that runs on both Intel and Apple Silicon Macs:

```bash
make bundle-macos
```

**Outputs:**
- `dist/macos/Tabular.app` - macOS application bundle
- `dist/macos/Tabular.dmg` - Disk image for distribution

### Linux Binaries
Creates binaries for x86_64 and aarch64 Linux systems:

```bash
make bundle-linux
```

**Outputs:**
- `dist/linux/tabular-x86_64-unknown-linux-gnu.tar.gz`
- `dist/linux/tabular-aarch64-unknown-linux-gnu.tar.gz`
- AppDir structure for potential AppImage creation

### Windows Binaries
Creates executables for x86_64 and aarch64 Windows systems:

```bash
make bundle-windows
```

**Outputs:**
- `dist/windows/tabular-x86_64-pc-windows-msvc.zip`
- `dist/windows/tabular-aarch64-pc-windows-msvc.zip`

## 🔧 Development Commands

### Quick Development Tasks

```bash
# Development build (debug mode)
make dev

# Run the application
make run

# Run tests
make test

# Check code formatting and linting
make check

# Format code
make fmt

# Show project information
make info
```

## 🏗️ Build Architecture

### Target Platforms

| Platform | Architecture | Target Triple |
|----------|-------------|---------------|
| macOS | Intel (x86_64) | `x86_64-apple-darwin` |
| macOS | Apple Silicon (ARM64) | `aarch64-apple-darwin` |
| Linux | x86_64 | `x86_64-unknown-linux-gnu` |
| Linux | ARM64 | `aarch64-unknown-linux-gnu` |
| Windows | x86_64 | `x86_64-pc-windows-msvc` |
| Windows | ARM64 | `aarch64-pc-windows-msvc` |

### Build Process

1. **Dependency Installation**: Install Rust targets and required tools
2. **Cross-Compilation**: Build for each target platform
3. **Universal Binary Creation**: Combine macOS binaries using `lipo`
4. **Packaging**: Create platform-specific packages (DMG, tar.gz, zip)
5. **Distribution**: Output ready-to-distribute packages

## 📁 Directory Structure

After building, the following structure is created:

```
tabular/
├── target/ # Rust build artifacts
│ ├── x86_64-apple-darwin/
│ ├── aarch64-apple-darwin/
│ ├── universal-apple-darwin/
│ └── ...
├── dist/ # Distribution packages
│ ├── macos/
│ │ ├── Tabular.app
│ │ └── Tabular.dmg
│ ├── linux/
│ │ ├── tabular-x86_64.tar.gz
│ │ └── tabular-aarch64.tar.gz
│ └── windows/
│ ├── tabular-x86_64.zip
│ └── tabular-aarch64.zip
└── ...
```

## 🤖 Continuous Integration

The project includes GitHub Actions workflows for automated building:

### Workflow Triggers
- **Push to main/develop**: Builds all platforms
- **Pull requests**: Builds all platforms for testing
- **Tag push (v*)**: Builds and creates a GitHub release

### Artifacts
- All builds are saved as GitHub Actions artifacts
- Tagged releases automatically create GitHub releases with binaries

## 🐛 Troubleshooting

### Common Issues

#### Missing Rust Targets
```bash
# Solution: Install missing targets
make install-deps
```

#### Cross-compilation Failures
```bash
# Solution: Install cross and Docker
cargo install cross
# Make sure Docker is running
```

#### macOS Code Signing Issues
```bash
# For development builds, you can skip code signing
# For distribution, you'll need an Apple Developer Certificate
```

#### Windows Build Failures
```bash
# Make sure you have MSVC build tools installed
# Alternative: Use the GNU toolchain (x86_64-pc-windows-gnu)
```

### Getting Help

If you encounter issues:

1. Check the build logs for specific error messages
2. Ensure all prerequisites are installed
3. Try cleaning and rebuilding: `make clean && make release`
4. Check the GitHub Issues for known problems

## 📝 Notes

- **Universal macOS Binary**: The macOS build creates a universal binary that works on both Intel and Apple Silicon Macs
- **Cross-Compilation**: Linux and Windows builds use cross-compilation for ARM64 targets
- **Size Optimization**: Release builds include optimizations for smaller binary size
- **Dependencies**: The build system automatically handles Rust target installation

## 🎯 Example Build Session

Here's a complete example of building for all platforms:

```bash
# Clone the repository
git clone https://github.com/your-repo/tabular.git
cd tabular

# Install dependencies and build everything
./build.sh all --deps

# Check the results
ls -la dist/
```

This will create distribution-ready packages for macOS, Linux, and Windows.

Join us at Telegram

![Telegram Group](screenshots/telegram.png)