graft-orm
v2.0.1
Published
A powerful, database-agnostic migration CLI tool with multi-database support and type-safe code generation
Readme
Graft ORM
A powerful, database-agnostic migration CLI tool built in Go with multi-database support, visual database editor (Graft Studio), and type-safe code generation for JavaScript/TypeScript.
✨ Features
- 🎨 Graft Studio: Visual database editor with React-based schema visualization
- 🗃️ Multi-Database Support: PostgreSQL, MySQL, SQLite
- 🔄 Migration Management: Create, apply, and track migrations
- 🔒 Safe Migration System: Transaction-based execution with automatic rollback
- 📤 Smart Export System: Multiple formats (JSON, CSV, SQLite)
- 🔧 Type-Safe Code Generation: Generate fully typed JavaScript/TypeScript code
- ⚡ Blazing Fast: 2.5x faster than Drizzle, 10x faster than Prisma
- 💻 Raw SQL Execution: Execute SQL files or inline queries
- 🎯 Prisma-like Commands: Familiar CLI interface
- 🎨 Enum Support: Full PostgreSQL ENUM support
📊 Performance
| Operation | Graft | Drizzle | Prisma | |-----------|-------|---------|--------| | Insert 1000 Users | 158ms | 224ms | 230ms | | Complex Query x500 | 4071ms | 12500ms | 56322ms | | Mixed Workload x1000 | 186ms | 1174ms | 10863ms | | TOTAL | 6947ms | 17149ms | 71551ms |
🚀 Installation
npm install -g graft-ormFor Bun Users
Bun blocks postinstall scripts by default. After installation, run:
bun pm trust graft-ormOr add to your package.json:
{
"trustedDependencies": ["graft-orm"]
}🏁 Quick Start
1. Initialize Project
graft init --postgresql # or --mysql, --sqliteThis creates:
your-project/
├── graft.config.json
├── .env
└── db/
├── schema/
│ └── schema.sql
└── queries/
└── users.sql2. Configure Database
# .env file
DATABASE_URL=postgresql://user:password@localhost:5432/mydb3. Define Schema
db/schema/schema.sql
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
);4. Write Queries
db/queries/users.sql
-- name: GetUser :one
SELECT id, name, email, created_at, updated_at FROM users
WHERE id = $1 LIMIT 1;
-- name: CreateUser :one
INSERT INTO users (name, email)
VALUES ($1, $2)
RETURNING id, name, email, created_at, updated_at;
-- name: ListUsers :many
SELECT id, name, email, created_at, updated_at FROM users
ORDER BY created_at DESC;
-- name: UpdateUser :one
UPDATE users
SET name = $2, email = $3, updated_at = NOW()
WHERE id = $1
RETURNING id, name, email, created_at, updated_at;
-- name: DeleteUser :exec
DELETE FROM users WHERE id = $1;5. Create Migration
graft migrate "create users table"6. Apply Migration
graft apply7. Generate Type-Safe Code
graft genGenerated Types (graft_gen/index.d.ts)
// Code generated by Graft. DO NOT EDIT.
export interface Users {
id: number | null;
name: string;
email: string;
created_at: Date;
updated_at: Date;
}
export interface GetUserResult {
id: number | null;
name: string;
email: string;
created_at: Date;
updated_at: Date;
}
export class Queries {
constructor(db: any);
getUser(id: number): Promise<GetUserResult | null>;
createUser(name: string, email: string): Promise<Users | null>;
listUsers(): Promise<Users[]>;
updateUser(id: number, name: string, email: string): Promise<Users | null>;
deleteUser(id: number): Promise<void>;
}
export function New(db: any): Queries;8. Use in Your Code
index.ts
import { Pool } from 'pg';
import { New } from './graft_gen/database';
const DATABASE_URL = process.env.DATABASE_URL || 'postgresql://postgres:postgres@localhost:5432/mydb';
async function main() {
const pool = new Pool({
connectionString: DATABASE_URL,
});
const db = New(pool);
// Create user - fully type-safe!
const newUser = await db.createUser('Alice', '[email protected]');
console.log('New user:', newUser);
// Get user by ID
const user = await db.getUser(newUser.id);
console.log('Found user:', user);
// List all users
const users = await db.listUsers();
console.log('All users:', users);
// Update user
const updated = await db.updateUser(newUser.id, 'Alice Smith', '[email protected]');
console.log('Updated user:', updated);
await pool.end();
}
main().catch((err) => {
console.error('Error:', err);
process.exit(1);
});📋 All Commands
Visual Database Editor
# Launch Graft Studio (web-based database editor)
graft studio
# Launch on custom port
graft studio --port 3000
# Connect to any database directly
graft studio --db "postgresql://user:pass@localhost:5432/mydb"
# Launch without opening browser
graft studio --browser=falseStudio Features:
- 📊 Data Browser: View and edit table data with inline editing
- 💻 SQL Editor: Execute queries with CodeMirror syntax highlighting
- 🎨 Schema Visualization: Interactive database diagram with React + ReactFlow
- 📤 CSV Export: Export query results to CSV
- 🔍 Search & Filter: Search across all tables
- ⚡ Real-time Updates: See changes immediately
Project Setup
# Initialize new project
graft init --postgresql
graft init --mysql
graft init --sqliteMigrations
# Create new migration
graft migrate "migration name"
# Create empty migration
graft migrate "custom migration" --empty
# Apply all pending migrations
graft apply
# Apply with force (skip confirmations)
graft apply --force
# Check migration status
graft statusCode Generation
# Generate type-safe code
graft genSchema Management
# Pull schema from existing database
graft pull
# Pull with backup
graft pull --backup
# Pull to custom file
graft pull --output custom-schema.sqlDatabase Export
# Export as JSON (default)
graft export
graft export --json
# Export as CSV
graft export --csv
# Export as SQLite
graft export --sqliteDatabase Operations
# Reset database (destructive!)
graft reset
# Reset with force
graft reset --force
# Execute raw SQL file
graft raw script.sql
graft raw migrations/seed.sql
# Execute inline SQL query
graft raw -q "SELECT * FROM users WHERE active = true"
graft raw "SELECT COUNT(*) FROM orders"
# Force file mode
graft raw --file queries/complex.sqlHelp & Info
# Launch Graft Studio
graft studio
# Show version
graft --version
graft -v
# Show help
graft --help
graft <command> --help⚙️ Configuration
graft.config.json
{
"version": "2",
"schema_path": "db/schema/schema.sql",
"queries": "db/queries/",
"migrations_path": "db/migrations",
"export_path": "db/export",
"database": {
"provider": "postgresql",
"url_env": "DATABASE_URL"
},
"gen": {
"js": {
"enabled": true,
"out": "graft_gen"
}
}
}🎨 PostgreSQL ENUM Support
Schema with ENUMs
CREATE TYPE user_role AS ENUM ('admin', 'user', 'guest');
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
role user_role NOT NULL DEFAULT 'user'
);Query with ENUM
-- name: GetUsersByRole :many
SELECT id, name, role FROM users
WHERE role = $1;Generated TypeScript
export type UserRole = 'admin' | 'user' | 'guest';
export interface Users {
id: number | null;
name: string;
role: UserRole;
}🔒 Safe Migrations
Every migration runs in a transaction with automatic rollback on failure:
$ graft apply
📦 Applying 2 migration(s)...
[1/2] 20251103_create_users
✅ Applied
[2/2] 20251103_add_email_index
✅ Applied
✅ All migrations applied successfullyIf a migration fails:
❌ Failed at migration: 20251103_bad_migration
Error: syntax error at or near "INVALID"
Transaction rolled back. Fix the error and run 'graft apply' again.🛡️ Conflict Detection
Graft automatically detects schema conflicts:
⚠️ Migration conflicts detected:
- Table 'users' already exists
- Column 'email' conflicts with existing column
Reset database to resolve conflicts? (y/n): y
Create export before applying? (y/n): y
📦 Creating export...
✅ Export created successfully
🔄 Resetting database and applying all migrations...📤 Export Formats
JSON Export
graft export --json{
"timestamp": "2025-11-03 16:30:00",
"version": "1.0",
"tables": {
"users": [
{"id": 1, "name": "Alice", "email": "[email protected]"}
]
}
}CSV Export
graft export --csvCreates directory with individual CSV files per table.
SQLite Export
graft export --sqliteCreates portable .db file.
🎨 Graft Studio
Launch the visual database editor:
graft studioOpen http://localhost:5555 (or your custom port)
Features:
1. Data Browser (/)
- View all tables in sidebar
- Click any table to view/edit data
- Double-click cells for inline editing
- Add/delete rows with intuitive modals
- Pagination (50 rows per page)
- Search across tables
- Foreign key hints
2. SQL Editor (/sql)
- Execute custom SQL queries
- CodeMirror editor with syntax highlighting
- Press Ctrl+Enter to run queries
- Export results to CSV
- Resizable split-pane interface
- Query history
3. Schema Visualization (/schema)
- Interactive database diagram
- React + ReactFlow rendering
- Automatic layout with Dagre algorithm
- Drag and drop tables
- Zoom and pan controls
- Foreign key relationship arrows
- MiniMap for navigation
Tech Stack:
- Backend: Go Fiber v2.52.9
- Frontend: React 18.2.0, ReactFlow 12.8.4, CodeMirror 5.65.2
- All assets embedded in single binary
💻 Raw SQL Execution
Execute SQL files or inline queries:
# Execute SQL file
graft raw script.sql
# Execute inline query
graft raw -q "SELECT * FROM users LIMIT 10"
# Auto-detection (file if exists, otherwise query)
graft raw "SELECT COUNT(*) FROM orders"Features:
- ✅ Beautiful table output for SELECT queries
- ✅ Multi-statement execution
- ✅ Transaction support
- ✅ Auto-detection of file vs query
- ✅ Formatted error messages
Example Output:
$ graft raw -q "SELECT id, name, email FROM users LIMIT 3"
🎯 Database: postgresql
⚡ Executing query...
✅ Query executed successfully
📊 3 row(s) returned
┌────┬────────────┬─────────────────────┐
│ id │ name │ email │
├────┼────────────┼─────────────────────┤
│ 1 │ Alice │ [email protected] │
│ 2 │ Bob │ [email protected] │
│ 3 │ Charlie │ [email protected] │
└────┴────────────┴─────────────────────┘🔧 Programmatic API
const graft = require('graft-orm');
// Execute commands
graft.exec('status');
graft.exec('migrate "add users"');
graft.exec('apply');
graft.exec('studio'); // Launch Studio
// Get binary path
const binaryPath = graft.getBinaryPath();📚 Examples
Check out complete examples:
🐛 Troubleshooting
Bun Postinstall Blocked
bun pm trust graft-ormBinary Not Found
npm install -g graft-orm --forceDatabase Connection Failed
Check your DATABASE_URL in .env file.
Studio Not Loading
Make sure port 5555 is not in use, or specify a different port:
graft studio --port 3000📖 Documentation
🌟 Key Highlights
- Visual Database Editor: Manage your database visually with Graft Studio
- Raw SQL Support: Execute SQL files or queries directly from CLI
- Type-Safe: Full TypeScript support with generated types
- Fast: 2.5x-10x faster than popular ORMs
- Multi-DB: PostgreSQL, MySQL, and SQLite support
- Zero Config: Works out of the box with sensible defaults
📄 License
MIT License - see LICENSE
