TORM is a lightweight Go ORM inspired by Prisma, providing schema-driven code generation, type-safe query builders, and automated migrations. It leverages a Prisma-style schema file (schema.prisma) as a single source of truth for database models and relationships. TORM generates Go structs, a Client for database operations, and SQL migration files automatically.
Current Version: v1.0.0
- Features
- Prerequisites
- Installation
- Project Structure
- Getting Started
- Example
- Commands Reference
- Configuration
- Contributing
- License
-
Schema-driven
Define your models and relationships in aschema.prismafile. TORM parses the schema and generates Go code accordingly. -
Code Generation
Generates Go structs for each model, aClientto connect to the database, and per-model service methods (CRUD, filtering, relations, aggregates, etc.). -
Type-Safe Query Builder
Query methods accept Go maps or typed values to construct SQL queries safely. -
Automated Migrations
migrate deploy: Apply pending migrations to the database.migrate dev: Generate new migration files from schema diffs, apply them, and update models.migrate reset: Rollback all migrations and reapply from scratch.migrate status: Show current migration status.
-
Many-to-Many Relations Support
Automatically creates connector tables for m2m relations and generates appropriate Go fields and service methods. -
Enum Support
Maps Prismaenumdefinitions to Gotypeandconstdeclarations. -
UUID & Auto-Increment
Supports@db.Uuid()for Postgres UUID defaults and@default(autoincrement())for integer primary keys. -
Zero-value Handling
Automatically treatsNULLvalues fortime.Time, pointers, and optional fields, returning Go zero values instead of panics.
- Go 1.23 or higher
- PostgreSQL (or compatible) 12 or higher
- A valid
schema.prismafile
-
Clone the repository:
go install github.com/TechXTT/TORM/cmd/torm@latest
TORM/
├── cmd/ # CLI entrypoint
│ └── torm/
│ └── main.go # `torm` command: migrate & codegen
├── example/ # Example application
│ ├── migrations/ # Pre-generated migration SQL files
│ ├── prisma/ # Prisma schema for the example
│ │ └── schema.prisma
│ ├── models/ # Generated Go models & client
│ ├── .env # Environment variables (e.g., DATABASE_URL)
│ └── main.go # Example usage of generated client
├── pkg/
│ ├── config/ # DSN extraction logic
│ │ └── dsn.go
│ ├── torm/ # Public API (user‐facing types & functions)
│ │ └── torm.go # High‐level orchestration (migrate & codegen)
│ ├── runtime/ # Core runtime: connector, session, migrations
│ │ ├── connector.go
│ │ ├── session.go
│ │ └── migrate.go
│ └── cli/ # Cobra CLI definitions
│ ├── root.go
│ └── migrate.go
├── pkg/internal/
│ ├── typeconv/ # Type‐conversion utilities
│ │ └── types.go
│ ├── generator/ # Schema parser & code generator
│ │ ├── parser.go
│ │ └── generator.go
│ └── migrate/ # Migration stub logic
│ └── stubs.go
├── go.mod
├── go.sum
├── README.md
└── .gitignore
TORM expects a Prisma-style schema file at prisma/schema.prisma (default path). Example:
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator torm {
provider = "torm"
}
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
posts Post[]
}
model Post {
id Int @id @default(autoincrement())
title String
content String?
author User? @relation(fields: [authorId], references: [id])
authorId Int?
tags Tag[] @relation("PostTags", references: [id])
}
model Tag {
id Int @id @default(autoincrement())
name String @unique
posts Post[] @relation("PostTags", references: [id])
}
enum ProjectType {
personal
team
enterprise
}- Many-to-Many
In the example above,PostandTaghave a many-to-many relation. TORM will generate apost_tagsjoin table (or customized join table name).
Run the migration and code generation commands to create Go models and a client for your database schema.
torm migrate dev This will:
- Parse
schema.prisma(default path or specified with--schema) - Generate Go structs (
models/*.go) - Generate a
client.gowith aClientstruct and per-model services - Run
go mod tidyin the output directory
TORM automatically generates SQL migration files by comparing your current schema.prisma with the latest applied schema.
-
Initialize Migrations Directory
On first run, TORM will createmigrations/0001_<Model>.up.sqland0001_<Model>.down.sqlfor each model. -
Develop Workflow
torm migrate dev \ --schema prisma/schema.prisma \ --dir migrations
- Compares the current Prisma schema to the last migration.
- If differences exist, generates new
NNNN_Model.up.sqlandNNNN_Model.down.sqlstubs. - Applies the new migration.
- Regenerates models and client.
-
Deploy Workflow
torm migrate deploy \ --schema prisma/schema.prisma \ --dir migrations
- Applies all pending migrations in order.
-
Reset All Migrations
torm migrate reset \ --schema prisma/schema.prisma \ --dir migrations
- Rolls back all migrations (in reverse order)
- Reapplies from the first migration
- Regenerates models and client
-
Migration Status
torm migrate status \ --schema prisma/schema.prisma \ --dir migrations
In your Go application:
package main
import (
"context"
"fmt"
"github.com/TechXTT/TORM/internal/model" // adjust import path
)
func main() {
// Instantiate the generated client
client := model.NewClient()
// Example: Create a new User
ctx := context.Background()
newUser := &model.User{
Email: "alice@example.com",
Name: "Alice",
}
err := client.UserService().Create(ctx, newUser)
if err != nil {
panic(err)
}
fmt.Printf("Created user with ID: %d\n", newUser.ID)
// Example: Fetch posts with related tags (many-to-many)
posts, err := client.PostService().FindMany(ctx, map[string]interface{}{"authorId": newUser.ID}, nil, 0, 10)
if err != nil {
panic(err)
}
for _, post := range posts {
fmt.Printf("Post: %s, Tags: %+v\n", post.Title, post.Tags)
}
}- Per-Model Service Methods
FindUnique(ctx, where map[string]interface{}) (*Model, error)FindFirst(ctx, where, orderBy []string, skip, take int) ([]*Model, error)FindMany(ctx, where, orderBy []string, skip, take int) ([]*Model, error)Create(ctx, data *Model) errorUpdate(ctx, where, data *Model) errorUpsert(ctx, where, createData, updateData *Model) errorDelete(ctx, where map[string]interface{}) errorCount(ctx, where map[string]interface{}) (int64, error)CreateMany(ctx, data []*Model) (int64, error)UpdateMany(ctx, where map[string]interface{}, data map[string]interface{}) (int64, error)DeleteMany(ctx, where map[string]interface{}) (int64, error)Aggregate(ctx, where map[string]interface{}, agg map[string][]string) (map[string]interface{}, error)GroupBy(ctx, by []string, where map[string]interface{}, agg map[string][]string) ([]map[string]interface{}, error)
Assume you have defined Project and Creator models in your Prisma schema:
model Project {
id Int @id @default(autoincrement())
name String
description String?
creators Creator[] @relation("CreatorProjects")
}
model Creator {
id Int @id @default(autoincrement())
name String
projects Project[] @relation("CreatorProjects")
}-
Generate code and migrations:
torm migrate dev -
Use in application:
client := model.NewClient() ctx := context.Background() // Create a creator creator := &model.Creator{Name: "Bob"} client.CreatorService().Create(ctx, creator) // Create a project and link to creator project := &model.Project{Name: "TORM Demo", Description: "Demonstration of TORM"} project.Creators = []*model.Creator{creator} client.ProjectService().Create(ctx, project) // Fetch project with creators (many-to-many) proj, _ := client.ProjectService().FindUnique(ctx, map[string]interface{}{"id": project.ID}) fmt.Println(proj.Creators)
-
Generate Models and Client
torm migrate dev \ --schema <schema.prisma> \ --dir <migrations_dir> -
Migrations
torm migrate [dev|deploy|reset|status] \ --schema <schema.prisma> \ --dir <migrations_dir> -
Help
torm --help torm migrate --help
-
Prisma Schema File
By default, TORM looks forprisma/schema.prisma. Override with--schemaflag. -
Output Directory
By default, TORM generates code inmodels/. -
Environment Variables
DATABASE_URL: Database connection string (Postgres).- If
sslmodeis not specified, TORM automatically appendssslmode=disablefor local development.
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/xyz) - Commit your changes (
git commit -m "[ADD] feature") - Push to your branch (
git push origin feature/xyz) - Open a Pull Request
Ensure that:
- All new code is covered by tests.
go fmtandgo mod tidypass.- Linting (
golangci-lint) reports no issues.
TORM is released under the MIT License.