Categorygithub.com/alexandergrom/qp
repositorypackage
0.2.1
Repository: https://github.com/alexandergrom/qp.git
Documentation: pkg.go.dev

# README

qp

Go Report Card GoDoc

Package qp is a simple query formatter.

Get the package

$ go get -u github.com/alexandergrom/qp

Use

var b = qp.
    Format("name = %p", "Tom").
    Format("age IN (%+p)", 18, 21, 30)

var q = qp.Query("SELECT id FROM table WHERE %s LIMIT %p", b, 10)
_ = q.String() // SELECT id FROM table WHERE name = $1 AND age IN ($2, $3, $4) LIMIT $5
_ = q.Params() // ["Tom", 18, 21, 30, 10]

The verbs

%s		convert to string
%p		convert to one placeholder or slice placeholders

The modifiers

+		capture all parameters

Examples

qp.Format("name: %s", "Tom Sawyer").String() // name: Tom Sawyer
qp.Format("name: %p", "Tom Sawyer").String() // name: $1

Slice processing ([]int, []int64, []string, []interface{})

qp.Format("fields: %s", []string{"id", "name", "age"}).String() // fields: id, name, age
qp.Format("params: %p", []string{"id", "name", "age"}).String() // params: $1, $2, $3

qp.Format("ints: %s", []int64{1, 2, 3}).String() // ints: 1, 2, 3
qp.Format("ints: %p", []int64{1, 2, 3}).String() // ints: $1, $2, $3

Modifiers

qp.Format("fields: %+s", "id", "name", "age").String() // fields: id, name, age
qp.Format("params: %+p", "id", "name", "age").String() // fields: $1, $2, $3

Some more complicated examples

qp.Format("params: %p", []interface{}{1, 2, 3, "four", []int{5, 6}}).String() // params: $1, $2, $3, $4, $5, $6
qp.Format("params: %+p", []int64{1, 2, 3}, 4).String() // params: $1, $2, $3, $4

Other examples

ids := []int64{1, 2, 3, 4, 5, 6}
query := qp.Format("SELECT name FROM users WHERE id IN (%p) LIMIT %p", ids, 10)
q := query.String() // SELECT name FROM users WHERE id IN ($1, $2, $3, $4, $5, $6) LIMIT $7
p := query.Params() // [1, 2, 3, 4, 5, 6, 10]

Nested format

filter := qp.
    Format("name = %p", "Tom").
    Format("age = %p", 12)
query := qp.Format("SELECT name FROM users WHERE %s LIMIT %p", filter, 10)
q := query.String() // SELECT name FROM users WHERE name = $1 AND age = $2 LIMIT $3
p := query.Params() // ["Tom", 12, 10]

Update

fields := []string{"name", "age"}
params := []interface{}{"Tom", 12}
query := qp.Format("UPDATE users SET (%s) = (%p) WHERE id = %p", fields, params, 1)
q := query.String() // UPDATE users SET (name, age) = ($1, $2) WHERE id = $3
p := query.Params() // ["Tom", 12, 1]

Insert

values := qp.
    Format("(%+p)", 1, "Tom", 12).
    Format("(%+p)", 2, "Huckleberry", 13).
    Jumper(", ")
query := qp.Format("INSERT INTO users (id, name, age) VALUES %s", values)
q := query.String() // INSERT INTO users (id, name, age) VALUES ($1, $2, $3), ($4, $5, $6)
p := query.Params() // [1, "Tom", 12, 2, "Huckleberry", 13]

Insert

values := qp.New().Jumper(", ")
for _, d := range data {
	values.Format("(%p)", d)
}
query := qp.Format("INSERT INTO users (id, name, age) VALUES %s", values)
q := query.String() // INSERT INTO users (id, name, age) VALUES ($1, $2, $3), ($4, $5, $6)
p := query.Params() // [1, "Tom", 12, 2, "Huckleberry", 13]

Filter

type (
    CarFilter struct {
        Mark      string
        Model     string
        Color     []int
        Price     []int
        Limit     int
        Offset    int
    }

    Car struct {
        Mark      string
        Model     string
        Color     int
        Price     int
        CreatedAt time.Time
        UpdatedAt time.Time
    }

    CarRepository struct {
        db *sql.DB
    }
)

func (r *CarRepository) GetByFilter(filter CarFilter) (_ []*Car, err error) {
    var builder = qp.Format("1=1")

    if len(filter.Mark) > 0 {
        builder.Format("mark = %p", filter.Mark)
    }

    if len(filter.Model) > 0 {
        builder.Format("model = %p", filter.Model)
    }

    if len(filter.Color) > 0 {
        builder.Format("color IN (%p)", colors)
    }

    if len(filter.Price) == 1 {
        builder.Format("price <= %p", filter.Price[0])
    } else if len(filter.Price) == 2 {
        builder.
            Format("price >= %p", filter.Price[0]).
            Format("price <= %p", filter.Price[1])
    }

    var query = qp.Format(`
        SELECT mark, model, color, price, created_at, updated_at
        FROM cars
        WHERE %s
        LIMIT %p
        OFFSET %p
    `, builder, filter.Limit, filter.Offset)

    var rows *sql.Rows
    if rows, err = r.db.Query(query.String(), query.Params()...); err != nil {
        return nil, err
    }
    defer rows.Close()

    var cars = make([]*Car, 0, filter.Limit)
    for rows.Next() {
        var car = new(Car)

        if err = rows.Scan(&car.Mark, &car.Model, &car.Color, &car.Price, &car.CreatedAt, &car.UpdatedAt); err != nil {
            return nil, err
        }

        cars = append(cars, car)
    }

    return cars, rows.Err()
}