gpagorm

package module
v0.1.5 Latest Latest
Warning

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

Go to latest
Published: May 3, 2026 License: MIT Imports: 19 Imported by: 2

README

GPAGorm - GORM Adapter for Go Persistence API

A type-safe GORM adapter implementation for the Go Persistence API (GPA), providing compile-time type safety and unified database operations across multiple SQL databases.

Features

  • Type-Safe Operations: Leverages Go generics for compile-time type safety
  • Multi-Database Support: PostgreSQL, MySQL, SQLite, and SQL Server
  • Unified API: Consistent interface across different database drivers
  • Transaction Support: Safe transaction handling with automatic rollback
  • Migration Support: Schema migration and table management
  • Raw SQL Support: Direct SQL execution when needed
  • Relationship Support: Preload relationships with type safety
  • Connection Pooling: Configurable connection pool settings

Supported Databases

  • PostgreSQL (postgres, postgresql)
  • MySQL (mysql)
  • SQLite (sqlite, sqlite3)
  • SQL Server (sqlserver, mssql)

Installation

go get github.com/lemmego/gpagorm

Quick Start

package main

import (
    "context"
    "log"

    "github.com/lemmego/gpa"
    "github.com/lemmego/gpagorm"
)

type User struct {
    ID    uint   `gorm:"primaryKey"`
    Name  string `gorm:"size:100"`
    Email string `gorm:"uniqueIndex"`
}

func main() {
    // Configure database connection
    config := gpa.Config{
        Driver:   "postgres",
        Host:     "localhost",
        Port:     5432,
        Database: "myapp",
        Username: "user",
        Password: "password",
    }

    // Create provider
    provider, err := gpagorm.NewProvider(config)
    if err != nil {
        log.Fatal(err)
    }
    defer provider.Close()

    // Get type-safe repository
    userRepo := gpagorm.GetRepository[User](provider)

    // Create user
    user := &User{Name: "John Doe", Email: "john@example.com"}
    err = userRepo.Create(context.Background(), user)
    if err != nil {
        log.Fatal(err)
    }

    // Find user by ID
    foundUser, err := userRepo.FindByID(context.Background(), user.ID)
    if err != nil {
        log.Fatal(err)
    }

    log.Printf("Found user: %+v", foundUser)
}

Configuration

Basic Configuration
config := gpa.Config{
    Driver:   "postgres",
    Host:     "localhost",
    Port:     5432,
    Database: "myapp",
    Username: "user",
    Password: "password",
}
Advanced Configuration
config := gpa.Config{
    Driver:          "postgres",
    Host:            "localhost",
    Port:            5432,
    Database:        "myapp",
    Username:        "user",
    Password:        "password",
    MaxOpenConns:    25,
    MaxIdleConns:    5,
    ConnMaxLifetime: time.Hour,
    ConnMaxIdleTime: time.Minute * 30,
    SSL: gpa.SSLConfig{
        Enabled:  true,
        Mode:     "require",
        CertFile: "/path/to/cert.pem",
        KeyFile:  "/path/to/key.pem",
        CAFile:   "/path/to/ca.pem",
    },
    Options: map[string]interface{}{
        "gorm": map[string]interface{}{
            "log_level":      "info",
            "singular_table": false,
        },
    },
}

API Reference

Repository Operations
// Create operations
err := repo.Create(ctx, entity)
err := repo.CreateBatch(ctx, entities)

// Read operations
entity, err := repo.FindByID(ctx, id)
entities, err := repo.FindAll(ctx, opts...)
entities, err := repo.Query(ctx, opts...)
entity, err := repo.QueryOne(ctx, opts...)

// Update operations
err := repo.Update(ctx, entity)
err := repo.UpdatePartial(ctx, id, updates)

// Delete operations
err := repo.Delete(ctx, id)
err := repo.DeleteByCondition(ctx, condition)

// Aggregation
count, err := repo.Count(ctx, opts...)
exists, err := repo.Exists(ctx, opts...)
Query Options
// Filtering
entities, err := repo.Query(ctx,
    gpa.Where("name", gpa.OpEqual, "John"),
    gpa.Where("age", gpa.OpGreaterThan, 18),
)

// Ordering
entities, err := repo.Query(ctx,
    gpa.OrderBy("name", gpa.ASC),
    gpa.OrderBy("created_at", gpa.DESC),
)

// Pagination
entities, err := repo.Query(ctx,
    gpa.Limit(10),
    gpa.Offset(20),
)

// Field selection
entities, err := repo.Query(ctx,
    gpa.Select("id", "name", "email"),
)

// Preloading relationships
entities, err := repo.FindWithRelations(ctx, []string{"Profile", "Orders"})
Transactions
err := repo.Transaction(ctx, func(txRepo gpa.Transaction[User]) error {
    // All operations within this function are part of the transaction
    user := &User{Name: "Jane", Email: "jane@example.com"}
    if err := txRepo.Create(ctx, user); err != nil {
        return err // Transaction will be rolled back
    }

    // More operations...
    return nil // Transaction will be committed
})
Raw SQL
// Raw query
users, err := repo.RawQuery(ctx, "SELECT * FROM users WHERE age > ?", []interface{}{18})

// Raw execution
result, err := repo.RawExec(ctx, "UPDATE users SET status = ? WHERE active = ?", []interface{}{"verified", true})
Schema Management
// Create table
err := repo.CreateTable(ctx)

// Migrate table
err := repo.MigrateTable(ctx)

// Drop table
err := repo.DropTable(ctx)

// Create index
err := repo.CreateIndex(ctx, []string{"email"}, true) // unique index

// Get table info
info, err := repo.GetTableInfo(ctx)

Error Handling

GPAGorm converts GORM errors to GPA errors for consistent error handling:

user, err := repo.FindByID(ctx, 999)
if err != nil {
    if gpaErr, ok := err.(gpa.GPAError); ok {
        switch gpaErr.Type {
        case gpa.ErrorTypeNotFound:
            log.Println("User not found")
        case gpa.ErrorTypeDuplicate:
            log.Println("Duplicate key violation")
        case gpa.ErrorTypeDatabase:
            log.Println("Database error:", gpaErr.Cause)
        }
    }
}

Testing

Run the test suite:

go test -v

License

This project is licensed under the MIT License - see the LICENSE.md file for details.

Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Dependencies

  • GORM - The fantastic ORM library for Golang
  • Go Persistence API - Unified persistence layer for Go
  • Database drivers for PostgreSQL, MySQL, SQLite, and SQL Server

Documentation

Overview

Package gpagorm provides field name validation to prevent SQL injection

Package gpagorm provides structured logging for entity hooks

Package gpagorm provides a GORM adapter for the Go Persistence API (GPA)

Package gpagorm provides a GORM adapter for the Go Persistence API (GPA)

Index

Constants

This section is empty.

Variables

View Source
var DefaultHookLogger = NewHookLogger(nil)

DefaultHookLogger is the default hook logger instance

Functions

func GetRepository

func GetRepository[T any](instanceName ...string) gpa.MigratableRepository[T]

GetRepository returns a type-safe repository for any entity type T If no instanceName provided, uses default instance Usage:

userRepo := gpagorm.GetRepository[User]()           // default
userRepo := gpagorm.GetRepository[User]("primary")  // named

func LogAfterCreateError added in v0.1.5

func LogAfterCreateError(ctx context.Context, entity interface{}, err error)

LogAfterCreateError logs an error from AfterCreate hook

func LogAfterDeleteError added in v0.1.5

func LogAfterDeleteError(ctx context.Context, entity interface{}, err error)

LogAfterDeleteError logs an error from AfterDelete hook

func LogAfterFindError added in v0.1.5

func LogAfterFindError(ctx context.Context, entity interface{}, err error)

LogAfterFindError logs an error from AfterFind hook

func LogAfterUpdateError added in v0.1.5

func LogAfterUpdateError(ctx context.Context, entity interface{}, err error)

LogAfterUpdateError logs an error from AfterUpdate hook

func LogBeforeCreateError added in v0.1.5

func LogBeforeCreateError(ctx context.Context, entity interface{}, err error)

LogBeforeCreateError logs an error from BeforeCreate hook

func LogBeforeDeleteError added in v0.1.5

func LogBeforeDeleteError(ctx context.Context, entity interface{}, err error)

LogBeforeDeleteError logs an error from BeforeDelete hook

func LogBeforeUpdateError added in v0.1.5

func LogBeforeUpdateError(ctx context.Context, entity interface{}, err error)

LogBeforeUpdateError logs an error from BeforeUpdate hook

func LogValidationError added in v0.1.5

func LogValidationError(ctx context.Context, entity interface{}, err error)

LogValidationError logs a validation error

func SupportedDrivers

func SupportedDrivers() []string

SupportedDrivers returns the list of supported database drivers

Types

type FieldValidationError added in v0.1.5

type FieldValidationError struct {
	Field  string
	Reason string
}

FieldValidationError represents an error that occurs when a field name fails validation.

func (*FieldValidationError) Error added in v0.1.5

func (e *FieldValidationError) Error() string

Error returns the error message for FieldValidationError.

type HookError added in v0.1.5

type HookError struct {
	HookType   string // e.g., "AfterCreate", "BeforeUpdate"
	EntityType string // e.g., "User", "Post"
	Err        error  // The original error
}

HookError represents an error that occurred during hook execution It wraps the original error with context about which hook failed

func NewHookError added in v0.1.5

func NewHookError(hookType, entityType string, err error) *HookError

NewHookError creates a new HookError

func (*HookError) Error added in v0.1.5

func (e *HookError) Error() string

Error returns the error message

func (*HookError) Unwrap added in v0.1.5

func (e *HookError) Unwrap() error

Unwrap returns the underlying error

type HookLogger added in v0.1.5

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

HookLogger provides structured logging for entity hook errors

func NewHookLogger added in v0.1.5

func NewHookLogger(logger *slog.Logger) *HookLogger

NewHookLogger creates a new hook logger

func (*HookLogger) LogHookError added in v0.1.5

func (h *HookLogger) LogHookError(ctx context.Context, entity interface{}, hookType string, hookName string, err error)

LogHookError logs an error that occurred during hook execution

func (*HookLogger) LogHookSuccess added in v0.1.5

func (h *HookLogger) LogHookSuccess(ctx context.Context, entity interface{}, hookType string, hookName string)

LogHookSuccess logs successful hook execution (debug level)

func (*HookLogger) LogValidationError added in v0.1.5

func (h *HookLogger) LogValidationError(ctx context.Context, entity interface{}, err error)

LogValidationError logs a validation error

type Provider

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

Provider implements gpa.Provider and gpa.SQLProvider using GORM

func NewProvider

func NewProvider(config gpa.Config) (*Provider, error)

NewProvider creates a new GORM provider instance

func (*Provider) BeginTx added in v0.1.1

func (p *Provider) BeginTx(ctx context.Context, opts *gpa.TxOptions) (interface{}, error)

BeginTx starts a transaction with specific isolation level

func (*Provider) Close

func (p *Provider) Close() error

Close closes the database connection

func (*Provider) Configure

func (p *Provider) Configure(config gpa.Config) error

Configure applies configuration to the provider

func (*Provider) DB added in v0.1.1

func (p *Provider) DB() interface{}

DB returns the underlying database/sql.DB instance

func (*Provider) Health

func (p *Provider) Health() error

Health checks the database connection health

func (*Provider) Migrate added in v0.1.1

func (p *Provider) Migrate(models ...interface{}) error

Migrate runs database migrations

func (*Provider) ProviderInfo

func (p *Provider) ProviderInfo() gpa.ProviderInfo

ProviderInfo returns information about this provider

func (*Provider) RawExec added in v0.1.1

func (p *Provider) RawExec(ctx context.Context, query string, args ...interface{}) (gpa.Result, error)

RawExec executes raw SQL without returning results

func (*Provider) RawQuery added in v0.1.1

func (p *Provider) RawQuery(ctx context.Context, query string, args ...interface{}) (interface{}, error)

RawQuery executes raw SQL and returns results

func (*Provider) SupportedFeatures

func (p *Provider) SupportedFeatures() []gpa.Feature

SupportedFeatures returns the list of supported features

type Repository

type Repository[T any] struct {
	// contains filtered or unexported fields
}

Repository implements type-safe GORM operations using Go generics. Provides compile-time type safety for all CRUD and SQL operations.

func NewRepository

func NewRepository[T any](db *gorm.DB, provider *Provider) *Repository[T]

NewRepository creates a new generic GORM repository for type T. Example: userRepo := NewRepository[User](db, provider)

func (*Repository[T]) Close

func (r *Repository[T]) Close() error

Close closes the repository (no-op for GORM).

func (*Repository[T]) Count

func (r *Repository[T]) Count(ctx context.Context, opts ...gpa.QueryOption) (int64, error)

Count returns the number of entities matching query options.

func (*Repository[T]) Create

func (r *Repository[T]) Create(ctx context.Context, entity *T) error

Create inserts a new entity with compile-time type safety.

func (*Repository[T]) CreateBatch

func (r *Repository[T]) CreateBatch(ctx context.Context, entities []*T) error

CreateBatch inserts multiple entities with compile-time type safety.

func (*Repository[T]) CreateIndex

func (r *Repository[T]) CreateIndex(ctx context.Context, fields []string, unique bool) error

CreateIndex creates an index on the specified fields.

func (*Repository[T]) CreateTable

func (r *Repository[T]) CreateTable(ctx context.Context) error

CreateTable creates a new table for entity type T.

func (*Repository[T]) Delete

func (r *Repository[T]) Delete(ctx context.Context, id interface{}) error

Delete removes an entity by ID with compile-time type safety.

func (*Repository[T]) DeleteByCondition

func (r *Repository[T]) DeleteByCondition(ctx context.Context, condition gpa.Condition) error

DeleteByCondition removes entities matching a condition.

func (*Repository[T]) DropIndex

func (r *Repository[T]) DropIndex(ctx context.Context, indexName string) error

DropIndex removes an index.

func (*Repository[T]) DropTable

func (r *Repository[T]) DropTable(ctx context.Context) error

DropTable drops the table for entity type T.

func (*Repository[T]) ExecSQL

func (r *Repository[T]) ExecSQL(ctx context.Context, sql string, args ...interface{}) (gpa.Result, error)

ExecSQL executes a raw SQL statement.

func (*Repository[T]) Exists

func (r *Repository[T]) Exists(ctx context.Context, opts ...gpa.QueryOption) (bool, error)

Exists checks if any entity matches the query options.

func (*Repository[T]) FindAll

func (r *Repository[T]) FindAll(ctx context.Context, opts ...gpa.QueryOption) ([]*T, error)

FindAll retrieves all entities with compile-time type safety.

func (*Repository[T]) FindByID

func (r *Repository[T]) FindByID(ctx context.Context, id interface{}) (*T, error)

FindByID retrieves a single entity by ID with compile-time type safety.

func (*Repository[T]) FindByIDWithRelations

func (r *Repository[T]) FindByIDWithRelations(ctx context.Context, id interface{}, relations []string) (*T, error)

FindByIDWithRelations retrieves an entity by ID with preloaded relationships.

func (*Repository[T]) FindBySQL

func (r *Repository[T]) FindBySQL(ctx context.Context, sql string, args []interface{}) ([]*T, error)

FindBySQL executes a raw SQL SELECT query with compile-time type safety.

func (*Repository[T]) FindWithRelations

func (r *Repository[T]) FindWithRelations(ctx context.Context, relations []string, opts ...gpa.QueryOption) ([]*T, error)

FindWithRelations retrieves entities with preloaded relationships.

func (*Repository[T]) GetEntityInfo

func (r *Repository[T]) GetEntityInfo() (*gpa.EntityInfo, error)

GetEntityInfo returns metadata about entity type T.

func (*Repository[T]) GetMigrationStatus

func (r *Repository[T]) GetMigrationStatus(ctx context.Context) (gpa.MigrationStatus, error)

GetMigrationStatus returns the current migration status for entity type T.

func (*Repository[T]) GetTableInfo

func (r *Repository[T]) GetTableInfo(ctx context.Context) (gpa.TableInfo, error)

GetTableInfo returns detailed information about the current table structure.

func (*Repository[T]) MigrateTable

func (r *Repository[T]) MigrateTable(ctx context.Context) error

MigrateTable migrates the table schema for entity type T.

func (*Repository[T]) Query

func (r *Repository[T]) Query(ctx context.Context, opts ...gpa.QueryOption) ([]*T, error)

Query retrieves entities based on query options with compile-time type safety.

func (*Repository[T]) QueryOne

func (r *Repository[T]) QueryOne(ctx context.Context, opts ...gpa.QueryOption) (*T, error)

QueryOne retrieves a single entity based on query options.

func (*Repository[T]) RawExec

func (r *Repository[T]) RawExec(ctx context.Context, query string, args []interface{}) (gpa.Result, error)

RawExec executes a raw SQL statement.

func (*Repository[T]) RawQuery

func (r *Repository[T]) RawQuery(ctx context.Context, query string, args []interface{}) ([]*T, error)

RawQuery executes a raw SQL query with compile-time type safety.

func (*Repository[T]) Transaction

func (r *Repository[T]) Transaction(ctx context.Context, fn gpa.TransactionFunc[T]) error

Transaction executes a function within a transaction with type safety.

func (*Repository[T]) Update

func (r *Repository[T]) Update(ctx context.Context, entity *T) error

Update modifies an existing entity with compile-time type safety.

func (*Repository[T]) UpdatePartial

func (r *Repository[T]) UpdatePartial(ctx context.Context, id interface{}, updates map[string]interface{}) error

UpdatePartial modifies specific fields of an entity.

type SQLResult

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

SQLResult implements gpa.Result interface

func (*SQLResult) LastInsertId

func (r *SQLResult) LastInsertId() (int64, error)

LastInsertId returns the last insert ID

func (*SQLResult) RowsAffected

func (r *SQLResult) RowsAffected() (int64, error)

RowsAffected returns the number of rows affected

type Transaction

type Transaction[T any] struct {
	*Repository[T]
}

TransactionG implements gpa.TransactionG using GORM with type safety.

func (*Transaction[T]) Commit

func (t *Transaction[T]) Commit() error

Commit commits the transaction (handled automatically by GORM).

func (*Transaction[T]) Rollback

func (t *Transaction[T]) Rollback() error

Rollback rolls back the transaction (handled automatically by GORM).

func (*Transaction[T]) RollbackToSavepoint

func (t *Transaction[T]) RollbackToSavepoint(name string) error

RollbackToSavepoint rolls back to a previously created savepoint.

func (*Transaction[T]) SetSavepoint

func (t *Transaction[T]) SetSavepoint(name string) error

SetSavepoint creates a savepoint within the transaction.

Jump to

Keyboard shortcuts

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