goSqlite

package module
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Jan 28, 2026 License: MIT Imports: 14 Imported by: 0

README

[!NOTE] This README was generated by Claude Code, get the ZH version from here.

cover

go-sqlite

pkg card license

Lightweight SQLite Query Builder built on database/sql and mattn/go-sqlite3, providing chainable API, connection pool management, and Context support.

Table of Contents

Features

  • Chainable API Design: Fluent method chaining for improved code readability
  • Connection Pool Management: Singleton pattern with sync.Once, supports multiple database instances
  • WAL Mode: Automatically enables Write-Ahead Logging for better concurrency
  • SQL Injection Protection: Built-in column name validation and SQL reserved keyword checking
  • Native Context Support: Full integration with context.Context for timeouts and cancellations
  • Conflict Resolution Strategies: Supports IGNORE, REPLACE, ABORT, FAIL, ROLLBACK
  • Type Safety: Explicit error wrapping and parameterized queries
  • Zero-Dependency Core: Relies only on standard library and mattn/go-sqlite3

Architecture

graph TB
    A[Connector] -->|singleton| B[Connection Pool]
    B --> C1[DB: key1]
    B --> C2[DB: key2]
    B --> C3[DB: keyN]

    C1 --> D[Builder]
    D --> E[Query Builder]
    E --> F1[SELECT]
    E --> F2[INSERT]
    E --> F3[UPDATE]
    E --> F4[DELETE]

    F1 --> G[SQL Validation Layer]
    G --> H[Parameterized Query]
    H --> I[database/sql]

Design Decisions:

  • Singleton Connector: Prevents duplicate connection overhead, uses sync.Mutex for concurrency safety
  • Builder Pattern: Creates new Builder instance per query to avoid state pollution
  • Validation Layer: Validates column names and reserved keywords before SQL construction

Installation

go get github.com/pardnchiu/go-sqlite

Requirements:

  • Go ≥ 1.20
  • CGO enabled (required by mattn/go-sqlite3)

Quick Start

package main

import (
    "log"
    goSqlite "github.com/pardnchiu/go-sqlite"
)

func main() {
    // Initialize connection
    conn, err := goSqlite.New(goSqlite.Config{
        Key:      "myapp",
        Path:     "./data.db",
        Lifetime: 3600,
    })
    if err != nil {
        log.Fatal(err)
    }
    defer conn.Close()

    // Get Builder
    db, err := conn.DB("myapp")
    if err != nil {
        log.Fatal(err)
    }

    // Create table
    err = db.Table("users").Create(
        goSqlite.Column{Name: "id", Type: "INTEGER", IsPrimary: true, AutoIncrease: true},
        goSqlite.Column{Name: "name", Type: "TEXT", IsNullable: false},
        goSqlite.Column{Name: "email", Type: "TEXT", IsUnique: true},
    )
    if err != nil {
        log.Fatal(err)
    }

    // Insert data
    lastID, err := db.Table("users").Insert(map[string]any{
        "name":  "Alice",
        "email": "alice@example.com",
    })
    if err != nil {
        log.Fatal(err)
    }
    log.Printf("Inserted ID: %d", lastID)

    // Query data
    rows, err := db.Table("users").Select("id", "name").Where("id = ?", lastID).Get()
    if err != nil {
        log.Fatal(err)
    }
    defer rows.Close()

    for rows.Next() {
        var id int
        var name string
        rows.Scan(&id, &name)
        log.Printf("User: %d - %s", id, name)
    }
}

Usage

Initialize Connection
// Basic configuration
conn, err := goSqlite.New(goSqlite.Config{
    Key:      "mydb",           // Connection identifier
    Path:     "./database.db",  // SQLite file path
    Lifetime: 3600,             // Connection lifetime in seconds
})

// Auto-generate Key from filename when omitted
conn, err := goSqlite.New(goSqlite.Config{
    Path: "./users.db", // Key automatically set to "users"
})

Connection Pool Settings:

  • MaxOpenConns: 8 (default)
  • MaxIdleConns: 2 (default)
  • journal_mode: WAL (automatically enabled)
Create Table
db, _ := conn.DB("mydb")

err := db.Table("products").Create(
    goSqlite.Column{
        Name:         "id",
        Type:         "INTEGER",
        IsPrimary:    true,
        AutoIncrease: true,
    },
    goSqlite.Column{
        Name:       "sku",
        Type:       "TEXT",
        IsUnique:   true,
        IsNullable: false,
    },
    goSqlite.Column{
        Name:    "price",
        Type:    "REAL",
        Default: 0.0,
    },
    goSqlite.Column{
        Name: "category_id",
        Type: "INTEGER",
        ForeignKey: &goSqlite.Foreign{
            Table:  "categories",
            Column: "id",
        },
    },
)
Insert Data
// Basic insert
lastID, err := db.Table("users").Insert(map[string]any{
    "name":  "Bob",
    "email": "bob@example.com",
})

// Ignore on conflict
lastID, err := db.Table("users").
    Conflict(goSqlite.Ignore).
    Insert(map[string]any{
        "email": "bob@example.com",
        "name":  "Bob",
    })

// Upsert (update on conflict)
lastID, err := db.Table("users").Insert(
    map[string]any{"email": "bob@example.com", "name": "Bob"},
    map[string]any{"name": "Bob Updated"}, // Update name on conflict
)

Conflict Strategies:

  • goSqlite.Ignore: Skip on conflict
  • goSqlite.Replace: Replace entire row on conflict
  • goSqlite.Abort: Abort transaction on conflict
  • goSqlite.Fail: Fail without rollback on conflict
  • goSqlite.Rollback: Rollback transaction on conflict
Query Data
// Query all columns
rows, err := db.Table("users").Get()

// Query specific columns
rows, err := db.Table("users").Select("id", "name").Get()

// WHERE conditions
rows, err := db.Table("users").
    Where("age > ?", 18).
    Where("status = ?", "active").
    Get()

// OR conditions
rows, err := db.Table("users").
    Where("role = ?", "admin").
    OrWhere("role = ?", "moderator").
    Get()

// LIMIT and OFFSET
rows, err := db.Table("users").
    Limit(10).
    Offset(20).
    Get()

// Ordering
rows, err := db.Table("users").
    OrderBy("created_at", goSqlite.Desc).
    OrderBy("name", goSqlite.Asc).
    Get()
Update Data
// Basic update
affected, err := db.Table("users").
    Where("id = ?", 1).
    Update(map[string]any{
        "name":  "Alice Updated",
        "email": "alice.new@example.com",
    })

// Increment numeric value
affected, err := db.Table("products").
    Where("id = ?", 100).
    Increase("stock", 10). // stock = stock + 10
    Update()

// Decrement numeric value
affected, err := db.Table("users").
    Where("id = ?", 1).
    Decrease("credits", 5). // credits = credits - 5
    Update()

// Toggle boolean value
affected, err := db.Table("settings").
    Where("key = ?", "notifications").
    Toggle("enabled"). // enabled = NOT enabled
    Update()
Delete Data
// Conditional delete
affected, err := db.Table("users").
    Where("status = ?", "inactive").
    Delete()

// Force delete all records (requires explicit force flag)
affected, err := db.Table("logs").Delete(true)

// Delete first 10 records
affected, err := db.Table("temp_data").
    OrderBy("created_at", goSqlite.Asc).
    Limit(10).
    Delete()

Safety Restrictions:

  • Requires Delete(true) when no WHERE conditions specified
  • SQLite does not support JOIN in DELETE operations
Advanced Queries
// JOIN operations
rows, err := db.Table("orders").
    Select("orders.id", "users.name", "products.title").
    Join("users", "orders.user_id = users.id").
    LeftJoin("products", "orders.product_id = products.id").
    Where("orders.status = ?", "completed").
    Get()

// Pagination with total count
rows, err := db.Table("posts").
    Select("id", "title").
    Where("published = ?", 1).
    OrderBy("created_at", goSqlite.Desc).
    Limit(20).
    Offset(40).
    Total(). // Calculate total count
    Get()

// Read total count
for rows.Next() {
    var id int
    var title string
    var total int // Total() adds total column to each row
    rows.Scan(&total, &id, &title)
}
Context Support
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

// Use Context in queries
rows, err := db.Table("users").
    Context(ctx).
    Where("status = ?", "active").
    Get()

// Use Context in inserts
lastID, err := db.Table("logs").
    Context(ctx).
    Insert(map[string]any{
        "level":   "info",
        "message": "operation completed",
    })

// Use Context in updates
affected, err := db.Table("sessions").
    Context(ctx).
    Where("expired_at < ?", time.Now().Unix()).
    Delete()

API Reference

Connector

New(config Config) (*Connector, error)

Create or retrieve Connector singleton.

Parameter Type Description
config.Key string Connection identifier (optional, defaults to filename)
config.Path string SQLite file path
config.Lifetime int Connection lifetime in seconds (optional)

DB(key string) (*Builder, error)

Retrieve Builder instance for specified key.

Query(key, query string, args ...any) (*sql.Rows, error)

Execute SELECT query directly.

Exec(key, query string, args ...any) (sql.Result, error)

Execute INSERT/UPDATE/DELETE query directly.

Close()

Close all database connections.

Builder

Table(name string) *Builder

Set target table name for operations.

Raw() *sql.DB

Retrieve underlying *sql.DB instance for advanced operations.

Create(columns ...Column) error

Create table if not exists.

Query Methods

Select(columns ...string) *Builder

Specify query columns (defaults to *).

Where(condition string, args ...any) *Builder

Add AND WHERE condition.

OrWhere(condition string, args ...any) *Builder

Add OR WHERE condition.

Join(table, on string) *Builder

Add INNER JOIN.

LeftJoin(table, on string) *Builder

Add LEFT JOIN.

OrderBy(column string, direction ...direction) *Builder

Add ordering (goSqlite.Asc or goSqlite.Desc).

Limit(num ...int) *Builder

Set LIMIT (one parameter) or OFFSET + LIMIT (two parameters).

Offset(num int) *Builder

Set OFFSET.

Total() *Builder

Include total count in results (uses COUNT(*) OVER()).

Get() (*sql.Rows, error)

Execute query and return result set.

Mutation Methods

Insert(data ...map[string]any) (int64, error)

Insert data and return LastInsertId. Second map (optional) for ON CONFLICT UPDATE.

Update(data ...map[string]any) (int64, error)

Update data and return affected rows count.

Delete(force ...bool) (int64, error)

Delete data and return affected rows count. Requires force=true without WHERE.

Advanced Operations

Conflict(strategy conflict) *Builder

Set INSERT conflict strategy.

Increase(column string, num ...int) *Builder

Increment column value (defaults to +1).

Decrease(column string, num ...int) *Builder

Decrement column value (defaults to -1).

Toggle(column string) *Builder

Toggle boolean column value.

Context(ctx context.Context) *Builder

Set query Context (for timeout/cancellation).

License

MIT License

Author

邱敬幃 Pardn Chiu

Stars

Star


©️ 2026 邱敬幃 Pardn Chiu

Documentation

Index

Constants

View Source
const (
	Ignore conflict = iota
	Replace
	Abort
	Fail
	Rollback
)
View Source
const (
	Asc direction = iota
	Desc
)

Variables

This section is empty.

Functions

This section is empty.

Types

type Builder

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

func NewBuilder

func NewBuilder(db *sql.DB) *Builder

func (*Builder) Conflict

func (b *Builder) Conflict(conflict conflict) *Builder

func (*Builder) Context added in v0.3.0

func (b *Builder) Context(ctx context.Context) *Builder

func (*Builder) Count

func (b *Builder) Count() (int64, error)

func (*Builder) CountContext

func (b *Builder) CountContext(ctx context.Context) (int64, error)

! Deprecated: Use Context(ctx).Count() in v1.0.0

func (*Builder) Create

func (b *Builder) Create(columns ...Column) error

func (*Builder) Decrease

func (b *Builder) Decrease(column string, num ...int) *Builder

func (*Builder) Delete added in v0.3.0

func (b *Builder) Delete(force ...bool) (int64, error)

func (*Builder) ExecAutoAsignContext added in v0.3.0

func (b *Builder) ExecAutoAsignContext(query string, args ...any) (sql.Result, error)

func (*Builder) First

func (b *Builder) First() (*sql.Row, error)

func (*Builder) FirstContext

func (b *Builder) FirstContext(ctx context.Context) (*sql.Row, error)

! Deprecated: Use Context(ctx).First() in v1.0.0

func (*Builder) Get

func (b *Builder) Get() (*sql.Rows, error)

func (*Builder) GetContext

func (b *Builder) GetContext(ctx context.Context) (*sql.Rows, error)

! Deprecated: Use Context(ctx).Get() in v1.0.0

func (*Builder) GetWithTotal

func (b *Builder) GetWithTotal() (*sql.Rows, error)

! Deprecated: Use Total(ctx).Get() in v1.0.0

func (*Builder) GetWithTotalContext

func (b *Builder) GetWithTotalContext(ctx context.Context) (*sql.Rows, error)

! Deprecated: Use Total(ctx).Context(ctx).Get() in v1.0.0

func (*Builder) GroupBy added in v0.4.0

func (b *Builder) GroupBy(columns ...string) *Builder

func (*Builder) Having added in v0.4.0

func (b *Builder) Having(condition string, args ...any) *Builder

func (*Builder) HavingBetween added in v0.4.0

func (b *Builder) HavingBetween(column string, start, end any) *Builder

func (*Builder) HavingEq added in v0.4.0

func (b *Builder) HavingEq(column string, value any) *Builder

func (*Builder) HavingGe added in v0.4.0

func (b *Builder) HavingGe(column string, value any) *Builder

func (*Builder) HavingGt added in v0.4.0

func (b *Builder) HavingGt(column string, value any) *Builder

func (*Builder) HavingIn added in v0.4.0

func (b *Builder) HavingIn(column string, values []any) *Builder

func (*Builder) HavingLe added in v0.4.0

func (b *Builder) HavingLe(column string, value any) *Builder

func (*Builder) HavingLt added in v0.4.0

func (b *Builder) HavingLt(column string, value any) *Builder

func (*Builder) HavingNotEq added in v0.4.0

func (b *Builder) HavingNotEq(column string, value any) *Builder

func (*Builder) HavingNotIn added in v0.4.0

func (b *Builder) HavingNotIn(column string, values []any) *Builder

func (*Builder) HavingNotNull added in v0.4.0

func (b *Builder) HavingNotNull(column string) *Builder

func (*Builder) HavingNull added in v0.4.0

func (b *Builder) HavingNull(column string) *Builder

func (*Builder) Increase

func (b *Builder) Increase(column string, num ...int) *Builder

func (*Builder) Insert

func (b *Builder) Insert(data ...map[string]any) (int64, error)

func (*Builder) InsertConflict

func (b *Builder) InsertConflict(conflict conflict, data ...map[string]any) (int64, error)

! Deprecated: Use Conflict(conflict).Insert() in v1.0.0

func (*Builder) InsertConflictReturningID

func (b *Builder) InsertConflictReturningID(conflict conflict, data ...map[string]any) (int64, error)

! Deprecated: Use Conflict(conflict).Insert() in v1.0.0

func (*Builder) InsertContexConflict

func (b *Builder) InsertContexConflict(ctx context.Context, conflict conflict, data ...map[string]any) (int64, error)

! Deprecated: Use Conflict(conflict).Context(ctx).Insert() in v1.0.0

func (*Builder) InsertContext

func (b *Builder) InsertContext(ctx context.Context, data ...map[string]any) (int64, error)

! Deprecated: Use Context(ctx).Insert() in v1.0.0

func (*Builder) InsertContextConflictReturningID

func (b *Builder) InsertContextConflictReturningID(ctx context.Context, conflict conflict, data ...map[string]any) (int64, error)

! Deprecated: Use Conflict(conflict).Context(ctx).Insert() in v1.0.0

func (*Builder) InsertContextReturningID

func (b *Builder) InsertContextReturningID(ctx context.Context, data ...map[string]any) (int64, error)

! Deprecated: Use Context(ctx).Insert() in v1.0.0

func (*Builder) InsertReturningID

func (b *Builder) InsertReturningID(data ...map[string]any) (int64, error)

! Deprecated: Use Insert() in v1.0.0

func (*Builder) Join

func (b *Builder) Join(table, on string) *Builder

func (*Builder) LeftJoin

func (b *Builder) LeftJoin(table, on string) *Builder

func (*Builder) Limit

func (b *Builder) Limit(num ...int) *Builder

func (*Builder) Offset

func (b *Builder) Offset(num int) *Builder

func (*Builder) OrHaving added in v0.4.0

func (b *Builder) OrHaving(condition string, args ...any) *Builder

func (*Builder) OrHavingBetween added in v0.4.0

func (b *Builder) OrHavingBetween(column string, start, end any) *Builder

func (*Builder) OrHavingEq added in v0.4.0

func (b *Builder) OrHavingEq(column string, value any) *Builder

func (*Builder) OrHavingGe added in v0.4.0

func (b *Builder) OrHavingGe(column string, value any) *Builder

func (*Builder) OrHavingGt added in v0.4.0

func (b *Builder) OrHavingGt(column string, value any) *Builder

func (*Builder) OrHavingIn added in v0.4.0

func (b *Builder) OrHavingIn(column string, values []any) *Builder

func (*Builder) OrHavingLe added in v0.4.0

func (b *Builder) OrHavingLe(column string, value any) *Builder

func (*Builder) OrHavingLt added in v0.4.0

func (b *Builder) OrHavingLt(column string, value any) *Builder

func (*Builder) OrHavingNotEq added in v0.4.0

func (b *Builder) OrHavingNotEq(column string, value any) *Builder

func (*Builder) OrHavingNotIn added in v0.4.0

func (b *Builder) OrHavingNotIn(column string, values []any) *Builder

func (*Builder) OrHavingNotNull added in v0.4.0

func (b *Builder) OrHavingNotNull(column string) *Builder

func (*Builder) OrHavingNull added in v0.4.0

func (b *Builder) OrHavingNull(column string) *Builder

func (*Builder) OrWhere

func (b *Builder) OrWhere(condition string, args ...any) *Builder

func (*Builder) OrWhereBetween

func (b *Builder) OrWhereBetween(column string, start, end any) *Builder

func (*Builder) OrWhereEq

func (b *Builder) OrWhereEq(column string, value any) *Builder

func (*Builder) OrWhereGe

func (b *Builder) OrWhereGe(column string, value any) *Builder

func (*Builder) OrWhereGt

func (b *Builder) OrWhereGt(column string, value any) *Builder

func (*Builder) OrWhereIn

func (b *Builder) OrWhereIn(column string, values []any) *Builder

func (*Builder) OrWhereLe

func (b *Builder) OrWhereLe(column string, value any) *Builder

func (*Builder) OrWhereLt

func (b *Builder) OrWhereLt(column string, value any) *Builder

func (*Builder) OrWhereNotEq

func (b *Builder) OrWhereNotEq(column string, value any) *Builder

func (*Builder) OrWhereNotIn

func (b *Builder) OrWhereNotIn(column string, values []any) *Builder

func (*Builder) OrWhereNotNull

func (b *Builder) OrWhereNotNull(column string) *Builder

func (*Builder) OrWhereNull

func (b *Builder) OrWhereNull(column string) *Builder

func (*Builder) OrderBy

func (b *Builder) OrderBy(column string, direction ...direction) *Builder

func (*Builder) Raw

func (b *Builder) Raw() *sql.DB

func (*Builder) Select

func (b *Builder) Select(columns ...string) *Builder

func (*Builder) Table

func (b *Builder) Table(name string) *Builder

func (*Builder) Toggle

func (b *Builder) Toggle(column string) *Builder

func (*Builder) Total

func (b *Builder) Total() *Builder

func (*Builder) Update

func (b *Builder) Update(data ...map[string]any) (int64, error)

func (*Builder) UpdateContext

func (b *Builder) UpdateContext(ctx context.Context, data ...map[string]any) (int64, error)

! Deprecated: Use Context(ctx).Update() in v1.0.0

func (*Builder) Where

func (b *Builder) Where(condition string, args ...any) *Builder

func (*Builder) WhereBetween

func (b *Builder) WhereBetween(column string, start, end any) *Builder

func (*Builder) WhereEq

func (b *Builder) WhereEq(column string, value any) *Builder

func (*Builder) WhereGe

func (b *Builder) WhereGe(column string, value any) *Builder

func (*Builder) WhereGt

func (b *Builder) WhereGt(column string, value any) *Builder

func (*Builder) WhereIn

func (b *Builder) WhereIn(column string, values []any) *Builder

func (*Builder) WhereLe

func (b *Builder) WhereLe(column string, value any) *Builder

func (*Builder) WhereLt

func (b *Builder) WhereLt(column string, value any) *Builder

func (*Builder) WhereNotEq

func (b *Builder) WhereNotEq(column string, value any) *Builder

func (*Builder) WhereNotIn

func (b *Builder) WhereNotIn(column string, values []any) *Builder

func (*Builder) WhereNotNull

func (b *Builder) WhereNotNull(column string) *Builder

func (*Builder) WhereNull

func (b *Builder) WhereNull(column string) *Builder

type Column

type Column struct {
	Name         string
	Type         string
	IsPrimary    bool
	IsNullable   bool
	AutoIncrease bool
	IsUnique     bool
	Default      any
	ForeignKey   *Foreign
}

type Config

type Config struct {
	Key      string `json:"key,omitempty"`
	Path     string `json:"path"`
	Lifetime int    `json:"lifetime,omitempty"` // sec
}

type Connector

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

func New

func New(c Config) (*Connector, error)

func (*Connector) Close

func (d *Connector) Close()

func (*Connector) DB

func (d *Connector) DB(key string) (*Builder, error)

func (*Connector) Exec

func (d *Connector) Exec(key, query string, args ...any) (sql.Result, error)

func (*Connector) ExecContext

func (d *Connector) ExecContext(ctx context.Context, key, query string, args ...any) (sql.Result, error)

func (*Connector) Query

func (d *Connector) Query(key, query string, args ...any) (*sql.Rows, error)

func (*Connector) QueryContext

func (d *Connector) QueryContext(ctx context.Context, key, query string, args ...any) (*sql.Rows, error)

type Foreign

type Foreign struct {
	Table  string
	Column string
}

type Join

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

type Union added in v0.3.0

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

type Where

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

Jump to

Keyboard shortcuts

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