Skip to content

gomodul/db

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

2 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

gomodul/db - Universal Database Abstraction Layer for Go

Write your repository code ONCE, use it with ANY backend!

Go Report Card GoDoc

🎯 Goal

gomodul/db allows you to write your repository code once and seamlessly switch between 11 different backends by only changing the connection DSN - no code modifications needed!

Supported Backends

Type Driver Status
SQL PostgreSQL, MySQL, SQLite βœ… Full Support
NoSQL MongoDB, Redis βœ… Full Support
Search Elasticsearch βœ… Full Support
API REST, GraphQL βœ… Full Support
RPC gRPC βœ… Full Support
Message Queue Kafka βœ… Full Support

πŸš€ Quick Start

Installation

go get github.com/gomodul/db

Basic Usage

package main

import (
    "log"
    "github.com/gomodul/db"
    "github.com/gomodul/db/builder"
)

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

func main() {
    // Open database connection
    database, err := db.Open(db.Config{
        DSN: "postgres://user:pass@localhost:5432/mydb",
        // Change DSN to switch backends!
        // DSN: "mongodb://localhost:27017/mydb"
        // DSN: "redis://localhost:6379"
        // DSN: "https://api.example.com"
    })
    if err != nil {
        log.Fatal(err)
    }
    defer database.Close()

    // Create repository
    repo := NewUserRepository(database)

    // Use it!
    user, err := repo.FindByID(1)
    if err != nil {
        log.Fatal(err)
    }
    log.Printf("Found user: %+v", user)
}

type UserRepository struct {
    db *builder.QueryBuilder
}

func NewUserRepository(database *db.DB) *UserRepository {
    return &UserRepository{db: database.Model(&User{})}
}

func (r *UserRepository) FindByID(id int64) (*User, error) {
    var user User
    err := r.db.Where("id = ?", id).First(&user)
    return &user, err
}

πŸ“– Documentation

Auto-Retry on Transient Failures

The library automatically retries failed queries on transient errors (network issues, timeouts, connection resets). Non-transient errors (like "not found" or "duplicate key") are not retried.

database, err := db.Open(db.Config{
    DSN: "postgres://user:pass@localhost:5432/mydb",
    // Retry configuration
    RetryMaxRetries: 3,                    // Max retry attempts
    RetryBaseDelay:  100 * time.Millisecond, // Initial delay
    RetryMaxDelay:   1 * time.Second,       // Max delay between retries
})

// Queries automatically retry on transient failures
db.Model(&User{}).Where("id = ?", 1).First(&user)

Transient errors that trigger retry:

  • Connection refused/reset
  • Broken pipe
  • Timeout/deadline exceeded
  • Network unreachable
  • Temporary failures

Non-transient errors (no retry):

  • Record not found
  • Duplicate key
  • Validation errors
  • Transaction done

Universal Query API

// Finding records
db.Model(&User{}).Where("status = ?", "active").Find(&users)
db.Model(&User{}).Where("age >= ?", 18).Limit(10).Find(&users)
db.Model(&User{}).Order("created_at DESC").Offset(10).Limit(10).Find(&users)

// Creating records
db.Model(&User{}).Create(&User{Name: "John", Email: "john@example.com"})

// Updating records
db.Model(&User{}).Where("id = ?", 1).Update(map[string]interface{}{
    "status": "inactive",
})

// Deleting records
db.Model(&User{}).Where("id = ?", 1).Delete()

// Counting
db.Model(&User{}).Where("status = ?", "active").Count()

Filtering Operations

Operator Description Example
= Equal Where("id = ?", 1)
!= Not Equal Where("status != ?", "deleted")
>, >=, <, <= Comparison Where("age > ?", 18)
IN In List Where("id IN ?", []int{1,2,3})
NOT IN Not In List Where("id NOT IN ?", []int{1,2})
LIKE Pattern Match Where("name LIKE ?", "%John%")
BETWEEN Range Where("age BETWEEN ?", []int{18,65})
IS NULL Null Check Where("deleted_at IS NULL")
AND, OR Logical Where("status = ? AND age >= ?", "active", 18)

Transaction Support

tx, err := database.BeginTx(ctx)
if err != nil {
    return err
}

defer func() {
    if err != nil {
        tx.Rollback()
    } else {
        tx.Commit()
    }
}()

// Execute operations within transaction
repo := NewUserRepository(database)
err = repo.Create(user1)
if err == nil {
    err = repo.Create(user2)
}

Backend Switching

Just change the DSN!

// PostgreSQL
db.Open(db.Config{DSN: "postgres://localhost:5432/mydb"})

// MySQL
db.Open(db.Config{DSN: "mysql://localhost:3306/mydb"})

// SQLite
db.Open(db.Config{DSN: "file:///tmp/mydb.sqlite"})

// MongoDB
db.Open(db.Config{
    DSN: "mongodb://localhost:27017",
    Database: "mydb",
})

// Redis
db.Open(db.Config{DSN: "redis://localhost:6379"})

// Elasticsearch
db.Open(db.Config{DSN: "http://localhost:9200"})

// REST API
db.Open(db.Config{
    DSN: "https://api.example.com",
    Options: map[string]interface{}{
        "token": "your-api-token",
    },
})

// GraphQL
db.Open(db.Config{
    DSN: "https://api.example.com/graphql",
    Options: map[string]interface{}{
        "token": "your-graphql-token",
    },
})

// gRPC
db.Open(db.Config{DSN: "localhost:50051"})

// Kafka
db.Open(db.Config{DSN: "localhost:9092"})

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              Programmer's Repository Layer                  β”‚
β”‚              (Write ONCE, works EVERYWHERE)                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                     β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚           Universal Query Builder (Fluent API)              β”‚
β”‚  db.Model(&User{}).Where("status = ?", "active").Find()    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                     β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              Universal Query Model (IR)                     β”‚
β”‚              Backend-agnostic query representation           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                     β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              Query Translator Layer                         β”‚
β”‚  SQL Translator β”‚ Mongo Translator β”‚ REST Translator        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                     β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                   Driver Layer                              β”‚
β”‚  SQL β”‚ NoSQL β”‚ API β”‚ RPC β”‚ GraphQL β”‚ Message Queue           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ§ͺ Testing

go test ./... -v

πŸ“ Examples

See the examples/ directory for complete examples:

🀝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

πŸ“„ License

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

πŸ™ Acknowledgments

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages