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 ¶
- Constants
- Variables
- func AppendTo(buf []byte, src any) ([]byte, error)
- func AppendWith(buf *[]byte, delim string, val any) (bool, error)
- func AppenderString(val AppenderTo) string
- func FieldDbName(field r.StructField) string
- func FieldJsonName(field r.StructField) string
- func Reify(vals ...Expr) (string, []any)
- func ReifyInline(q string, arg map[string]any) string
- func String(src any) (string, error)
- func TryAppend(buf []byte, src any) []byte
- func TryAppendWith(buf *[]byte, delim string, val any) bool
- func TryString(val any) string
- func TypeCols(typ r.Type) string
- func TypeColsDeep(typ r.Type) string
- type AliasedPath
- type And
- type Ands
- type Any
- type AppenderTo
- type ArgDict
- type ArrayAppender
- type Assign
- type Bui
- func (self *Bui) Any(val any)
- func (self *Bui) Arg(val any)
- func (self *Bui) CatchExprs(vals ...Expr) (err error)
- func (self *Bui) Expr(val Expr)
- func (self *Bui) Exprs(vals ...Expr)
- func (self Bui) Get() ([]byte, []any)
- func (self *Bui) Grow(textLen, argsLen int)
- func (self *Bui) OrphanArg(val any) OrdinalParam
- func (self *Bui) OrphanParam(val OrdinalParam)
- func (self Bui) Reify() (string, []any)
- func (self *Bui) Set(text []byte, args []any)
- func (self *Bui) Space()
- func (self *Bui) Str(val string)
- func (self Bui) String() string
- func (self *Bui) SubAny(val any)
- func (self *Bui) SubExpr(val Expr)
- type Call
- type Cols
- type ColsDeep
- type Comma
- type CommaAppender
- type Cond
- type Delete
- type DeleteVoid
- type Dict
- type Dir
- type Eq
- type EqAny
- type Err
- type ErrEmptyExpr
- type ErrInternal
- type ErrInvalidInput
- type ErrMissingArgument
- type ErrOrdinalOutOfBounds
- type ErrStr
- type ErrUnexpectedEOF
- type ErrUnexpectedParameter
- type ErrUnknownField
- type ErrUnusedArgument
- type Expr
- type Exprs
- type Filter
- type Haser
- type Ident
- type Identifier
- type Insert
- type InsertVoid
- type Int64A
- type Jel
- func (self Jel) AppendExpr(text []byte, args []any) ([]byte, []any)
- func (self Jel) AppendTo(text []byte) []byte
- func (self *Jel) OrType(typ any)
- func (self *Jel) Parse(val string) error
- func (self Jel) String() string
- func (self *Jel) UnmarshalJSON(val []byte) error
- func (self *Jel) UnmarshalText(val []byte) error
- type LaxDict
- type Limit
- type LimitUint
- type List
- type NamedParam
- type NamedRanger
- type Neq
- type NeqAny
- type Not
- type Nullable
- type Nulls
- type Offset
- type OffsetUint
- type Op
- type Or
- type Ord
- type OrdAsc
- type OrdAscNullsFirst
- type OrdAscNullsLast
- type OrdDesc
- type OrdDescNullsFirst
- type OrdDescNullsLast
- type OrdNullsFirst
- type OrdNullsLast
- type OrderBy
- type Ordering
- type OrdinalParam
- type OrdinalRanger
- type Ords
- func (self *Ords) Add(vals ...Expr)
- func (self Ords) AppendExpr(text []byte, args []any) ([]byte, []any)
- func (self Ords) AppendTo(text []byte) []byte
- func (self *Ords) Grow(size int)
- func (self Ords) IsEmpty() bool
- func (self Ords) Len() (count int)
- func (self Ords) MarshalJSON() ([]byte, error)
- func (self *Ords) Or(vals ...Expr)
- func (self *Ords) OrdsParser(typ any) (out OrdsParser)
- func (self *Ords) OrdsPtr() *Ords
- func (self Ords) RowNumberOver() RowNumberOver
- func (self Ords) String() string
- func (self *Ords) Zero()
- type OrdsParser
- type Ors
- type ParamExpr
- type ParseOpt
- type ParserOrds
- type Partial
- type Path
- type Prefix
- type Prep
- type PseudoPath
- type ReturningAll
- type RowNumberOver
- type Select
- type SelectCols
- type SelectColsDeep
- type SelectCount
- type SelectString
- type Seq
- type SliceCommaAppender
- type Sparse
- type Str
- type StrQ
- type StringDQA
- type StringSQA
- type StructAssign
- type StructDict
- type StructInsert
- type StructValues
- type StructsInsert
- type Table
- type TagFilter
- type Token
- type TokenType
- type Tokenizer
- type Update
- type UpdateVoid
- type Upsert
- type UpsertConflict
- type UpsertConflictVoid
- type UpsertVoid
- type Wrap
Examples ¶
- Package (Composition)
- AliasedPath
- And (Slice)
- And (Struct)
- Ands
- Any
- Assign
- Bui
- Bui.CatchExprs
- Call (Arguments)
- Call (Empty)
- Call (SubExpression)
- Call (SubExpressions)
- Cols (NonStruct)
- Cols (Struct)
- ColsDeep (NonStruct)
- ColsDeep (Struct)
- Delete (Filtered)
- Delete (Unfiltered)
- DictQ
- Eq
- EqAny
- Exprs
- Ident
- Ident (Interpolation)
- Identifier
- Insert (Empty)
- Insert (NonEmpty)
- Jel
- LimitUint
- ListQ
- Neq
- NeqAny
- Not
- OffsetUint
- Or (Slice)
- Or (Struct)
- Ords (Empty)
- Ords (Manual)
- Ords.OrdsParser
- Ors
- ParserOrds.ParseSlice
- ParserOrds.UnmarshalJSON
- Path
- PseudoPath
- RowNumberOver (Empty)
- RowNumberOver (NonEmpty)
- Select (Filtered)
- Select (Unfiltered)
- SelectCols (AsIs)
- SelectCols (Cols)
- SelectColsDeep (AsIs)
- SelectColsDeep (Cols)
- SelectCount
- Str (StringInterpolation)
- StrQ (Empty)
- StrQ (Nested)
- StrQ (Simple)
- StrQ (StructInput)
- StrQ (Structs)
- StructAssign
- StructInsert (Empty)
- StructInsert (NonEmpty)
- StructValues
- StructsInsert (Empty)
- StructsInsert (NonEmpty)
- Update
Constants ¶
const ( TagNameDb = `db` TagNameJson = `json` )
Variables ¶
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.
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.
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 ¶
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 ¶
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 ¶
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 String ¶
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 TryAppendWith ¶
Variant of `AppendWith` that panics on error.
func TypeCols ¶
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 ¶
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 ¶
Implement the `Expr` interface, making this a sub-expression.
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 ¶
Implement the `Expr` interface, making this a sub-expression.
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 ¶
Implement the `Expr` interface, making this a sub-expression.
type AppenderTo ¶
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 `{}`.
type Assign ¶
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 ¶
Implement the `Expr` interface, making this a sub-expression.
type Bui ¶
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 ¶
Prealloc tool. Makes a `Bui` with the specified capacity of the text and args buffers.
func (*Bui) 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) CatchExprs ¶
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 ¶
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 ¶
Appends each expr by calling `(*Bui).Expr`. They will be space-separated as necessary.
func (*Bui) Grow ¶
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 ¶
Shortcut for `self.String(), self.Args`. Go database drivers tend to require `string, []any` as inputs for queries and statements.
func (*Bui) Set ¶
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 ¶
Appends the provided string, delimiting it from the previous text with a space if necessary.
func (*Bui) SubAny ¶
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.
type Call ¶
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 ¶
Implement the `Expr` interface, making this a sub-expression.
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 ¶
Implement the `Expr` interface, making this a sub-expression.
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 ¶
Implement the `Expr` interface, making this a sub-expression.
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 ¶
Implement the `Expr` interface, making this a sub-expression.
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 ¶
Implement the `Expr` interface, making this a sub-expression.
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 ¶
Implement the `Expr` interface, making this a sub-expression.
type DeleteVoid ¶
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 ¶
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) GotOrdinal ¶
Implement part of the `ArgDict` interface. Always returns `nil, false`.
func (Dict) RangeNamed ¶
Implement `NamedRanger` to automatically validate used/unused arguments.
type Dir ¶
type Dir byte
Short for "direction". Enum for ordering direction: none, "asc", "desc".
func (Dir) AppendTo ¶
Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.
func (Dir) GoString ¶
Implement `fmt.GoStringer` for debug purposes. Returns valid Go code representing this value.
func (Dir) MarshalText ¶
Implement `encoding.TextUnmarshaler`.
func (*Dir) UnmarshalText ¶
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 ¶
Implement the `Expr` interface, making this a sub-expression.
func (Eq) AppendLhs ¶
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).
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 ¶
Implement the `Expr` interface, making this a sub-expression.
type Err ¶
All errors generated by this package have this type, usually wrapped into a more specialized one: `ErrInvalidInput{Err{...}}`.
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.
type ErrInternal ¶
type ErrInternal struct{ Err }
Specialized type for errors reported by some functions.
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.
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.
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.
type ErrStr ¶
type ErrStr string
String typedef that implements `error`. Errors of this type can be defined as constants.
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.
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.
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.
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.
type Expr ¶
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 ¶
Implement the `Expr` interface, making this a sub-expression.
type Filter ¶
type Filter interface{ AllowField(r.StructField) bool }
Filters struct fields. Used by `Sparse` and `ParseOpt`. Implemented by `TagFilter`.
type Haser ¶
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 ¶
Implement the `Expr` interface, making this a sub-expression.
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 ¶
Implement the `Expr` interface, making this a sub-expression.
type InsertVoid ¶
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 Jel ¶
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 ¶
Shortcut for instantiating `Jel` with the type of the given value. The input is used only as a type carrier.
func (Jel) AppendExpr ¶
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 ¶
Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.
func (*Jel) OrType ¶
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) UnmarshalJSON ¶
Stores the input for future use in `.AppendExpr`. Input must be valid JSON.
func (*Jel) UnmarshalText ¶
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) GotOrdinal ¶
Implement part of the `ArgDict` interface. Always returns `nil, false`.
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 ¶
Implement the `Expr` interface, making this a sub-expression.
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 ¶
Implement the `Expr` interface, making this a sub-expression.
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) GotOrdinal ¶
Implement part of the `ArgDict` interface.
func (List) RangeOrdinal ¶
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 ¶
Implement the `Expr` interface, making this a sub-expression.
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 ¶
Implement the `Expr` interface, making this a sub-expression.
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 ¶
Implement the `Expr` interface, making this a sub-expression.
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".
func (Nulls) AppendTo ¶
Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.
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 ¶
Implement the `Expr` interface, making this a sub-expression.
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.
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 ¶
Implement the `Expr` interface, making this a sub-expression.
type Ord ¶
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 ¶
Implement the `Expr` interface, making this a sub-expression.
type OrdAsc ¶
type OrdAsc []string
Same as `Ord{Path: path, Dir: DirAsc}` but more syntactically convenient and uses less memory.
func (OrdAsc) AppendExpr ¶
Implement the `Expr` interface, making this a sub-expression.
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 ¶
Implement the `Expr` interface, making this a sub-expression.
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 ¶
Implement the `Expr` interface, making this a sub-expression.
type Ordering ¶
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 ¶
Implement the `Expr` interface, making this a sub-expression.
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) AppendExpr ¶
Implement the `Expr` interface, making this a sub-expression.
func (Ords) AppendTo ¶
Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.
func (Ords) MarshalJSON ¶
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) 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) 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.
type OrdsParser ¶
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 ¶
Implement the `Expr` interface, making this a sub-expression.
type ParamExpr ¶
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`.
type ParserOrds ¶
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 ¶
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.
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 ¶
Implement the `Expr` interface, making this a sub-expression.
func (Path) AppendTo ¶
Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.
type Prefix ¶
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 ¶
Implement the `Expr` interface, making this a sub-expression.
type Prep ¶
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 ¶
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 ¶
Implement the `ParamExpr` interface. Builds the expression by using the provided named args. Used internally by `StrQ`.
func (Prep) AppendTo ¶
Implement the `AppenderTo` interface, sometimes allowing more efficient text encoding.
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 ¶
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 ¶
Implement the `Expr` interface, making this a sub-expression.
type SelectCols ¶
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 ¶
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 ¶
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 ¶
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 ¶
Implement the `Expr` interface, making this a sub-expression.
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 ¶
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 ¶
Implement the `Expr` interface, making this a sub-expression.
type StrQ ¶
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 ¶
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 ¶
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 (StrQ) AppendExpr ¶
Implement the `Expr` interface, making this a sub-expression.
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 ¶
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 ¶
Implement the `Expr` interface, making this a sub-expression.
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 ¶
Represents an arbitrary chunk of SQL text parsed by `Tokenizer`.
func (Token) IsInvalid ¶
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.
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.
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 ¶
Implement the `Expr` interface, making this a sub-expression.
type UpdateVoid ¶
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 ¶
Implement the `Expr` interface, making this a sub-expression.
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 ¶
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 ¶
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 ¶
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 ¶
Difference from `Trio`: if the expr is nil, nothing is appended. Implement the `Expr` interface, making this a sub-expression.