sqlutil

package module
v1.10.0 Latest Latest
Warning

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

Go to latest
Published: Jan 20, 2026 License: MIT Imports: 4 Imported by: 0

README

sqlutil

Build Status Go Report Card go.dev reference

A powerful and flexible collection of Go helpers for database operations. sqlutil simplifies common database tasks with a clean, chainable API that works with PostgreSQL, MySQL, and SQLite.

Features

  • Clean, intuitive API for CRUD operations
  • Support for multiple SQL flavors (PostgreSQL, MySQL, SQLite)
  • Flexible filtering with comparison operators (=, <>, >, <, >=, <=, LIKE, IN, NOT IN)
  • Pagination and ordering support
  • Field selection to retrieve only needed columns
  • Row locking support (FOR UPDATE)
  • Works with *sql.DB, *sql.Conn, and *sql.Tx
  • Built on top of sqlquery and scany

Installation

go get github.com/allisson/sqlutil

Table of Contents

Quick Start

package main

import (
	"context"
	"database/sql"
	"fmt"
	"log"

	"github.com/allisson/sqlutil"
	_ "github.com/lib/pq"
)

type User struct {
	ID    int    `db:"id"`
	Name  string `db:"name" fieldtag:"insert,update"`
	Email string `db:"email" fieldtag:"insert,update"`
	Age   int    `db:"age" fieldtag:"insert,update"`
}

func main() {
	// Connect to database
	db, err := sql.Open("postgres", "postgres://user:password@localhost/mydb?sslmode=disable")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	ctx := context.Background()
	flavor := sqlutil.PostgreSQLFlavor

	// Insert a user
	user := User{Name: "Alice", Email: "alice@example.com", Age: 30}
	if err := sqlutil.Insert(ctx, db, flavor, "insert", "users", &user); err != nil {
		log.Fatal(err)
	}

	// Get a user
	var alice User
	opts := sqlutil.NewFindOptions(flavor).WithFilter("email", "alice@example.com")
	if err := sqlutil.Get(ctx, db, "users", opts, &alice); err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Found user: %+v\n", alice)

	// Update the user
	alice.Age = 31
	if err := sqlutil.Update(ctx, db, flavor, "update", "users", alice.ID, &alice); err != nil {
		log.Fatal(err)
	}

	// Delete the user
	if err := sqlutil.Delete(ctx, db, flavor, "users", alice.ID); err != nil {
		log.Fatal(err)
	}
}

Database Setup

For the examples below, we'll use this table structure:

CREATE TABLE users (
	id SERIAL PRIMARY KEY,
	name VARCHAR(255) NOT NULL,
	email VARCHAR(255) UNIQUE NOT NULL,
	age INTEGER NOT NULL,
	country VARCHAR(100),
	active BOOLEAN DEFAULT true,
	created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Run a PostgreSQL database with Docker:

docker run --name sqlutil-postgres \
	-e POSTGRES_USER=user \
	-e POSTGRES_PASSWORD=password \
	-e POSTGRES_DB=sqlutil \
	-p 5432:5432 \
	-d postgres:14-alpine

Basic CRUD Operations

Insert

Insert a single record into the database:

package main

import (
	"context"
	"database/sql"
	"log"

	"github.com/allisson/sqlutil"
	_ "github.com/lib/pq"
)

type User struct {
	ID        int    `db:"id"`
	Name      string `db:"name" fieldtag:"insert,update"`
	Email     string `db:"email" fieldtag:"insert,update"`
	Age       int    `db:"age" fieldtag:"insert,update"`
	Country   string `db:"country" fieldtag:"insert,update"`
	Active    bool   `db:"active" fieldtag:"insert,update"`
}

func main() {
	db, _ := sql.Open("postgres", "postgres://user:password@localhost/sqlutil?sslmode=disable")
	defer db.Close()

	ctx := context.Background()
	flavor := sqlutil.PostgreSQLFlavor

	// Insert a new user
	newUser := User{
		Name:    "Bob Smith",
		Email:   "bob@example.com",
		Age:     28,
		Country: "USA",
		Active:  true,
	}

	// The "insert" tag tells sqlutil to use fields marked with fieldtag:"insert"
	if err := sqlutil.Insert(ctx, db, flavor, "insert", "users", &newUser); err != nil {
		log.Fatal(err)
	}

	log.Println("User inserted successfully")
}
Get (Single Record)

Retrieve a single record from the database:

// Get user by ID
var user User
opts := sqlutil.NewFindOptions(flavor).WithFilter("id", 1)
if err := sqlutil.Get(ctx, db, "users", opts, &user); err != nil {
	log.Fatal(err)
}
fmt.Printf("User: %+v\n", user)

// Get user by email
var userByEmail User
opts = sqlutil.NewFindOptions(flavor).WithFilter("email", "bob@example.com")
if err := sqlutil.Get(ctx, db, "users", opts, &userByEmail); err != nil {
	log.Fatal(err)
}

// Get user with specific fields only
var partialUser struct {
	ID    int    `db:"id"`
	Name  string `db:"name"`
	Email string `db:"email"`
}
opts = sqlutil.NewFindOptions(flavor).
	WithFields([]string{"id", "name", "email"}).
	WithFilter("id", 1)
if err := sqlutil.Get(ctx, db, "users", opts, &partialUser); err != nil {
	log.Fatal(err)
}
Select (Multiple Records)

Retrieve multiple records from the database:

// Get all users
var users []User
opts := sqlutil.NewFindAllOptions(flavor)
if err := sqlutil.Select(ctx, db, "users", opts, &users); err != nil {
	log.Fatal(err)
}
fmt.Printf("Found %d users\n", len(users))

// Get active users only
var activeUsers []User
opts = sqlutil.NewFindAllOptions(flavor).WithFilter("active", true)
if err := sqlutil.Select(ctx, db, "users", opts, &activeUsers); err != nil {
	log.Fatal(err)
}

// Get users with pagination
var pagedUsers []User
opts = sqlutil.NewFindAllOptions(flavor).
	WithLimit(10).
	WithOffset(0).
	WithOrderBy("created_at DESC")
if err := sqlutil.Select(ctx, db, "users", opts, &pagedUsers); err != nil {
	log.Fatal(err)
}
Update

Update existing records:

// Update user by ID
user := User{
	ID:      1,
	Name:    "Bob Smith Jr.",
	Email:   "bob.jr@example.com",
	Age:     29,
	Country: "USA",
	Active:  true,
}

// The "update" tag tells sqlutil to use fields marked with fieldtag:"update"
if err := sqlutil.Update(ctx, db, flavor, "update", "users", user.ID, &user); err != nil {
	log.Fatal(err)
}

// Update with custom options (more flexible)
updateOpts := sqlutil.NewUpdateOptions(flavor).
	WithSet("age", 30).
	WithSet("country", "Canada").
	WithFilter("id", 1)

if err := sqlutil.UpdateWithOptions(ctx, db, flavor, "users", updateOpts); err != nil {
	log.Fatal(err)
}

// Bulk update - update all inactive users
updateOpts = sqlutil.NewUpdateOptions(flavor).
	WithSet("active", false).
	WithFilter("age.lt", 18)

if err := sqlutil.UpdateWithOptions(ctx, db, flavor, "users", updateOpts); err != nil {
	log.Fatal(err)
}
Delete

Delete records from the database:

// Delete user by ID
if err := sqlutil.Delete(ctx, db, flavor, "users", 1); err != nil {
	log.Fatal(err)
}

// Delete with custom options (more flexible)
deleteOpts := sqlutil.NewDeleteOptions(flavor).WithFilter("active", false)
if err := sqlutil.DeleteWithOptions(ctx, db, flavor, "users", deleteOpts); err != nil {
	log.Fatal(err)
}

// Delete users older than 65
deleteOpts = sqlutil.NewDeleteOptions(flavor).WithFilter("age.gt", 65)
if err := sqlutil.DeleteWithOptions(ctx, db, flavor, "users", deleteOpts); err != nil {
	log.Fatal(err)
}

// Delete users from specific country
deleteOpts = sqlutil.NewDeleteOptions(flavor).WithFilter("country", "USA")
if err := sqlutil.DeleteWithOptions(ctx, db, flavor, "users", deleteOpts); err != nil {
	log.Fatal(err)
}

Advanced Queries

Filtering

sqlutil supports a wide range of filter operators:

ctx := context.Background()
flavor := sqlutil.PostgreSQLFlavor

// Equality
opts := sqlutil.NewFindAllOptions(flavor).WithFilter("age", 30)
// WHERE age = 30

// Not equal
opts = sqlutil.NewFindAllOptions(flavor).WithFilter("age.not", 30)
// WHERE age <> 30

// Greater than
opts = sqlutil.NewFindAllOptions(flavor).WithFilter("age.gt", 18)
// WHERE age > 18

// Greater than or equal
opts = sqlutil.NewFindAllOptions(flavor).WithFilter("age.gte", 18)
// WHERE age >= 18

// Less than
opts = sqlutil.NewFindAllOptions(flavor).WithFilter("age.lt", 65)
// WHERE age < 65

// Less than or equal
opts = sqlutil.NewFindAllOptions(flavor).WithFilter("age.lte", 65)
// WHERE age <= 65

// LIKE operator
opts = sqlutil.NewFindAllOptions(flavor).WithFilter("name.like", "%Smith%")
// WHERE name LIKE '%Smith%'

// IN operator
opts = sqlutil.NewFindAllOptions(flavor).WithFilter("country.in", "USA,Canada,Mexico")
// WHERE country IN ('USA', 'Canada', 'Mexico')

// NOT IN operator
opts = sqlutil.NewFindAllOptions(flavor).WithFilter("country.notin", "USA,Canada")
// WHERE country NOT IN ('USA', 'Canada')

// IS NULL
opts = sqlutil.NewFindAllOptions(flavor).WithFilter("country.null", true)
// WHERE country IS NULL

// IS NOT NULL
opts = sqlutil.NewFindAllOptions(flavor).WithFilter("country.null", false)
// WHERE country IS NOT NULL

// Multiple filters (AND condition)
opts = sqlutil.NewFindAllOptions(flavor).
	WithFilter("age.gte", 18).
	WithFilter("age.lte", 65).
	WithFilter("active", true).
	WithFilter("country", "USA")
// WHERE age >= 18 AND age <= 65 AND active = true AND country = 'USA'

// Complex example: Find active users aged 25-40 from specific countries
var users []User
opts = sqlutil.NewFindAllOptions(flavor).
	WithFilter("active", true).
	WithFilter("age.gte", 25).
	WithFilter("age.lte", 40).
	WithFilter("country.in", "USA,Canada,UK")

if err := sqlutil.Select(ctx, db, "users", opts, &users); err != nil {
	log.Fatal(err)
}
Field Selection

Retrieve only the fields you need:

// Define a struct with only the fields you need
type UserBasic struct {
	ID    int    `db:"id"`
	Name  string `db:"name"`
	Email string `db:"email"`
}

// Select only specific fields
var users []UserBasic
opts := sqlutil.NewFindAllOptions(flavor).
	WithFields([]string{"id", "name", "email"}).
	WithFilter("active", true)

if err := sqlutil.Select(ctx, db, "users", opts, &users); err != nil {
	log.Fatal(err)
}
// SELECT id, name, email FROM users WHERE active = true

// Get single user with limited fields
var userBasic UserBasic
opts := sqlutil.NewFindOptions(flavor).
	WithFields([]string{"id", "name", "email"}).
	WithFilter("id", 1)

if err := sqlutil.Get(ctx, db, "users", opts, &userBasic); err != nil {
	log.Fatal(err)
}
Pagination

Implement pagination for large result sets:

// Page 1: First 10 users
var page1 []User
opts := sqlutil.NewFindAllOptions(flavor).
	WithLimit(10).
	WithOffset(0).
	WithOrderBy("id ASC")

if err := sqlutil.Select(ctx, db, "users", opts, &page1); err != nil {
	log.Fatal(err)
}

// Page 2: Next 10 users
var page2 []User
opts = sqlutil.NewFindAllOptions(flavor).
	WithLimit(10).
	WithOffset(10).
	WithOrderBy("id ASC")

if err := sqlutil.Select(ctx, db, "users", opts, &page2); err != nil {
	log.Fatal(err)
}

// Pagination helper function
func GetUserPage(ctx context.Context, db *sql.DB, page, pageSize int) ([]User, error) {
	var users []User
	offset := (page - 1) * pageSize
	
	opts := sqlutil.NewFindAllOptions(flavor).
		WithLimit(pageSize).
		WithOffset(offset).
		WithOrderBy("id ASC")
	
	err := sqlutil.Select(ctx, db, "users", opts, &users)
	return users, err
}

// Usage
page1Users, err := GetUserPage(ctx, db, 1, 20) // First page, 20 items
page2Users, err := GetUserPage(ctx, db, 2, 20) // Second page, 20 items
Ordering

Sort results by one or multiple columns:

// Order by single column ascending
opts := sqlutil.NewFindAllOptions(flavor).WithOrderBy("name ASC")

// Order by single column descending
opts = sqlutil.NewFindAllOptions(flavor).WithOrderBy("created_at DESC")

// Order by multiple columns
opts = sqlutil.NewFindAllOptions(flavor).WithOrderBy("country ASC, age DESC")

// Complex example: Get top 10 youngest active users from USA
var youngUsers []User
opts = sqlutil.NewFindAllOptions(flavor).
	WithFilter("active", true).
	WithFilter("country", "USA").
	WithOrderBy("age ASC").
	WithLimit(10)

if err := sqlutil.Select(ctx, db, "users", opts, &youngUsers); err != nil {
	log.Fatal(err)
}
Row Locking

Use row locking for concurrent operations:

// FOR UPDATE - locks rows for update
opts := sqlutil.NewFindAllOptions(flavor).
	WithFilter("active", true).
	WithForUpdate("")

// FOR UPDATE SKIP LOCKED - skip rows that are already locked
opts = sqlutil.NewFindAllOptions(flavor).
	WithFilter("active", true).
	WithForUpdate("SKIP LOCKED")

// FOR UPDATE NOWAIT - return immediately if rows are locked
opts = sqlutil.NewFindAllOptions(flavor).
	WithFilter("active", true).
	WithForUpdate("NOWAIT")

// Example: Process queue items with row locking
tx, err := db.BeginTx(ctx, nil)
if err != nil {
	log.Fatal(err)
}
defer tx.Rollback()

var queueItems []QueueItem
opts := sqlutil.NewFindAllOptions(flavor).
	WithFilter("status", "pending").
	WithOrderBy("created_at ASC").
	WithLimit(10).
	WithForUpdate("SKIP LOCKED")

if err := sqlutil.Select(ctx, tx, "queue", opts, &queueItems); err != nil {
	log.Fatal(err)
}

// Process items...
for _, item := range queueItems {
	// Process item
	updateOpts := sqlutil.NewUpdateOptions(flavor).
		WithSet("status", "processed").
		WithFilter("id", item.ID)
	
	if err := sqlutil.UpdateWithOptions(ctx, tx, flavor, "queue", updateOpts); err != nil {
		log.Fatal(err)
	}
}

tx.Commit()

Bulk Operations

Efficiently handle multiple operations:

// Insert multiple users
users := []User{
	{Name: "Alice", Email: "alice@example.com", Age: 30, Country: "USA"},
	{Name: "Bob", Email: "bob@example.com", Age: 25, Country: "Canada"},
	{Name: "Charlie", Email: "charlie@example.com", Age: 35, Country: "UK"},
}

for _, user := range users {
	if err := sqlutil.Insert(ctx, db, flavor, "insert", "users", &user); err != nil {
		log.Fatal(err)
	}
}

// Bulk update with filter
updateOpts := sqlutil.NewUpdateOptions(flavor).
	WithSet("active", false).
	WithFilter("country.in", "USA,Canada,Mexico")

if err := sqlutil.UpdateWithOptions(ctx, db, flavor, "users", updateOpts); err != nil {
	log.Fatal(err)
}

// Bulk delete with filter
deleteOpts := sqlutil.NewDeleteOptions(flavor).
	WithFilter("active", false).
	WithFilter("age.lt", 18)

if err := sqlutil.DeleteWithOptions(ctx, db, flavor, "users", deleteOpts); err != nil {
	log.Fatal(err)
}

Using with Transactions

sqlutil works seamlessly with database transactions:

// Start a transaction
tx, err := db.BeginTx(ctx, nil)
if err != nil {
	log.Fatal(err)
}
defer tx.Rollback() // Rollback if not committed

// Insert user
user := User{Name: "David", Email: "david@example.com", Age: 40, Country: "France"}
if err := sqlutil.Insert(ctx, tx, flavor, "insert", "users", &user); err != nil {
	log.Fatal(err)
}

// Get the inserted user
var insertedUser User
opts := sqlutil.NewFindOptions(flavor).WithFilter("email", "david@example.com")
if err := sqlutil.Get(ctx, tx, "users", opts, &insertedUser); err != nil {
	log.Fatal(err)
}

// Update the user
insertedUser.Age = 41
if err := sqlutil.Update(ctx, tx, flavor, "update", "users", insertedUser.ID, &insertedUser); err != nil {
	log.Fatal(err)
}

// Commit the transaction
if err := tx.Commit(); err != nil {
	log.Fatal(err)
}

// Example: Transfer operation with rollback
func TransferUser(ctx context.Context, db *sql.DB, userID int, newCountry string) error {
	tx, err := db.BeginTx(ctx, nil)
	if err != nil {
		return err
	}
	defer tx.Rollback()

	// Get user
	var user User
	opts := sqlutil.NewFindOptions(flavor).WithFilter("id", userID)
	if err := sqlutil.Get(ctx, tx, "users", opts, &user); err != nil {
		return err
	}

	// Update country
	updateOpts := sqlutil.NewUpdateOptions(flavor).
		WithSet("country", newCountry).
		WithFilter("id", userID)
	
	if err := sqlutil.UpdateWithOptions(ctx, tx, flavor, "users", updateOpts); err != nil {
		return err
	}

	// Commit transaction
	return tx.Commit()
}

Multiple SQL Flavors

sqlutil supports PostgreSQL, MySQL, and SQLite:

PostgreSQL
import (
	"github.com/allisson/sqlutil"
	_ "github.com/lib/pq"
)

db, _ := sql.Open("postgres", "postgres://user:password@localhost/mydb?sslmode=disable")
flavor := sqlutil.PostgreSQLFlavor

opts := sqlutil.NewFindOptions(flavor).WithFilter("id", 1)
MySQL
import (
	"github.com/allisson/sqlutil"
	_ "github.com/go-sql-driver/mysql"
)

db, _ := sql.Open("mysql", "user:password@tcp(localhost:3306)/mydb")
flavor := sqlutil.MySQLFlavor

opts := sqlutil.NewFindOptions(flavor).WithFilter("id", 1)
SQLite
import (
	"github.com/allisson/sqlutil"
	_ "github.com/mattn/go-sqlite3"
)

db, _ := sql.Open("sqlite3", "./mydb.db")
flavor := sqlutil.SQLiteFlavor

opts := sqlutil.NewFindOptions(flavor).WithFilter("id", 1)
Cross-Database Compatibility

Write database-agnostic code by passing the flavor as a parameter:

type UserRepository struct {
	db     *sql.DB
	flavor sqlutil.Flavor
}

func NewUserRepository(db *sql.DB, flavor sqlutil.Flavor) *UserRepository {
	return &UserRepository{db: db, flavor: flavor}
}

func (r *UserRepository) GetByID(ctx context.Context, id int) (*User, error) {
	var user User
	opts := sqlutil.NewFindOptions(r.flavor).WithFilter("id", id)
	err := sqlutil.Get(ctx, r.db, "users", opts, &user)
	return &user, err
}

func (r *UserRepository) GetActiveUsers(ctx context.Context) ([]User, error) {
	var users []User
	opts := sqlutil.NewFindAllOptions(r.flavor).
		WithFilter("active", true).
		WithOrderBy("name ASC")
	err := sqlutil.Select(ctx, r.db, "users", opts, &users)
	return users, err
}

// Works with any database flavor
pgRepo := NewUserRepository(pgDB, sqlutil.PostgreSQLFlavor)
mysqlRepo := NewUserRepository(mysqlDB, sqlutil.MySQLFlavor)
sqliteRepo := NewUserRepository(sqliteDB, sqlutil.SQLiteFlavor)

Complete Example

Here's a complete example demonstrating various features:

package main

import (
	"context"
	"database/sql"
	"fmt"
	"log"

	"github.com/allisson/sqlutil"
	_ "github.com/lib/pq"
)

type User struct {
	ID        int    `db:"id"`
	Name      string `db:"name" fieldtag:"insert,update"`
	Email     string `db:"email" fieldtag:"insert,update"`
	Age       int    `db:"age" fieldtag:"insert,update"`
	Country   string `db:"country" fieldtag:"insert,update"`
	Active    bool   `db:"active" fieldtag:"insert,update"`
}

func main() {
	// Connect to database
	db, err := sql.Open("postgres", "postgres://user:password@localhost/sqlutil?sslmode=disable")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	ctx := context.Background()
	flavor := sqlutil.PostgreSQLFlavor

	// Create table
	_, err = db.ExecContext(ctx, `
		CREATE TABLE IF NOT EXISTS users (
			id SERIAL PRIMARY KEY,
			name VARCHAR(255) NOT NULL,
			email VARCHAR(255) UNIQUE NOT NULL,
			age INTEGER NOT NULL,
			country VARCHAR(100),
			active BOOLEAN DEFAULT true
		)
	`)
	if err != nil {
		log.Fatal(err)
	}

	// Insert users
	users := []User{
		{Name: "Alice Johnson", Email: "alice@example.com", Age: 30, Country: "USA", Active: true},
		{Name: "Bob Smith", Email: "bob@example.com", Age: 25, Country: "Canada", Active: true},
		{Name: "Charlie Brown", Email: "charlie@example.com", Age: 35, Country: "UK", Active: true},
		{Name: "David Lee", Email: "david@example.com", Age: 28, Country: "USA", Active: false},
	}

	for _, user := range users {
		if err := sqlutil.Insert(ctx, db, flavor, "insert", "users", &user); err != nil {
			log.Printf("Error inserting user: %v", err)
		}
	}

	// Get single user by email
	var alice User
	opts := sqlutil.NewFindOptions(flavor).WithFilter("email", "alice@example.com")
	if err := sqlutil.Get(ctx, db, "users", opts, &alice); err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Found user: %+v\n", alice)

	// Get all active users from USA
	var activeUSAUsers []User
	opts2 := sqlutil.NewFindAllOptions(flavor).
		WithFilter("active", true).
		WithFilter("country", "USA").
		WithOrderBy("name ASC")
	
	if err := sqlutil.Select(ctx, db, "users", opts2, &activeUSAUsers); err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Active USA users: %d\n", len(activeUSAUsers))

	// Get users with age between 25 and 30
	var youngUsers []User
	opts3 := sqlutil.NewFindAllOptions(flavor).
		WithFilter("age.gte", 25).
		WithFilter("age.lte", 30).
		WithOrderBy("age ASC")
	
	if err := sqlutil.Select(ctx, db, "users", opts3, &youngUsers); err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Users aged 25-30: %d\n", len(youngUsers))

	// Update user
	alice.Age = 31
	alice.Country = "Canada"
	if err := sqlutil.Update(ctx, db, flavor, "update", "users", alice.ID, &alice); err != nil {
		log.Fatal(err)
	}

	// Bulk update: deactivate all users older than 30
	updateOpts := sqlutil.NewUpdateOptions(flavor).
		WithSet("active", false).
		WithFilter("age.gt", 30)
	
	if err := sqlutil.UpdateWithOptions(ctx, db, flavor, "users", updateOpts); err != nil {
		log.Fatal(err)
	}

	// Get users with pagination
	page1 := []User{}
	paginationOpts := sqlutil.NewFindAllOptions(flavor).
		WithLimit(2).
		WithOffset(0).
		WithOrderBy("name ASC")
	
	if err := sqlutil.Select(ctx, db, "users", paginationOpts, &page1); err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Page 1: %d users\n", len(page1))

	// Delete inactive users
	deleteOpts := sqlutil.NewDeleteOptions(flavor).WithFilter("active", false)
	if err := sqlutil.DeleteWithOptions(ctx, db, flavor, "users", deleteOpts); err != nil {
		log.Fatal(err)
	}
	fmt.Println("Inactive users deleted")
}

License

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

Contributing

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

  • sqlquery - SQL query builder for Go
  • scany - Library for scanning data from a database into Go structs

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	MySQLFlavor      = sqlquery.MySQLFlavor
	PostgreSQLFlavor = sqlquery.PostgreSQLFlavor
	SQLiteFlavor     = sqlquery.SQLiteFlavor
)

Functions

func Delete

func Delete(ctx context.Context, db Querier, flavor Flavor, tableName string, id interface{}) error

Delete deletes a record from the database table by its ID. It builds a DELETE query using sqlquery.DeleteQuery with a WHERE clause matching the given ID, then executes the query.

func DeleteWithOptions added in v1.8.0

func DeleteWithOptions(ctx context.Context, db Querier, flavor Flavor, tableName string, options *DeleteOptions) error

DeleteWithOptions deletes records from the database table based on custom criteria. It builds a DELETE query using sqlquery.DeleteWithOptionsQuery with the provided options, which allow for complex WHERE clauses to match multiple records. This provides more flexibility than the simple Delete function.

func Get

func Get(ctx context.Context, db Querier, tableName string, options *FindOptions, dst interface{}) error

Get retrieves a single record from the database and scans it into dst. It builds a SELECT query using sqlquery.FindQuery with the provided options, then uses scany's sqlscan.Get to scan the result into the destination struct. Returns an error if no rows are found or if scanning fails.

func Insert

func Insert(ctx context.Context, db Querier, flavor Flavor, tag, tableName string, structValue interface{}) error

Insert inserts a new record into the database table. It builds an INSERT query using sqlquery.InsertQuery based on the struct fields that match the specified tag (e.g., "insert"), then executes the query. The structValue parameter should be a pointer to a struct with appropriate field tags.

func Select

func Select(ctx context.Context, db Querier, tableName string, options *FindAllOptions, dst interface{}) error

Select retrieves multiple records from the database and scans them into dst. It builds a SELECT query using sqlquery.FindAllQuery with the provided options, then uses scany's sqlscan.Select to scan the results into the destination slice. The dst parameter should be a pointer to a slice of structs.

func Update

func Update(ctx context.Context, db Querier, flavor Flavor, tag, tableName string, id interface{}, structValue interface{}) error

Update updates an existing record in the database table by its ID. It builds an UPDATE query using sqlquery.UpdateQuery based on the struct fields that match the specified tag (e.g., "update"), adding a WHERE clause for the given ID. The structValue parameter should be a pointer to a struct with appropriate field tags.

func UpdateWithOptions added in v1.8.0

func UpdateWithOptions(ctx context.Context, db Querier, flavor Flavor, tableName string, options *UpdateOptions) error

UpdateWithOptions updates records in the database table based on custom criteria. It builds an UPDATE query using sqlquery.UpdateWithOptionsQuery with the provided options, which allow for complex WHERE clauses and multiple field updates. This provides more flexibility than the simple Update function.

Types

type DeleteOptions added in v1.8.0

type DeleteOptions = sqlquery.DeleteOptions

func NewDeleteOptions added in v1.8.0

func NewDeleteOptions(flavor Flavor) *DeleteOptions

NewDeleteOptions creates and returns a new DeleteOptions instance for the specified SQL flavor. DeleteOptions is used to build DELETE queries with support for filtering conditions.

type FindAllOptions

type FindAllOptions = sqlquery.FindAllOptions

func NewFindAllOptions

func NewFindAllOptions(flavor Flavor) *FindAllOptions

NewFindAllOptions creates and returns a new FindAllOptions instance for the specified SQL flavor. FindAllOptions is used to build queries for finding multiple records with support for field selection, filtering, pagination (limit/offset), ordering, and row locking (FOR UPDATE).

type FindOptions

type FindOptions = sqlquery.FindOptions

func NewFindOptions

func NewFindOptions(flavor Flavor) *FindOptions

NewFindOptions creates and returns a new FindOptions instance for the specified SQL flavor. FindOptions is used to build queries for finding a single record with support for field selection, filtering, and various comparison operators.

type Flavor

type Flavor = sqlquery.Flavor

type Querier added in v1.2.0

type Querier interface {
	QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)
	ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
}

Querier is an abstraction over *sql.DB, *sql.Conn, and *sql.Tx. It provides a common interface for executing queries and commands against a database, allowing functions to work with any of these types.

type UpdateOptions added in v1.8.0

type UpdateOptions = sqlquery.UpdateOptions

func NewUpdateOptions added in v1.8.0

func NewUpdateOptions(flavor Flavor) *UpdateOptions

NewUpdateOptions creates and returns a new UpdateOptions instance for the specified SQL flavor. UpdateOptions is used to build UPDATE queries with support for filtering and setting multiple fields.

Jump to

Keyboard shortcuts

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