sqlb

package module
v1.0.7 Latest Latest
Warning

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

Go to latest
Published: Sep 6, 2025 License: Unlicense Imports: 15 Imported by: 0

README

Overview

sqlb: SQL Builder for Go. Features:

  • Supports plain SQL queries with ordinal or named params.
    • Supports argument lists.
    • Supports argument maps.
    • Supports argument structs.
  • Supports generating SQL clauses from structs.
    • Generate "select" clauses from structs.
    • Generate "insert" clauses from structs.
    • Generate "update" clauses from structs.
    • Generate "delete" clauses from structs.
    • Generate "and" and "or" conditional clauses from structs.
  • Provides data structures forming an SQL DSL in Go.
    • Shortcuts for common queries such as select, insert, update, delete.
    • Arbitrarily composable and nestable.
    • Uses data literals, not a builder API.
  • Supports an optional "JSON Expression Language" (JEL) for expressing SQL expressions with nested Lisp-style calls in JSON.
  • Supports safely parsing "order by" clauses from JSON and text, for specific struct types, converting field names from "json" field tags to "db" field tags.
  • Supports "sparse" structs, where not all fields are "present", allowing to implement HTTP PATCH semantics without sacrificing static typing.
  • Compatible with standard SQL syntax, biased towards Postgres.
  • Decently optimized.
  • Small and dependency-free.

API docs: https://pkg.go.dev/github.com/mitranim/sqlb.

See the sibling library https://github.com/mitranim/gos for scanning SQL rows into structs.

Examples

All examples imply the following import:

import s "github.com/mitranim/sqlb"

Query with named parameters and structs

func ExampleStrQ_structs() {
  type Output struct {
    Col0 string `db:"col0"`
    Col1 string `db:"col1"`
  }

  type Filter struct {
    Col2 int64 `db:"col2"`
    Col3 int64 `db:"col3"`
  }

  fmt.Println(s.Reify(
    s.StrQ{`
      select :cols from some_table where :filter
    `, s.Dict{
      `cols`:   s.Cols{(*Output)(nil)},
      `filter`: s.And{Filter{10, 20}},
    }},
  ))
  // Output:
  // select "col0", "col1" from some_table where "col2" = $1 and "col3" = $2 [10 20]
}

AST-style query building

func ExampleInsert_nonEmpty() {
  type Fields struct {
    Col0 int64 `db:"col0"`
    Col1 int64 `db:"col1"`
  }

  fmt.Println(s.Reify(s.Insert{`some_table`, Fields{10, 20}}))

  // Output:
  // insert into "some_table" ("col0", "col1") values ($1, $2) returning * [10 20]
}

Composition

func Example_composition() {
  inner := s.StrQ{
    `select * from some_table where col0 = :val`,
    s.Dict{`val`: 10},
  }

  outer := s.StrQ{
    `select * from (:inner) as _ where col1 = :val`,
    s.Dict{`inner`: inner, `val`: 20},
  }

  fmt.Println(s.Reify(outer))
  // Output:
  // select * from (select * from some_table where col0 = $1) as _ where col1 = $2 [10 20]
}

Changelog

v0.7.4

Minor fix for reporting types in error messages. Some internal tweaks.

v0.7.3

Added UpsertConflictVoid, UpsertConflict.

v0.7.2

Added ValidateUnusedArguments that globally disables or enables argument validation.

Internal improvements in errors.

v0.7.1

Added InsertVoid, UpdateVoid, DeleteVoid, UpsertVoid.

v0.7.0

Renamed method .Append in various types to .AppendTo for consistency with other libraries.

Renamed interface Appender to AppenderTo.

v0.6.8

Added LaxDict: dictionary of named arguments similar to Dict, but without support for validating unused arguments.

v0.6.7

Fixed an edge case bug in Upsert.

v0.6.6

Fixed support for non-empty sparse structs in Upsert.

v0.6.5

Add Upsert.

v0.6.4

OrdsParser support default "dir" and "nulls" in struct tags:

type Ordable struct {
  Name string `json:"name" db:"name" ord.dir:"desc" ord.nulls:"last"`
}

v0.6.3

  • Dir supports text parsing and encoding.
  • Minor breaking change: Bui.Arg now appends both an argument and a parameter.

v0.6.2

CommaAppender and ArrayAppender are now parametrized on the element type.

v0.6.1

Added StructsInsert, StructsInsertOf.

v0.6.0

  • Support role:"ref" struct field annotation for pointer-like generic types.

  • Require Go 1.18.

v0.5.3

Added SliceCommaAppender.

v0.5.2

Update now defaults to where null rather than where true. The new behavior is aligned with Delete.

Embedded struct fields tagged with db:"" or db:"-" are now completely ignored. The old behavior treated them as untagged, traversing them. The new behavior allows to completely skip an embedded struct, on an opt-in basis, without having to modify the db tags of its inner fields.

v0.5.1

Added optional support for a hidden Nullable interface, shared with the library github.com/mitranim/gt.

v0.5.0

  • Revised ords parsing.
    • Split OrdsParser into two types:
      • ParserOrds → suitable for inclusion into other types.
      • OrdsParser → suitable for transient, stackframe-local use.
    • Added (*Ords).OrdsParser suitable for use by types that embed Ords and implement custom parsing methods.
    • Support arbitrary filters for struct fields.
    • Added TagFilter for field filtering.
  • Renamed Sparse.HasField to Sparse.AllowField. Filter uses a method with the same signature, and the old name didn't make sense for it.
  • Misc:
    • Renamed (*Ords).AppendVals(*Ords).Add.
    • Added (*Ords).Zero.
    • Replaced Ords.Grow with (*Ords).Grow that modifies the receiver.

v0.4.3

Add SelectCount.

v0.4.2

Add Limit, Offset, LimitUint, OffsetUint.

v0.4.1

Exported ErrEmptyAssign used by StructAssign and Update to indicate the inability to generate a valid SQL "update set" clause.

v0.4.0

Added low-level tools for text encoding and SQL array encoding:

  • ArrayAppender
  • CommaAppender
  • String
  • TryString
  • Append
  • TryAppend
  • TryAppendWith
  • AppendWith
  • AppenderString

Breaking changes:

  • Removed useless expression type Int.
  • Renamed Bui.TryExprs to Bui.CatchExprs.

v0.3.0

Revised AST-style expressions:

  • Removed uselessly low-level exprs such as Space, ReturningStar, and so on.
  • Added higher-level shortcuts for extremely common yet simple operations:
    • Select
    • Insert
    • Update
    • Delete

v0.2.1

Added Sparse and Partial to support "sparse" structs, allowing to implement HTTP PATCH semantics more easily, efficiently, and correctly.

v0.2.0

Full API revision. Added many AST/DSL-like types for common expressions. Optimized parsing and expression building. Use caching and pooling to minimize redundant work. String-based query building now uses partial parsing with caching, and should no longer be a measurable expense. Ported JEL support from github.com/mitranim/jel.

v0.1.17

Added Ords.OrType.

v0.1.16

Added NamedArg.Norm. Improved NamedArg.IsNil and NamedArgs.Conditions. They now use the driver.Valuer.Value method, if present, to determine null-ness, which works for non-pointer "nullable" types.

v0.1.15

Ords.Or is now a value method that returns a modified version, rather than a pointer method that mutated the original.

v0.1.14

StructMap and StructNamedArgs now tolerate nil inputs. Previously, they tolerated non-nil interfaces where the underlying value was a nil struct pointer. Now they also allow nil interfaces.

v0.1.13

Fixed the bug where the Ords.Lax mode was appending malformed ords, instead of skipping them entirely.

v0.1.12

  • StrQuery now interpolates directly, without invoking (*Query).Append on the provided query. This allows to interpolate StrQuery strings that contain parameter placeholders. Use at your own risk.

  • (*Query).Append no longer has an argument length limit.

v0.1.11

Added Ords.Lax: a boolean that causes Ords to skip unknown fields during parsing.

v0.1.10

Breaking changes in the name of efficiency:

  • NamedArgs.Conditions now uses = and is null, as appropriate, instead of previous is not distinct from. At the time of writing, Postgres (version <= 12) is unable to use indexes for is not distinct from, which may result in much slower queries. The new approach avoids this gotcha.

  • In Ord, nulls last is now opt-in rather than default. In addition, asc/desc in input strings is now optional. This more precisely reflects SQL semantics and allows finer-grained control. More importantly, it avoids a potential performance gotcha. At the time of writing, Postgres (version <= 12) is unable to use normal indexes for nulls last ordering. Instead it requires specialized indexes where nulls last is set explicitly. Making it opt-in reduces the chance of accidental slowness.

    • Added OrdAscNl and OrdDescNl for convenient construction.

    • Minor breaking change: Ord.IsDesc is now Ord.Desc.

  • Minor breaking change: removed Ord.IsValid.

Non-breaking additions:

  • Ords.RowNumber(): generates a Postgres window function expression row_number() over (order by ...), falling back on a constant value when the ordering is empty.

  • QueryOrd(): shortcut for making a Query with a single .Append() invocation.

  • QueryNamed(): shortcut for making a Query with a single .AppendNamed() invocation.

0.1.9

Added Ords and Ord: structured representation of order by, able to decode from external input such as JSON, but also flexible enough to store arbitrary sub-queries. Ported from github.com/mitranim/jel, while also adding the ability to store sub-queries rather than only identifiers.

0.1.8

Added StrQuery.

0.1.7

Corrected CheckUnused to be true by default, which was always intended.

0.1.6

Added CheckUnused which allows to opt out of unused parameter checks in Query.Append and Query.AppendNamed. Can be convenient for development.

0.1.5

Minor bugfix: Query.String is now implemented on the non-pointer type, as intended. Also updated the sqlp dependency.

0.1.4

Breaking changes in Query: simpler interface, better performance.

Instead of storing and operating on a parsed AST, Query now stores the query text as []byte. We use sqlp.Tokenizer to parse inputs without generating an AST, transcoding parameters on the fly. IQuery now simply appends to an externally-passed Query, instead of having to return a parsed AST representation. All together, this significantly simplifies the implementation of Query and any external IQuery types.

0.1.3

Added Query.Clear().

0.1.2

Breaking: methods of NamedArgs now return queries, suitable for inclusion into other queries. Separate methods for strings and arg slices have been removed.

0.1.1

Dependency update.

0.1.0

First tagged release.

License

https://unlicense.org

Misc

I'm receptive to suggestions. If this library almost satisfies you but needs changes, open an issue or chat me up. Contacts: https://mitranim.com/#contacts

Documentation

Overview

Example (Composition)

Copy of `ExampleStrQ_nested` for package-level docs.

package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	inner := s.StrQ{
		`select * from some_table where col0 = :val`,
		s.Dict{`val`: 10},
	}

	outer := s.StrQ{
		`select * from (:inner) as _ where col1 = :val`,
		s.Dict{`inner`: inner, `val`: 20},
	}

	fmt.Println(s.Reify(outer))
}
Output:

select * from (select * from some_table where col0 = $1) as _ where col1 = $2 [10 20]

Index

Examples

Constants

View Source
const (
	TagNameDb   = `db`
	TagNameJson = `json`
)

Variables

View Source
var ErrEmptyAssign = error(ErrEmptyExpr{Err{
	`building SQL assignment expression`,
	ErrStr(`assignment must have at least one field`),
}})

Used by `StructAssign` to indicate that no fields were provided, and therefore it was unable to generate valid SQL for an "update set" clause. This can happen because the input struct was missing or empty, or because all fields were excluded through the use of `Sparse`. User code should detect this error to skip the DB request altogether.

View Source
var Ops = map[string]Op{
	`and`:                  OpInfix,
	`or`:                   OpInfix,
	`not`:                  OpPrefix,
	`is null`:              OpPostfix,
	`is not null`:          OpPostfix,
	`is true`:              OpPostfix,
	`is not true`:          OpPostfix,
	`is false`:             OpPostfix,
	`is not false`:         OpPostfix,
	`is unknown`:           OpPostfix,
	`is not unknown`:       OpPostfix,
	`is distinct from`:     OpInfix,
	`is not distinct from`: OpInfix,
	`=`:                    OpInfix,
	`~`:                    OpInfix,
	`~*`:                   OpInfix,
	`~=`:                   OpInfix,
	`<>`:                   OpInfix,
	`<`:                    OpInfix,
	`>`:                    OpInfix,
	`>=`:                   OpInfix,
	`<=`:                   OpInfix,
	`@@`:                   OpInfix,
	`any`:                  OpAny,
	`between`:              OpBetween,
}

Known SQL operations used in JEL. Serves as a whitelist, allowing us to differentiate them from casts, and describes how to transform JEL Lisp-style calls into SQL expressions (prefix, infix, etc.). This is case-sensitive and whitespace-sensitive.

View Source
var ValidateUnusedArguments = true

Enables validation of unused arguments in parametrized queries generated via `ListQ` / `DictQ` / `StructQ` / `StrQ` / `Preparse` / `Prep`. By default, validation is enabled. It can be disabled in two ways: globally by changing this variable to `false`, or by using an argument dictionary without support for argument validation, such as `LaxDict`.

Functions

func AppendTo

func AppendTo(buf []byte, src any) ([]byte, error)

Missing feature of the standard library: append the text representation of an arbitrary value to the buffer, prioritizing "append"-style encoding functions over "string"-style functions for efficiency, using only "intentional" representations, and without swallowing errors.

Supports ONLY the following types, in this order of priority. For other types, returns an error.

  • `AppenderTo`
  • `encoding.TextMarshaler`
  • `fmt.Stringer`
  • Built-in primitive types.
  • Aliases of `[]byte`.

Special cases:

  • Nil: append nothing, return buffer as-is.
  • Integers: use `strconv.AppendInt` in base 10.
  • Floats: use `strconv.AppendFloat` without scientific notation.

Used internally by `CommaAppender`, exported for advanced users.

func AppendWith

func AppendWith(buf *[]byte, delim string, val any) (bool, error)

Attempts to append the given delimiter and the text representation of the given value, via `AppendTo`. If after delimiter non-zero amount of bytes was appended, returns true. Otherwise reverts the buffer to the original length and returns false. If the buffer got reallocated with increased capacity, preserves the new capacity.

func AppenderString

func AppenderString(val AppenderTo) string

Tiny shortcut for encoding an `AppenderTo` implementation to a string by using its `.AppendTo` method, without paying for a string-to-byte conversion. Used internally by many `Expr` implementations. Exported because it's handy for defining new types.

func FieldDbName

func FieldDbName(field r.StructField) string

Returns the field's DB column name from the "db" tag, following the JSON convention of eliding anything after a comma and treating "-" as a non-name.

func FieldJsonName

func FieldJsonName(field r.StructField) string

Returns the field's JSON column name from the "json" tag, following the same conventions as the `encoding/json` package.

func Reify

func Reify(vals ...Expr) (string, []any)

Encodes the provided expressions and returns the resulting text and args. Shortcut for using `(*Bui).Exprs` and `Bui.Reify`. Provided mostly for examples. Actual code may want to use `Bui`:

bui := MakeBui(4096, 64)
panic(bui.CatchExprs(someExprs...))
text, args := bui.Reify()

func ReifyInline added in v1.0.3

func ReifyInline(q string, arg map[string]any) string

func String

func String(src any) (string, error)

Missing feature of the standard library: return a string representation of an arbitrary value intended only for machine use, only for "intentionally" encodable types, without swallowing errors. Differences from `fmt.Sprint`:

  • Nil input = "" output.

  • Returns errors separately, without encoding them into the output. This is important when the output is intended to be passed to another system rather than read by humans.

  • Supports ONLY the following types, in this order of priority. For other types, returns an error.

  • `fmt.Stringer`

  • `AppenderTo`

  • `encoding.TextMarshaler`

  • Built-in primitive types.

  • Encodes floats without the scientific notation.

  • Aliases of `[]byte`.

func TryAppend

func TryAppend(buf []byte, src any) []byte

Variant of `AppendTo` that panics on error.

func TryAppendWith

func TryAppendWith(buf *[]byte, delim string, val any) bool

Variant of `AppendWith` that panics on error.

func TryString

func TryString(val any) string

Variant of `String` that panics on error.

func TypeCols

func TypeCols(typ r.Type) string

Returns the output of `Cols` for the given type, but takes `reflect.Type` as input, rather than a type-carrying `any`. Used internally by `Cols`. The result is cached and reused. Subsequent calls for the same type are nearly free.

func TypeColsDeep

func TypeColsDeep(typ r.Type) string

Returns the output of `ColsDeep` for the given type, but takes `reflect.Type` as input, rather than a type-carrying `any`. Used internally by `ColsDeep`. The result is cached and reused. Subsequent calls for the same type are nearly free.

Types

type AliasedPath

type AliasedPath []string

Represents an arbitrarily-nested SQL path that gets encoded as `Path` followed by `PseudoPath` alias. Useful for building "select" clauses. Used internally by `ColsDeep`.

Example
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.AliasedPath{`one`})
	fmt.Println(s.AliasedPath{`one`, `two`})
	fmt.Println(s.AliasedPath{`one`, `two`, `three`})
}
Output:

"one"
("one")."two" as "one.two"
("one")."two"."three" as "one.two.three"

func (AliasedPath) AppendExpr

func (self AliasedPath) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (AliasedPath) AppendTo

func (self AliasedPath) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (AliasedPath) Norm

func (self AliasedPath) Norm() Expr

Normalizes the expression, returning nil or a single `Ident` if the length allows this. Otherwise returns self as-is.

func (AliasedPath) String

func (self AliasedPath) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type And

type And [1]any

Represents a sequence of arbitrary sub-expressions or arguments joined by the SQL `and` operator. Rules for the inner value:

  • nil or empty -> fallback to `true`
  • single `Expr` -> render it as-is
  • non-empty slice -> render its individual elements joined by `and`
  • non-empty struct -> render column equality conditions joined by `and`
Example (Slice)
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	type list = []any

	fmt.Println(s.Reify(s.And{nil}))
	fmt.Println(s.Reify(s.And{list{}}))
	fmt.Println(s.Reify(s.And{list{true, false, s.Ident(`some_col`)}}))

}
Output:

true []
true []
$1 and $2 and ("some_col") [true false]
Example (Struct)
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.Reify(s.And{struct{}{}}))

	fmt.Println(s.Reify(s.And{struct {
		Col0 bool `db:"col0"`
		Col1 any  `db:"col1"`
		Col2 any  `db:"col2"`
	}{
		true,
		nil,
		s.Call{`some_func`, []int{10}},
	}}))

}
Output:

true []
"col0" = $1 and "col1" is null and "col2" = (some_func ($2)) [true 10]

func (And) AppendExpr

func (self And) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (And) AppendTo

func (self And) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (And) String

func (self And) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type Ands

type Ands []any

Syntactic shortcut, same as `And` with a slice of sub-expressions or arguments.

Example
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.Reify(s.Ands{}))
	fmt.Println(s.Reify(s.Ands{true, false, s.Ident(`some_col`)}))
}
Output:

true []
$1 and $2 and ("some_col") [true false]

func (Ands) AppendExpr

func (self Ands) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (Ands) AppendTo

func (self Ands) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (Ands) String

func (self Ands) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type Any

type Any [1]any

Represents an SQL "any()" expression. The inner value may be an instance of `Expr`, or an arbitrary argument.

Example
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.Reify(s.Any{}))
	fmt.Println(s.Reify(s.Any{[]int{10, 20}}))
	fmt.Println(s.Reify(s.Any{s.Table{`some_table`}}))

}
Output:

any ($1) [<nil>]
any ($1) [[10 20]]
any (table "some_table") []

func (Any) AppendExpr

func (self Any) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (Any) AppendTo

func (self Any) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (Any) String

func (self Any) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type AppenderTo

type AppenderTo interface{ AppendTo([]byte) []byte }

Appends a text repesentation. Sometimes allows better efficiency than `fmt.Stringer`. Implemented by all `Expr` types in this package.

type ArgDict

type ArgDict interface {
	IsEmpty() bool
	Len() int
	GotOrdinal(int) (any, bool)
	GotNamed(string) (any, bool)
}

Dictionary of arbitrary arguments, ordinal and/or named. Used as input to `ParamExpr` (parametrized expressions). This package provides multiple implementations: slice-based `List`, map-based `Dict`, and struct-based `StructDict`. May optionally implement `OrdinalRanger` and `NamedRanger` to validate used/unused arguments.

type ArrayAppender

type ArrayAppender[A AppenderTo] []A

Intermediary tool for implementing SQL array encoding. Has the same behavior as `CommaAppender`, but the text output is always enclosed in `{}`.

func (ArrayAppender[A]) AppendTo

func (self ArrayAppender[A]) AppendTo(buf []byte) []byte

Implement `AppenderTo`. Same as `CommaAppender.AppendTo`, but the output is always enclosed in `{}`.

func (ArrayAppender[_]) Get

func (self ArrayAppender[_]) Get() any

func (ArrayAppender[_]) String

func (self ArrayAppender[_]) String() string

Implement `fmt.Stringer`. Same as `CommaAppender.String`, but the output is always enclosed in `{}`.

func (ArrayAppender[_]) Value

func (self ArrayAppender[_]) Value() (driver.Value, error)

type Assign

type Assign struct {
	Lhs Ident
	Rhs any
}

Represents an SQL assignment such as `"some_col" = arbitrary_expression`. The LHS must be a column name, while the RHS can be an `Expr` instance or an arbitrary argument.

Example
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.Reify(s.Assign{
		`some_col`,
		`arbitrary_value`,
	}))

	fmt.Println(s.Reify(s.Assign{
		`some_col`,
		s.Path{`some_table`, `another_col`},
	}))

}
Output:

"some_col" = $1 [arbitrary_value]
"some_col" = (("some_table")."another_col") []

func (Assign) AppendExpr

func (self Assign) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (Assign) AppendTo

func (self Assign) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (Assign) String

func (self Assign) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type Bui

type Bui struct {
	Text []byte
	Args []any
}

Short for "builder". Tiny shortcut for building SQL expressions. Significantly simplifies the code and avoids various common mistakes. Used internally by most `Expr` implementations in this package. Careful use of `Bui` incurs very litte overhead compared to writing the corresponding code inline. The design may allow future Go versions to optimize it away completely.

Example
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.Reify(SomeExpr{}))
}

type SomeExpr struct{}

func (self SomeExpr) AppendExpr(text []byte, args []any) ([]byte, []any) {
	bui := s.Bui{text, args}
	bui.Str(`select`)
	bui.Any(`some_value`)
	return bui.Get()
}
Output:

select $1 [some_value]

func MakeBui

func MakeBui(textCap, argsCap int) Bui

Prealloc tool. Makes a `Bui` with the specified capacity of the text and args buffers.

func (*Bui) Any

func (self *Bui) Any(val any)

Appends an arbitrary value. If the value implements `Expr`, this calls `(*Bui).Expr`, which may append to the text and args in arbitrary ways. Otherwise, appends an argument to the inner slice of args, and the corresponding ordinal parameter such as "$1"/"$2"/.../"$N" to the text.

func (*Bui) Arg

func (self *Bui) Arg(val any)

Appends an argument to `.Args` and a corresponding ordinal parameter to `.Text`.

func (*Bui) CatchExprs

func (self *Bui) CatchExprs(vals ...Expr) (err error)

Same as `(*Bui).Exprs` but catches panics. Since many functions in this package use panics, this should be used for final reification by apps that insist on errors-as-values.

Example
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	bui := s.MakeBui(1024, 16)

	err := bui.CatchExprs(
		s.Select{`some_table`, s.Ands{true, false}},
	)
	if err != nil {
		panic(err)
	}

	text, args := bui.Reify()
	fmt.Println(text)
	fmt.Println(args)

}
Output:

select * from "some_table" where $1 and $2
[true false]

func (*Bui) Expr

func (self *Bui) Expr(val Expr)

Appends an expression, delimited from the preceding text by a space, if necessary. Nil input is a nop: nothing will be appended.

Should be used only if you already have an `Expr` value. If you have a concrete value that implements the interface, call `bui.Set(val.AppendExpr(bui.Get())` instead, to avoid a heap allocation and a minor slowdown.

func (*Bui) Exprs

func (self *Bui) Exprs(vals ...Expr)

Appends each expr by calling `(*Bui).Expr`. They will be space-separated as necessary.

func (Bui) Get

func (self Bui) Get() ([]byte, []any)

Returns text and args as-is. Useful shortcut for passing them to `AppendExpr`.

func (*Bui) Grow

func (self *Bui) Grow(textLen, argsLen int)

Increases the capacity (not length) of the text and args buffers by the specified amounts. If there's already enough capacity, avoids allocation.

func (*Bui) OrphanArg

func (self *Bui) OrphanArg(val any) OrdinalParam

Appends an arg to the inner slice of args, returning the corresponding ordinal parameter that should be appended to the text. Requires caution: does not append the corresponding ordinal parameter.

func (*Bui) OrphanParam

func (self *Bui) OrphanParam(val OrdinalParam)

Appends an ordinal parameter such as "$1", space-separated from previous text if necessary. Requires caution: does not verify the existence of the corresponding argument.

func (Bui) Reify

func (self Bui) Reify() (string, []any)

Shortcut for `self.String(), self.Args`. Go database drivers tend to require `string, []any` as inputs for queries and statements.

func (*Bui) Set

func (self *Bui) Set(text []byte, args []any)

Replaces text and args with the inputs. The following idiom is equivalent to `bui.Expr` but more efficient if the expression type is concrete, avoiding an interface-induced allocation:

bui.Set(SomeExpr{}.AppendExpr(bui.Get()))

func (*Bui) Space

func (self *Bui) Space()

Adds a space if the preceding text doesn't already end with a terminator.

func (*Bui) Str

func (self *Bui) Str(val string)

Appends the provided string, delimiting it from the previous text with a space if necessary.

func (Bui) String

func (self Bui) String() string

Returns inner text as a string, performing a free cast.

func (*Bui) SubAny

func (self *Bui) SubAny(val any)

Appends an arbitrary value or sub-expression. Like `(*Bui).Any`, but if the value implements `Expr`, this uses `(*Bui).SubExpr` in order to parenthesize the sub-expression.

func (*Bui) SubExpr

func (self *Bui) SubExpr(val Expr)

Appends a sub-expression wrapped in parens. Nil input is a nop: nothing will be appended.

Performance note: if you have a concrete value rather than an `Expr`, calling this method will allocate, so you may want to avoid it. If you already have an `Expr`, calling this is fine.

type Call

type Call struct {
	Text string
	Args any
}

Represents an SQL function call expression. The text prefix is optional and usually represents a function name. The args must be either nil, a single `Expr`, or a slice of arbitrary sub-expressions or arguments.

Example (Arguments)
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.Reify(s.Call{`some_func`, []int{10, 20, 30}}))
}
Output:

some_func ($1, $2, $3) [10 20 30]
Example (Empty)
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.Call{`some_func`, nil})
}
Output:

some_func ()
Example (SubExpression)
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.Call{`exists`, s.Table{`some_table`}})
}
Output:

exists (table "some_table")
Example (SubExpressions)
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.Call{`some_func`, []s.Ident{`one`, `two`}})
}
Output:

some_func (("one"), ("two"))

func (Call) AppendExpr

func (self Call) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (Call) AppendTo

func (self Call) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (Call) String

func (self Call) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type Cols

type Cols [1]any

Represents a column list for a "select" expression. The inner value may be of any type, and is used as a type carrier; its actual value is ignored. If the inner value is a struct or struct slice, the resulting expression is a list of column names corresponding to its fields, using a "db" tag. Otherwise the expression is `*`.

Unlike many other struct-scanning expressions, this doesn't support filtering via `Sparse`. It operates at the level of a struct type, not an individual struct value.

TODO actually support `Sparse` because it's used for insert.

Example (NonStruct)
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.Cols{})
	fmt.Println(s.Cols{(*int)(nil)})
	fmt.Println(s.Cols{(*[]string)(nil)})
}
Output:

*
*
*
Example (Struct)
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	type Internal struct {
		Id   string `db:"id"`
		Name string `db:"name"`
	}

	type External struct {
		Id       string   `db:"id"`
		Name     string   `db:"name"`
		Internal Internal `db:"internal"`
	}

	fmt.Println(s.Cols{(*External)(nil)})
}
Output:

"id", "name", "internal"

func (Cols) AppendExpr

func (self Cols) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (Cols) AppendTo

func (self Cols) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (Cols) String

func (self Cols) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type ColsDeep

type ColsDeep [1]any

Represents a column list for a "select" expression. The inner value may be of any type, and is used as a type carrier; its actual value is ignored. If the inner value is a struct or struct slice, the resulting expression is a list of column names corresponding to its fields, using a "db" tag. Otherwise the expression is `*`.

Unlike `Cols`, this has special support for nested structs and nested column paths. See the examples.

Unlike many other struct-scanning expressions, this doesn't support filtering via `Sparse`. It operates at the level of a struct type, not an individual struct value.

Example (NonStruct)
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.ColsDeep{})
	fmt.Println(s.ColsDeep{(*int)(nil)})
	fmt.Println(s.ColsDeep{(*[]string)(nil)})
}
Output:

*
*
*
Example (Struct)
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	type Internal struct {
		Id   string `db:"id"`
		Name string `db:"name"`
	}

	type External struct {
		Id       string   `db:"id"`
		Name     string   `db:"name"`
		Internal Internal `db:"internal"`
	}

	fmt.Println(s.ColsDeep{(*External)(nil)})
}
Output:

"id", "name", ("internal")."id" as "internal.id", ("internal")."name" as "internal.name"

func (ColsDeep) AppendExpr

func (self ColsDeep) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (ColsDeep) AppendTo

func (self ColsDeep) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (ColsDeep) String

func (self ColsDeep) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type Comma

type Comma [1]any

Represents a comma-separated list of arbitrary sub-expressions. The inner value may be nil or a single `Expr`, otherwise it must be a slice.

func (Comma) AppendExpr

func (self Comma) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (Comma) AppendTo

func (self Comma) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (Comma) String

func (self Comma) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type CommaAppender

type CommaAppender[A AppenderTo] []A

Intermediary tool for implementing SQL array encoding. Combines multiple arbitrary text encoders. On demand (on a call to `.AppendTo` or `.String`), combines their text representations, separating them with a comma, while skipping any empty representations. The output will never contain a dangling leading comma, double comma, or leading trailing comma, unless they were explicitly generated by the inner encoders. Compare `SliceCommaAppender` which takes an arbitrary slice.

func (CommaAppender[_]) AppendTo

func (self CommaAppender[_]) AppendTo(buf []byte) []byte

Implement `AppenderTo`. Appends comma-separated text representations of the inner encoders to the output buffer, skipping any empty representations.

func (CommaAppender[_]) String

func (self CommaAppender[_]) String() string

Implement `fmt.Stringer` by calling `.AppendTo`.

type Cond

type Cond Seq

Superset of `Seq` with additional support for structs. When the inner value is a struct, this generates a sequence of equality expressions, comparing the struct's column names against the corresponding field values. Field values may be arbitrary sub-expressions or arguments.

This is mostly an internal tool for building other expression types. Used internally by `And` and `Or`.

func (Cond) AppendExpr

func (self Cond) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (Cond) AppendTo

func (self Cond) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (Cond) String

func (self Cond) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type Delete

type Delete DeleteVoid

Shortcut for simple `delete from A where B returning *` expressions. See the examples. Also see `DeleteVoid` which doesn't have `returning *`.

Example (Filtered)
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	type Filter struct {
		Col0 int64 `db:"col0"`
		Col1 int64 `db:"col1"`
	}

	fmt.Println(s.Reify(s.Delete{`some_table`, Filter{10, 20}}))

}
Output:

delete from "some_table" where "col0" = $1 and "col1" = $2 returning * [10 20]
Example (Unfiltered)
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.Reify(s.Delete{`some_table`, nil}))
}
Output:

delete from "some_table" where null returning * []

func (Delete) AppendExpr

func (self Delete) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (Delete) AppendTo

func (self Delete) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (Delete) String

func (self Delete) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type DeleteVoid

type DeleteVoid struct {
	From  Ident
	Where any
}

Shortcut for simple `delete from A where B` expressions. Also see `Delete` which appends `returning *`.

func (DeleteVoid) AppendExpr

func (self DeleteVoid) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (DeleteVoid) AppendTo

func (self DeleteVoid) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (DeleteVoid) String

func (self DeleteVoid) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type Dict

type Dict map[string]any

Variant of `map[string]any` conforming to the `ArgDict` interface. Supports only named parameters, not ordinal parameters. Used for `StrQ`. See the `DictQ` shortcut.

func (Dict) GotNamed

func (self Dict) GotNamed(key string) (any, bool)

Implement part of the `ArgDict` interface.

func (Dict) GotOrdinal

func (self Dict) GotOrdinal(int) (any, bool)

Implement part of the `ArgDict` interface. Always returns `nil, false`.

func (Dict) IsEmpty

func (self Dict) IsEmpty() bool

Implement part of the `ArgDict` interface.

func (Dict) Len

func (self Dict) Len() int

Implement part of the `ArgDict` interface.

func (Dict) RangeNamed

func (self Dict) RangeNamed(fun func(string))

Implement `NamedRanger` to automatically validate used/unused arguments.

type Dir

type Dir byte

Short for "direction". Enum for ordering direction: none, "asc", "desc".

const (
	DirNone Dir = 0
	DirAsc  Dir = 1
	DirDesc Dir = 2
)

func (Dir) AppendTo

func (self Dir) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (Dir) GoString

func (self Dir) GoString() string

Implement `fmt.GoStringer` for debug purposes. Returns valid Go code representing this value.

func (Dir) MarshalJSON

func (self Dir) MarshalJSON() ([]byte, error)

Implement `json.Marshaler`.

func (Dir) MarshalText

func (self Dir) MarshalText() ([]byte, error)

Implement `encoding.TextUnmarshaler`.

func (*Dir) Parse

func (self *Dir) Parse(src string) error

Parses from a string, which must be either empty, "asc" or "desc".

func (Dir) String

func (self Dir) String() string

Implement `fmt.Stringer` for debug purposes.

func (*Dir) UnmarshalText

func (self *Dir) UnmarshalText(src []byte) error

Implement `encoding.TextMarshaler`.

type Eq

type Eq [2]any

Short for "equal". Represents SQL equality such as `A = B` or `A is null`. Counterpart to `Neq`.

Example
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.Reify(s.Eq{10, 20}))

	fmt.Println(s.Reify(s.Eq{
		s.Ident(`some_col`),
		nil,
	}))

	fmt.Println(s.Reify(s.Eq{
		s.Ident(`some_col`),
		s.Ident(`another_col`),
	}))

	fmt.Println(s.Reify(s.Eq{
		s.Ident(`some_col`),
		s.Path{`some_table`, `another_col`},
	}))

}
Output:

$1 = $2 [10 20]
("some_col") is null []
("some_col") = ("another_col") []
("some_col") = (("some_table")."another_col") []

func (Eq) AppendExpr

func (self Eq) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (Eq) AppendLhs

func (self Eq) AppendLhs(text []byte, args []any) ([]byte, []any)

Note: LHS and RHS are encoded differently because some SQL equality expressions are asymmetric. For example, `any` allows an array only on the RHS, and there's no way to invert it (AFAIK).

func (Eq) AppendRhs

func (self Eq) AppendRhs(text []byte, args []any) ([]byte, []any)

func (Eq) AppendTo

func (self Eq) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (Eq) String

func (self Eq) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type EqAny

type EqAny [2]any

Represents an SQL expression `A = any(B)`. Counterpart to `NeqAny`.

Example
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.Reify(s.EqAny{
		10,
		[]int{20, 30},
	}))

	fmt.Println(s.Reify(s.EqAny{
		s.Ident(`some_col`),
		[]int{20, 30},
	}))

	fmt.Println(s.Reify(s.EqAny{
		s.Ident(`some_col`),
		s.Table{`some_table`},
	}))

}
Output:

$1 = any ($2) [10 [20 30]]
("some_col") = any ($1) [[20 30]]
("some_col") = any (table "some_table") []

func (EqAny) AppendExpr

func (self EqAny) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (EqAny) AppendTo

func (self EqAny) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (EqAny) String

func (self EqAny) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type Err

type Err struct {
	While string
	Cause error
}

All errors generated by this package have this type, usually wrapped into a more specialized one: `ErrInvalidInput{Err{...}}`.

func (Err) Error

func (self Err) Error() string

Implement the `error` interface.

func (Err) Format

func (self Err) Format(out fmt.State, verb rune)

Implement the `fmt.Formatter` interface. Similar to `Err.Error`, but when formatting `.Cause`, uses `%+v`. By convention used by various libraries, this may print the cause's stack trace, if any.

func (Err) Unwrap

func (self Err) Unwrap() error

Implement a hidden interface in "errors".

type ErrEmptyExpr

type ErrEmptyExpr struct{ Err }

Specialized type for errors reported by some functions.

func (ErrEmptyExpr) Error

func (self ErrEmptyExpr) Error() string

Implement the `error` interface.

func (ErrEmptyExpr) Format

func (self ErrEmptyExpr) Format(out fmt.State, verb rune)

Implement the `fmt.Formatter` interface.

type ErrInternal

type ErrInternal struct{ Err }

Specialized type for errors reported by some functions.

func (ErrInternal) Error

func (self ErrInternal) Error() string

Implement the `error` interface.

func (ErrInternal) Format

func (self ErrInternal) Format(out fmt.State, verb rune)

Implement the `fmt.Formatter` interface.

type ErrInvalidInput

type ErrInvalidInput struct{ Err }

Specialized type for errors reported by some functions.

func (ErrInvalidInput) Error

func (self ErrInvalidInput) Error() string

Implement the `error` interface.

func (ErrInvalidInput) Format

func (self ErrInvalidInput) Format(out fmt.State, verb rune)

Implement the `fmt.Formatter` interface.

type ErrMissingArgument

type ErrMissingArgument struct{ Err }

Specialized type for errors reported by some functions.

func (ErrMissingArgument) Error

func (self ErrMissingArgument) Error() string

Implement the `error` interface.

func (ErrMissingArgument) Format

func (self ErrMissingArgument) Format(out fmt.State, verb rune)

Implement the `fmt.Formatter` interface.

type ErrOrdinalOutOfBounds

type ErrOrdinalOutOfBounds struct{ Err }

Specialized type for errors reported by some functions.

func (ErrOrdinalOutOfBounds) Error

func (self ErrOrdinalOutOfBounds) Error() string

Implement the `error` interface.

func (ErrOrdinalOutOfBounds) Format

func (self ErrOrdinalOutOfBounds) Format(out fmt.State, verb rune)

Implement the `fmt.Formatter` interface.

type ErrStr

type ErrStr string

String typedef that implements `error`. Errors of this type can be defined as constants.

func (ErrStr) Error

func (self ErrStr) Error() string

Implement `error`.

func (ErrStr) String

func (self ErrStr) String() string

Implement `fmt.Stringer`.

type ErrUnexpectedEOF

type ErrUnexpectedEOF struct{ Err }

Specialized type for errors reported by some functions.

func (ErrUnexpectedEOF) Error

func (self ErrUnexpectedEOF) Error() string

Implement the `error` interface.

func (ErrUnexpectedEOF) Format

func (self ErrUnexpectedEOF) Format(out fmt.State, verb rune)

Implement the `fmt.Formatter` interface.

type ErrUnexpectedParameter

type ErrUnexpectedParameter struct{ Err }

Specialized type for errors reported by some functions.

func (ErrUnexpectedParameter) Error

func (self ErrUnexpectedParameter) Error() string

Implement the `error` interface.

func (ErrUnexpectedParameter) Format

func (self ErrUnexpectedParameter) Format(out fmt.State, verb rune)

Implement the `fmt.Formatter` interface.

type ErrUnknownField

type ErrUnknownField struct{ Err }

Specialized type for errors reported by some functions.

func (ErrUnknownField) Error

func (self ErrUnknownField) Error() string

Implement the `error` interface.

func (ErrUnknownField) Format

func (self ErrUnknownField) Format(out fmt.State, verb rune)

Implement the `fmt.Formatter` interface.

type ErrUnusedArgument

type ErrUnusedArgument struct{ Err }

Specialized type for errors reported by some functions.

func (ErrUnusedArgument) Error

func (self ErrUnusedArgument) Error() string

Implement the `error` interface.

func (ErrUnusedArgument) Format

func (self ErrUnusedArgument) Format(out fmt.State, verb rune)

Implement the `fmt.Formatter` interface.

type Expr

type Expr interface {
	AppendExpr([]byte, []any) ([]byte, []any)
}

Short for "expression". Defines an arbitrary SQL expression. The method appends arbitrary SQL text. In both the input and output, the arguments must correspond to the parameters in the SQL text. Different databases support different styles of ordinal parameters. This package always generates Postgres-style ordinal parameters such as "$1", renumerating them as necessary.

This method is allowed to panic. Use `(*Bui).CatchExprs` to catch expression-encoding panics and convert them to errors.

All `Expr` types in this package also implement `AppenderTo` and `fmt.Stringer`.

type Exprs

type Exprs []Expr

Variable-sized sequence of expressions. When encoding, expressions will be space-separated if necessary.

Example
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	type Filter struct {
		Slug string `db:"slug"`
	}

	fmt.Println(s.Reify(
		s.Select{`some_table`, Filter{`some_slug`}},
	))
}
Output:

select * from "some_table" where "slug" = $1 [some_slug]

func (Exprs) AppendExpr

func (self Exprs) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (Exprs) AppendTo

func (self Exprs) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (Exprs) String

func (self Exprs) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type Filter

type Filter interface{ AllowField(r.StructField) bool }

Filters struct fields. Used by `Sparse` and `ParseOpt`. Implemented by `TagFilter`.

type Haser

type Haser interface{ Has(string) bool }

Used by `Partial` for filtering struct fields. See `Sparse` and `Partial` for explanations.

type Ident

type Ident string

Represents an SQL identifier, always quoted.

Example
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.Ident(``))
	fmt.Println(s.Ident(`one`))
}
Output:

""
"one"
Example (Interpolation)
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.Reify(
		s.StrQ{
			`select :col from some_table where :col <> :val`,
			s.Dict{
				`col`: s.Ident(`some_col`),
				`val`: `some_val`,
			},
		},
	))
}
Output:

select "some_col" from some_table where "some_col" <> $1 [some_val]

func (Ident) AppendExpr

func (self Ident) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (Ident) AppendTo

func (self Ident) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (Ident) BuiAppend

func (self Ident) BuiAppend(bui *Bui)

Shortcut for internal use.

func (Ident) String

func (self Ident) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type Identifier

type Identifier []string

Represents a nested SQL identifier where all elements are quoted but not parenthesized. Useful for schema-qualified paths. For nested paths that don't begin with a schema, use `Path` instead.

Example
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.Identifier{`one`})
	fmt.Println(s.Identifier{`one`, `two`})
	fmt.Println(s.Identifier{`one`, `two`, `three`})
}
Output:

"one"
"one"."two"
"one"."two"."three"

func (Identifier) AppendExpr

func (self Identifier) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (Identifier) AppendTo

func (self Identifier) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (Identifier) Norm

func (self Identifier) Norm() Expr

Normalizes the expression, returning nil or a single `Ident` if the length allows this. Otherwise returns self as-is.

func (Identifier) String

func (self Identifier) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type Insert

type Insert InsertVoid

Shortcut for simple `insert into A (B) values (C) returning *` expressions. See the examples. Also see `InsertVoid` which doesn't have `returning *`.

Example (Empty)
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.Reify(s.Insert{`some_table`, nil}))
}
Output:

insert into "some_table" default values returning * []
Example (NonEmpty)
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	type Fields struct {
		Col0 int64 `db:"col0"`
		Col1 int64 `db:"col1"`
	}

	fmt.Println(s.Reify(s.Insert{`some_table`, Fields{10, 20}}))

}
Output:

insert into "some_table" ("col0", "col1") values ($1, $2) returning * [10 20]

func (Insert) AppendExpr

func (self Insert) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (Insert) AppendTo

func (self Insert) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (Insert) String

func (self Insert) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type InsertVoid

type InsertVoid struct {
	Into   Ident
	Fields any
}

Shortcut for simple `insert into A (B) values (C)` expressions. Also see `Insert` which appends `returning *`.

func (InsertVoid) AppendExpr

func (self InsertVoid) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (InsertVoid) AppendTo

func (self InsertVoid) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (InsertVoid) String

func (self InsertVoid) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type Int64A added in v1.0.2

type Int64A int64

func (Int64A) AppendTo added in v1.0.2

func (a Int64A) AppendTo(buf []byte) []byte

func (Int64A) String added in v1.0.2

func (a Int64A) String() string

type Jel

type Jel struct {
	Type r.Type
	Text string
}

Short for "JSON Expression Language". Provides support for expressing a whitelisted subset of SQL with JSON, as Lisp-style nested lists. Transcodes JSON to SQL on the fly. Implements `Expr`. Can be transparently used as a sub-expression in other `sqlb` expressions. See the provided example.

Expressions are Lisp-style, using nested lists to express "calls". This syntax is used for all SQL operations. Binary infix operators are considered variadic.

Lists are used for calls and casts. The first element must be a string. It may be one of the whitelisted operators or functions, listed in `Ops`. If not, it must be a field name or a dot-separated field path. Calls are arbitrarily nestable.

["and", true, ["or", true, ["and", true, false]]]

["<=", 10, 20]

["=", "someField", "otherField"]

["and",
	["=", "someField", "otherField"],
	["<=", "dateField", ["dateField", "9999-01-01T00:00:00Z"]]
]

Transcoding from JSON to SQL is done by consulting two things: the built-in whitelist of SQL operations (`Ops`, shared), and a struct type provided to that particular decoder. The struct serves as a whitelist of available identifiers, and allows to determine value types via casting.

Casting allows to decode arbitrary JSON directly into the corresponding Go type:

["someDateField", "9999-01-01T00:00:00Z"]

["someGeoField", {"lng": 10, "lat": 20}]

Such decoded values are substituted with ordinal parameters such as $1, and appended to the slice of arguments (see below).

A string not in a call position and not inside a cast is interpreted as an identifier: field name or nested field path, dot-separated. It must be found on the reference struct, otherwise transcoding fails with an error.

"someField"

"outerField.innerField"

Literal numbers, booleans, and nulls that occur outside of casts are decoded into their Go equivalents. Like casts, they're substituted with ordinal parameters and appended to the slice of arguments.

JSON queries are transcoded against a struct, by matching fields tagged with `json` against fields tagged with `db`. Literal values are JSON-decoded into the types of the corresponding struct fields.

type Input struct {
	FieldOne string `json:"fieldOne" db:"field_one"`
	FieldTwo struct {
		FieldThree *time.Time `json:"fieldThree" db:"field_three"`
	} `json:"fieldTwo" db:"field_two"`
}

const src = `
	["and",
		["=", "fieldOne", ["fieldOne", "literal string"]],
		["<", "fieldTwo.fieldThree", ["fieldTwo.fieldThree", "9999-01-01T00:00:00Z"]]
	]
`

expr := Jel{Type: reflect.TypeOf((*Input)(nil)).Elem(), Text: src}
text, args := Reify(expr)

The result is roughly equivalent to the following (formatted for clarity):

text := `
	"field_one" = 'literal string'
	and
	("field_two")."field_three" < '9999-01-01T00:00:00Z'
`
args := []any{"literal string", time.Time("9999-01-01T00:00:00Z")}
Example
package main

import (
	"fmt"
	r "reflect"
	"time"

	"github.com/vmedinskiy/sqlb"
)

func main() {
	type Internal struct {
		InternalTime *time.Time `json:"internalTime" db:"internal_time"`
	}

	type External struct {
		ExternalName string   `json:"externalName" db:"external_name"`
		Internal     Internal `json:"internal"     db:"internal"`
	}

	const src = `
		["and",
			["or",
				false,
				["=", "externalName", ["externalName", "literal string"]]
			],
			["and",
				true,
				["<", "internal.internalTime", ["internal.internalTime", "9999-01-01T00:00:00Z"]]
			]
		]
	`

	expr := sqlb.Jel{
		Type: r.TypeOf((*External)(nil)).Elem(),
		Text: src,
	}

	text, args := sqlb.Reify(expr)

	fmt.Println(string(text))
	fmt.Printf("%#v\n", args)

}
Output:

(($1 or ("external_name" = $2)) and ($3 and (("internal")."internal_time" < $4)))
[]interface {}{false, "literal string", true, time.Date(9999, time.January, 1, 0, 0, 0, 0, time.UTC)}

func JelFor

func JelFor(typ any) Jel

Shortcut for instantiating `Jel` with the type of the given value. The input is used only as a type carrier.

func (Jel) AppendExpr

func (self Jel) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement `Expr`, allowing this to be used as a sub-expression in queries built with "github.com/mitranim/sqlb". Always generates a valid boolean expression, falling back on "true" if empty.

func (Jel) AppendTo

func (self Jel) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (*Jel) OrType

func (self *Jel) OrType(typ any)

If `.Type` is empty, sets the type of the provided value. Otherwise this is a nop. The input is used only as a type carrier; its actual value is ignored.

func (*Jel) Parse

func (self *Jel) Parse(val string) error

Stores the input for future use in `.AppendExpr`. Input must be valid JSON.

func (Jel) String

func (self Jel) String() string

Implement the `fmt.Stringer` interface for debug purposes.

func (*Jel) UnmarshalJSON

func (self *Jel) UnmarshalJSON(val []byte) error

Stores the input for future use in `.AppendExpr`. Input must be valid JSON.

func (*Jel) UnmarshalText

func (self *Jel) UnmarshalText(val []byte) error

Stores the input for future use in `.AppendExpr`. Input must be valid JSON.

type LaxDict

type LaxDict Dict

Variant of `Dict` without support for validating unused arguments. Note that missing arguments are still detected and cause errors. Useful when generating the dictionary dynamically, rather than hardcoding the set of keys. Must be used with `StrQ` or `Prep`, rather than with `DictQ`, because the latter always converts the given dictionary to `Dict`.

func (LaxDict) GotNamed

func (self LaxDict) GotNamed(key string) (any, bool)

Implement part of the `ArgDict` interface.

func (LaxDict) GotOrdinal

func (self LaxDict) GotOrdinal(int) (any, bool)

Implement part of the `ArgDict` interface. Always returns `nil, false`.

func (LaxDict) IsEmpty

func (self LaxDict) IsEmpty() bool

Implement part of the `ArgDict` interface.

func (LaxDict) Len

func (self LaxDict) Len() int

Implement part of the `ArgDict` interface.

type Limit

type Limit [1]any

Represents SQL expression "limit N" with an arbitrary argument or sub-expression. Implements `Expr`:

  • If nil -> append nothing.
  • If expr -> append "limit (<sub-expression>)".
  • If val -> append "limit $N" with the corresponding argument.

func (Limit) AppendExpr

func (self Limit) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (Limit) AppendTo

func (self Limit) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (Limit) String

func (self Limit) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type LimitUint

type LimitUint uint64

Represents SQL expression "limit N" with a number. Implements `Expr`:

  • If 0 -> append nothing.
  • Otherwise -> append literal "limit <N>" such as "limit 1".

Because this is uint64, you can safely and correctly decode arbitrary user input into this value, for example into a struct field of this type.

Example
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.Reify(
		s.Exprs{s.Select{`some_table`, nil}, s.LimitUint(10)},
	))
}
Output:

select * from "some_table" limit 10 []

func (LimitUint) AppendExpr

func (self LimitUint) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (LimitUint) AppendTo

func (self LimitUint) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (LimitUint) String

func (self LimitUint) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type List

type List []any

Variant of `[]any` conforming to the `ArgDict` interface. Supports only ordinal parameters, not named parameters. Used for `StrQ`. See the `ListQ` shortcut.

func (List) GotNamed

func (self List) GotNamed(string) (any, bool)

Implement part of the `ArgDict` interface. Always returns `nil, false`.

func (List) GotOrdinal

func (self List) GotOrdinal(key int) (any, bool)

Implement part of the `ArgDict` interface.

func (List) IsEmpty

func (self List) IsEmpty() bool

Implement part of the `ArgDict` interface.

func (List) Len

func (self List) Len() int

Implement part of the `ArgDict` interface.

func (List) RangeOrdinal

func (self List) RangeOrdinal(fun func(int))

Implement `OrdinalRanger` to automatically validate used/unused arguments.

type NamedParam

type NamedParam string

Represents a named parameter such as ":blah". Mostly for internal use.

func (NamedParam) AppendExpr

func (self NamedParam) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (NamedParam) AppendTo

func (self NamedParam) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (NamedParam) Key

func (self NamedParam) Key() string

Converts to the corresponding dictionary key, which is a plain string. This is a free cast, used to increase code clarity.

func (NamedParam) String

func (self NamedParam) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type NamedRanger

type NamedRanger interface {
	/**
	Must iterate over known argument names, calling the function for each name.
	The func is provided by this package, and will panic for each unused
	argument.
	*/
	RangeNamed(func(string))
}

Optional extension for `ArgDict`. If implemented, this is used to validate used/unused named arguments after building a parametrized SQL expression such as `StrQ`/`Prep`.

type Neq

type Neq [2]any

Short for "not equal". Represents SQL non-equality such as `A <> B` or `A is not null`. Counterpart to `Eq`.

Example
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.Reify(s.Neq{10, 20}))

	fmt.Println(s.Reify(s.Neq{
		s.Ident(`some_col`),
		nil,
	}))

	fmt.Println(s.Reify(s.Neq{
		s.Ident(`some_col`),
		s.Ident(`another_col`),
	}))

	fmt.Println(s.Reify(s.Neq{
		s.Ident(`some_col`),
		s.Path{`some_table`, `another_col`},
	}))

}
Output:

$1 <> $2 [10 20]
("some_col") is not null []
("some_col") <> ("another_col") []
("some_col") <> (("some_table")."another_col") []

func (Neq) AppendExpr

func (self Neq) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (Neq) AppendLhs

func (self Neq) AppendLhs(text []byte, args []any) ([]byte, []any)

See the comment on `Eq.AppendLhs`.

func (Neq) AppendRhs

func (self Neq) AppendRhs(text []byte, args []any) ([]byte, []any)

func (Neq) AppendTo

func (self Neq) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (Neq) String

func (self Neq) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type NeqAny

type NeqAny [2]any

Represents an SQL expression `A <> any(B)`. Counterpart to `EqAny`.

Example
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.Reify(s.NeqAny{
		10,
		[]int{20, 30},
	}))

	fmt.Println(s.Reify(s.NeqAny{
		s.Ident(`some_col`),
		[]int{20, 30},
	}))

	fmt.Println(s.Reify(s.NeqAny{
		s.Ident(`some_col`),
		s.Table{`some_table`},
	}))

}
Output:

$1 <> any ($2) [10 [20 30]]
("some_col") <> any ($1) [[20 30]]
("some_col") <> any (table "some_table") []

func (NeqAny) AppendExpr

func (self NeqAny) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (NeqAny) AppendTo

func (self NeqAny) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (NeqAny) String

func (self NeqAny) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type Not

type Not [1]any

Represents SQL logical negation such as `not A`. The inner value can be an instance of `Expr` or an arbitrary argument.

Example
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.Reify(s.Not{}))
	fmt.Println(s.Reify(s.Not{true}))
	fmt.Println(s.Reify(s.Not{s.Ident(`some_col`)}))
}
Output:

not $1 [<nil>]
not $1 [true]
not ("some_col") []

func (Not) AppendExpr

func (self Not) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (Not) AppendTo

func (self Not) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (Not) String

func (self Not) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type Nullable

type Nullable interface{ IsNull() bool }

Optional interface that allows `sqlb` to determine if a given value is null, allowing some expressions to generate `is null` / `is not null` clauses. Not actually required; nils of Go nilable types are automatically considered null, and `sqlb` falls back on encoding the value via `driver.Valuer`. This interface is supported for additional flexibility and efficiency.

type Nulls

type Nulls byte

Enum for nulls handling in ordering: none, "nulls first", "nulls last".

const (
	NullsNone  Nulls = 0
	NullsFirst Nulls = 1
	NullsLast  Nulls = 2
)

func (Nulls) AppendTo

func (self Nulls) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (Nulls) GoString

func (self Nulls) GoString() string

Implement `fmt.GoStringer` for debug purposes. Returns valid Go code representing this value.

func (Nulls) String

func (self Nulls) String() string

Implement `fmt.Stringer` for debug purposes.

type Offset

type Offset [1]any

Represents SQL expression "offset N" with an arbitrary sub-expression. Implements `Expr`:

  • If nil -> append nothing.
  • If expr -> append "offset (<sub-expression>)".
  • If val -> append "offset $N" with the corresponding argument.

func (Offset) AppendExpr

func (self Offset) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (Offset) AppendTo

func (self Offset) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (Offset) String

func (self Offset) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type OffsetUint

type OffsetUint uint64

Represents SQL expression "offset N" with a number. Implements `Expr`:

  • If 0 -> append nothing.
  • Otherwise -> append literal "offset <N>" such as "offset 1".

Because this is uint64, you can safely and correctly decode arbitrary user input into this value, for example into a struct field of this type.

Example
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.Reify(
		s.Exprs{s.Select{`some_table`, nil}, s.OffsetUint(10)},
	))
}
Output:

select * from "some_table" offset 10 []

func (OffsetUint) AppendExpr

func (self OffsetUint) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (OffsetUint) AppendTo

func (self OffsetUint) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (OffsetUint) String

func (self OffsetUint) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type Op

type Op byte

Syntax type of SQL operator expressions used in JEL. Allows us to convert JEL Lisp-style "calls" into SQL-style operations that use prefix, infix, etc.

const (
	OpPrefix Op = iota + 1
	OpPostfix
	OpInfix
	OpFunc
	OpAny
	OpBetween
)

type Or

type Or [1]any

Represents a sequence of arbitrary sub-expressions or arguments joined by the SQL `or` operator. Rules for the inner value:

  • nil or empty -> fallback to `false`
  • single `Expr` -> render it as-is
  • non-empty slice -> render its individual elements joined by `or`
  • non-empty struct -> render column equality conditions joined by `or`
Example (Slice)
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	type list = []any

	fmt.Println(s.Reify(s.Or{nil}))
	fmt.Println(s.Reify(s.Or{list{}}))
	fmt.Println(s.Reify(s.Or{list{true, false, s.Ident(`some_col`)}}))

}
Output:

false []
false []
$1 or $2 or ("some_col") [true false]
Example (Struct)
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.Reify(s.Or{struct{}{}}))

	fmt.Println(s.Reify(s.Or{struct {
		Col0 bool `db:"col0"`
		Col1 any  `db:"col1"`
		Col2 any  `db:"col2"`
	}{
		true,
		nil,
		s.Call{`some_func`, []int{10}},
	}}))

}
Output:

false []
"col0" = $1 or "col1" is null or "col2" = (some_func ($2)) [true 10]

func (Or) AppendExpr

func (self Or) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (Or) AppendTo

func (self Or) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (Or) String

func (self Or) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type Ord

type Ord struct {
	Path  Path
	Dir   Dir
	Nulls Nulls
}

Structured representation of an arbitrary SQL ordering expression. This is not the entire "order by" clause (see `Ords`), but rather just one element in that clause. Also see `Ords`, `OrdsParser`, and the various provided examples.

func (Ord) AppendExpr

func (self Ord) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (Ord) AppendTo

func (self Ord) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (Ord) IsEmpty

func (self Ord) IsEmpty() bool

True if the path is empty.

func (Ord) String

func (self Ord) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type OrdAsc

type OrdAsc []string

Same as `Ord{Path: path, Dir: DirAsc}` but more syntactically convenient and uses less memory.

func (OrdAsc) AppendExpr

func (self OrdAsc) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (OrdAsc) AppendTo

func (self OrdAsc) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (OrdAsc) String

func (self OrdAsc) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type OrdAscNullsFirst

type OrdAscNullsFirst []string

Same as `Ord{Path: path, Dir: DirAsc, Nulls: NullsFirst}` but more syntactically convenient and uses less memory.

func (OrdAscNullsFirst) AppendExpr

func (self OrdAscNullsFirst) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (OrdAscNullsFirst) AppendTo

func (self OrdAscNullsFirst) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (OrdAscNullsFirst) String

func (self OrdAscNullsFirst) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type OrdAscNullsLast

type OrdAscNullsLast []string

Same as `Ord{Path: path, Dir: DirAsc, Nulls: NullsLast}` but more syntactically convenient and uses less memory.

func (OrdAscNullsLast) AppendExpr

func (self OrdAscNullsLast) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (OrdAscNullsLast) AppendTo

func (self OrdAscNullsLast) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (OrdAscNullsLast) String

func (self OrdAscNullsLast) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type OrdDesc

type OrdDesc []string

Same as `Ord{Path: path, Dir: DirDesc}` but more syntactically convenient and uses less memory.

func (OrdDesc) AppendExpr

func (self OrdDesc) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (OrdDesc) AppendTo

func (self OrdDesc) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (OrdDesc) String

func (self OrdDesc) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type OrdDescNullsFirst

type OrdDescNullsFirst []string

Same as `Ord{Path: path, Dir: DirDesc, Nulls: NullsFirst}` but more syntactically convenient and uses less memory.

func (OrdDescNullsFirst) AppendExpr

func (self OrdDescNullsFirst) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (OrdDescNullsFirst) AppendTo

func (self OrdDescNullsFirst) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (OrdDescNullsFirst) String

func (self OrdDescNullsFirst) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type OrdDescNullsLast

type OrdDescNullsLast []string

Same as `Ord{Path: path, Dir: DirDesc, Nulls: NullsLast}` but more syntactically convenient and uses less memory.

func (OrdDescNullsLast) AppendExpr

func (self OrdDescNullsLast) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (OrdDescNullsLast) AppendTo

func (self OrdDescNullsLast) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (OrdDescNullsLast) String

func (self OrdDescNullsLast) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type OrdNullsFirst

type OrdNullsFirst []string

Same as `Ord{Path: path, Nulls: NullsFirst}` but more syntactically convenient and uses less memory.

func (OrdNullsFirst) AppendExpr

func (self OrdNullsFirst) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (OrdNullsFirst) AppendTo

func (self OrdNullsFirst) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (OrdNullsFirst) String

func (self OrdNullsFirst) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type OrdNullsLast

type OrdNullsLast []string

Same as `Ord{Path: path, Nulls: NullsLast}` but more syntactically convenient and uses less memory.

func (OrdNullsLast) AppendExpr

func (self OrdNullsLast) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (OrdNullsLast) AppendTo

func (self OrdNullsLast) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (OrdNullsLast) String

func (self OrdNullsLast) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type OrderBy

type OrderBy [1]Expr

If the provided expression is not nil, prepends the keywords "order by" to it. If the provided expression is nil, this is a nop.

func (OrderBy) AppendExpr

func (self OrderBy) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (OrderBy) AppendTo

func (self OrderBy) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (OrderBy) String

func (self OrderBy) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type Ordering

type Ordering struct {
	Expr  Expr
	Dir   Dir
	Nulls Nulls
	Using Expr
}

Structured representation of an arbitrary SQL ordering expression. This is not the entire "order by" clause (see `Ords`), but rather just one element in that clause. This is the general-case representation, but because most ordering expressions use only column names and direction, a more specialized representation is preferred: `Ord`. This is provided just-in-case.

func (Ordering) AppendExpr

func (self Ordering) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (Ordering) AppendTo

func (self Ordering) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (Ordering) String

func (self Ordering) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type OrdinalParam

type OrdinalParam int

Represents an ordinal parameter such as "$1". Mostly for internal use.

func (OrdinalParam) AppendExpr

func (self OrdinalParam) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (OrdinalParam) AppendTo

func (self OrdinalParam) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (OrdinalParam) FromIndex

func (self OrdinalParam) FromIndex() OrdinalParam

Inverse of `OrdinalParam.Index`: increments by 1, converting index to param.

func (OrdinalParam) Index

func (self OrdinalParam) Index() int

Returns the corresponding Go index (starts at zero).

func (OrdinalParam) String

func (self OrdinalParam) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type OrdinalRanger

type OrdinalRanger interface {
	/**
	Must iterate over argument indexes from 0 to N, calling the function for each
	index. The func is provided by this package, and will panic for each unused
	argument.
	*/
	RangeOrdinal(func(int))
}

Optional extension for `ArgDict`. If implemented, this is used to validate used/unused ordinal arguments after building a parametrized SQL expression such as `StrQ`/`Prep`.

type Ords

type Ords []Expr

Short for "orderings". Sequence of arbitrary expressions used for an SQL "order by" clause. Nil elements are treated as non-existent. If there are no non-nil elements, the resulting expression is empty. Otherwise, the resulting expression is "order by" followed by comma-separated sub-expressions. You can construct `Ords` manually, or parse client inputs via `OrdsParser`. See the examples.

Example (Empty)
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.Ords{})
}
Example (Manual)
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.Ords{
		s.OrdDesc{`col0`},
		s.Str(`random() asc`),
	})
}
Output:

order by "col0" desc, random() asc

func (*Ords) Add

func (self *Ords) Add(vals ...Expr)

Convenience method for appending.

func (Ords) AppendExpr

func (self Ords) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (Ords) AppendTo

func (self Ords) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (*Ords) Grow

func (self *Ords) Grow(size int)

Resizes to ensure that space capacity is `<= size`.

func (Ords) IsEmpty

func (self Ords) IsEmpty() bool

Returns true if there are no non-nil items.

func (Ords) Len

func (self Ords) Len() (count int)

Returns the amount of non-nil items.

func (Ords) MarshalJSON

func (self Ords) MarshalJSON() ([]byte, error)

Allows types that embed `Ords` to behave like a slice in JSON encoding, avoiding some edge issues. For example, this allows an empty `ParserOrds` to be encoded as JSON `null` rather than a struct, allowing types that include it as a field to be used for encoding JSON, not just decoding it. However, this doesn't make ords encoding/decoding actually reversible. Decoding "consults" a struct type to convert JSON field names to DB column names. Ideally, JSON marshaling would perform the same process in reverse, which is not currently implemented.

func (*Ords) Or

func (self *Ords) Or(vals ...Expr)

If empty, sets the given vals. Otherwise it's a nop.

func (*Ords) OrdsParser

func (self *Ords) OrdsParser(typ any) (out OrdsParser)

Returns an `OrdsParser` that can decode arbitrary JSON or a string slice into the given `*Ords` pointer. Initializes the parser to the provided type, using `typ` only as a type carrier.

Example
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	type SomeStruct struct {
		Col0 string `json:"jsonField0" db:"dbCol0"`
		Col1 string `json:"jsonField1" db:"dbCol1"`
	}

	var ords s.Ords
	err := ords.OrdsParser((*SomeStruct)(nil)).ParseSlice([]string{
		`jsonField0 asc`,
		`jsonField1 desc nulls last`,
	})
	if err != nil {
		panic(err)
	}

	fmt.Printf("%#v\n\n", ords)
	fmt.Println(ords)
}
Output:

sqlb.Ords{sqlb.OrdAsc{"dbCol0"}, sqlb.OrdDescNullsLast{"dbCol1"}}

order by "dbCol0" asc, "dbCol1" desc nulls last

func (*Ords) OrdsPtr

func (self *Ords) OrdsPtr() *Ords

Sometimes handy for types that embed `Ords`.

func (Ords) RowNumberOver

func (self Ords) RowNumberOver() RowNumberOver

Returns an expression for the Postgres window function `row_number`:

Ords{}.RowNumber()
-> `0`

Ords{OrdAsc(`col`)}.RowNumber()
-> `row_number() over (order by "col" asc)`

As shown above, empty `Ords` generates `0`. The Postgres query planner should optimize away any ordering by this constant column.

func (Ords) String

func (self Ords) String() string

Implement the `fmt.Stringer` interface for debug purposes.

func (*Ords) Zero

func (self *Ords) Zero()

Empties the receiver. If the receiver was non-nil, its length is reduced to 0 while keeping any capacity, and it remains non-nil.

type OrdsParser

type OrdsParser struct {
	*Ords
	ParseOpt
}

Similar to `ParserOrds`, but intended to be transient and stackframe-local, rather than included into other types. Usually obtained by calling `(*Ords).OrdsParser`.

func (OrdsParser) ParseSlice

func (self OrdsParser) ParseSlice(src []string) (err error)

See `(*ParserOrds).ParseSlice` for docs.

func (OrdsParser) UnmarshalJSON

func (self OrdsParser) UnmarshalJSON(src []byte) (err error)

Implement `json.Unmarshaler`. See `(*ParserOrds).UnmarshalJSON` for docs.

type Ors

type Ors []any

Syntactic shortcut, same as `Or` with a slice of sub-expressions or arguments.

Example
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.Reify(s.Ors{}))
	fmt.Println(s.Reify(s.Ors{true, false, s.Ident(`some_col`)}))
}
Output:

false []
$1 or $2 or ("some_col") [true false]

func (Ors) AppendExpr

func (self Ors) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (Ors) AppendTo

func (self Ors) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (Ors) String

func (self Ors) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type ParamExpr

type ParamExpr interface {
	AppendParamExpr([]byte, []any, ArgDict) ([]byte, []any)
}

Short for "parametrized expression". Similar to `Expr`, but requires an external input in order to be a valid expression. Implemented by preparsed query types, namely by `Prep`.

type ParseOpt

type ParseOpt struct {
	/**
	Must be a struct type. Ords parsing uses this to detect which fields are
	allowed, and to convert JSON field names to DB column names.
	*/
	Type r.Type

	/**
	Optional filter. When non-nil, this is invoked for each struct field during
	ords parsing. If this returns false, the field is "unknown" and may generate
	a parse error depending on `.Lax`.
	*/
	Filter Filter

	/**
	When true, unknown JSON fields are skipped/ignored durung parsing. When false,
	unknown JSON fields cause ords parsing to fail with a descriptive error.
	*/
	Lax bool
}

Options related to parsing text into `Ords`. Used by `ParserOrds` and `OrdsParser`.

func (*ParseOpt) OrType

func (self *ParseOpt) OrType(typ any)

If `.Type` is empty, sets the type of the provided value. Otherwise this is a nop. The input is used only as a type carrier; its actual value is ignored. The type is consulted when decoding orderings from an input such as JSON.

type ParserOrds

type ParserOrds struct {
	Ords
	ParseOpt
}

Contains `Ords` and parsing options, and implements decoder interfaces such as `json.Unmarshaler`. Intended to be included into other structs. Unmarshals text into inner `Ords` in accordance with the parsing options.

func (*ParserOrds) ParseSlice

func (self *ParserOrds) ParseSlice(src []string) error

Parses a string slice which must consist of individual ordering strings such as "one.two.three desc". Ignores empty strings. Used internally for parsing JSON. String slices may also come from URL queries, form-encoded data, and so on. Supported input format:

<path> <asc|desc>? <nulls first | nulls last>?

Each path can be a single identifier or dot-separated:

one
one.two
one.two.three

The path MUST correspond to JSON-tagged fields in the reference struct type, which MUST have corresponding DB column names. The parsed ordering uses DB column names, rather than the original JSON names.

Example
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	type SomeStruct struct {
		Col0 string `json:"jsonField0" db:"dbCol0"`
		Col1 string `json:"jsonField1" db:"dbCol1"`
	}

	var par s.ParserOrds
	par.OrType((*SomeStruct)(nil))

	err := par.ParseSlice([]string{`jsonField0 asc`, `jsonField1 desc nulls last`})
	if err != nil {
		panic(err)
	}

	fmt.Printf("%#v\n\n", par.Ords)
	fmt.Println(par.Ords)
}
Output:

sqlb.Ords{sqlb.OrdAsc{"dbCol0"}, sqlb.OrdDescNullsLast{"dbCol1"}}

order by "dbCol0" asc, "dbCol1" desc nulls last

func (*ParserOrds) UnmarshalJSON

func (self *ParserOrds) UnmarshalJSON(src []byte) error

Implement `json.Unmarshaler`. Consults `.Type` to determine known field paths, and converts them to DB column paths, rejecting unknown identifiers. The JSON input must represent an array of strings. See the method `.ParseSlice` for more docs.

Example
package main

import (
	"encoding/json"
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	type SomeStruct struct {
		Col0 string `json:"jsonField0" db:"dbCol0"`
		Col1 string `json:"jsonField1" db:"dbCol1"`
	}

	var par s.ParserOrds
	par.OrType((*SomeStruct)(nil))

	err := json.Unmarshal(
		[]byte(`["jsonField0 asc", "jsonField1 desc nulls last"]`),
		&par,
	)
	if err != nil {
		panic(err)
	}

	fmt.Printf("%#v\n\n", par.Ords)
	fmt.Println(par.Ords)
}
Output:

sqlb.Ords{sqlb.OrdAsc{"dbCol0"}, sqlb.OrdDescNullsLast{"dbCol1"}}

order by "dbCol0" asc, "dbCol1" desc nulls last

type Partial

type Partial struct {
	Val any
	Fil Haser
}

Implements `Sparse` by filtering fields on their JSON names, using only explicit "json" tags. Fields without explicit "json" names are automatically considered missing. Fields with "json" tags must be present in the provided string set represented by `.Fil`.

Designed for compatibility with HTTP request decoders provided by "github.com/mitranim/rd", which either implement `Haser` or can easily generate one. Example PATCH endpoint using "rd":

import "github.com/mitranim/rd"
import "github.com/mitranim/try"
import s "github.com/mitranim/sqlb"

dec := rd.TryDownload(req)

var input SomeStructType
try.To(dec.Decode(&input))

expr := s.Exprs{
	s.Update{s.Ident(`some_table`)},
	s.Set{s.StructAssign{s.Partial{input, dec.Haser()}}},
}

func (Partial) AllowField

func (self Partial) AllowField(field r.StructField) bool

Implement `Sparse`, using the underlying filter.

func (Partial) Get

func (self Partial) Get() any

Implement `Sparse`, returning the underlying value.

type Path

type Path []string

Represents a nested SQL identifier where the first outer element is parenthesized, and every element is quoted. Useful for nested paths that begin with a table or view name. For schema-qualified paths, use `Identifier` instead.

Example
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.Path{`one`})
	fmt.Println(s.Path{`one`, `two`})
	fmt.Println(s.Path{`one`, `two`, `three`})
}
Output:

"one"
("one")."two"
("one")."two"."three"

func (Path) AppendExpr

func (self Path) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (Path) AppendTo

func (self Path) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (Path) Norm

func (self Path) Norm() Expr

Normalizes the expression, returning nil or a single `Ident` if the length allows this. Otherwise returns self as-is.

func (Path) String

func (self Path) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type Prefix

type Prefix struct {
	Prefix string
	Expr   Expr
}

Combines an expression with a string prefix. If the expr is nil, this is a nop, and the prefix is ignored. Mostly an internal tool for building other expression types.

func (Prefix) AppendExpr

func (self Prefix) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (Prefix) AppendTo

func (self Prefix) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (Prefix) String

func (self Prefix) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type Prep

type Prep struct {
	Source    string
	Tokens    []Token
	HasParams bool
}

Short for "preparsed" or "prepared". Partially parsed representation of parametrized SQL expressions, suited for efficiently building SQL queries by providing arguments. Supports both ordinal and named parameters/arguments. To avoid redundant work, this should be parsed and cached only once for each SQL query; this deduplication is done by `Preparse` which is also used internally by `StrQ`. User code doesn't need to construct this.

func Preparse

func Preparse(val string) Prep

Returns a parsed `Prep` for the given source string. Panics if parsing fails. Caches the result for each source string, reusing it for future calls. Used internally by `StrQ`. User code shouldn't have to call this, but it's exported just in case.

func (Prep) AppendParamExpr

func (self Prep) AppendParamExpr(text []byte, args []any, dict ArgDict) ([]byte, []any)

Implement the `ParamExpr` interface. Builds the expression by using the provided named args. Used internally by `StrQ`.

func (Prep) AppendTo

func (self Prep) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (*Prep) Parse

func (self *Prep) Parse()

Parses `self.Source`, modifying the receiver. Panics if parsing fails.

func (Prep) String

func (self Prep) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type PseudoPath

type PseudoPath []string

Represents an arbitrarily-nested SQL path that gets encoded as a SINGLE quoted identifier, where elements are dot-separated. This is a common convention for nested structs, supported by SQL-scanning libraries such as https://github.com/mitranim/gos.

Example
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.PseudoPath{`one`})
	fmt.Println(s.PseudoPath{`one`, `two`})
	fmt.Println(s.PseudoPath{`one`, `two`, `three`})
}
Output:

"one"
"one.two"
"one.two.three"

func (PseudoPath) AppendExpr

func (self PseudoPath) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (PseudoPath) AppendTo

func (self PseudoPath) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (PseudoPath) Norm

func (self PseudoPath) Norm() Expr

Normalizes the expression, returning nil or a single `Ident` if the length allows this. Otherwise returns self as-is.

func (PseudoPath) String

func (self PseudoPath) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type ReturningAll

type ReturningAll struct{}

Represents the Postgres `returning *` clause.

func (ReturningAll) AppendExpr

func (self ReturningAll) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (ReturningAll) AppendTo

func (self ReturningAll) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (ReturningAll) String

func (ReturningAll) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type RowNumberOver

type RowNumberOver [1]Expr

Represents the Postgres window function `row_number`:

RowNumberOver{}
-> `0`

RowNumberOver{Ords{OrdDesc{Ident(`some_col`)}}}
-> `row_number() over (order by "col" desc)`

When the inner expression is nil and the output is `0`, the Postgres query planner should be able to optimize it away.

Example (Empty)
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.RowNumberOver{})
}
Output:

0
Example (NonEmpty)
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.RowNumberOver{s.Ords{s.OrdDesc{`some_col`}}})
}
Output:

row_number() over (order by "some_col" desc)

func (RowNumberOver) AppendExpr

func (self RowNumberOver) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (RowNumberOver) AppendTo

func (self RowNumberOver) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (RowNumberOver) String

func (self RowNumberOver) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type Select

type Select struct {
	From  Ident
	Where any
}

Shortcut for simple "select * from A where B" expressions. See the examples.

Example (Filtered)
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	type Filter struct {
		Col0 int64 `db:"col0"`
		Col1 int64 `db:"col1"`
	}

	fmt.Println(s.Reify(s.Select{`some_table`, Filter{10, 20}}))
}
Output:

select * from "some_table" where "col0" = $1 and "col1" = $2 [10 20]
Example (Unfiltered)
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.Reify(s.Select{`some_table`, nil}))
}
Output:

select * from "some_table" []

func (Select) AppendExpr

func (self Select) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (Select) AppendTo

func (self Select) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (Select) String

func (self Select) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type SelectCols

type SelectCols struct {
	From Expr
	Type any
}

Wraps an arbitrary sub-expression, using `Cols{.Type}` to select specific columns from it. If `.Type` doesn't specify a set of columns, for example because it's not a struct type, then this uses the sub-expression as-is without wrapping. Counterpart to `SelectColsDeep`.

Example (AsIs)
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.SelectCols{s.Table{`some_table`}, nil})
}
Output:

table "some_table"
Example (Cols)
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	type SomeStruct struct {
		Col0 string `db:"col0"`
		Col1 string `db:"col1"`
		Col2 string `db:"-"`
	}

	fmt.Println(s.SelectCols{s.Table{`some_table`}, (*SomeStruct)(nil)})
}
Output:

with _ as (table "some_table") select "col0", "col1" from _

func (SelectCols) AppendExpr

func (self SelectCols) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (SelectCols) AppendTo

func (self SelectCols) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (SelectCols) String

func (self SelectCols) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type SelectColsDeep

type SelectColsDeep struct {
	From Expr
	Type any
}

Wraps an arbitrary sub-expression, using `ColsDeep{.Type}` to select specific columns from it. If `.Type` doesn't specify a set of columns, for example because it's not a struct type, then this uses the sub-expression as-is without wrapping. Counterpart to `SelectCols`.

Example (AsIs)
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.SelectColsDeep{s.Table{`some_table`}, nil})
}
Output:

table "some_table"
Example (Cols)
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	type SomeStruct struct {
		Outer string `db:"outer"`
		Inner struct {
			Name string `db:"name"`
		} `db:"inner"`
	}

	fmt.Println(s.SelectColsDeep{s.Table{`some_table`}, (*SomeStruct)(nil)})
}
Output:

with _ as (table "some_table") select "outer", ("inner")."name" as "inner.name" from _

func (SelectColsDeep) AppendExpr

func (self SelectColsDeep) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (SelectColsDeep) AppendTo

func (self SelectColsDeep) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (SelectColsDeep) String

func (self SelectColsDeep) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type SelectCount

type SelectCount [1]Expr

Shortcut for selecting `count(*)` from an arbitrary sub-expression. Equivalent to `s.SelectString{expr, "count(*)"}`.

Example
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(
		s.SelectCount{s.Table{`some_table`}},
	)
}
Output:

with _ as (table "some_table") select count(*) from _

func (SelectCount) AppendExpr

func (self SelectCount) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (SelectCount) AppendTo

func (self SelectCount) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (SelectCount) String

func (self SelectCount) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type SelectString

type SelectString struct {
	From Expr
	What string
}

Represents an SQL expression "select .What from (.From) as _". Mostly an internal tool for building other expression types. Used internally by `Cols` and `ColsDeep`; see their docs and examples.

func (SelectString) AppendExpr

func (self SelectString) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (SelectString) AppendTo

func (self SelectString) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (SelectString) String

func (self SelectString) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type Seq

type Seq struct {
	Empty string
	Delim string
	Val   any
}

Represents a sequence of arbitrary sub-expressions or arguments, joined with a customizable delimiter, with a customizable fallback in case of empty list. This is mostly an internal tool for building other sequences, such as `And` and `Or`. The inner value may be nil or a single `Expr`, otherwise it must be a slice.

func (Seq) AppendExpr

func (self Seq) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (Seq) AppendTo

func (self Seq) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (Seq) String

func (self Seq) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type SliceCommaAppender

type SliceCommaAppender [1]any

Intermediary tool for implementing SQL array encoding. The inner value must be either nil, a slice/array, or a pointer to a slice/array, where each element must implement `AppenderTo`. When `.AppendTo` or `.String` is called, this combines the text representations of the elements, separating them with a comma, while skipping any empty representations. The output will never contain a dangling leading comma, double comma, or leading trailing comma, unless they were explicitly generated by the inner encoders. Compare `CommaAppender` which itself is a slice.

func (SliceCommaAppender) AppendTo

func (self SliceCommaAppender) AppendTo(buf []byte) []byte

Implement `AppenderTo`. Appends comma-separated text representations of the inner encoders to the output buffer, skipping any empty representations.

func (SliceCommaAppender) String

func (self SliceCommaAppender) String() string

Implement `fmt.Stringer` by calling `.AppendTo`.

type Sparse

type Sparse interface {
	Filter
	Get() any
}

Represents an arbitrary struct where not all fields are "present". Calling `.Get` returns the underlying struct value. Calling `.AllowField` answers the question "is this field present?".

Secretly supported by struct-scanning expressions such as `StructInsert`, `StructAssign`, `StructValues`, `Cond`, and more. These types attempt to upcast the inner value to `Sparse`, falling back on using the inner value as-is. This allows to correctly implement REST "PATCH" semantics by using only the fields that were present in a particular HTTP request, while keeping this functionality optional.

Concrete implementation: `Partial`.

type Str

type Str string

Shortcut for interpolating strings into queries. Because this implements `Expr`, when used as an argument in another expression, this will be directly interpolated into the resulting query string. See the examples.

Example (StringInterpolation)
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.Reify(
		s.StrQ{
			`select :col from some_table where :col <> :val`,
			s.Dict{
				`col`: s.Str(`some_col`),
				`val`: `some_val`,
			},
		},
	))
}
Output:

select some_col from some_table where some_col <> $1 [some_val]

func (Str) AppendExpr

func (self Str) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (Str) AppendTo

func (self Str) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (Str) String

func (self Str) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type StrQ

type StrQ struct {
	Text string
	Args ArgDict
}

Short for "string query". Represents an SQL query with parameters such as "$1" or ":param_name". Args may be a list of ordinal args (via `List`), a dictionary (via `Dict`), a struct (via `StructDict`), or an arbitrary user-defined implementation conforming to the interface. When generating the final expression, parameters are converted to Postgres-style ordinal parameters such as "$1".

Expressions/queries are composable. Named arguments that implement the `Expr` interface do not become ordinal parameters/arguments. Instead, they're treated as sub-expressions, and may include arbitrary text with their own arguments. Parameter collisions between outer and inner queries are completely avoided.

Uses `Preparse` to avoid redundant parsing. Each source string is parsed only once, and the resulting `Prep` is cached. As a result, `StrQ` has little measurable overhead.

Example (Empty)
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.Reify(s.StrQ{}))
}
Output:

[]
Example (Nested)
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	inner := s.StrQ{
		`select * from some_table where col0 = :val`,
		s.Dict{`val`: 10},
	}

	outer := s.StrQ{
		`select * from (:inner) as _ where col1 = :val`,
		s.Dict{`inner`: inner, `val`: 20},
	}

	fmt.Println(s.Reify(outer))
}
Output:

select * from (select * from some_table where col0 = $1) as _ where col1 = $2 [10 20]
Example (Simple)
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.Reify(
		s.StrQ{
			`select * from some_table where col_one = :one and col_two = :two`,
			s.Dict{
				`one`: 10,
				`two`: 20,
			},
		},
	))
}
Output:

select * from some_table where col_one = $1 and col_two = $2 [10 20]
Example (StructInput)
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	type Output struct {
		Col0 string `db:"col0"`
		Col1 string `db:"col1"`
	}

	type Filter struct {
		Col2 int64 `db:"col2"`
		Col3 int64 `db:"col3"`
	}

	type Input struct {
		Cols   s.Cols
		Filter s.And
	}

	fmt.Println(s.Reify(
		s.StructQ(`
			select :Cols from some_table where :Filter
		`, Input{
			s.Cols{(*Output)(nil)},
			s.And{Filter{10, 20}},
		}),
	))
}
Output:

select "col0", "col1" from some_table where "col2" = $1 and "col3" = $2 [10 20]
Example (Structs)
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	type Output struct {
		Col0 string `db:"col0"`
		Col1 string `db:"col1"`
	}

	type Filter struct {
		Col2 int64 `db:"col2"`
		Col3 int64 `db:"col3"`
	}

	fmt.Println(s.Reify(
		s.StrQ{
			`select :cols from some_table where :filter`,
			s.Dict{
				`cols`:   s.Cols{(*Output)(nil)},
				`filter`: s.And{Filter{10, 20}},
			},
		},
	))
}
Output:

select "col0", "col1" from some_table where "col2" = $1 and "col3" = $2 [10 20]

func DictQ

func DictQ(text string, args map[string]any) StrQ

Shortcut for `StrQ{text, Dict(args)}`.

Example
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.Reify(
		s.DictQ(`
			select * from some_table where col_one = :one and col_two = :two
		`, map[string]any{
			`one`: 10,
			`two`: 20,
		}),
	))
}
Output:

select * from some_table where col_one = $1 and col_two = $2 [10 20]

func ListQ

func ListQ(text string, args ...any) StrQ

Shortcut for `StrQ{text, List(args)}`.

Example
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.Reify(
		s.ListQ(`
			select * from some_table where col_one = $1 and col_two = $2
		`, 10, 20),
	))
}
Output:

select * from some_table where col_one = $1 and col_two = $2 [10 20]

func StructQ

func StructQ(text string, args any) StrQ

Shortcut for `StrQ{text, StructDict{reflect.ValueOf(args)}}`.

func (StrQ) AppendExpr

func (self StrQ) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (StrQ) AppendTo

func (self StrQ) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (StrQ) String

func (self StrQ) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type StringDQA added in v1.0.5

type StringDQA string // double quoted string

func (StringDQA) AppendTo added in v1.0.5

func (sq StringDQA) AppendTo(buf []byte) []byte

func (StringDQA) String added in v1.0.5

func (sq StringDQA) String() string

type StringSQA added in v1.0.5

type StringSQA string // single quoted string

func (StringSQA) AppendTo added in v1.0.5

func (sq StringSQA) AppendTo(buf []byte) []byte

func (StringSQA) String added in v1.0.5

func (sq StringSQA) String() string

type StructAssign

type StructAssign [1]any

Represents an SQL assignment clause suitable for "update set" operations. The inner value must be a struct. The resulting expression consists of comma-separated assignments with column names and values derived from the provided struct. See the example.

Supports filtering. If the inner value implements `Sparse`, then not all fields are considered to be "present", which is useful for PATCH semantics. See the docs on `Sparse` and `Part`. If there are NO fields, panics with `ErrEmptyAssign`, which can be detected by user code via `errors.Is`.

Example
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.Reify(s.StructAssign{struct {
		Col0 bool `db:"col0"`
		Col1 any  `db:"col1"`
		Col2 any  `db:"col2"`
	}{
		true,
		nil,
		s.Call{`some_func`, []int{10}},
	}}))
}
Output:

"col0" = $1, "col1" = $2, "col2" = (some_func ($3)) [true <nil> 10]

func (StructAssign) AppendExpr

func (self StructAssign) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (StructAssign) AppendTo

func (self StructAssign) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (StructAssign) String

func (self StructAssign) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type StructDict

type StructDict [1]r.Value

Implements `ArgDict` by reading struct fields and methods by name. Supports only named parameters, not ordinal parameters. The inner value must be either invalid or a struct. Compared to `Dict`, a struct is way faster to construct, but reading fields by name is way slower. Used for `StrQ`. See the `StructQ` shortcut.

func (StructDict) GotNamed

func (self StructDict) GotNamed(key string) (any, bool)

Implement part of the `ArgDict` interface.

func (StructDict) GotOrdinal

func (self StructDict) GotOrdinal(int) (any, bool)

Implement part of the `ArgDict` interface. Always returns `nil, false`.

func (StructDict) IsEmpty

func (self StructDict) IsEmpty() bool

Implement part of the `ArgDict` interface.

func (StructDict) Len

func (self StructDict) Len() int

Implement part of the `ArgDict` interface. Always returns 0.

type StructInsert

type StructInsert [1]any

Represents a names-and-values clause suitable for insertion. The inner value must be nil or a struct. Nil or empty struct generates a "default values" clause. Otherwise the resulting expression has SQL column names and values generated by scanning the input struct. See the examples.

Supports filtering. If the inner value implements `Sparse`, then not all fields are considered to be "present", which is useful for PATCH semantics. See the docs on `Sparse` and `Part`.

Example (Empty)
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.StructInsert{})
}
Output:

default values
Example (NonEmpty)
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.Reify(s.StructInsert{struct {
		Col0 bool `db:"col0"`
		Col1 any  `db:"col1"`
		Col2 any  `db:"col2"`
	}{
		true,
		nil,
		s.Call{`some_func`, []int{10}},
	}}))
}
Output:

("col0", "col1", "col2") values ($1, $2, (some_func ($3))) [true <nil> 10]

func (StructInsert) AppendExpr

func (self StructInsert) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (StructInsert) AppendTo

func (self StructInsert) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (StructInsert) String

func (self StructInsert) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type StructValues

type StructValues [1]any

Represents comma-separated values from the "db"-tagged fields of an arbitrary struct. Field/column names are ignored. Values may be arbitrary sub-expressions or arguments. The value passed to `StructValues` may be nil, which is equivalent to an empty struct. It may also be an arbitrarily-nested struct pointer, which is automatically dereferenced.

Supports filtering. If the inner value implements `Sparse`, then not all fields are considered to be "present", which is useful for PATCH semantics. See the docs on `Sparse` and `Part`.

Example
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.Reify(s.StructValues{struct {
		Col0 bool `db:"col0"`
		Col1 any  `db:"col1"`
		Col2 any  `db:"col2"`
	}{
		true,
		nil,
		s.Call{`some_func`, []int{10}},
	}}))
}
Output:

$1, $2, (some_func ($3)) [true <nil> 10]

func (StructValues) AppendExpr

func (self StructValues) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (StructValues) AppendTo

func (self StructValues) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (StructValues) String

func (self StructValues) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type StructsInsert

type StructsInsert[A any] []A

Variant of `StructInsert` that supports multiple structs. Generates a names-and-values clause suitable for bulk insertion. The inner type must be a struct. An empty slice generates an empty expression. See the examples.

Example (Empty)
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	fmt.Println(s.StructsInsertOf[any]())
}
Example (NonEmpty)
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	type Row struct {
		Col0 bool   `db:"col0"`
		Col1 int64  `db:"col1"`
		Col2 string `db:"col2"`
	}

	fmt.Println(s.Reify(s.StructsInsertOf(
		Row{true, 10, `one`},
		Row{false, 20, `two`},
	)))
}
Output:

("col0", "col1", "col2") values ($1, $2, $3), ($4, $5, $6) [true 10 one false 20 two]

func StructsInsertOf

func StructsInsertOf[A any](val ...A) StructsInsert[A]

Shortcut for creating `StructsInsert` from the given values. Workaround for lack of type inference in type literals.

func (StructsInsert[A]) AppendExpr

func (self StructsInsert[A]) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (StructsInsert[_]) AppendTo

func (self StructsInsert[_]) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (StructsInsert[_]) String

func (self StructsInsert[_]) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type Table

type Table Identifier

Same as `Identifier`, but preceded by the word "table". The SQL clause "table some_name" is equivalent to "select * from some_name".

func (Table) AppendExpr

func (self Table) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (Table) AppendTo

func (self Table) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (Table) String

func (self Table) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type TagFilter

type TagFilter string

Implements `Filter` by requiring that the struct field has this specific tag. The tag's value for any given field is ignored, only its existence is checked.

func (TagFilter) AllowField

func (self TagFilter) AllowField(field r.StructField) bool

type Token

type Token struct {
	Text string
	Type TokenType
}

Represents an arbitrary chunk of SQL text parsed by `Tokenizer`.

func (Token) IsInvalid

func (self Token) IsInvalid() bool

True if the token's type is `TokenTypeInvalid`. This is used to detect end of iteration when calling `(*Tokenizer).Next`.

func (Token) ParseNamedParam

func (self Token) ParseNamedParam() NamedParam

Assumes that the token has `TokenTypeNamedParam` and looks like a Postgres-style named param: ":one", ":two" and so on. Parses and returns the parameter's name without the leading ":". Panics if the text had the wrong structure.

func (Token) ParseOrdinalParam

func (self Token) ParseOrdinalParam() OrdinalParam

Assumes that the token has `TokenTypeOrdinalParam` and looks like a Postgres-style ordinal param: "$1", "$2" and so on. Parses and returns the number. Panics if the text had the wrong structure.

func (Token) String

func (self Token) String() string

Implement `fmt.Stringer` for debug purposes.

type TokenType

type TokenType byte

Part of `Token`.

const (
	TokenTypeInvalid TokenType = iota
	TokenTypeText
	TokenTypeWhitespace
	TokenTypeQuotedSingle
	TokenTypeQuotedDouble
	TokenTypeQuotedGrave
	TokenTypeCommentLine
	TokenTypeCommentBlock
	TokenTypeDoubleColon
	TokenTypeOrdinalParam
	TokenTypeNamedParam
)

type Tokenizer

type Tokenizer struct {
	Source    string
	Transform func(Token) Token
	// contains filtered or unexported fields
}

Partial SQL tokenizer used internally by `(*Prep).Parse` to parse queries, in particular to convert named parameters into other expressions.

Goals:

  • Correctly parse whitespace, comments, quoted strings and identifiers, ordinal parameters, named parameters.

  • Decently fast and allocation-free tokenization.

Non-goals:

  • Full SQL parser.

Notable limitations:

  • No special support for dollar-quoted strings, which are rarely if ever used in dynamically-generated queries.

func (*Tokenizer) Next

func (self *Tokenizer) Next() Token

Returns the next token if possible. When the tokenizer reaches the end, this returns an empty `Token{}`. Call `Token.IsInvalid` to detect the end.

type Update

type Update UpdateVoid

Shortcut for simple `update A set B where C returning *` expressions. See the examples. Also see `UpdateVoid` which doesn't have `returning *`.

Example
package main

import (
	"fmt"

	s "github.com/vmedinskiy/sqlb"
)

func main() {
	type Filter struct {
		Col0 int64 `db:"col0"`
		Col1 int64 `db:"col1"`
	}

	type Fields struct {
		Col2 int64 `db:"col2"`
		Col3 int64 `db:"col3"`
	}

	fmt.Println(s.Reify(
		s.Update{`some_table`, Filter{10, 20}, Fields{30, 40}},
	))

}
Output:

update "some_table" set "col2" = $1, "col3" = $2 where "col0" = $3 and "col1" = $4 returning * [30 40 10 20]

func (Update) AppendExpr

func (self Update) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (Update) AppendTo

func (self Update) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (Update) String

func (self Update) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type UpdateVoid

type UpdateVoid struct {
	What   Ident
	Where  any
	Fields any
}

Shortcut for simple `update A set B where C` expressions. Also see `Update` which appends `returning *`.

func (UpdateVoid) AppendExpr

func (self UpdateVoid) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (UpdateVoid) AppendTo

func (self UpdateVoid) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (UpdateVoid) String

func (self UpdateVoid) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type Upsert

type Upsert UpsertVoid

Same as `UpsertVoid` but also appends `returning *`.

func (Upsert) AppendExpr

func (self Upsert) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (Upsert) AppendTo

func (self Upsert) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (Upsert) String

func (self Upsert) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type UpsertConflict

type UpsertConflict UpsertConflictVoid

Same as `UpsertConflictVoid` but also appends `returning *`.

func (UpsertConflict) AppendExpr

func (self UpsertConflict) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (UpsertConflict) AppendTo

func (self UpsertConflict) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (UpsertConflict) String

func (self UpsertConflict) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type UpsertConflictVoid

type UpsertConflictVoid struct {
	What Ident
	Conf Str
	Cols any
}

Represents an SQL upsert query. Similar to `UpsertVoid` (see its comment / doc), but instead of generating the conflict clause from the provided "key" fields, requires the caller to provide a hardcoded conflict target string (the `.Conf` field). Useful for conflicts that involve partial indexes. Also see `UpsertConflict` which appends the `returning *` clause.

func (UpsertConflictVoid) AppendExpr

func (self UpsertConflictVoid) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (UpsertConflictVoid) AppendTo

func (self UpsertConflictVoid) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (UpsertConflictVoid) String

func (self UpsertConflictVoid) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type UpsertVoid

type UpsertVoid struct {
	What Ident
	Keys any
	Cols any
}

Represents an SQL upsert query like this:

insert into some_table
	(key_0, key_1, col_2, col_3)
values
	($1, $2, $3, $4)
on conflict (key_0, key_1)
do update set
	key_0 = excluded.key_0,
	key_1 = excluded.key_1,
	col_2 = excluded.col_2,
	col_3 = excluded.col_3

Notes:

  • `.Keys` must be a struct.
  • `.Keys` supports `Sparse` and may be empty.
  • When `.Keys` is empty, this is equivalent to the `Insert` type.
  • `.Cols` must be a struct.
  • `.Cols` supports `Sparse` and may be empty.
  • `.Keys` provides names and values for key columns which participate in the `on conflict` clause.
  • `.Cols` provides names and values for other columns.

Also see `Upsert` which appends the `returning *` clause.

func (UpsertVoid) AppendExpr

func (self UpsertVoid) AppendExpr(text []byte, args []any) ([]byte, []any)

Implement the `Expr` interface, making this a sub-expression.

func (UpsertVoid) AppendTo

func (self UpsertVoid) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (UpsertVoid) String

func (self UpsertVoid) String() string

Implement the `fmt.Stringer` interface for debug purposes.

type Wrap

type Wrap struct {
	Prefix string
	Expr   Expr
	Suffix string
}

Combines an expression with a string prefix and suffix. If the expr is nil, this is a nop, and the prefix and suffix are ignored. Mostly an internal tool for building other expression types.

func (Wrap) AppendExpr

func (self Wrap) AppendExpr(text []byte, args []any) ([]byte, []any)

Difference from `Trio`: if the expr is nil, nothing is appended. Implement the `Expr` interface, making this a sub-expression.

func (Wrap) AppendTo

func (self Wrap) AppendTo(text []byte) []byte

Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.

func (Wrap) String

func (self Wrap) String() string

Implement the `fmt.Stringer` interface for debug purposes.

Jump to

Keyboard shortcuts

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