sqlb

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Oct 24, 2021 License: Unlicense Imports: 14 Imported by: 1

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.
    • Arbitrarily composable and nestable structures.
    • 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.
  • 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 Example_astQueryBuilding() {
  var Select = func(ident s.Ident, where interface{}) s.Expr {
    return s.Exprs{
      s.SelectStar{},
      s.From{ident},
      s.Where{s.And{where}},
    }
  }

  type Filter struct {
    Col0 int64 `db:"col0"`
    Col1 int64 `db:"col1"`
  }

  fmt.Println(s.Reify(
    Select(`some_table`, Filter{10, 20}),
  ))
  // Output:
  // select * from "some_table" where "col0" = $1 and "col1" = $2 [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.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 (AstQueryBuilding)
package main

import (
	"fmt"

	s "github.com/mitranim/sqlb"
)

func main() {
	var Select = func(ident s.Ident, where interface{}) s.Expr {
		return s.Exprs{
			s.SelectStar{},
			s.From{ident},
			s.Where{s.And{where}},
		}
	}

	type Filter struct {
		Col0 int64 `db:"col0"`
		Col1 int64 `db:"col1"`
	}

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

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

Copy of `ExampleStrQ_nested` for package-level docs.

package main

import (
	"fmt"

	s "github.com/mitranim/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

This section is empty.

Variables

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.

Functions

func FieldDbName added in v0.2.0

func FieldDbName(field reflect.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 added in v0.2.0

func FieldJsonName(field reflect.StructField) string

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

func Reify added in v0.2.0

func Reify(vals ...Expr) (string, []interface{})

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.TryExprs(someExprs...))
text, args := bui.Reify()

func TypeCols added in v0.2.0

func TypeCols(typ reflect.Type) string

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

func TypeColsDeep added in v0.2.0

func TypeColsDeep(typ reflect.Type) string

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

Types

type AliasedPath added in v0.2.0

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/mitranim/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) Append added in v0.2.0

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

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

func (AliasedPath) AppendExpr added in v0.2.0

func (self AliasedPath) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (AliasedPath) Norm added in v0.2.0

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 added in v0.2.0

func (self AliasedPath) String() string

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

type And added in v0.2.0

type And [1]interface{}

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/mitranim/sqlb"
)

func main() {
	type list = []interface{}

	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/mitranim/sqlb"
)

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

	fmt.Println(s.Reify(s.And{struct {
		Col0 bool        `db:"col0"`
		Col1 interface{} `db:"col1"`
		Col2 interface{} `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) Append added in v0.2.0

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

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

func (And) AppendExpr added in v0.2.0

func (self And) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (And) String added in v0.2.0

func (self And) String() string

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

type Ands added in v0.2.0

type Ands []interface{}

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

Example
package main

import (
	"fmt"

	s "github.com/mitranim/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) Append added in v0.2.0

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

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

func (Ands) AppendExpr added in v0.2.0

func (self Ands) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (Ands) String added in v0.2.0

func (self Ands) String() string

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

type Any added in v0.2.0

type Any [1]interface{}

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/mitranim/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.Exprs{
			s.SelectStar{},
			s.From{s.Ident(`some_table`)},
		}},
	))

}
Output:

any ($1) [<nil>]
any ($1) [[10 20]]
any (select * from "some_table") []

func (Any) Append added in v0.2.0

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

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

func (Any) AppendExpr added in v0.2.0

func (self Any) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (Any) String added in v0.2.0

func (self Any) String() string

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

type Appender added in v0.2.0

type Appender interface {
	Append([]byte) []byte
}

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

type ArgDict added in v0.2.0

type ArgDict interface {
	IsEmpty() bool
	Len() int
	GotOrdinal(int) (interface{}, bool)
	GotNamed(string) (interface{}, 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 Assign added in v0.2.0

type Assign struct {
	Lhs Ident
	Rhs interface{}
}

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/mitranim/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) Append added in v0.2.0

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

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

func (Assign) AppendExpr added in v0.2.0

func (self Assign) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (Assign) String added in v0.2.0

func (self Assign) String() string

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

type Bui added in v0.2.0

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

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/mitranim/sqlb"
)

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

type SomeExpr struct{}

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

select $1 [some_value]

func MakeBui added in v0.2.0

func MakeBui(textCap, argsCap int) Bui

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

func (*Bui) Any added in v0.2.0

func (self *Bui) Any(val interface{})

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 added in v0.2.0

func (self *Bui) Arg(val interface{}) OrdinalParam

Appends an arg to the inner slice of args, returning the corresponding ordinal parameter that should be appended to the text.

func (*Bui) Expr added in v0.2.0

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 added in v0.2.0

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

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

func (Bui) Get added in v0.2.0

func (self Bui) Get() ([]byte, []interface{})

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

func (*Bui) Grow added in v0.2.0

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) Param added in v0.2.0

func (self *Bui) Param(val OrdinalParam)

Appends an ordinal parameter such as "$1", space-separated from previous text if necessary.

func (Bui) Reify added in v0.2.0

func (self Bui) Reify() (string, []interface{})

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

func (*Bui) Set added in v0.2.0

func (self *Bui) Set(text []byte, args []interface{})

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 allocation:

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

func (*Bui) Space added in v0.2.0

func (self *Bui) Space()

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

func (*Bui) Str added in v0.2.0

func (self *Bui) Str(val string)

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

func (Bui) String added in v0.2.0

func (self Bui) String() string

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

func (*Bui) SubAny added in v0.2.0

func (self *Bui) SubAny(val interface{})

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 added in v0.2.0

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.

func (*Bui) TryExprs added in v0.2.0

func (self *Bui) TryExprs(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/mitranim/sqlb"
)

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

	err := bui.TryExprs(
		s.SelectStar{},
		s.From{s.Ident(`some_table`)},
		s.Where{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]

type Call added in v0.2.0

type Call struct {
	Text string
	Args interface{}
}

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/mitranim/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/mitranim/sqlb"
)

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

some_func ()
Example (SubExpression)
package main

import (
	"fmt"

	s "github.com/mitranim/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/mitranim/sqlb"
)

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

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

func (Call) Append added in v0.2.0

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

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

func (Call) AppendExpr added in v0.2.0

func (self Call) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (Call) String added in v0.2.0

func (self Call) String() string

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

type Cols

type Cols [1]interface{}

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 `*`.

Example (NonStruct)
package main

import (
	"fmt"

	s "github.com/mitranim/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/mitranim/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) Append added in v0.2.0

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

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

func (Cols) AppendExpr added in v0.2.0

func (self Cols) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (Cols) String added in v0.2.0

func (self Cols) String() string

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

type ColsDeep added in v0.2.0

type ColsDeep [1]interface{}

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.

Example (NonStruct)
package main

import (
	"fmt"

	s "github.com/mitranim/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/mitranim/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) Append added in v0.2.0

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

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

func (ColsDeep) AppendExpr added in v0.2.0

func (self ColsDeep) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (ColsDeep) String added in v0.2.0

func (self ColsDeep) String() string

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

type Comma added in v0.2.0

type Comma [1]interface{}

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) Append added in v0.2.0

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

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

func (Comma) AppendExpr added in v0.2.0

func (self Comma) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (Comma) String added in v0.2.0

func (self Comma) String() string

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

type Cond added in v0.2.0

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) Append added in v0.2.0

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

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

func (Cond) AppendExpr added in v0.2.0

func (self Cond) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (Cond) String added in v0.2.0

func (self Cond) String() string

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

type DeleteFrom added in v0.2.0

type DeleteFrom [1]Expr

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

func (DeleteFrom) Append added in v0.2.0

func (self DeleteFrom) Append(text []byte) []byte

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

func (DeleteFrom) AppendExpr added in v0.2.0

func (self DeleteFrom) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (DeleteFrom) String added in v0.2.0

func (self DeleteFrom) String() string

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

type Dict added in v0.2.0

type Dict map[string]interface{}

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

func (Dict) GotNamed added in v0.2.0

func (self Dict) GotNamed(key string) (interface{}, bool)

Implement part of the `ArgDict` interface.

func (Dict) GotOrdinal added in v0.2.0

func (self Dict) GotOrdinal(int) (interface{}, bool)

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

func (Dict) IsEmpty added in v0.2.0

func (self Dict) IsEmpty() bool

Implement part of the `ArgDict` interface.

func (Dict) Len added in v0.2.0

func (self Dict) Len() int

Implement part of the `ArgDict` interface.

func (Dict) RangeNamed added in v0.2.0

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

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

type Dir added in v0.2.0

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) Append added in v0.2.0

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

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

func (Dir) GoString added in v0.2.0

func (self Dir) GoString() string

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

func (Dir) String added in v0.2.0

func (self Dir) String() string

Implement `fmt.Stringer` for debug purposes.

type Eq added in v0.2.0

type Eq [2]interface{}

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/mitranim/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) Append added in v0.2.0

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

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

func (Eq) AppendExpr added in v0.2.0

func (self Eq) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (Eq) AppendLhs added in v0.2.0

func (self Eq) AppendLhs(text []byte, args []interface{}) ([]byte, []interface{})

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 added in v0.2.0

func (self Eq) AppendRhs(text []byte, args []interface{}) ([]byte, []interface{})

func (Eq) String added in v0.2.0

func (self Eq) String() string

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

type EqAny added in v0.2.0

type EqAny [2]interface{}

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

Example
package main

import (
	"fmt"

	s "github.com/mitranim/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.Exprs{
			s.SelectStar{},
			s.From{s.Ident(`some_table`)},
		},
	}))

}
Output:

$1 = any ($2) [10 [20 30]]
("some_col") = any ($1) [[20 30]]
("some_col") = any (select * from "some_table") []

func (EqAny) Append added in v0.2.0

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

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

func (EqAny) AppendExpr added in v0.2.0

func (self EqAny) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (EqAny) String added in v0.2.0

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) Unwrap

func (self Err) Unwrap() error

Implement a hidden interface in "errors".

type ErrInternal added in v0.1.11

type ErrInternal struct{ Err }

Specialized type for errors reported by some functions.

func (ErrInternal) Error added in v0.2.0

func (self ErrInternal) Error() string

Implement the `error` interface.

type ErrInvalidInput

type ErrInvalidInput struct{ Err }

Specialized type for errors reported by some functions.

func (ErrInvalidInput) Error added in v0.2.0

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 added in v0.2.0

func (self ErrMissingArgument) Error() string

Implement the `error` interface.

type ErrOrdinalOutOfBounds added in v0.1.6

type ErrOrdinalOutOfBounds struct{ Err }

Specialized type for errors reported by some functions.

func (ErrOrdinalOutOfBounds) Error added in v0.2.0

func (self ErrOrdinalOutOfBounds) Error() string

Implement the `error` interface.

type ErrUnexpectedEOF added in v0.2.0

type ErrUnexpectedEOF struct{ Err }

Specialized type for errors reported by some functions.

func (ErrUnexpectedEOF) Error added in v0.2.0

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 added in v0.2.0

func (self ErrUnexpectedParameter) Error() string

Implement the `error` interface.

type ErrUnknownField added in v0.1.11

type ErrUnknownField struct{ Err }

Specialized type for errors reported by some functions.

func (ErrUnknownField) Error added in v0.2.0

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 added in v0.2.0

func (self ErrUnusedArgument) Error() string

Implement the `error` interface.

type Expr added in v0.2.0

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

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).TryExprs` to catch expression-encoding panics and convert them to errors.

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

type Exprs added in v0.2.0

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/mitranim/sqlb"
)

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

	fmt.Println(s.Reify(
		s.Exprs{
			s.SelectStar{},
			s.From{s.Ident(`some_table`)},
			s.Where{s.And{Filter{`some_slug`}}},
		},
	))
}
Output:

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

func (Exprs) Append added in v0.2.0

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

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

func (Exprs) AppendExpr added in v0.2.0

func (self Exprs) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (Exprs) String added in v0.2.0

func (self Exprs) String() string

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

type From added in v0.2.0

type From [1]Expr

If the provided expression is not nil, prepends the keyword "from" to it. If the provided expression is nil, this is a nop.

Example
package main

import (
	"fmt"

	s "github.com/mitranim/sqlb"
)

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

	type Filter struct {
		Id int64 `db:"id"`
	}

	fmt.Println(s.Reify(
		s.Select{s.Cols{(*Output)(nil)}},
		s.From{s.Ident(`some_table`)},
		s.Where{s.And{Filter{10}}},
	))
}
Output:

select "col0", "col1" from "some_table" where "id" = $1 [10]

func (From) Append added in v0.2.0

func (self From) Append(text []byte) []byte

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

func (From) AppendExpr added in v0.2.0

func (self From) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (From) String added in v0.2.0

func (self From) String() string

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

type Ident added in v0.2.0

type Ident string

Represents an SQL identifier, always quoted.

Example
package main

import (
	"fmt"

	s "github.com/mitranim/sqlb"
)

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

""
"one"
Example (Interpolation)
package main

import (
	"fmt"

	s "github.com/mitranim/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) Append added in v0.2.0

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

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

func (Ident) AppendExpr added in v0.2.0

func (self Ident) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (Ident) String added in v0.2.0

func (self Ident) String() string

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

type Identifier added in v0.2.0

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/mitranim/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) Append added in v0.2.0

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

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

func (Identifier) AppendExpr added in v0.2.0

func (self Identifier) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (Identifier) Norm added in v0.2.0

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 added in v0.2.0

func (self Identifier) String() string

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

type InsertInto added in v0.2.0

type InsertInto [1]Expr

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

func (InsertInto) Append added in v0.2.0

func (self InsertInto) Append(text []byte) []byte

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

func (InsertInto) AppendExpr added in v0.2.0

func (self InsertInto) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (InsertInto) String added in v0.2.0

func (self InsertInto) String() string

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

type Int added in v0.2.0

type Int int

An expression that interpolates itself as text representing a literal integer, instead of adding an ordinal parameter and an argument.

func (Int) Append added in v0.2.0

func (self Int) Append(text []byte) []byte

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

func (Int) AppendExpr added in v0.2.0

func (self Int) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (Int) String added in v0.2.0

func (self Int) String() string

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

type IsNotNull added in v0.2.0

type IsNotNull struct{}

Equivalent to `Str("is not null")`, but zero-sized.

func (IsNotNull) Append added in v0.2.0

func (self IsNotNull) Append(text []byte) []byte

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

func (IsNotNull) AppendExpr added in v0.2.0

func (self IsNotNull) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (IsNotNull) String added in v0.2.0

func (self IsNotNull) String() string

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

type IsNull added in v0.2.0

type IsNull struct{}

Equivalent to `Str("is null")`, but zero-sized.

func (IsNull) Append added in v0.2.0

func (self IsNull) Append(text []byte) []byte

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

func (IsNull) AppendExpr added in v0.2.0

func (self IsNull) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (IsNull) String added in v0.2.0

func (self IsNull) String() string

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

type Jel added in v0.2.0

type Jel struct {
	Type reflect.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 := []interface{}{"literal string", time.Time("9999-01-01T00:00:00Z")}
Example
package main

import (
	"fmt"
	"reflect"
	"time"

	"github.com/mitranim/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: reflect.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 added in v0.2.0

func JelFor(typ interface{}) Jel

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

func (Jel) Append added in v0.2.0

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

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

func (Jel) AppendExpr added in v0.2.0

func (self Jel) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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) OrType added in v0.2.0

func (self *Jel) OrType(typ interface{})

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 added in v0.2.0

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

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

func (Jel) String added in v0.2.0

func (self Jel) String() string

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

func (*Jel) UnmarshalJSON added in v0.2.0

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

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

func (*Jel) UnmarshalText added in v0.2.0

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

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

type List added in v0.2.0

type List []interface{}

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

func (List) GotNamed added in v0.2.0

func (self List) GotNamed(string) (interface{}, bool)

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

func (List) GotOrdinal added in v0.2.0

func (self List) GotOrdinal(key int) (interface{}, bool)

Implement part of the `ArgDict` interface.

func (List) IsEmpty added in v0.2.0

func (self List) IsEmpty() bool

Implement part of the `ArgDict` interface.

func (List) Len added in v0.2.0

func (self List) Len() int

Implement part of the `ArgDict` interface.

func (List) RangeOrdinal added in v0.2.0

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

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

type NamedParam added in v0.2.0

type NamedParam string

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

func (NamedParam) Append added in v0.2.0

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

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

func (NamedParam) AppendExpr added in v0.2.0

func (self NamedParam) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (NamedParam) Key added in v0.2.0

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 added in v0.2.0

func (self NamedParam) String() string

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

type NamedRanger added in v0.2.0

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 added in v0.2.0

type Neq [2]interface{}

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/mitranim/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) Append added in v0.2.0

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

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

func (Neq) AppendExpr added in v0.2.0

func (self Neq) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (Neq) AppendLhs added in v0.2.0

func (self Neq) AppendLhs(text []byte, args []interface{}) ([]byte, []interface{})

See the comment on `Eq.AppendLhs`.

func (Neq) AppendRhs added in v0.2.0

func (self Neq) AppendRhs(text []byte, args []interface{}) ([]byte, []interface{})

func (Neq) String added in v0.2.0

func (self Neq) String() string

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

type NeqAny added in v0.2.0

type NeqAny [2]interface{}

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

Example
package main

import (
	"fmt"

	s "github.com/mitranim/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.Exprs{
			s.SelectStar{},
			s.From{s.Ident(`some_table`)},
		},
	}))

}
Output:

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

func (NeqAny) Append added in v0.2.0

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

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

func (NeqAny) AppendExpr added in v0.2.0

func (self NeqAny) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (NeqAny) String added in v0.2.0

func (self NeqAny) String() string

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

type Not added in v0.2.0

type Not [1]interface{}

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/mitranim/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) Append added in v0.2.0

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

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

func (Not) AppendExpr added in v0.2.0

func (self Not) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (Not) String added in v0.2.0

func (self Not) String() string

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

type Null added in v0.2.0

type Null struct{}

Equivalent to `Str("null")`, but zero-sized.

func (Null) Append added in v0.2.0

func (self Null) Append(text []byte) []byte

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

func (Null) AppendExpr added in v0.2.0

func (self Null) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (Null) String added in v0.2.0

func (self Null) String() string

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

type Nulls added in v0.2.0

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) Append added in v0.2.0

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

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

func (Nulls) GoString added in v0.2.0

func (self Nulls) GoString() string

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

func (Nulls) String added in v0.2.0

func (self Nulls) String() string

Implement `fmt.Stringer` for debug purposes.

type Op added in v0.2.0

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 added in v0.2.0

type Or [1]interface{}

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/mitranim/sqlb"
)

func main() {
	type list = []interface{}

	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/mitranim/sqlb"
)

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

	fmt.Println(s.Reify(s.Or{struct {
		Col0 bool        `db:"col0"`
		Col1 interface{} `db:"col1"`
		Col2 interface{} `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) Append added in v0.2.0

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

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

func (Or) AppendExpr added in v0.2.0

func (self Or) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (Or) String added in v0.2.0

func (self Or) String() string

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

type Ord added in v0.1.10

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) Append added in v0.2.0

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

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

func (Ord) AppendExpr added in v0.2.0

func (self Ord) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (Ord) IsEmpty added in v0.2.0

func (self Ord) IsEmpty() bool

True if the path is empty.

func (Ord) String added in v0.1.10

func (self Ord) String() string

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

type OrdAsc added in v0.1.10

type OrdAsc []string

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

func (OrdAsc) Append added in v0.2.0

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

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

func (OrdAsc) AppendExpr added in v0.2.0

func (self OrdAsc) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (OrdAsc) String added in v0.2.0

func (self OrdAsc) String() string

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

type OrdAscNullsFirst added in v0.2.0

type OrdAscNullsFirst []string

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

func (OrdAscNullsFirst) Append added in v0.2.0

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

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

func (OrdAscNullsFirst) AppendExpr added in v0.2.0

func (self OrdAscNullsFirst) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (OrdAscNullsFirst) String added in v0.2.0

func (self OrdAscNullsFirst) String() string

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

type OrdAscNullsLast added in v0.2.0

type OrdAscNullsLast []string

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

func (OrdAscNullsLast) Append added in v0.2.0

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

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

func (OrdAscNullsLast) AppendExpr added in v0.2.0

func (self OrdAscNullsLast) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (OrdAscNullsLast) String added in v0.2.0

func (self OrdAscNullsLast) String() string

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

type OrdDesc added in v0.1.10

type OrdDesc []string

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

func (OrdDesc) Append added in v0.2.0

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

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

func (OrdDesc) AppendExpr added in v0.2.0

func (self OrdDesc) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (OrdDesc) String added in v0.2.0

func (self OrdDesc) String() string

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

type OrdDescNullsFirst added in v0.2.0

type OrdDescNullsFirst []string

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

func (OrdDescNullsFirst) Append added in v0.2.0

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

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

func (OrdDescNullsFirst) AppendExpr added in v0.2.0

func (self OrdDescNullsFirst) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (OrdDescNullsFirst) String added in v0.2.0

func (self OrdDescNullsFirst) String() string

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

type OrdDescNullsLast added in v0.2.0

type OrdDescNullsLast []string

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

func (OrdDescNullsLast) Append added in v0.2.0

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

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

func (OrdDescNullsLast) AppendExpr added in v0.2.0

func (self OrdDescNullsLast) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (OrdDescNullsLast) String added in v0.2.0

func (self OrdDescNullsLast) String() string

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

type OrdNullsFirst added in v0.2.0

type OrdNullsFirst []string

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

func (OrdNullsFirst) Append added in v0.2.0

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

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

func (OrdNullsFirst) AppendExpr added in v0.2.0

func (self OrdNullsFirst) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (OrdNullsFirst) String added in v0.2.0

func (self OrdNullsFirst) String() string

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

type OrdNullsLast added in v0.2.0

type OrdNullsLast []string

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

func (OrdNullsLast) Append added in v0.2.0

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

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

func (OrdNullsLast) AppendExpr added in v0.2.0

func (self OrdNullsLast) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (OrdNullsLast) String added in v0.2.0

func (self OrdNullsLast) String() string

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

type OrderBy added in v0.2.0

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) Append added in v0.2.0

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

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

func (OrderBy) AppendExpr added in v0.2.0

func (self OrderBy) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (OrderBy) String added in v0.2.0

func (self OrderBy) String() string

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

type Ordering added in v0.2.0

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) Append added in v0.2.0

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

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

func (Ordering) AppendExpr added in v0.2.0

func (self Ordering) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (Ordering) String added in v0.2.0

func (self Ordering) String() string

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

type OrdinalParam added in v0.2.0

type OrdinalParam int

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

func (OrdinalParam) Append added in v0.2.0

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

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

func (OrdinalParam) AppendExpr added in v0.2.0

func (self OrdinalParam) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (OrdinalParam) FromIndex added in v0.2.0

func (self OrdinalParam) FromIndex() OrdinalParam

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

func (OrdinalParam) Index added in v0.2.0

func (self OrdinalParam) Index() int

Returns the corresponding Go index (starts at zero).

func (OrdinalParam) String added in v0.2.0

func (self OrdinalParam) String() string

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

type OrdinalRanger added in v0.2.0

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 added in v0.1.10

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 via `OrdsParser`. See the examples.

Example (Empty)
package main

import (
	"fmt"

	s "github.com/mitranim/sqlb"
)

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

import (
	"fmt"

	s "github.com/mitranim/sqlb"
)

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

order by "col0" desc, random() asc
Example (Parse)
package main

import (
	"fmt"

	s "github.com/mitranim/sqlb"
)

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

	parser := s.OrdsParserFor((*SomeStruct)(nil))

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

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

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

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

func (Ords) Append added in v0.1.10

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

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

func (Ords) AppendExpr added in v0.2.0

func (self Ords) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (*Ords) AppendVals added in v0.2.0

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

Convenience method for appending.

func (Ords) Grow added in v0.2.0

func (self Ords) Grow(size int) Ords

Resizes to ensure that space capacity is `<= size`, returning the modified version.

func (Ords) IsEmpty added in v0.1.10

func (self Ords) IsEmpty() bool

Returns true if there are no non-nil items.

func (Ords) Len added in v0.1.10

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

Returns the amount of non-nil items.

func (*Ords) Or added in v0.1.10

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

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

func (Ords) RowNumberOver added in v0.2.0

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 added in v0.2.0

func (self Ords) String() string

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

type OrdsParser added in v0.2.0

type OrdsParser struct {
	Ords
	Type reflect.Type
	Lax  bool
}

Parses text into `Ords`. Supports parsing JSON and arbitrary string slices, such as from `url.Values`. External input is a list of ordering strings. Each ordering string is parsed against the struct type stored in `OrdsParser.Type`. The type must be provided before parsing any inputs.

`OrdsParser.Type` serves two purposes: mapping JSON field names to DB column names, and whitelisting. The identifiers in the input must match JSON field names or paths (for nested structs). The output contains only DB column names. By default, any unknown identifiers in the input cause a parsing error. Setting `OrdsParser.Lax = true` causes unknown identifiers to be completely ignored.

While `Ords` can technically contain arbitrary `Expr` values, the `Ords` generated by `OrdsParser` consists only of specialized ordering types such as `OrdAsc`, `OrdDesc`, etc.

See the examples for `(*OrdsParser).ParseSlice` and `(*OrdsParser).UnmarshalJSON`.

func OrdsParserFor added in v0.2.0

func OrdsParserFor(val interface{}) (out OrdsParser)

Shortcut for empty `OrdsParser` intended for parsing. The input is used only as a type carrier. The parsing process will consult the provided type. See the example on `OrdsParser`.

func (*OrdsParser) OrType added in v0.2.0

func (self *OrdsParser) OrType(typ interface{})

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.

func (*OrdsParser) ParseSlice added in v0.2.0

func (self *OrdsParser) ParseSlice(vals []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/mitranim/sqlb"
)

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

	parser := s.OrdsParserFor((*SomeStruct)(nil))

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

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

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

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

func (*OrdsParser) UnmarshalJSON added in v0.2.0

func (self *OrdsParser) UnmarshalJSON(input []byte) error

Implement decoding from JSON. Consults `.Type` to determine known field paths, and converts them to DB column paths, rejecting unknown identifiers.

Example
package main

import (
	"encoding/json"
	"fmt"

	s "github.com/mitranim/sqlb"
)

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

	parser := s.OrdsParserFor((*SomeStruct)(nil))

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

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

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

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

type Ors added in v0.2.0

type Ors []interface{}

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

Example
package main

import (
	"fmt"

	s "github.com/mitranim/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) Append added in v0.2.0

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

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

func (Ors) AppendExpr added in v0.2.0

func (self Ors) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (Ors) String added in v0.2.0

func (self Ors) String() string

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

type Pair added in v0.2.0

type Pair [2]Expr

Same as `Exprs` but fixed-size. Can be marginally more efficient.

func (Pair) Append added in v0.2.0

func (self Pair) Append(text []byte) []byte

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

func (Pair) AppendExpr added in v0.2.0

func (self Pair) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (Pair) String added in v0.2.0

func (self Pair) String() string

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

type ParamExpr added in v0.2.0

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

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 Parens added in v0.2.0

type Parens [1]Expr

Arbitrary expression wrapped in parens. If the inner expression is nil, this is represented as "()".

func (Parens) Append added in v0.2.0

func (self Parens) Append(text []byte) []byte

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

func (Parens) AppendExpr added in v0.2.0

func (self Parens) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (Parens) String added in v0.2.0

func (self Parens) String() string

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

type Path added in v0.2.0

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/mitranim/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) Append added in v0.2.0

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

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

func (Path) AppendExpr added in v0.2.0

func (self Path) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (Path) Norm added in v0.2.0

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 added in v0.2.0

func (self Path) String() string

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

type Prefix added in v0.2.0

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) Append added in v0.2.0

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

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

func (Prefix) AppendExpr added in v0.2.0

func (self Prefix) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (Prefix) String added in v0.2.0

func (self Prefix) String() string

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

type Prep added in v0.2.0

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 added in v0.2.0

func Preparse(val string) Prep

Returns a parsed `Prep` for the given source string. Panics if parsing fails. Caches the result, 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) Append added in v0.2.0

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

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

func (Prep) AppendParamExpr added in v0.2.0

func (self Prep) AppendParamExpr(text []byte, args []interface{}, dict ArgDict) ([]byte, []interface{})

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

func (*Prep) Parse added in v0.2.0

func (self *Prep) Parse()

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

func (Prep) String added in v0.2.0

func (self Prep) String() string

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

type PseudoPath added in v0.2.0

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/mitranim/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) Append added in v0.2.0

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

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

func (PseudoPath) AppendExpr added in v0.2.0

func (self PseudoPath) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (PseudoPath) Norm added in v0.2.0

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 added in v0.2.0

func (self PseudoPath) String() string

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

type Returning added in v0.2.0

type Returning [1]Expr

If the provided expression is not nil, prepends the keyword "returning" to it. If the provided expression is nil, this is a nop.

func (Returning) Append added in v0.2.0

func (self Returning) Append(text []byte) []byte

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

func (Returning) AppendExpr added in v0.2.0

func (self Returning) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (Returning) String added in v0.2.0

func (self Returning) String() string

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

type ReturningStar added in v0.2.0

type ReturningStar struct{}

Equivalent to `Str("returning *")`, but zero-sized.

func (ReturningStar) Append added in v0.2.0

func (self ReturningStar) Append(text []byte) []byte

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

func (ReturningStar) AppendExpr added in v0.2.0

func (self ReturningStar) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (ReturningStar) String added in v0.2.0

func (self ReturningStar) String() string

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

type RowNumberOver added in v0.2.0

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/mitranim/sqlb"
)

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

0
Example (NonEmpty)
package main

import (
	"fmt"

	s "github.com/mitranim/sqlb"
)

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

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

func (RowNumberOver) Append added in v0.2.0

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

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

func (RowNumberOver) AppendExpr added in v0.2.0

func (self RowNumberOver) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (RowNumberOver) String added in v0.2.0

func (self RowNumberOver) String() string

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

type Select added in v0.2.0

type Select [1]Expr

If the provided expression is not nil, prepends the keyword "select" to it. If the provided expression is nil, this is a nop.

Example
package main

import (
	"fmt"

	s "github.com/mitranim/sqlb"
)

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

	type Filter struct {
		Id int64 `db:"id"`
	}

	fmt.Println(s.Reify(
		s.Select{s.Cols{(*Output)(nil)}},
		s.From{s.Ident(`some_table`)},
		s.Where{s.And{Filter{10}}},
	))
}
Output:

select "col0", "col1" from "some_table" where "id" = $1 [10]

func (Select) Append added in v0.2.0

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

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

func (Select) AppendExpr added in v0.2.0

func (self Select) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (Select) String added in v0.2.0

func (self Select) String() string

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

type SelectCols added in v0.2.0

type SelectCols struct {
	From Expr
	Type interface{}
}

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/mitranim/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/mitranim/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) Append added in v0.2.0

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

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

func (SelectCols) AppendExpr added in v0.2.0

func (self SelectCols) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (SelectCols) String added in v0.2.0

func (self SelectCols) String() string

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

type SelectColsDeep added in v0.2.0

type SelectColsDeep struct {
	From Expr
	Type interface{}
}

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/mitranim/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/mitranim/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) Append added in v0.2.0

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

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

func (SelectColsDeep) AppendExpr added in v0.2.0

func (self SelectColsDeep) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (SelectColsDeep) String added in v0.2.0

func (self SelectColsDeep) String() string

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

type SelectStar added in v0.2.0

type SelectStar struct{}

Equivalent to `Str("select *")`, but zero-sized.

func (SelectStar) Append added in v0.2.0

func (self SelectStar) Append(text []byte) []byte

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

func (SelectStar) AppendExpr added in v0.2.0

func (self SelectStar) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (SelectStar) String added in v0.2.0

func (self SelectStar) String() string

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

type SelectString added in v0.2.0

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) Append added in v0.2.0

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

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

func (SelectString) AppendExpr added in v0.2.0

func (self SelectString) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (SelectString) String added in v0.2.0

func (self SelectString) String() string

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

type Seq added in v0.2.0

type Seq struct {
	Empty string
	Delim string
	Val   interface{}
}

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) Append added in v0.2.0

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

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

func (Seq) AppendExpr added in v0.2.0

func (self Seq) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (Seq) String added in v0.2.0

func (self Seq) String() string

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

type Set added in v0.2.0

type Set [1]Expr

If the provided expression is not nil, prepends the keyword "set" to it. If the provided expression is nil, this is a nop.

func (Set) Append added in v0.2.0

func (self Set) Append(text []byte) []byte

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

func (Set) AppendExpr added in v0.2.0

func (self Set) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (Set) String added in v0.2.0

func (self Set) String() string

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

type Space added in v0.2.0

type Space struct{}

Primitive expression that inserts a space between other expressions. Unnecessary because other exprs automatically add spaces as necessary. Provided just in case.

func (Space) Append added in v0.2.0

func (self Space) Append(text []byte) []byte

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

func (Space) AppendExpr added in v0.2.0

func (self Space) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (Space) String added in v0.2.0

func (self Space) String() string

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

type Star added in v0.2.0

type Star struct{}

Equivalent to `Str("*")`, but zero-sized.

func (Star) Append added in v0.2.0

func (self Star) Append(text []byte) []byte

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

func (Star) AppendExpr added in v0.2.0

func (self Star) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (Star) String added in v0.2.0

func (self Star) String() string

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

type Str added in v0.2.0

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 (ExprInterpolation)
package main

import (
	"fmt"

	s "github.com/mitranim/sqlb"
)

func main() {
	fmt.Println(s.Reify(
		s.Select{s.Ident(`some_col`)},
		s.From{s.Ident(`some_table`)},
		s.Where{s.Neq{s.Ident(`some_col`), `some_val`}},
	))
}
Output:

select "some_col" from "some_table" where ("some_col") <> $1 [some_val]
Example (StringInterpolation)
package main

import (
	"fmt"

	s "github.com/mitranim/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 (Str) Append added in v0.2.0

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

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

func (Str) AppendExpr added in v0.2.0

func (self Str) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (Str) String added in v0.2.0

func (self Str) String() string

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

type StrQ added in v0.2.0

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/mitranim/sqlb"
)

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

[]
Example (Nested)
package main

import (
	"fmt"

	s "github.com/mitranim/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/mitranim/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/mitranim/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/mitranim/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 added in v0.2.0

func DictQ(text string, args map[string]interface{}) StrQ

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

Example
package main

import (
	"fmt"

	s "github.com/mitranim/sqlb"
)

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

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

func ListQ added in v0.2.0

func ListQ(text string, args ...interface{}) StrQ

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

Example
package main

import (
	"fmt"

	s "github.com/mitranim/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 added in v0.2.0

func StructQ(text string, args interface{}) StrQ

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

func (StrQ) Append added in v0.2.0

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

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

func (StrQ) AppendExpr added in v0.2.0

func (self StrQ) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (StrQ) String added in v0.2.0

func (self StrQ) String() string

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

type StructAssign added in v0.2.0

type StructAssign [1]interface{}

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.

Example
package main

import (
	"fmt"

	s "github.com/mitranim/sqlb"
)

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

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

func (StructAssign) Append added in v0.2.0

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

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

func (StructAssign) AppendExpr added in v0.2.0

func (self StructAssign) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (StructAssign) String added in v0.2.0

func (self StructAssign) String() string

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

type StructDict added in v0.2.0

type StructDict [1]reflect.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 added in v0.2.0

func (self StructDict) GotNamed(key string) (interface{}, bool)

Implement part of the `ArgDict` interface.

func (StructDict) GotOrdinal added in v0.2.0

func (self StructDict) GotOrdinal(int) (interface{}, bool)

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

func (StructDict) IsEmpty added in v0.2.0

func (self StructDict) IsEmpty() bool

Implement part of the `ArgDict` interface.

func (StructDict) Len added in v0.2.0

func (self StructDict) Len() int

Implement part of the `ArgDict` interface. Always returns 0.

type StructInsert added in v0.2.0

type StructInsert [1]interface{}

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.

Example (Empty)
package main

import (
	"fmt"

	s "github.com/mitranim/sqlb"
)

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

default values
Example (NonEmpty)
package main

import (
	"fmt"

	s "github.com/mitranim/sqlb"
)

func main() {
	fmt.Println(s.Reify(s.StructInsert{struct {
		Col0 bool        `db:"col0"`
		Col1 interface{} `db:"col1"`
		Col2 interface{} `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) Append added in v0.2.0

func (self StructInsert) Append(text []byte) []byte

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

func (StructInsert) AppendExpr added in v0.2.0

func (self StructInsert) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (StructInsert) String added in v0.2.0

func (self StructInsert) String() string

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

type StructValues added in v0.2.0

type StructValues [1]interface{}

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.

Example
package main

import (
	"fmt"

	s "github.com/mitranim/sqlb"
)

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

$1, $2, (some_func ($3)) [true <nil> 10]

func (StructValues) Append added in v0.2.0

func (self StructValues) Append(text []byte) []byte

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

func (StructValues) AppendExpr added in v0.2.0

func (self StructValues) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (StructValues) String added in v0.2.0

func (self StructValues) String() string

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

type SubQ added in v0.2.0

type SubQ [1]Expr

Represents sub-select wrapping such as `(<some_expr>) as _`. Mostly an internal tool for building other expression types.

func (SubQ) Append added in v0.2.0

func (self SubQ) Append(text []byte) []byte

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

func (SubQ) AppendExpr added in v0.2.0

func (self SubQ) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (SubQ) String added in v0.2.0

func (self SubQ) String() string

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

type Table added in v0.2.0

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) Append added in v0.2.0

func (self Table) Append(text []byte) []byte

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

func (Table) AppendExpr added in v0.2.0

func (self Table) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (Table) String added in v0.2.0

func (self Table) String() string

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

type Token added in v0.2.0

type Token struct {
	Text string
	Type TokenType
}

Represents an arbitrary chunk of SQL text parsed by `Tokenizer`.

func (Token) IsInvalid added in v0.2.0

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 added in v0.2.0

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 added in v0.2.0

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 added in v0.2.0

func (self Token) String() string

Implement `fmt.Stringer` for debug purposes.

type TokenType added in v0.2.0

type TokenType byte

Part of `Token`.

const (
	TokenTypeInvalid TokenType = iota
	TokenTypeText
	TokenTypeWhitespace
	TokenTypeQuotedSingle
	TokenTypeQuotedDouble
	TokenTypeQuotedGrave
	TokenTypeCommentLine
	TokenTypeCommentBlock
	TokenTypeDoubleColon
	TokenTypeOrdinalParam
	TokenTypeNamedParam
)

type Tokenizer added in v0.2.0

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 content, ordinal parameters, named parameters.

  • Decently fast and allocation-free tokenization.

Non-goals:

  • Full SQL parser.

func (*Tokenizer) Next added in v0.2.0

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 Trio added in v0.2.0

type Trio [3]Expr

Same as `Exprs` but fixed-size. Can be marginally more efficient.

func (Trio) Append added in v0.2.0

func (self Trio) Append(text []byte) []byte

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

func (Trio) AppendExpr added in v0.2.0

func (self Trio) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (Trio) String added in v0.2.0

func (self Trio) String() string

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

type Update added in v0.2.0

type Update [1]Expr

If the provided expression is not nil, prepends the keyword "update" to it. If the provided expression is nil, this is a nop.

func (Update) Append added in v0.2.0

func (self Update) Append(text []byte) []byte

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

func (Update) AppendExpr added in v0.2.0

func (self Update) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (Update) String added in v0.2.0

func (self Update) String() string

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

type Where added in v0.2.0

type Where [1]Expr

If the provided expression is not nil, prepends the keyword "where" to it. If the provided expression is nil, this is a nop.

Example
package main

import (
	"fmt"

	s "github.com/mitranim/sqlb"
)

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

	type Filter struct {
		Id int64 `db:"id"`
	}

	fmt.Println(s.Reify(
		s.Select{s.Cols{(*Output)(nil)}},
		s.From{s.Ident(`some_table`)},
		s.Where{s.And{Filter{10}}},
	))
}
Output:

select "col0", "col1" from "some_table" where "id" = $1 [10]

func (Where) Append added in v0.2.0

func (self Where) Append(text []byte) []byte

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

func (Where) AppendExpr added in v0.2.0

func (self Where) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

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

func (Where) String added in v0.2.0

func (self Where) String() string

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

type Wrap added in v0.2.0

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) Append added in v0.2.0

func (self Wrap) Append(text []byte) []byte

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

func (Wrap) AppendExpr added in v0.2.0

func (self Wrap) AppendExpr(text []byte, args []interface{}) ([]byte, []interface{})

Difference from `Trio`: if the expr is nil, nothing is appended. Implement the `Expr` interface, making this a sub-expression.

func (Wrap) String added in v0.2.0

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