neat

package module
v0.7.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 4, 2026 License: AGPL-3.0 Imports: 6 Imported by: 0

README

Neat ORM

Tests Status Go Report Card PkgGoDev codecov

A powerful and elegant ORM (Object-Relational Mapping) library for Go, designed to provide a clean and intuitive interface for database operations. Neat aims to feature parity with Laravel's Eloquent ORM while being built from scratch without GORM dependencies.

Features

  • Query Builder: Fluent and intuitive query building interface
  • ORM: Full ORM support with models and relationships
  • Schema Builder: Database schema creation and modification
  • Migrations: Database migration system (ORM driver supported)
  • Seeders: Database seeding for test and initial data
  • Factories: Test data generation with factory pattern
  • Multiple Database Support: MySQL, PostgreSQL, SQLite, SQL Server, Turso
  • Transactions: Robust transaction support
  • Observers: Model lifecycle event system
  • Soft Deletes: Soft delete functionality
  • Associations: BelongsTo, HasMany, HasOne relationships
  • Connection Pooling: Efficient connection management
  • Context Support: Full context.Context support throughout

Installation

go get github.com/dracory/neat

Quick Start

package main

import (
    "context"
    "log"
    
    "github.com/dracory/neat"
)

type User struct {
    ID       uint   `json:"id"`
    Name     string `json:"name"`
    Email    string `json:"email"`
}

func main() {
    // Create database connection
    db, err := neat.NewFromDSN("mysql://user:password@localhost:3306/mydb")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()
    
    // Query users
    var users []User
    err = db.Query().Where("name", "John").Get(&users)
    if err != nil {
        log.Fatal(err)
    }
    
    log.Printf("Found %d users", len(users))
}

Configuration

Using DSN String
db, err := neat.NewFromDSN("mysql://user:password@localhost:3306/mydb")
Using DBConfig
config := neat.DBConfig{
    Default: "default",
    Connections: map[string]neat.ConnectionConfig{
        "default": {
            Driver:   "mysql",
            Host:     "localhost",
            Port:     3306,
            Database: "mydb",
            Username: "user",
            Password: "password",
        },
    },
}

db, err := neat.New(config)
Supported DSN Formats
  • MySQL: mysql://user:password@localhost:3306/database
  • PostgreSQL: postgres://user:password@localhost:5432/database?sslmode=disable
  • SQLite: sqlite:///path/to/database.db
  • SQL Server: sqlserver://user:password@localhost:1433?database=database

ORM Usage

Creating Records
user := User{
    Name:  "John Doe",
    Email: "john@example.com",
}
err := db.Query().Create(&user)
Querying Records
var user User
err := db.Query().Where("id", 1).First(&user)

var users []User
err := db.Query().Where("name", "John").Get(&users)
Updating Records
err := db.Query().Where("id", 1).Update("name", "Jane")
Deleting Records
result, err := db.Query().Where("id", 1).Delete()
Transactions
err := db.Transaction(func(tx neat.Query) error {
    err := tx.Create(&user1)
    if err != nil {
        return err
    }
    
    err = tx.Create(&user2)
    if err != nil {
        return err
    }
    
    return nil
})

Schema Builder

err := db.Schema().Create("users", func(table neat.Blueprint) {
    table.ID()
    table.String("name")
    table.String("email").Unique()
    table.Timestamps()
})

Observers

type UserObserver struct{}

func (o *UserObserver) Creating(event neat.Event) error {
    log.Println("Creating user")
    return nil
}

func (o *UserObserver) Created(event neat.Event) error {
    log.Println("User created")
    return nil
}

// Register observer
db.Orm().Observe([]neat.ModelToObserver{
    {Model: User{}, Observer: UserObserver{}},
})

Soft Deletes

type User struct {
    neat.SoftDeletes
    ID   uint
    Name string
}

// Soft delete
db.Query().Where("id", 1).Delete()

// Include soft-deleted records
db.Query().WithTrashed().Where("id", 1).First(&user)

// Only soft-deleted records
db.Query().OnlyTrashed().Where("id", 1).First(&user)

// Restore soft-deleted record
db.Query().Restore(&user)

// Force delete (permanent)
db.Query().ForceDelete(&user)

Associations

type Post struct {
    ID     uint
    Title  string
    UserID uint
}

type User struct {
    ID    uint
    Name  string
    Posts []Post
}

// Eager loading
db.Query().With("posts").Where("id", 1).First(&user)

// Lazy loading
db.Query().Load(&user, "posts")

// Association operations
db.Query().Association("posts").Append(&user, &post)

Supported Databases

  • MySQL 5.7+
  • PostgreSQL 12+
  • SQLite 3+
  • SQL Server 2017+
  • Turso (SQLite edge)

API Documentation

For detailed API documentation, see the docs directory.

Examples

For more examples, see the examples directory.

License

This project is licensed under the GNU Affero General Public License v3.0 - see the LICENSE file for details.

Testing

Running Integration Tests with Docker Compose

The project includes a Docker Compose configuration for running integration tests locally with MySQL and PostgreSQL:

# Start the database containers
docker-compose up -d

# Run MySQL integration tests
go test -v -tags=integration ./integration_tests/mysql/...

# Run PostgreSQL integration tests
go test -v -tags=integration ./integration_tests/postgres/...

# Stop the containers when done
docker-compose down

The Docker Compose setup includes:

  • MySQL 8.0 on port 3306 (user: root, password: root, database: test)
  • PostgreSQL 15 on port 55432 (user: test, password: test, database: test)
Running Unit Tests
go test ./...
Running All Tests
go test -v ./...
Generating Coverage Reports

To generate a coverage report locally:

# Generate coverage profile
go test -coverprofile=coverage.out -covermode=atomic ./...

# View coverage percentage in terminal
go tool cover -func=coverage.out

# Generate HTML coverage report
go tool cover -html=coverage.out -o coverage.html

The HTML report can be opened in a browser to see detailed coverage information for each file and function.

Contributing

Contributions are welcome! Please open an issue or submit a pull request. For detailed contribution guidelines, see CONTRIBUTING.md.

Roadmap

Current Status

Neat ORM is actively developed with the following features implemented:

  • ✅ Query Builder with fluent interface
  • ✅ ORM with model support
  • ✅ Schema Builder for database operations
  • ✅ Migration system (ORM driver)
  • ✅ Seeder system for data seeding
  • ✅ Factory pattern for test data
  • ✅ Multiple database support (MySQL, PostgreSQL, SQLite, SQL Server, Turso)
  • ✅ Transaction support
  • ✅ Observer system for model events
  • ✅ Soft deletes
  • ✅ Associations (BelongsTo, HasMany, HasOne)
  • ✅ Connection pooling
  • ✅ Context support
Planned Features
  • Additional migration drivers (SQL, custom drivers)
  • More relationship types (HasManyThrough, BelongsToMany)
  • Query caching
  • Full-text search support
  • Polymorphic relationships
  • Scopes and global scopes
  • Mutators and accessors
  • Model casting
  • Validation integration
  • Query builder debugging tools
  • Additional database drivers

For detailed implementation plans, see docs/implementation/plan.md.

Documentation

Index

Constants

View Source
const (
	EventCreating  = "model.creating"
	EventCreated   = "model.created"
	EventUpdating  = "model.updating"
	EventUpdated   = "model.updated"
	EventSaving    = "model.saving"
	EventSaved     = "model.saved"
	EventDeleting  = "model.deleting"
	EventDeleted   = "model.deleted"
	EventRestoring = "model.restoring"
	EventRestored  = "model.restored"
)

Event names for model lifecycle events.

Variables

This section is empty.

Functions

func New added in v0.2.0

func New(cfg DBConfig, opts ...database.Option) (*database.Database, error)

New creates a new Database instance from a DBConfig. It converts the neat.DBConfig to the internal database.db.DBConfig and initializes the database.

func NewFromDSN added in v0.2.0

func NewFromDSN(dsn string, opts ...database.Option) (*database.Database, error)

NewFromDSN creates a new Database instance from a DSN string. It parses the DSN and initializes the database connection.

Types

type ConnectionConfig

type ConnectionConfig struct {
	Driver       string // "postgres", "mysql", "sqlite", "sqlserver", "turso"
	Dsn          string
	Host         string
	Port         int
	Database     string
	Username     string
	Password     string
	Charset      string
	Schema       string // postgres only
	SSLMode      string // postgres only
	Loc          string // mysql only
	Timezone     string // postgres only
	Prefix       string
	Singular     bool
	NoLowerCase  bool
	NameReplacer any
	Read         []ReplicaConfig
	Write        []ReplicaConfig
}

ConnectionConfig holds configuration for a single database connection.

func (ConnectionConfig) String added in v0.7.0

func (c ConnectionConfig) String() string

String returns a string representation of ConnectionConfig with password masked.

type DBConfig

type DBConfig struct {
	// Default connection name
	Default string
	// Connection configurations
	Connections map[string]ConnectionConfig
	// Migration configuration
	Migrations MigrationConfig
	// Pool configuration
	Pool PoolConfig
	// Debug mode
	Debug bool
	// Slow query threshold in milliseconds
	SlowThreshold int
}

DBConfig holds the database configuration for the standalone module.

func (*DBConfig) Add

func (c *DBConfig) Add(name string, configuration any)

Add implements config.Config interface for DBConfig (stub). It adds a new configuration entry.

func (*DBConfig) Env

func (c *DBConfig) Env(envName string, defaultValue ...any) any

Env implements config.Config interface for DBConfig (stub). It retrieves an environment variable value.

func (*DBConfig) Get

func (c *DBConfig) Get(path string, defaultValue ...any) any

Get implements config.Config interface for DBConfig. It retrieves any value from the configuration based on the given path.

func (*DBConfig) GetBool

func (c *DBConfig) GetBool(path string, defaultValue ...any) bool

GetBool implements config.Config interface for DBConfig. It retrieves a boolean value from the configuration based on the given path.

func (*DBConfig) GetInt

func (c *DBConfig) GetInt(path string, defaultValue ...any) int

GetInt implements config.Config interface for DBConfig. It retrieves an integer value from the configuration based on the given path.

func (*DBConfig) GetString

func (c *DBConfig) GetString(path string, defaultValue ...any) string

GetString implements config.Config interface for DBConfig. It retrieves a string value from the configuration based on the given path.

type Database added in v0.2.0

type Database = database.Database

Database is an alias for the database.Database type.

type EventBus added in v0.2.0

type EventBus struct {
	// contains filtered or unexported fields
}

EventBus is a lightweight internal event bus for model lifecycle events.

func NewEventBus added in v0.2.0

func NewEventBus() *EventBus

NewEventBus creates a new EventBus. It initializes an empty event bus with no registered listeners.

func (*EventBus) Dispatch added in v0.2.0

func (e *EventBus) Dispatch(eventName string, event any)

Dispatch dispatches an event to all registered listeners. It calls each handler synchronously in the order they were registered.

func (*EventBus) Forget added in v0.2.0

func (e *EventBus) Forget(eventName string)

Forget removes all listeners for the given event name. This clears all handlers registered for the specified event.

func (*EventBus) Listen added in v0.2.0

func (e *EventBus) Listen(eventName string, handler EventHandler)

Listen registers a handler for the given event name. The handler will be called whenever the event is dispatched.

type EventHandler added in v0.2.0

type EventHandler func(event any)

EventHandler is a function that handles an event.

type MigrationConfig

type MigrationConfig struct {
	Driver string // "sql" or "orm"
	Table  string // default: "migrations"
}

MigrationConfig holds migration configuration.

type PoolConfig

type PoolConfig struct {
	MaxIdleConns    int
	MaxOpenConns    int
	ConnMaxLifetime time.Duration
	ConnMaxIdleTime time.Duration
	QueryTimeout    time.Duration // default: 30 seconds
}

PoolConfig holds connection pool configuration.

type ReplicaConfig added in v0.2.0

type ReplicaConfig struct {
	Host     string
	Port     int
	Database string
	Username string
	Password string
}

ReplicaConfig holds connection details for a single read or write replica.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL