Skip to content

Commit

Permalink
Add New and BuildFn (#29)
Browse files Browse the repository at this point in the history
  • Loading branch information
cristaloleg authored Oct 26, 2023
1 parent c0f250f commit 4fea658
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 20 deletions.
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ This tiny library helps to build queries and handles parameter indexing.
## Features

* Simple and easy.
* Safe & fast.
* Safe and fast.
* Tested.
* Dependency-free.

See [these docs][pkg-url] or [GUIDE.md](GUIDE.md) for more details.
See [docs][pkg-url] or [GUIDE.md](GUIDE.md) for more details.

## Install

Expand All @@ -36,12 +36,12 @@ go get github.com/cristalhq/builq
```go
cols := builq.Columns{"foo, bar"}

var b builq.Builder
b.Addf("SELECT %s FROM %s", cols, "users").
Addf("WHERE active IS TRUE").
Addf("AND user_id = %$ OR user = %$", 42, "root")
q := builq.New()
q("SELECT %s FROM %s", cols, "users")
q("WHERE active IS TRUE")
q("AND user_id = %$ OR user = %$", 42, "root")

query, args, err := b.Build()
query, args, err := q.Build()
if err != nil {
panic(err)
}
Expand Down
53 changes: 40 additions & 13 deletions builq.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,31 @@ type OnelineBuilder struct {
Builder
}

// BuildFn represents [Builder.Addf]. Just for the easier BuilderFunc declaration.
type BuildFn func(format constString, args ...any) *Builder

// Build the query and arguments.
func (q BuildFn) Build() (query string, args []any, err error) {
return q("").Build()
}

// DebugBuild the query, good for debugging but not for REAL usage.
func (q BuildFn) DebugBuild() string {
return q("").DebugBuild()
}

// New returns a new query builder, same as [Builder].
func New() BuildFn {
var b Builder
return b.Addf
}

// New returns a new query builder, same as [OnelineBuilder].
func NewOneline() BuildFn {
var b OnelineBuilder
return b.Addf
}

// Addf formats according to a format specifier, writes to query and appends args.
// Format param must be a constant string.
func (b *OnelineBuilder) Addf(format constString, args ...any) *Builder {
Expand All @@ -56,30 +81,32 @@ func (b *Builder) Addf(format constString, args ...any) *Builder {
return b.addf(format, args...)
}

func (b *Builder) addf(format constString, args ...any) *Builder {
if len(b.parts) == 0 {
// TODO: better defaults
b.parts = make([]string, 0, 10)
b.args = make([][]any, 0, 10)
}
b.parts = append(b.parts, string(format))
b.args = append(b.args, args)
return b
}

// Build the query and arguments.
func (b *Builder) Build() (query string, args []any, err error) {
query, args = b.build()
return query, args, b.err
}

// DebugBuild the query, good for debugging but not for REAL usage.
func (b *Builder) DebugBuild() (query string) {
b.debug = true
query, _ = b.build()
b.debug = false
return query
}

func (b *Builder) build() (string, []any) {
func (b *Builder) addf(format constString, args ...any) *Builder {
if len(b.parts) == 0 {
// TODO: better defaults
b.parts = make([]string, 0, 10)
b.args = make([][]any, 0, 10)
}
b.parts = append(b.parts, string(format))
b.args = append(b.args, args)
return b
}

func (b *Builder) build() (_ string, _ []any) {
var query strings.Builder
// TODO: better default (sum of parts + est len of indexes)
query.Grow(100)
Expand Down Expand Up @@ -121,7 +148,7 @@ var (
// errUnsupportedVerb when %X is found and X isn't supported.
errUnsupportedVerb = errors.New("unsupported verb")

// errIncorrectVerb is passed like `%+`.`
// errIncorrectVerb is passed like `%+`.
errIncorrectVerb = errors.New("incorrect verb")

// errMixedPlaceholders when $ AND ? are mixed in 1 query.
Expand Down
27 changes: 27 additions & 0 deletions example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,33 @@ import (
"github.com/cristalhq/builq"
)

func ExampleNew() {
cols := builq.Columns{"foo, bar"}

q := builq.New()
q("SELECT %s FROM %s", cols, "users")
q("WHERE active IS TRUE")
q("AND user_id = %$ OR user = %$", 42, "root")

query, args, err := q.Build()
if err != nil {
panic(err)
}

fmt.Printf("query:\n%v", query)
fmt.Printf("args:\n%v", args)

// Output:
//
// query:
// SELECT foo, bar FROM users
// WHERE active IS TRUE
// AND user_id = $1 OR user = $2
//
// args:
// [42 root]
}

func ExampleBuilder() {
cols := builq.Columns{"foo", "bar"}

Expand Down

0 comments on commit 4fea658

Please sign in to comment.