vendor dependencies with dep

This commit is contained in:
dhax 2017-09-25 20:20:52 +02:00
parent 93d8310491
commit 1384296a47
2712 changed files with 965742 additions and 0 deletions

120
vendor/github.com/go-pg/pg/orm/count_estimate.go generated vendored Normal file
View file

@ -0,0 +1,120 @@
package orm
import (
"fmt"
"sync"
"github.com/go-pg/pg/internal"
)
// Placeholder that is replaced with count(*).
const placeholder = `'_go_pg_placeholder'`
// https://wiki.postgresql.org/wiki/Count_estimate
var pgCountEstimateFunc = fmt.Sprintf(`
CREATE OR REPLACE FUNCTION _go_pg_count_estimate_v2(query text, threshold int)
RETURNS int AS $$
DECLARE
rec record;
nrows int;
BEGIN
FOR rec IN EXECUTE 'EXPLAIN ' || query LOOP
nrows := substring(rec."QUERY PLAN" FROM ' rows=(\d+)');
EXIT WHEN nrows IS NOT NULL;
END LOOP;
-- Return the estimation if there are too many rows.
IF nrows > threshold THEN
RETURN nrows;
END IF;
-- Otherwise execute real count query.
query := replace(query, 'SELECT '%s'', 'SELECT count(*)');
EXECUTE query INTO nrows;
IF nrows IS NULL THEN
nrows := 0;
END IF;
RETURN nrows;
END;
$$ LANGUAGE plpgsql;
`, placeholder)
// CountEstimate uses EXPLAIN to get estimated number of rows matching the query.
// If that number is bigger than the threshold it returns the estimation.
// Otherwise it executes another query using count aggregate function and
// returns the result.
//
// Based on https://wiki.postgresql.org/wiki/Count_estimate
func (q *Query) CountEstimate(threshold int) (int, error) {
if q.stickyErr != nil {
return 0, q.stickyErr
}
query, err := q.countSelectQuery(placeholder).AppendQuery(nil)
if err != nil {
return 0, err
}
for i := 0; i < 3; i++ {
var count int
_, err = q.db.QueryOne(
Scan(&count),
"SELECT _go_pg_count_estimate_v2(?, ?)",
string(query), threshold,
)
if err != nil {
if pgerr, ok := err.(internal.PGError); ok && pgerr.Field('C') == "42883" {
// undefined_function
if err := q.createCountEstimateFunc(); err != nil {
return 0, err
}
continue
}
}
return count, err
}
return 0, err
}
func (q *Query) createCountEstimateFunc() error {
_, err := q.db.Exec(pgCountEstimateFunc)
return err
}
// SelectAndCountEstimate runs Select and CountEstimate in two goroutines,
// waits for them to finish and returns the result.
func (q *Query) SelectAndCountEstimate(threshold int, values ...interface{}) (count int, err error) {
if q.stickyErr != nil {
return 0, q.stickyErr
}
var wg sync.WaitGroup
wg.Add(2)
var mu sync.Mutex
go func() {
defer wg.Done()
if e := q.Select(values...); e != nil {
mu.Lock()
err = e
mu.Unlock()
}
}()
go func() {
defer wg.Done()
var e error
count, e = q.CountEstimate(threshold)
if e != nil {
mu.Lock()
err = e
mu.Unlock()
}
}()
wg.Wait()
return count, err
}

122
vendor/github.com/go-pg/pg/orm/create_table.go generated vendored Normal file
View file

@ -0,0 +1,122 @@
package orm
import (
"errors"
"strconv"
)
type CreateTableOptions struct {
Temp bool
IfNotExists bool
Varchar int // replaces PostgreSQL data type `text` with `varchar(n)`
FKConstraints bool // whether to create foreign key constraints
}
func CreateTable(db DB, model interface{}, opt *CreateTableOptions) (Result, error) {
return NewQuery(db, model).CreateTable(opt)
}
type createTableQuery struct {
q *Query
opt *CreateTableOptions
}
func (q createTableQuery) Copy() QueryAppender {
return q
}
func (q createTableQuery) Query() *Query {
return q.q
}
func (q createTableQuery) AppendQuery(b []byte) ([]byte, error) {
if q.q.stickyErr != nil {
return nil, q.q.stickyErr
}
if q.q.model == nil {
return nil, errors.New("pg: Model is nil")
}
table := q.q.model.Table()
b = append(b, "CREATE "...)
if q.opt != nil && q.opt.Temp {
b = append(b, "TEMP "...)
}
b = append(b, "TABLE "...)
if q.opt != nil && q.opt.IfNotExists {
b = append(b, "IF NOT EXISTS "...)
}
b = q.q.appendTableName(b)
b = append(b, " ("...)
for i, field := range table.Fields {
b = append(b, field.Column...)
b = append(b, " "...)
if q.opt != nil && q.opt.Varchar > 0 &&
field.SQLType == "text" && !field.HasFlag(customTypeFlag) {
b = append(b, "varchar("...)
b = strconv.AppendInt(b, int64(q.opt.Varchar), 10)
b = append(b, ")"...)
} else {
b = append(b, field.SQLType...)
}
if field.HasFlag(NotNullFlag) {
b = append(b, " NOT NULL"...)
}
if field.HasFlag(UniqueFlag) {
b = append(b, " UNIQUE"...)
}
if field.Default != "" {
b = append(b, " DEFAULT "...)
b = append(b, field.Default...)
}
if i != len(table.Fields)-1 {
b = append(b, ", "...)
}
}
b = appendPKConstraint(b, table.PKs)
if q.opt != nil && q.opt.FKConstraints {
for _, rel := range table.Relations {
b = q.appendFKConstraint(b, table, rel)
}
}
b = append(b, ")"...)
return b, nil
}
func appendPKConstraint(b []byte, pks []*Field) []byte {
if len(pks) == 0 {
return b
}
b = append(b, ", PRIMARY KEY ("...)
b = appendColumns(b, pks)
b = append(b, ")"...)
return b
}
func (q createTableQuery) appendFKConstraint(b []byte, table *Table, rel *Relation) []byte {
if rel.Type != HasOneRelation {
return b
}
b = append(b, ", FOREIGN KEY ("...)
b = appendColumns(b, rel.FKs)
b = append(b, ")"...)
b = append(b, " REFERENCES "...)
b = q.q.FormatQuery(b, string(rel.JoinTable.Name))
b = append(b, " ("...)
b = appendColumns(b, rel.JoinTable.PKs)
b = append(b, ")"...)
b = append(b, " ON DELETE CASCADE"...)
return b
}

70
vendor/github.com/go-pg/pg/orm/create_table_test.go generated vendored Normal file
View file

@ -0,0 +1,70 @@
package orm
import (
"database/sql"
"time"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
type CreateTableModel struct {
Id int
Int8 int8
Uint8 uint8
Int16 int16
Uint16 uint16
Int32 int32
Uint32 uint32
Int64 int64
Uint64 uint64
Float32 float32
Float64 float64
Decimal float64 `sql:"type:'decimal(10,10)'"`
ByteSlice []byte
ByteArray [32]byte
String string `sql:"default:'D\\'Angelo'"`
Varchar string `sql:",type:varchar(500)"`
Time time.Time `sql:"default:now()"`
NotNull int `sql:",notnull"`
Unique int `sql:",unique"`
NullBool sql.NullBool
NullFloat64 sql.NullFloat64
NullInt64 sql.NullInt64
NullString sql.NullString
Slice []int
SliceArray []int `pg:",array"`
Map map[int]int
Struct struct{}
}
type CreateTableWithoutPKModel struct {
String string
}
var _ = Describe("CreateTable", func() {
It("creates new table", func() {
q := NewQuery(nil, &CreateTableModel{})
b, err := createTableQuery{q: q}.AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`CREATE TABLE "create_table_models" ("id" bigserial, "int8" smallint, "uint8" smallint, "int16" smallint, "uint16" integer, "int32" integer, "uint32" bigint, "int64" bigint, "uint64" decimal, "float32" real, "float64" double precision, "decimal" decimal(10,10), "byte_slice" bytea, "byte_array" bytea, "string" text DEFAULT 'D''Angelo', "varchar" varchar(500), "time" timestamptz DEFAULT now(), "not_null" bigint NOT NULL, "unique" bigint UNIQUE, "null_bool" boolean, "null_float64" double precision, "null_int64" bigint, "null_string" text, "slice" jsonb, "slice_array" bigint[], "map" jsonb, "struct" jsonb, PRIMARY KEY ("id"))`))
})
It("creates new table without primary key", func() {
q := NewQuery(nil, &CreateTableWithoutPKModel{})
b, err := createTableQuery{q: q}.AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`CREATE TABLE "create_table_without_pk_models" ("string" text)`))
})
It("creates new table with Varchar=255", func() {
q := NewQuery(nil, &CreateTableWithoutPKModel{})
opt := &CreateTableOptions{Varchar: 255}
b, err := createTableQuery{q: q, opt: opt}.AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`CREATE TABLE "create_table_without_pk_models" ("string" varchar(255))`))
})
})

61
vendor/github.com/go-pg/pg/orm/delete.go generated vendored Normal file
View file

@ -0,0 +1,61 @@
package orm
import "github.com/go-pg/pg/internal"
func Delete(db DB, model interface{}) error {
res, err := NewQuery(db, model).Delete()
if err != nil {
return err
}
return internal.AssertOneRow(res.RowsAffected())
}
type deleteQuery struct {
q *Query
}
var _ QueryAppender = (*deleteQuery)(nil)
func (q deleteQuery) Copy() QueryAppender {
return deleteQuery{
q: q.q.Copy(),
}
}
func (q deleteQuery) Query() *Query {
return q.q
}
func (q deleteQuery) AppendQuery(b []byte) ([]byte, error) {
if q.q.stickyErr != nil {
return nil, q.q.stickyErr
}
var err error
if len(q.q.with) > 0 {
b, err = q.q.appendWith(b)
if err != nil {
return nil, err
}
}
b = append(b, "DELETE FROM "...)
b = q.q.appendFirstTableWithAlias(b)
if q.q.hasOtherTables() {
b = append(b, " USING "...)
b = q.q.appendOtherTables(b)
}
b, err = q.q.mustAppendWhere(b)
if err != nil {
return nil, err
}
if len(q.q.returning) > 0 {
b = q.q.appendReturning(b)
}
return b, nil
}

22
vendor/github.com/go-pg/pg/orm/delete_test.go generated vendored Normal file
View file

@ -0,0 +1,22 @@
package orm
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
type DeleteTest struct{}
var _ = Describe("Delete", func() {
It("supports WITH", func() {
q := NewQuery(nil, &DeleteTest{}).
WrapWith("wrapper").
Model(&DeleteTest{}).
Table("wrapper").
Where("delete_test.id = wrapper.id")
b, err := deleteQuery{q}.AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`WITH "wrapper" AS (SELECT FROM "delete_tests" AS "delete_test") DELETE FROM "delete_tests" AS "delete_test" USING "wrapper" WHERE (delete_test.id = wrapper.id)`))
})
})

45
vendor/github.com/go-pg/pg/orm/drop_table.go generated vendored Normal file
View file

@ -0,0 +1,45 @@
package orm
import "errors"
type DropTableOptions struct {
IfExists bool
Cascade bool
}
func DropTable(db DB, model interface{}, opt *DropTableOptions) (Result, error) {
return NewQuery(db, model).DropTable(opt)
}
type dropTableQuery struct {
q *Query
opt *DropTableOptions
}
func (q dropTableQuery) Copy() QueryAppender {
return q
}
func (q dropTableQuery) Query() *Query {
return q.q
}
func (q dropTableQuery) AppendQuery(b []byte) ([]byte, error) {
if q.q.stickyErr != nil {
return nil, q.q.stickyErr
}
if q.q.model == nil {
return nil, errors.New("pg: Model is nil")
}
b = append(b, "DROP TABLE "...)
if q.opt != nil && q.opt.IfExists {
b = append(b, "IF EXISTS "...)
}
b = q.q.appendTableName(b)
if q.opt != nil && q.opt.Cascade {
b = append(b, " CASCADE"...)
}
return b, nil
}

29
vendor/github.com/go-pg/pg/orm/drop_table_test.go generated vendored Normal file
View file

@ -0,0 +1,29 @@
package orm
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
type DropTableModel struct{}
var _ = Describe("CreateTable", func() {
It("drops table", func() {
q := NewQuery(nil, &DropTableModel{})
b, err := dropTableQuery{q: q}.AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`DROP TABLE "drop_table_models"`))
})
It("drops table if exists", func() {
q := NewQuery(nil, &DropTableModel{})
b, err := dropTableQuery{
q: q,
opt: &DropTableOptions{IfExists: true},
}.AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`DROP TABLE IF EXISTS "drop_table_models"`))
})
})

95
vendor/github.com/go-pg/pg/orm/field.go generated vendored Normal file
View file

@ -0,0 +1,95 @@
package orm
import (
"reflect"
"github.com/go-pg/pg/types"
)
const (
PrimaryKeyFlag = uint8(1) << iota
ForeignKeyFlag
NotNullFlag
UniqueFlag
ArrayFlag
customTypeFlag
)
type Field struct {
Type reflect.Type
GoName string // struct field name, e.g. Id
SQLName string // SQL name, .e.g. id
Column types.Q // escaped SQL name
SQLType string
Index []int
Default types.Q
flags uint8
append types.AppenderFunc
scan types.ScannerFunc
isZero func(reflect.Value) bool
}
func (f *Field) Copy() *Field {
copy := *f
copy.Index = copy.Index[:len(f.Index):len(f.Index)]
return &copy
}
func (f *Field) SetFlag(flag uint8) {
f.flags |= flag
}
func (f *Field) HasFlag(flag uint8) bool {
return f.flags&flag != 0
}
func (f *Field) Value(strct reflect.Value) reflect.Value {
return strct.FieldByIndex(f.Index)
}
func (f *Field) IsZero(strct reflect.Value) bool {
fv := f.Value(strct)
return f.isZero(fv)
}
func (f *Field) OmitZero(strct reflect.Value) bool {
return !f.HasFlag(NotNullFlag) && f.isZero(f.Value(strct))
}
func (f *Field) AppendValue(b []byte, strct reflect.Value, quote int) []byte {
fv := f.Value(strct)
if !f.HasFlag(NotNullFlag) && f.isZero(fv) {
return types.AppendNull(b, quote)
}
return f.append(b, fv, quote)
}
func (f *Field) ScanValue(strct reflect.Value, b []byte) error {
fv := fieldByIndex(strct, f.Index)
return f.scan(fv, b)
}
type Method struct {
Index int
flags int8
appender func([]byte, reflect.Value, int) []byte
}
func (m *Method) Has(flag int8) bool {
return m.flags&flag != 0
}
func (m *Method) Value(strct reflect.Value) reflect.Value {
return strct.Method(m.Index).Call(nil)[0]
}
func (m *Method) AppendValue(dst []byte, strct reflect.Value, quote int) []byte {
mv := m.Value(strct)
return m.appender(dst, mv, quote)
}

281
vendor/github.com/go-pg/pg/orm/format.go generated vendored Normal file
View file

@ -0,0 +1,281 @@
package orm
import (
"bytes"
"fmt"
"sort"
"strconv"
"strings"
"github.com/go-pg/pg/internal/parser"
"github.com/go-pg/pg/types"
)
var formatter Formatter
type FormatAppender interface {
AppendFormat([]byte, QueryFormatter) []byte
}
type sepFormatAppender interface {
FormatAppender
AppendSep([]byte) []byte
}
//------------------------------------------------------------------------------
type queryParamsAppender struct {
query string
params []interface{}
}
var _ FormatAppender = (*queryParamsAppender)(nil)
func Q(query string, params ...interface{}) queryParamsAppender {
return queryParamsAppender{query, params}
}
func (q queryParamsAppender) AppendFormat(b []byte, f QueryFormatter) []byte {
return f.FormatQuery(b, q.query, q.params...)
}
func (q queryParamsAppender) AppendValue(b []byte, quote int) ([]byte, error) {
return q.AppendFormat(b, formatter), nil
}
//------------------------------------------------------------------------------
type whereGroupAppender struct {
sep string
where []sepFormatAppender
}
var _ FormatAppender = (*whereAppender)(nil)
var _ sepFormatAppender = (*whereAppender)(nil)
func (q whereGroupAppender) AppendSep(b []byte) []byte {
return append(b, q.sep...)
}
func (q whereGroupAppender) AppendFormat(b []byte, f QueryFormatter) []byte {
b = append(b, '(')
for i, app := range q.where {
if i > 0 {
b = append(b, ' ')
b = app.AppendSep(b)
b = append(b, ' ')
}
b = app.AppendFormat(b, f)
}
b = append(b, ')')
return b
}
//------------------------------------------------------------------------------
type whereAppender struct {
sep string
where string
params []interface{}
}
var _ FormatAppender = (*whereAppender)(nil)
var _ sepFormatAppender = (*whereAppender)(nil)
func (q whereAppender) AppendSep(b []byte) []byte {
return append(b, q.sep...)
}
func (q whereAppender) AppendFormat(b []byte, f QueryFormatter) []byte {
b = append(b, '(')
b = f.FormatQuery(b, q.where, q.params...)
b = append(b, ')')
return b
}
//------------------------------------------------------------------------------
type fieldAppender struct {
field string
}
var _ FormatAppender = (*fieldAppender)(nil)
func (a fieldAppender) AppendFormat(b []byte, f QueryFormatter) []byte {
return types.AppendField(b, a.field, 1)
}
//------------------------------------------------------------------------------
type Formatter struct {
namedParams map[string]interface{}
}
func (f Formatter) String() string {
if len(f.namedParams) == 0 {
return ""
}
var keys []string
for k, _ := range f.namedParams {
keys = append(keys, k)
}
sort.Strings(keys)
var ss []string
for _, k := range keys {
ss = append(ss, fmt.Sprintf("%s=%v", k, f.namedParams[k]))
}
return " " + strings.Join(ss, " ")
}
func (f Formatter) copy() Formatter {
var cp Formatter
for param, value := range f.namedParams {
cp.SetParam(param, value)
}
return cp
}
func (f *Formatter) SetParam(param string, value interface{}) {
if f.namedParams == nil {
f.namedParams = make(map[string]interface{})
}
f.namedParams[param] = value
}
func (f *Formatter) WithParam(param string, value interface{}) Formatter {
cp := f.copy()
cp.SetParam(param, value)
return cp
}
func (f Formatter) Append(dst []byte, src string, params ...interface{}) []byte {
if (params == nil && f.namedParams == nil) || strings.IndexByte(src, '?') == -1 {
return append(dst, src...)
}
return f.append(dst, parser.NewString(src), params)
}
func (f Formatter) AppendBytes(dst, src []byte, params ...interface{}) []byte {
if (params == nil && f.namedParams == nil) || bytes.IndexByte(src, '?') == -1 {
return append(dst, src...)
}
return f.append(dst, parser.New(src), params)
}
func (f Formatter) FormatQuery(dst []byte, query string, params ...interface{}) []byte {
return f.Append(dst, query, params...)
}
func (f Formatter) append(dst []byte, p *parser.Parser, params []interface{}) []byte {
var paramsIndex int
var namedParamsOnce bool
var tableParams *tableParams
var model tableModel
if len(params) > 0 {
var ok bool
model, ok = params[len(params)-1].(tableModel)
if ok {
params = params[:len(params)-1]
}
}
for p.Valid() {
b, ok := p.ReadSep('?')
if !ok {
dst = append(dst, b...)
continue
}
if len(b) > 0 && b[len(b)-1] == '\\' {
dst = append(dst, b[:len(b)-1]...)
dst = append(dst, '?')
continue
}
dst = append(dst, b...)
if id, numeric := p.ReadIdentifier(); id != "" {
if numeric {
idx, err := strconv.Atoi(id)
if err != nil {
goto restore_param
}
if idx >= len(params) {
goto restore_param
}
dst = f.appendParam(dst, params[idx])
continue
}
if f.namedParams != nil {
if param, ok := f.namedParams[id]; ok {
dst = f.appendParam(dst, param)
continue
}
}
if !namedParamsOnce && len(params) > 0 {
namedParamsOnce = true
if len(params) > 0 {
tableParams, ok = newTableParams(params[len(params)-1])
if ok {
params = params[:len(params)-1]
}
}
}
if tableParams != nil {
dst, ok = tableParams.AppendParam(dst, f, id)
if ok {
continue
}
}
if model != nil {
dst, ok = model.AppendParam(dst, f, id)
if ok {
continue
}
}
restore_param:
dst = append(dst, '?')
dst = append(dst, id...)
continue
}
if paramsIndex >= len(params) {
dst = append(dst, '?')
continue
}
param := params[paramsIndex]
paramsIndex++
dst = f.appendParam(dst, param)
}
return dst
}
type queryAppender interface {
AppendQuery(dst []byte) ([]byte, error)
}
func (f Formatter) appendParam(b []byte, param interface{}) []byte {
switch param := param.(type) {
case queryAppender:
bb, err := param.AppendQuery(b)
if err != nil {
return types.AppendError(b, err)
}
return bb
case FormatAppender:
return param.AppendFormat(b, f)
default:
return types.Append(b, param, 1)
}
}

203
vendor/github.com/go-pg/pg/orm/format_test.go generated vendored Normal file
View file

@ -0,0 +1,203 @@
package orm_test
import (
"database/sql/driver"
"errors"
"fmt"
"math"
"testing"
"github.com/go-pg/pg/orm"
"github.com/go-pg/pg/types"
)
type ValuerError string
func (e ValuerError) Value() (driver.Value, error) {
return nil, errors.New(string(e))
}
type StructFormatter struct {
tableName struct{} `sql:"my_name,alias:my_alias"`
String string
NotNull string `sql:",notnull"`
Iface interface{}
}
func (StructFormatter) Method() string {
return "method_value"
}
func (StructFormatter) MethodParam() types.Q {
return types.Q("?string")
}
func (StructFormatter) MethodWithArgs(string) string {
return "method_value"
}
func (StructFormatter) MethodWithCompositeReturn() (string, string) {
return "method_value1", "method_value2"
}
type EmbeddedStructFormatter struct {
*StructFormatter
}
func (EmbeddedStructFormatter) Method2() string {
return "method_value2"
}
type params []interface{}
type paramsMap map[string]interface{}
type formatTest struct {
q string
params params
paramsMap paramsMap
wanted string
}
var (
structv = &StructFormatter{
String: "string_value",
Iface: "iface_value",
}
embeddedStructv = &EmbeddedStructFormatter{structv}
)
var formatTests = []formatTest{
{q: "?", params: params{ValuerError("error")}, wanted: "?!(error)"},
{q: "?", wanted: "?"},
{q: "? ? ?", params: params{"foo", "bar"}, wanted: "'foo' 'bar' ?"},
{q: "?0 ?1", params: params{"foo", "bar"}, wanted: "'foo' 'bar'"},
{q: "?0 ?1 ?2", params: params{"foo", "bar"}, wanted: "'foo' 'bar' ?2"},
{q: "?0 ?1 ?0", params: params{"foo", "bar"}, wanted: "'foo' 'bar' 'foo'"},
{q: "one ?foo two", wanted: "one ?foo two"},
{q: "one ?foo two", params: params{structv}, wanted: "one ?foo two"},
{q: "one ?MethodWithArgs two", params: params{structv}, wanted: "one ?MethodWithArgs two"},
{q: "one ?MethodWithCompositeReturn two", params: params{structv}, wanted: "one ?MethodWithCompositeReturn two"},
{q: "?", params: params{uint64(math.MaxUint64)}, wanted: "18446744073709551615"},
{q: "?", params: params{orm.Q("query")}, wanted: "query"},
{q: "?", params: params{types.F("field")}, wanted: `"field"`},
{q: "?", params: params{structv}, wanted: `'{"String":"string_value","NotNull":"","Iface":"iface_value"}'`},
{q: `\? ?`, params: params{1}, wanted: "? 1"},
{q: `?`, params: params{types.Q(`\?`)}, wanted: `\?`},
{q: `?`, params: params{types.Q(`\\?`)}, wanted: `\\?`},
{q: `?`, params: params{types.Q(`\?param`)}, wanted: `\?param`},
{q: "?string", params: params{structv}, wanted: `'string_value'`},
{q: "?iface", params: params{structv}, wanted: `'iface_value'`},
{q: "?string", params: params{&StructFormatter{}}, wanted: `NULL`},
{
q: "? ?string ?",
params: params{"one", "two", structv},
wanted: "'one' 'string_value' 'two'",
},
{
q: "?string ?Method",
params: params{structv},
wanted: "'string_value' 'method_value'",
},
{
q: "?string ?Method ?Method2",
params: params{embeddedStructv},
wanted: "'string_value' 'method_value' 'method_value2'",
},
{
q: "?string",
params: params{structv},
paramsMap: paramsMap{"string": "my_value"},
wanted: "'my_value'",
},
{
q: "?",
params: params{types.Q("?string")},
paramsMap: paramsMap{"string": "my_value"},
wanted: "?string",
},
{
q: "?",
params: params{types.F("?string")},
paramsMap: paramsMap{"string": types.Q("my_value")},
wanted: `"?string"`,
},
{
q: "?",
params: params{orm.Q("?string")},
paramsMap: paramsMap{"string": "my_value"},
wanted: "'my_value'",
},
{
q: "?MethodParam",
params: params{structv},
paramsMap: paramsMap{"string": "my_value"},
wanted: "?string",
},
}
func TestFormatQuery(t *testing.T) {
for _, test := range formatTests {
var f orm.Formatter
for k, v := range test.paramsMap {
f.SetParam(k, v)
}
got := f.Append(nil, test.q, test.params...)
if string(got) != test.wanted {
t.Fatalf(
"got %q, wanted %q (q=%q params=%v paramsMap=%v)",
got, test.wanted, test.q, test.params, test.paramsMap,
)
}
}
}
func BenchmarkFormatQueryWithoutParams(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = orm.Q("SELECT * FROM my_table WHERE id = 1")
}
}
func BenchmarkFormatQuery1Param(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = orm.Q("SELECT * FROM my_table WHERE id = ?", 1)
}
}
func BenchmarkFormatQuery10Params(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = orm.Q(
"SELECT * FROM my_table WHERE id IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
)
}
}
func BenchmarkFormatQuerySprintf(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = fmt.Sprintf("SELECT * FROM my_table WHERE id = %d", 1)
}
}
func BenchmarkFormatQueryStructParam(b *testing.B) {
param := StructFormatter{
String: "1",
}
for i := 0; i < b.N; i++ {
_ = orm.Q("SELECT * FROM my_table WHERE id = ?string", param)
}
}
func BenchmarkFormatQueryStructMethod(b *testing.B) {
param := StructFormatter{}
for i := 0; i < b.N; i++ {
_ = orm.Q("SELECT * FROM my_table WHERE id = ?Method", &param)
}
}

180
vendor/github.com/go-pg/pg/orm/hook.go generated vendored Normal file
View file

@ -0,0 +1,180 @@
package orm
import "reflect"
const (
AfterQueryHookFlag = uint8(1) << iota
AfterSelectHookFlag
BeforeInsertHookFlag
AfterInsertHookFlag
BeforeUpdateHookFlag
AfterUpdateHookFlag
BeforeDeleteHookFlag
AfterDeleteHookFlag
)
type hookStubs struct{}
func (hookStubs) Init() error {
return nil
}
func (hookStubs) AfterQuery(_ DB) error {
return nil
}
func (hookStubs) AfterSelect(_ DB) error {
return nil
}
func (hookStubs) BeforeInsert(_ DB) error {
return nil
}
func (hookStubs) AfterInsert(_ DB) error {
return nil
}
func (hookStubs) BeforeUpdate(_ DB) error {
return nil
}
func (hookStubs) AfterUpdate(_ DB) error {
return nil
}
func (hookStubs) BeforeDelete(_ DB) error {
return nil
}
func (hookStubs) AfterDelete(_ DB) error {
return nil
}
func callHookSlice(slice reflect.Value, ptr bool, db DB, hook func(reflect.Value, DB) error) error {
var firstErr error
for i := 0; i < slice.Len(); i++ {
var err error
if ptr {
err = hook(slice.Index(i), db)
} else {
err = hook(slice.Index(i).Addr(), db)
}
if err != nil && firstErr == nil {
firstErr = err
}
}
return firstErr
}
type afterQueryHook interface {
AfterQuery(db DB) error
}
var afterQueryHookType = reflect.TypeOf((*afterQueryHook)(nil)).Elem()
func callAfterQueryHook(v reflect.Value, db DB) error {
return v.Interface().(afterQueryHook).AfterQuery(db)
}
func callAfterQueryHookSlice(slice reflect.Value, ptr bool, db DB) error {
return callHookSlice(slice, ptr, db, callAfterQueryHook)
}
type afterSelectHook interface {
AfterSelect(db DB) error
}
var afterSelectHookType = reflect.TypeOf((*afterSelectHook)(nil)).Elem()
func callAfterSelectHook(v reflect.Value, db DB) error {
return v.Interface().(afterSelectHook).AfterSelect(db)
}
func callAfterSelectHookSlice(slice reflect.Value, ptr bool, db DB) error {
return callHookSlice(slice, ptr, db, callAfterSelectHook)
}
type beforeInsertHook interface {
BeforeInsert(db DB) error
}
var beforeInsertHookType = reflect.TypeOf((*beforeInsertHook)(nil)).Elem()
func callBeforeInsertHook(v reflect.Value, db DB) error {
return v.Interface().(beforeInsertHook).BeforeInsert(db)
}
func callBeforeInsertHookSlice(slice reflect.Value, ptr bool, db DB) error {
return callHookSlice(slice, ptr, db, callBeforeInsertHook)
}
type afterInsertHook interface {
AfterInsert(db DB) error
}
var afterInsertHookType = reflect.TypeOf((*afterInsertHook)(nil)).Elem()
func callAfterInsertHook(v reflect.Value, db DB) error {
return v.Interface().(afterInsertHook).AfterInsert(db)
}
func callAfterInsertHookSlice(slice reflect.Value, ptr bool, db DB) error {
return callHookSlice(slice, ptr, db, callAfterInsertHook)
}
type beforeUpdateHook interface {
BeforeUpdate(db DB) error
}
var beforeUpdateHookType = reflect.TypeOf((*beforeUpdateHook)(nil)).Elem()
func callBeforeUpdateHook(v reflect.Value, db DB) error {
return v.Interface().(beforeUpdateHook).BeforeUpdate(db)
}
func callBeforeUpdateHookSlice(slice reflect.Value, ptr bool, db DB) error {
return callHookSlice(slice, ptr, db, callBeforeUpdateHook)
}
type afterUpdateHook interface {
AfterUpdate(db DB) error
}
var afterUpdateHookType = reflect.TypeOf((*afterUpdateHook)(nil)).Elem()
func callAfterUpdateHook(v reflect.Value, db DB) error {
return v.Interface().(afterUpdateHook).AfterUpdate(db)
}
func callAfterUpdateHookSlice(slice reflect.Value, ptr bool, db DB) error {
return callHookSlice(slice, ptr, db, callAfterUpdateHook)
}
type beforeDeleteHook interface {
BeforeDelete(db DB) error
}
var beforeDeleteHookType = reflect.TypeOf((*beforeDeleteHook)(nil)).Elem()
func callBeforeDeleteHook(v reflect.Value, db DB) error {
return v.Interface().(beforeDeleteHook).BeforeDelete(db)
}
func callBeforeDeleteHookSlice(slice reflect.Value, ptr bool, db DB) error {
return callHookSlice(slice, ptr, db, callBeforeDeleteHook)
}
type afterDeleteHook interface {
AfterDelete(db DB) error
}
var afterDeleteHookType = reflect.TypeOf((*afterDeleteHook)(nil)).Elem()
func callAfterDeleteHook(v reflect.Value, db DB) error {
return v.Interface().(afterDeleteHook).AfterDelete(db)
}
func callAfterDeleteHookSlice(slice reflect.Value, ptr bool, db DB) error {
return callHookSlice(slice, ptr, db, callAfterDeleteHook)
}

17
vendor/github.com/go-pg/pg/orm/inflection.go generated vendored Normal file
View file

@ -0,0 +1,17 @@
package orm
import (
"github.com/jinzhu/inflection"
)
var tableNameInflector func(string) string
func init() {
SetTableNameInflector(inflection.Plural)
}
// SetTableNameInflector overrides the default func that pluralizes
// model name to get table name, e.g. my_article becomes my_articles.
func SetTableNameInflector(fn func(string) string) {
tableNameInflector = fn
}

139
vendor/github.com/go-pg/pg/orm/insert.go generated vendored Normal file
View file

@ -0,0 +1,139 @@
package orm
import (
"errors"
"reflect"
)
func Insert(db DB, v ...interface{}) error {
_, err := NewQuery(db, v...).Insert()
return err
}
type insertQuery struct {
q *Query
returningFields []*Field
}
var _ QueryAppender = (*insertQuery)(nil)
func (q insertQuery) Copy() QueryAppender {
return insertQuery{
q: q.q.Copy(),
}
}
func (q insertQuery) Query() *Query {
return q.q
}
func (q insertQuery) AppendQuery(b []byte) ([]byte, error) {
if q.q.stickyErr != nil {
return nil, q.q.stickyErr
}
if q.q.model == nil {
return nil, errors.New("pg: Model is nil")
}
table := q.q.model.Table()
value := q.q.model.Value()
var err error
if len(q.q.with) > 0 {
b, err = q.q.appendWith(b)
if err != nil {
return nil, err
}
}
b = append(b, "INSERT INTO "...)
if q.q.onConflict != nil {
b = q.q.appendFirstTableWithAlias(b)
} else {
b = q.q.appendFirstTable(b)
}
b = append(b, " ("...)
if q.q.hasModel() {
b = appendColumns(b, table.Fields)
} else if q.q.columns != nil {
b = q.q.appendColumns(b)
}
b = append(b, ')')
if q.q.hasModel() {
b = append(b, " VALUES ("...)
if value.Kind() == reflect.Struct {
b = q.appendValues(b, table.Fields, value)
} else {
for i := 0; i < value.Len(); i++ {
el := value.Index(i)
if el.Kind() == reflect.Interface {
el = el.Elem()
}
b = q.appendValues(b, table.Fields, reflect.Indirect(el))
if i != value.Len()-1 {
b = append(b, "), ("...)
}
}
}
b = append(b, ')')
}
if q.q.hasOtherTables() {
b = append(b, " SELECT * FROM "...)
b = q.q.appendOtherTables(b)
}
if q.q.onConflict != nil {
b = append(b, " ON CONFLICT "...)
b = q.q.onConflict.AppendFormat(b, q.q)
if q.q.onConflictDoUpdate() {
if len(q.q.set) > 0 {
b = q.q.appendSet(b)
}
if len(q.q.updWhere) > 0 {
b = q.q.appendUpdWhere(b)
}
}
}
if len(q.q.returning) > 0 {
b = q.q.appendReturning(b)
} else if len(q.returningFields) > 0 {
b = q.appendReturningFields(b, q.returningFields)
}
return b, nil
}
func (q *insertQuery) appendValues(b []byte, fields []*Field, v reflect.Value) []byte {
for i, f := range fields {
if i > 0 {
b = append(b, ", "...)
}
if f.OmitZero(v) {
b = append(b, "DEFAULT"...)
q.addReturningField(f)
} else {
b = f.AppendValue(b, v, 1)
}
}
return b
}
func (ins *insertQuery) addReturningField(field *Field) {
for _, f := range ins.returningFields {
if f == field {
return
}
}
ins.returningFields = append(ins.returningFields, field)
}
func (insertQuery) appendReturningFields(b []byte, fields []*Field) []byte {
b = append(b, " RETURNING "...)
b = appendColumns(b, fields)
return b
}

128
vendor/github.com/go-pg/pg/orm/insert_test.go generated vendored Normal file
View file

@ -0,0 +1,128 @@
package orm
import (
"github.com/go-pg/pg/types"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
type InsertTest struct {
Id int
Value string
}
type EmbeddingTest struct {
tableName struct{} `sql:"name"`
Id int
Field int
}
type EmbeddedInsertTest struct {
tableName struct{} `sql:"my_name"`
EmbeddingTest
Field2 int
}
type OverrideInsertTest struct {
EmbeddingTest `pg:",override"`
Field2 int
}
type InsertNullTest struct {
F1 int
F2 int `sql:",notnull"`
F3 int `sql:",pk"`
F4 int `sql:",pk,notnull"`
}
type InsertQTest struct {
Geo types.Q
Func types.ValueAppender
}
var _ = Describe("Insert", func() {
It("multi inserts", func() {
q := NewQuery(nil, &InsertTest{
Id: 1,
Value: "hello",
}, &InsertTest{
Id: 2,
})
b, err := insertQuery{q: q}.AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`INSERT INTO "insert_tests" ("id", "value") VALUES (1, 'hello'), (2, DEFAULT) RETURNING "value"`))
})
It("supports ON CONFLICT DO UPDATE", func() {
q := NewQuery(nil, &InsertTest{}).
Where("1 = 1").
OnConflict("(unq1) DO UPDATE").
Set("count1 = count1 + 1").
Where("2 = 2")
b, err := insertQuery{q: q}.AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`INSERT INTO "insert_tests" AS "insert_test" ("id", "value") VALUES (DEFAULT, DEFAULT) ON CONFLICT (unq1) DO UPDATE SET count1 = count1 + 1 WHERE (2 = 2) RETURNING "id", "value"`))
})
It("supports ON CONFLICT DO NOTHING", func() {
q := NewQuery(nil, &InsertTest{}).
OnConflict("(unq1) DO NOTHING").
Set("count1 = count1 + 1").
Where("cond1 IS TRUE")
b, err := insertQuery{q: q}.AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`INSERT INTO "insert_tests" AS "insert_test" ("id", "value") VALUES (DEFAULT, DEFAULT) ON CONFLICT (unq1) DO NOTHING RETURNING "id", "value"`))
})
It("supports custom table name on embedded struct", func() {
q := NewQuery(nil, &EmbeddedInsertTest{})
b, err := insertQuery{q: q}.AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`INSERT INTO my_name ("id", "field", "field2") VALUES (DEFAULT, DEFAULT, DEFAULT) RETURNING "id", "field", "field2"`))
})
It("overrides table name with embedded struct", func() {
q := NewQuery(nil, &OverrideInsertTest{})
b, err := insertQuery{q: q}.AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`INSERT INTO name ("id", "field", "field2") VALUES (DEFAULT, DEFAULT, DEFAULT) RETURNING "id", "field", "field2"`))
})
It("supports notnull", func() {
q := NewQuery(nil, &InsertNullTest{})
b, err := insertQuery{q: q}.AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`INSERT INTO "insert_null_tests" ("f1", "f2", "f3", "f4") VALUES (DEFAULT, 0, DEFAULT, 0) RETURNING "f1", "f3"`))
})
It("inserts types.Q", func() {
q := NewQuery(nil, &InsertQTest{
Geo: types.Q("ST_GeomFromText('POLYGON((75.150000 29.530000, 77.000000 29.000000, 77.600000 29.500000, 75.150000 29.530000))')"),
Func: Q("my_func(?)", "param"),
})
b, err := insertQuery{q: q}.AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`INSERT INTO "insert_q_tests" ("geo", "func") VALUES (ST_GeomFromText('POLYGON((75.150000 29.530000, 77.000000 29.000000, 77.600000 29.500000, 75.150000 29.530000))'), my_func('param'))`))
})
It("supports FROM", func() {
q := NewQuery(nil, &InsertTest{})
q = q.WrapWith("data").
TableExpr("dst").
ColumnExpr("dst_col1, dst_col2").
TableExpr("data")
b, err := insertQuery{q: q}.AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`WITH "data" AS (SELECT "insert_test"."id", "insert_test"."value" FROM "insert_tests" AS "insert_test") INSERT INTO dst (dst_col1, dst_col2) SELECT * FROM data`))
})
})

278
vendor/github.com/go-pg/pg/orm/join.go generated vendored Normal file
View file

@ -0,0 +1,278 @@
package orm
import (
"github.com/go-pg/pg/internal"
"github.com/go-pg/pg/types"
)
type join struct {
Parent *join
BaseModel tableModel
JoinModel tableModel
Rel *Relation
ApplyQuery func(*Query) (*Query, error)
Columns []string
}
func (j *join) Select(db DB) error {
switch j.Rel.Type {
case HasManyRelation:
return j.selectMany(db)
case Many2ManyRelation:
return j.selectM2M(db)
}
panic("not reached")
}
func (j *join) selectMany(db DB) error {
q, err := j.manyQuery(db)
if err != nil {
return err
}
return q.Select()
}
func (j *join) manyQuery(db DB) (*Query, error) {
root := j.JoinModel.Root()
index := j.JoinModel.ParentIndex()
manyModel := newManyModel(j)
q := NewQuery(db, manyModel)
if j.ApplyQuery != nil {
var err error
q, err = j.ApplyQuery(q)
if err != nil {
return nil, err
}
}
q.columns = append(q.columns, hasManyColumnsAppender{j})
baseTable := j.BaseModel.Table()
var where []byte
where = append(where, "("...)
where = columns(where, j.JoinModel.Table().Alias, "", j.Rel.FKs)
where = append(where, ") IN ("...)
where = appendChildValues(where, root, index, baseTable.PKs)
where = append(where, ")"...)
q = q.Where(internal.BytesToString(where))
if j.Rel.Polymorphic {
q = q.Where(
`? IN (?, ?)`,
types.F(j.Rel.BasePrefix+"type"),
baseTable.ModelName, baseTable.TypeName,
)
}
return q, nil
}
func (j *join) selectM2M(db DB) error {
q, err := j.m2mQuery(db)
if err != nil {
return err
}
return q.Select()
}
func (j *join) m2mQuery(db DB) (*Query, error) {
m2mModel := newM2MModel(j)
q := NewQuery(db, m2mModel)
if j.ApplyQuery != nil {
var err error
q, err = j.ApplyQuery(q)
if err != nil {
return nil, err
}
}
q.columns = append(q.columns, hasManyColumnsAppender{j})
index := j.JoinModel.ParentIndex()
baseTable := j.BaseModel.Table()
var join []byte
join = append(join, "JOIN "...)
if db != nil {
join = db.FormatQuery(join, string(j.Rel.M2MTableName))
} else {
join = append(join, j.Rel.M2MTableName...)
}
join = append(join, " AS "...)
join = append(join, j.Rel.M2MTableAlias...)
join = append(join, " ON ("...)
join = columns(join, j.Rel.M2MTableAlias, j.Rel.BasePrefix, baseTable.PKs)
join = append(join, ") IN ("...)
join = appendChildValues(join, j.BaseModel.Root(), index, baseTable.PKs)
join = append(join, ")"...)
q = q.Join(internal.BytesToString(join))
joinAlias := j.JoinModel.Table().Alias
for _, pk := range j.JoinModel.Table().PKs {
q = q.Where(
"?.? = ?.?",
joinAlias, pk.Column,
j.Rel.M2MTableAlias, types.F(j.Rel.JoinPrefix+pk.SQLName),
)
}
return q, nil
}
func (j *join) hasParent() bool {
if j.Parent != nil {
switch j.Parent.Rel.Type {
case HasOneRelation, BelongsToRelation:
return true
}
}
return false
}
func (j *join) appendAlias(b []byte) []byte {
b = append(b, '"')
b = appendAlias(b, j, true)
b = append(b, '"')
return b
}
func (j *join) appendAliasColumn(b []byte, column string) []byte {
b = append(b, '"')
b = appendAlias(b, j, true)
b = append(b, "__"...)
b = types.AppendField(b, column, 2)
b = append(b, '"')
return b
}
func (j *join) appendBaseAlias(b []byte) []byte {
if j.hasParent() {
b = append(b, '"')
b = appendAlias(b, j.Parent, true)
b = append(b, '"')
return b
}
return append(b, j.BaseModel.Table().Alias...)
}
func appendAlias(b []byte, j *join, topLevel bool) []byte {
if j.hasParent() {
b = appendAlias(b, j.Parent, topLevel)
topLevel = false
}
if !topLevel {
b = append(b, "__"...)
}
b = append(b, j.Rel.Field.SQLName...)
return b
}
func (j *join) appendHasOneColumns(b []byte) []byte {
if j.Columns == nil {
for i, f := range j.JoinModel.Table().Fields {
if i > 0 {
b = append(b, ", "...)
}
b = j.appendAlias(b)
b = append(b, '.')
b = append(b, f.Column...)
b = append(b, " AS "...)
b = j.appendAliasColumn(b, f.SQLName)
}
return b
}
for i, column := range j.Columns {
if i > 0 {
b = append(b, ", "...)
}
b = j.appendAlias(b)
b = append(b, '.')
b = types.AppendField(b, column, 1)
b = append(b, " AS "...)
b = j.appendAliasColumn(b, column)
}
return b
}
func (j *join) appendHasOneJoin(db DB, b []byte) []byte {
b = append(b, "LEFT JOIN "...)
if db != nil {
b = db.FormatQuery(b, string(j.JoinModel.Table().Name))
} else {
b = append(b, j.JoinModel.Table().Name...)
}
b = append(b, " AS "...)
b = j.appendAlias(b)
b = append(b, " ON "...)
if j.Rel.Type == HasOneRelation {
joinTable := j.Rel.JoinTable
for i, fk := range j.Rel.FKs {
if i > 0 {
b = append(b, " AND "...)
}
b = j.appendAlias(b)
b = append(b, '.')
b = append(b, joinTable.PKs[i].Column...)
b = append(b, " = "...)
b = j.appendBaseAlias(b)
b = append(b, '.')
b = append(b, fk.Column...)
}
} else {
baseTable := j.BaseModel.Table()
for i, fk := range j.Rel.FKs {
if i > 0 {
b = append(b, " AND "...)
}
b = j.appendAlias(b)
b = append(b, '.')
b = append(b, fk.Column...)
b = append(b, " = "...)
b = j.appendBaseAlias(b)
b = append(b, '.')
b = append(b, baseTable.PKs[i].Column...)
}
}
return b
}
type hasManyColumnsAppender struct {
*join
}
func (q hasManyColumnsAppender) AppendFormat(b []byte, f QueryFormatter) []byte {
if q.Rel.M2MTableAlias != "" {
b = append(b, q.Rel.M2MTableAlias...)
b = append(b, ".*, "...)
}
joinTable := q.JoinModel.Table()
if q.Columns == nil {
for i, f := range joinTable.Fields {
if i > 0 {
b = append(b, ", "...)
}
b = append(b, joinTable.Alias...)
b = append(b, '.')
b = append(b, f.Column...)
}
return b
}
for i, column := range q.Columns {
if i > 0 {
b = append(b, ", "...)
}
b = append(b, joinTable.Alias...)
b = append(b, '.')
b = types.AppendField(b, column, 1)
}
return b
}

51
vendor/github.com/go-pg/pg/orm/join_test.go generated vendored Normal file
View file

@ -0,0 +1,51 @@
package orm
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
type JoinTest struct {
tableName struct{} `sql:"JoinTest,alias:JoinTest"`
Id int
HasOne *HasOne
HasOneId int
BelongsTo *BelongsTo
}
type HasOne struct {
tableName struct{} `sql:"HasOne,alias:HasOne"`
Id int
HasOne *HasOne
HasOneId int
}
type BelongsTo struct {
tableName struct{} `sql:"BelongsTo,alias:BelongsTo"`
Id int
JoinTestId int
}
var _ = Describe("Select", func() {
It("supports has one", func() {
q := NewQuery(nil, &JoinTest{}).Relation("HasOne.HasOne", nil)
b, err := selectQuery{q: q}.AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`SELECT JoinTest."id", JoinTest."has_one_id", "has_one"."id" AS "has_one__id", "has_one"."has_one_id" AS "has_one__has_one_id", "has_one__has_one"."id" AS "has_one__has_one__id", "has_one__has_one"."has_one_id" AS "has_one__has_one__has_one_id" FROM JoinTest AS JoinTest LEFT JOIN HasOne AS "has_one" ON "has_one"."id" = JoinTest."has_one_id" LEFT JOIN HasOne AS "has_one__has_one" ON "has_one__has_one"."id" = "has_one"."has_one_id"`))
})
It("supports belongs to", func() {
q := NewQuery(nil, &JoinTest{}).Relation("BelongsTo", nil)
b, err := selectQuery{q: q}.AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`SELECT JoinTest."id", JoinTest."has_one_id", "belongs_to"."id" AS "belongs_to__id", "belongs_to"."join_test_id" AS "belongs_to__join_test_id" FROM JoinTest AS JoinTest LEFT JOIN BelongsTo AS "belongs_to" ON "belongs_to"."join_test_id" = JoinTest."id"`))
})
})

13
vendor/github.com/go-pg/pg/orm/main_test.go generated vendored Normal file
View file

@ -0,0 +1,13 @@
package orm_test
import (
"testing"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
func TestGinkgo(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "ORM")
}

88
vendor/github.com/go-pg/pg/orm/model.go generated vendored Normal file
View file

@ -0,0 +1,88 @@
package orm
import (
"database/sql"
"errors"
"fmt"
"reflect"
"github.com/go-pg/pg/types"
)
type useQueryOne interface {
useQueryOne() bool
}
type Model interface {
ColumnScanner
Init() error
// NewModel returns ColumnScanner that is used to scan columns
// from the current row.
NewModel() ColumnScanner
// AddModel adds ColumnScanner to the Collection.
AddModel(ColumnScanner) error
AfterQuery(DB) error
AfterSelect(DB) error
BeforeInsert(DB) error
AfterInsert(DB) error
BeforeUpdate(DB) error
AfterUpdate(DB) error
BeforeDelete(DB) error
AfterDelete(DB) error
}
func NewModel(values ...interface{}) (Model, error) {
if len(values) > 1 {
return Scan(values...), nil
}
v0 := values[0]
switch v0 := v0.(type) {
case Model:
return v0, nil
case sql.Scanner:
return Scan(v0), nil
}
v := reflect.ValueOf(v0)
if !v.IsValid() {
return nil, errors.New("pg: Model(nil)")
}
if v.Kind() != reflect.Ptr {
return nil, fmt.Errorf("pg: Model(non-pointer %T)", v0)
}
v = v.Elem()
switch v.Kind() {
case reflect.Struct:
return newStructTableModelValue(v), nil
case reflect.Slice:
typ := v.Type()
structType := indirectType(typ.Elem())
if structType.Kind() == reflect.Struct && structType != timeType {
m := sliceTableModel{
structTableModel: structTableModel{
table: Tables.Get(structType),
root: v,
},
slice: v,
}
m.init(typ)
return &m, nil
} else {
return &sliceModel{
slice: v,
scan: types.Scanner(structType),
}, nil
}
}
return Scan(v0), nil
}

19
vendor/github.com/go-pg/pg/orm/model_discard.go generated vendored Normal file
View file

@ -0,0 +1,19 @@
package orm
type Discard struct {
hookStubs
}
var _ Model = (*Discard)(nil)
func (d Discard) NewModel() ColumnScanner {
return d
}
func (Discard) AddModel(_ ColumnScanner) error {
return nil
}
func (Discard) ScanColumn(colIdx int, colName string, b []byte) error {
return nil
}

42
vendor/github.com/go-pg/pg/orm/model_scan.go generated vendored Normal file
View file

@ -0,0 +1,42 @@
package orm
import (
"fmt"
"github.com/go-pg/pg/types"
)
type valuesModel struct {
hookStubs
values []interface{}
}
var _ Model = valuesModel{}
func Scan(values ...interface{}) valuesModel {
return valuesModel{
values: values,
}
}
func (valuesModel) useQueryOne() bool {
return true
}
func (m valuesModel) NewModel() ColumnScanner {
return m
}
func (valuesModel) AddModel(_ ColumnScanner) error {
return nil
}
func (m valuesModel) ScanColumn(colIdx int, colName string, b []byte) error {
if colIdx >= len(m.values) {
return fmt.Errorf(
"pg: no Scan var for column index=%d name=%q",
colIdx, colName,
)
}
return types.Scan(m.values[colIdx], b)
}

35
vendor/github.com/go-pg/pg/orm/model_slice.go generated vendored Normal file
View file

@ -0,0 +1,35 @@
package orm
import (
"reflect"
"github.com/go-pg/pg/internal"
)
type sliceModel struct {
hookStubs
slice reflect.Value
scan func(reflect.Value, []byte) error
}
var _ Model = (*sliceModel)(nil)
func (m *sliceModel) Init() error {
if m.slice.IsValid() && m.slice.Len() > 0 {
m.slice.Set(m.slice.Slice(0, 0))
}
return nil
}
func (m *sliceModel) NewModel() ColumnScanner {
return m
}
func (sliceModel) AddModel(_ ColumnScanner) error {
return nil
}
func (m *sliceModel) ScanColumn(colIdx int, _ string, b []byte) error {
v := internal.SliceNextElem(m.slice)
return m.scan(v, b)
}

107
vendor/github.com/go-pg/pg/orm/model_table.go generated vendored Normal file
View file

@ -0,0 +1,107 @@
package orm
import (
"errors"
"fmt"
"reflect"
)
type tableModel interface {
Model
Table() *Table
Relation() *Relation
AppendParam([]byte, QueryFormatter, string) ([]byte, bool)
Join(string, func(*Query) (*Query, error)) (bool, *join)
GetJoin(string) *join
GetJoins() []join
AddJoin(join) *join
Root() reflect.Value
Index() []int
ParentIndex() []int
Mount(reflect.Value)
Value() reflect.Value
scanColumn(int, string, []byte) (bool, error)
}
func newTableModel(value interface{}) (tableModel, error) {
if value, ok := value.(tableModel); ok {
return value, nil
}
v := reflect.ValueOf(value)
if !v.IsValid() {
return nil, errors.New("pg: Model(nil)")
}
if v.Kind() != reflect.Ptr {
return nil, fmt.Errorf("pg: Model(non-pointer %T)", value)
}
if v.IsNil() {
typ := v.Type().Elem()
if typ.Kind() == reflect.Struct {
return newStructTableModelType(typ), nil
}
return nil, errors.New("pg: Model(nil)")
}
return newTableModelValue(v.Elem())
}
func newTableModelValue(v reflect.Value) (tableModel, error) {
switch v.Kind() {
case reflect.Struct:
return newStructTableModelValue(v), nil
case reflect.Slice:
structType := sliceElemType(v)
if structType.Kind() == reflect.Struct {
m := sliceTableModel{
structTableModel: structTableModel{
table: Tables.Get(structType),
root: v,
},
slice: v,
}
m.init(v.Type())
return &m, nil
}
}
return nil, fmt.Errorf("pg: Model(unsupported %s)", v.Type())
}
func newTableModelIndex(root reflect.Value, index []int, rel *Relation) (tableModel, error) {
typ := typeByIndex(root.Type(), index)
if typ.Kind() == reflect.Struct {
return &structTableModel{
table: Tables.Get(typ),
rel: rel,
root: root,
index: index,
}, nil
}
if typ.Kind() == reflect.Slice {
structType := indirectType(typ.Elem())
if structType.Kind() == reflect.Struct {
m := sliceTableModel{
structTableModel: structTableModel{
table: Tables.Get(structType),
rel: rel,
root: root,
index: index,
},
}
m.init(typ)
return &m, nil
}
}
return nil, fmt.Errorf("pg: NewModel(%s)", typ)
}

120
vendor/github.com/go-pg/pg/orm/model_table_m2m.go generated vendored Normal file
View file

@ -0,0 +1,120 @@
package orm
import (
"fmt"
"reflect"
)
type m2mModel struct {
*sliceTableModel
baseTable *Table
rel *Relation
buf []byte
dstValues map[string][]reflect.Value
columns map[string]string
}
var _ tableModel = (*m2mModel)(nil)
func newM2MModel(join *join) *m2mModel {
baseTable := join.BaseModel.Table()
joinModel := join.JoinModel.(*sliceTableModel)
dstValues := dstValues(joinModel, baseTable.PKs)
m := &m2mModel{
sliceTableModel: joinModel,
baseTable: baseTable,
rel: join.Rel,
dstValues: dstValues,
columns: make(map[string]string),
}
if !m.sliceOfPtr {
m.strct = reflect.New(m.table.Type).Elem()
}
return m
}
func (m *m2mModel) NewModel() ColumnScanner {
if m.sliceOfPtr {
m.strct = reflect.New(m.table.Type).Elem()
} else {
m.strct.Set(m.table.zeroStruct)
}
m.structInited = false
m.structTableModel.NewModel()
return m
}
func (m *m2mModel) AddModel(model ColumnScanner) error {
m.buf = modelIdMap(m.buf[:0], m.columns, m.rel.BasePrefix, m.baseTable.PKs)
dstValues, ok := m.dstValues[string(m.buf)]
if !ok {
return fmt.Errorf("pg: can't find dst value for model id=%q", m.buf)
}
for _, v := range dstValues {
if m.sliceOfPtr {
v.Set(reflect.Append(v, m.strct.Addr()))
} else {
v.Set(reflect.Append(v, m.strct))
}
}
return nil
}
func (m *m2mModel) AfterQuery(db DB) error {
if !m.rel.JoinTable.HasFlag(AfterQueryHookFlag) {
return nil
}
var retErr error
for _, slices := range m.dstValues {
for _, slice := range slices {
err := callAfterQueryHookSlice(slice, m.sliceOfPtr, db)
if err != nil && retErr == nil {
retErr = err
}
}
}
return retErr
}
func (m *m2mModel) AfterSelect(db DB) error {
return nil
}
func (m *m2mModel) BeforeInsert(db DB) error {
return nil
}
func (m *m2mModel) AfterInsert(db DB) error {
return nil
}
func (m *m2mModel) BeforeUpdate(db DB) error {
return nil
}
func (m *m2mModel) AfterUpdate(db DB) error {
return nil
}
func (m *m2mModel) BeforeDelete(db DB) error {
return nil
}
func (m *m2mModel) AfterDelete(db DB) error {
return nil
}
func (m *m2mModel) ScanColumn(colIdx int, colName string, b []byte) error {
ok, err := m.sliceTableModel.scanColumn(colIdx, colName, b)
if ok {
return err
}
m.columns[colName] = string(b)
return nil
}

105
vendor/github.com/go-pg/pg/orm/model_table_many.go generated vendored Normal file
View file

@ -0,0 +1,105 @@
package orm
import (
"fmt"
"reflect"
)
type manyModel struct {
*sliceTableModel
rel *Relation
buf []byte
dstValues map[string][]reflect.Value
}
var _ tableModel = (*manyModel)(nil)
func newManyModel(j *join) *manyModel {
joinModel := j.JoinModel.(*sliceTableModel)
dstValues := dstValues(joinModel, j.BaseModel.Table().PKs)
m := manyModel{
sliceTableModel: joinModel,
rel: j.Rel,
dstValues: dstValues,
}
if !m.sliceOfPtr {
m.strct = reflect.New(m.table.Type).Elem()
}
return &m
}
func (m *manyModel) NewModel() ColumnScanner {
if m.sliceOfPtr {
m.strct = reflect.New(m.table.Type).Elem()
} else {
m.strct.Set(m.table.zeroStruct)
}
m.structInited = false
m.structTableModel.NewModel()
return m
}
func (m *manyModel) AddModel(model ColumnScanner) error {
m.buf = modelId(m.buf[:0], m.strct, m.rel.FKs)
dstValues, ok := m.dstValues[string(m.buf)]
if !ok {
return fmt.Errorf("pg: can't find dst value for model id=%q", m.buf)
}
for _, v := range dstValues {
if m.sliceOfPtr {
v.Set(reflect.Append(v, m.strct.Addr()))
} else {
v.Set(reflect.Append(v, m.strct))
}
}
return nil
}
func (m *manyModel) AfterQuery(db DB) error {
if !m.rel.JoinTable.HasFlag(AfterQueryHookFlag) {
return nil
}
var retErr error
for _, slices := range m.dstValues {
for _, slice := range slices {
err := callAfterQueryHookSlice(slice, m.sliceOfPtr, db)
if err != nil && retErr == nil {
retErr = err
}
}
}
return retErr
}
func (m *manyModel) AfterSelect(db DB) error {
return nil
}
func (m *manyModel) BeforeInsert(db DB) error {
return nil
}
func (m *manyModel) AfterInsert(db DB) error {
return nil
}
func (m *manyModel) BeforeUpdate(db DB) error {
return nil
}
func (m *manyModel) AfterUpdate(db DB) error {
return nil
}
func (m *manyModel) BeforeDelete(db DB) error {
return nil
}
func (m *manyModel) AfterDelete(db DB) error {
return nil
}

128
vendor/github.com/go-pg/pg/orm/model_table_slice.go generated vendored Normal file
View file

@ -0,0 +1,128 @@
package orm
import "reflect"
type sliceTableModel struct {
structTableModel
slice reflect.Value
sliceOfPtr bool
}
var _ tableModel = (*sliceTableModel)(nil)
func (m *sliceTableModel) init(sliceType reflect.Type) {
switch sliceType.Elem().Kind() {
case reflect.Ptr, reflect.Interface:
m.sliceOfPtr = true
}
}
func (sliceTableModel) useQueryOne() {}
func (m *sliceTableModel) Join(name string, apply func(*Query) (*Query, error)) (bool, *join) {
return m.join(m.Value(), name, apply)
}
func (m *sliceTableModel) Bind(bind reflect.Value) {
m.slice = bind.Field(m.index[len(m.index)-1])
}
func (m *sliceTableModel) Value() reflect.Value {
return m.slice
}
func (m *sliceTableModel) Init() error {
if m.slice.IsValid() && m.slice.Len() > 0 {
m.slice.Set(m.slice.Slice(0, 0))
}
return nil
}
func (m *sliceTableModel) NewModel() ColumnScanner {
m.strct = m.nextElem()
m.structInited = false
m.structTableModel.NewModel()
return m
}
func (m *sliceTableModel) AfterQuery(db DB) error {
if !m.table.HasFlag(AfterQueryHookFlag) {
return nil
}
return callAfterQueryHookSlice(m.slice, m.sliceOfPtr, db)
}
func (m *sliceTableModel) AfterSelect(db DB) error {
if !m.table.HasFlag(AfterSelectHookFlag) {
return nil
}
return callAfterSelectHookSlice(m.slice, m.sliceOfPtr, db)
}
func (m *sliceTableModel) BeforeInsert(db DB) error {
if !m.table.HasFlag(BeforeInsertHookFlag) {
return nil
}
return callBeforeInsertHookSlice(m.slice, m.sliceOfPtr, db)
}
func (m *sliceTableModel) AfterInsert(db DB) error {
if !m.table.HasFlag(AfterInsertHookFlag) {
return nil
}
return callAfterInsertHookSlice(m.slice, m.sliceOfPtr, db)
}
func (m *sliceTableModel) BeforeUpdate(db DB) error {
if !m.table.HasFlag(BeforeUpdateHookFlag) {
return nil
}
return callBeforeUpdateHookSlice(m.slice, m.sliceOfPtr, db)
}
func (m *sliceTableModel) AfterUpdate(db DB) error {
if !m.table.HasFlag(AfterUpdateHookFlag) {
return nil
}
return callAfterUpdateHookSlice(m.slice, m.sliceOfPtr, db)
}
func (m *sliceTableModel) BeforeDelete(db DB) error {
if !m.table.HasFlag(BeforeDeleteHookFlag) {
return nil
}
return callBeforeDeleteHookSlice(m.slice, m.sliceOfPtr, db)
}
func (m *sliceTableModel) AfterDelete(db DB) error {
if !m.table.HasFlag(AfterDeleteHookFlag) {
return nil
}
return callAfterDeleteHookSlice(m.slice, m.sliceOfPtr, db)
}
func (m *sliceTableModel) nextElem() reflect.Value {
if m.slice.Len() < m.slice.Cap() {
m.slice.Set(m.slice.Slice(0, m.slice.Len()+1))
elem := m.slice.Index(m.slice.Len() - 1)
if m.sliceOfPtr {
if elem.IsNil() {
elem.Set(reflect.New(elem.Type().Elem()))
}
return elem.Elem()
} else {
return elem
}
}
if m.sliceOfPtr {
elem := reflect.New(m.table.Type)
m.slice.Set(reflect.Append(m.slice, elem))
return elem.Elem()
} else {
m.slice.Set(reflect.Append(m.slice, m.table.zeroStruct))
return m.slice.Index(m.slice.Len() - 1)
}
}

314
vendor/github.com/go-pg/pg/orm/model_table_struct.go generated vendored Normal file
View file

@ -0,0 +1,314 @@
package orm
import (
"fmt"
"reflect"
"strings"
)
type structTableModel struct {
table *Table
rel *Relation
joins []join
root reflect.Value
index []int
strct reflect.Value
structInited bool
}
var _ tableModel = (*structTableModel)(nil)
func newStructTableModelValue(v reflect.Value) *structTableModel {
return &structTableModel{
table: Tables.Get(v.Type()),
root: v,
strct: v,
}
}
func newStructTableModelType(typ reflect.Type) *structTableModel {
return &structTableModel{
table: Tables.Get(typ),
}
}
func (structTableModel) useQueryOne() bool {
return true
}
func (m *structTableModel) Table() *Table {
return m.table
}
func (m *structTableModel) Relation() *Relation {
return m.rel
}
func (m *structTableModel) AppendParam(b []byte, f QueryFormatter, name string) ([]byte, bool) {
b, ok := m.table.AppendParam(b, m.strct, name)
if ok {
return b, true
}
switch name {
case "TableName":
b = f.FormatQuery(b, string(m.table.Name))
return b, true
case "TableAlias":
b = append(b, m.table.Alias...)
return b, true
case "Columns":
b = appendColumns(b, m.table.Fields)
return b, true
}
return b, false
}
func (m *structTableModel) Root() reflect.Value {
return m.root
}
func (m *structTableModel) Index() []int {
return m.index
}
func (m *structTableModel) ParentIndex() []int {
return m.index[:len(m.index)-len(m.rel.Field.Index)]
}
func (m *structTableModel) Value() reflect.Value {
return m.strct
}
func (m *structTableModel) Mount(host reflect.Value) {
m.strct = host.FieldByIndex(m.rel.Field.Index)
m.structInited = false
}
func (m *structTableModel) initStruct() {
if m.structInited {
return
}
m.structInited = true
if m.strct.Kind() == reflect.Interface {
m.strct = m.strct.Elem()
}
if m.strct.Kind() == reflect.Ptr {
if m.strct.IsNil() {
m.strct.Set(reflect.New(m.strct.Type().Elem()))
m.strct = m.strct.Elem()
} else {
m.strct = m.strct.Elem()
}
}
m.mountJoins()
}
func (m *structTableModel) mountJoins() {
for i := range m.joins {
j := &m.joins[i]
switch j.Rel.Type {
case HasOneRelation, BelongsToRelation:
j.JoinModel.Mount(m.strct)
}
}
}
func (structTableModel) Init() error {
return nil
}
func (m *structTableModel) NewModel() ColumnScanner {
m.initStruct()
return m
}
func (m *structTableModel) AddModel(_ ColumnScanner) error {
return nil
}
func (m *structTableModel) AfterQuery(db DB) error {
if !m.table.HasFlag(AfterQueryHookFlag) {
return nil
}
return callAfterQueryHook(m.strct.Addr(), db)
}
func (m *structTableModel) AfterSelect(db DB) error {
if !m.table.HasFlag(AfterSelectHookFlag) {
return nil
}
return callAfterSelectHook(m.strct.Addr(), db)
}
func (m *structTableModel) BeforeInsert(db DB) error {
if !m.table.HasFlag(BeforeInsertHookFlag) {
return nil
}
return callBeforeInsertHook(m.strct.Addr(), db)
}
func (m *structTableModel) AfterInsert(db DB) error {
if !m.table.HasFlag(AfterInsertHookFlag) {
return nil
}
return callAfterInsertHook(m.strct.Addr(), db)
}
func (m *structTableModel) BeforeUpdate(db DB) error {
if !m.table.HasFlag(BeforeUpdateHookFlag) {
return nil
}
return callBeforeUpdateHook(m.strct.Addr(), db)
}
func (m *structTableModel) AfterUpdate(db DB) error {
if !m.table.HasFlag(AfterUpdateHookFlag) {
return nil
}
return callAfterUpdateHook(m.strct.Addr(), db)
}
func (m *structTableModel) BeforeDelete(db DB) error {
if !m.table.HasFlag(BeforeDeleteHookFlag) {
return nil
}
return callBeforeDeleteHook(m.strct.Addr(), db)
}
func (m *structTableModel) AfterDelete(db DB) error {
if !m.table.HasFlag(AfterDeleteHookFlag) {
return nil
}
return callAfterDeleteHook(m.strct.Addr(), db)
}
func (m *structTableModel) ScanColumn(colIdx int, colName string, b []byte) error {
ok, err := m.scanColumn(colIdx, colName, b)
if ok {
return err
}
return fmt.Errorf("pg: can't find column=%s in model=%s", colName, m.table.Type.Name())
}
func (m *structTableModel) scanColumn(colIdx int, colName string, b []byte) (bool, error) {
m.initStruct()
joinName, fieldName := splitColumn(colName)
if joinName != "" {
if join := m.GetJoin(joinName); join != nil {
return join.JoinModel.scanColumn(colIdx, fieldName, b)
}
if m.table.ModelName == joinName {
return m.scanColumn(colIdx, fieldName, b)
}
}
field, ok := m.table.FieldsMap[colName]
if !ok {
return false, nil
}
return true, field.ScanValue(m.strct, b)
}
func (m *structTableModel) GetJoin(name string) *join {
for i := range m.joins {
j := &m.joins[i]
if j.Rel.Field.GoName == name || j.Rel.Field.SQLName == name {
return j
}
}
return nil
}
func (m *structTableModel) GetJoins() []join {
return m.joins
}
func (m *structTableModel) AddJoin(j join) *join {
m.joins = append(m.joins, j)
return &m.joins[len(m.joins)-1]
}
func (m *structTableModel) Join(name string, apply func(*Query) (*Query, error)) (bool, *join) {
return m.join(m.Value(), name, apply)
}
func (m *structTableModel) join(
bind reflect.Value, name string, apply func(*Query) (*Query, error),
) (bool, *join) {
path := strings.Split(name, ".")
index := make([]int, 0, len(path))
currJoin := join{
BaseModel: m,
JoinModel: m,
}
var created bool
var lastJoin *join
var hasColumnName bool
for _, name := range path {
rel, ok := currJoin.JoinModel.Table().Relations[name]
if !ok {
hasColumnName = true
break
}
currJoin.Rel = rel
index = append(index, rel.Field.Index...)
if j := currJoin.JoinModel.GetJoin(name); j != nil {
currJoin.BaseModel = j.BaseModel
currJoin.JoinModel = j.JoinModel
created = false
lastJoin = j
} else {
model, err := newTableModelIndex(bind, index, rel)
if err != nil {
return false, nil
}
currJoin.Parent = lastJoin
currJoin.BaseModel = currJoin.JoinModel
currJoin.JoinModel = model
created = true
lastJoin = currJoin.BaseModel.AddJoin(currJoin)
}
}
// No joins with such name.
if lastJoin == nil {
return false, nil
}
if apply != nil {
lastJoin.ApplyQuery = apply
}
if hasColumnName {
column := path[len(path)-1]
if column == "_" {
if lastJoin.Columns == nil {
lastJoin.Columns = make([]string, 0)
}
} else {
lastJoin.Columns = append(lastJoin.Columns, column)
}
}
return created, lastJoin
}
func splitColumn(s string) (string, string) {
ind := strings.Index(s, "__")
if ind == -1 {
return "", s
}
return s[:ind], s[ind+2:]
}

41
vendor/github.com/go-pg/pg/orm/orm.go generated vendored Normal file
View file

@ -0,0 +1,41 @@
package orm
import "io"
// ColumnScanner is used to scan column values.
type ColumnScanner interface {
// Scan assigns a column value from a row.
//
// An error should be returned if the value can not be stored
// without loss of information.
ScanColumn(colIdx int, colName string, b []byte) error
}
type QueryAppender interface {
Copy() QueryAppender
Query() *Query
AppendQuery(dst []byte) ([]byte, error)
}
type QueryFormatter interface {
FormatQuery(b []byte, query string, params ...interface{}) []byte
}
// DB is a common interface for pg.DB and pg.Tx types.
type DB interface {
Model(model ...interface{}) *Query
Select(model interface{}) error
Insert(model ...interface{}) error
Update(model ...interface{}) error
Delete(model interface{}) error
Exec(query interface{}, params ...interface{}) (Result, error)
ExecOne(query interface{}, params ...interface{}) (Result, error)
Query(coll, query interface{}, params ...interface{}) (Result, error)
QueryOne(model, query interface{}, params ...interface{}) (Result, error)
CopyFrom(r io.Reader, query interface{}, params ...interface{}) (Result, error)
CopyTo(w io.Writer, query interface{}, params ...interface{}) (Result, error)
QueryFormatter
}

986
vendor/github.com/go-pg/pg/orm/query.go generated vendored Normal file
View file

@ -0,0 +1,986 @@
package orm
import (
"errors"
"fmt"
"io"
"reflect"
"strings"
"sync"
"time"
"github.com/go-pg/pg/internal"
"github.com/go-pg/pg/types"
)
type withQuery struct {
name string
query *Query
}
type Query struct {
db DB
stickyErr error
model tableModel
ignoreModel bool
with []withQuery
tables []FormatAppender
columns []FormatAppender
set []FormatAppender
where []sepFormatAppender
updWhere []sepFormatAppender
joins []FormatAppender
group []FormatAppender
having []queryParamsAppender
order []FormatAppender
onConflict *queryParamsAppender
returning []queryParamsAppender
limit int
offset int
selFor FormatAppender
}
var _ queryAppender = (*Query)(nil)
func NewQuery(db DB, model ...interface{}) *Query {
return (&Query{}).DB(db).Model(model...)
}
// New returns new zero Query binded to the current db and model.
func (q *Query) New() *Query {
return &Query{
db: q.db,
model: q.model,
ignoreModel: true,
}
}
func (q *Query) AppendQuery(b []byte) ([]byte, error) {
return selectQuery{q: q}.AppendQuery(b)
}
// Copy returns copy of the Query.
func (q *Query) Copy() *Query {
copy := &Query{
db: q.db,
stickyErr: q.stickyErr,
model: q.model,
ignoreModel: q.ignoreModel,
tables: q.tables[:len(q.tables):len(q.tables)],
columns: q.columns[:len(q.columns):len(q.columns)],
set: q.set[:len(q.set):len(q.set)],
where: q.where[:len(q.where):len(q.where)],
updWhere: q.updWhere[:len(q.updWhere):len(q.updWhere)],
joins: q.joins[:len(q.joins):len(q.joins)],
group: q.group[:len(q.group):len(q.group)],
having: q.having[:len(q.having):len(q.having)],
order: q.order[:len(q.order):len(q.order)],
onConflict: q.onConflict,
returning: q.returning[:len(q.returning):len(q.returning)],
limit: q.limit,
offset: q.offset,
}
for _, with := range q.with {
copy = copy.With(with.name, with.query.Copy())
}
return copy
}
func (q *Query) err(err error) *Query {
if q.stickyErr == nil {
q.stickyErr = err
}
return q
}
func (q *Query) DB(db DB) *Query {
q.db = db
for _, with := range q.with {
with.query.db = db
}
return q
}
func (q *Query) Model(model ...interface{}) *Query {
var err error
switch l := len(model); {
case l == 0:
q.model = nil
case l == 1:
q.model, err = newTableModel(model[0])
case l > 1:
q.model, err = newTableModel(&model)
}
if err != nil {
q = q.err(err)
}
if q.ignoreModel {
q.ignoreModel = false
}
return q
}
// With adds subq as common table expression with the given name.
func (q *Query) With(name string, subq *Query) *Query {
q.with = append(q.with, withQuery{name, subq})
return q
}
// WrapWith creates new Query and adds to it current query as
// common table expression with the given name.
func (q *Query) WrapWith(name string) *Query {
wrapper := q.New()
wrapper.with = q.with
q.with = nil
wrapper = wrapper.With(name, q)
return wrapper
}
func (q *Query) Table(tables ...string) *Query {
for _, table := range tables {
q.tables = append(q.tables, fieldAppender{table})
}
return q
}
func (q *Query) TableExpr(expr string, params ...interface{}) *Query {
q.tables = append(q.tables, queryParamsAppender{expr, params})
return q
}
// Column adds column to the Query quoting it according to PostgreSQL rules.
// ColumnExpr can be used to bypass quoting restriction.
func (q *Query) Column(columns ...string) *Query {
for _, column := range columns {
if column == "_" {
if q.columns == nil {
q.columns = make([]FormatAppender, 0)
}
continue
}
if q.model != nil {
if _, j := q.model.Join(column, nil); j != nil {
continue
}
}
q.columns = append(q.columns, fieldAppender{column})
}
return q
}
// ColumnExpr adds column expression to the Query.
func (q *Query) ColumnExpr(expr string, params ...interface{}) *Query {
q.columns = append(q.columns, queryParamsAppender{expr, params})
return q
}
func (q *Query) getFields() ([]*Field, error) {
return q._getFields(false)
}
func (q *Query) getDataFields() ([]*Field, error) {
return q._getFields(true)
}
func (q *Query) _getFields(filterPKs bool) ([]*Field, error) {
table := q.model.Table()
var columns []*Field
for _, col := range q.columns {
f, ok := col.(fieldAppender)
if !ok {
continue
}
field, err := table.GetField(f.field)
if err != nil {
return nil, err
}
if filterPKs && field.HasFlag(PrimaryKeyFlag) {
continue
}
columns = append(columns, field)
}
return columns, nil
}
func (q *Query) Relation(name string, apply func(*Query) (*Query, error)) *Query {
if _, j := q.model.Join(name, apply); j == nil {
return q.err(fmt.Errorf(
"model=%s does not have relation=%s",
q.model.Table().Type.Name(), name,
))
}
return q
}
func (q *Query) Set(set string, params ...interface{}) *Query {
q.set = append(q.set, queryParamsAppender{set, params})
return q
}
func (q *Query) Where(where string, params ...interface{}) *Query {
q.addWhere(&whereAppender{
sep: "AND",
where: where,
params: params,
})
return q
}
func (q *Query) WhereOr(where string, params ...interface{}) *Query {
q.addWhere(&whereAppender{
sep: "OR",
where: where,
params: params,
})
return q
}
// WhereGroup encloses conditions added in the function in parentheses.
//
// q.Where("TRUE").
// WhereGroup(func(q *orm.Query) (*orm.Query, error)) {
// q = q.WhereOr("FALSE").WhereOr("TRUE").
// return q, nil
// })
//
// generates
//
// WHERE TRUE AND (FALSE OR TRUE)
func (q *Query) WhereGroup(fn func(*Query) (*Query, error)) *Query {
return q.whereGroup("AND", fn)
}
// WhereOrGroup encloses conditions added in the function in parentheses.
//
// q.Where("TRUE").
// WhereOrGroup(func(q *orm.Query) (*orm.Query, error)) {
// q = q.Where("FALSE").Where("TRUE").
// return q, nil
// })
//
// generates
//
// WHERE TRUE OR (FALSE AND TRUE)
func (q *Query) WhereOrGroup(fn func(*Query) (*Query, error)) *Query {
return q.whereGroup("OR", fn)
}
func (q *Query) whereGroup(conj string, fn func(*Query) (*Query, error)) *Query {
saved := q.where
q.where = nil
newq, err := fn(q)
if err != nil {
q.err(err)
return q
}
f := whereGroupAppender{
sep: conj,
where: newq.where,
}
newq.where = saved
newq.addWhere(f)
return newq
}
// WhereIn is a shortcut for Where and pg.In to work with IN operator:
//
// WhereIn("id IN (?)", 1, 2, 3)
func (q *Query) WhereIn(where string, params ...interface{}) *Query {
return q.Where(where, types.In(params))
}
func (q *Query) addWhere(f sepFormatAppender) {
if q.onConflictDoUpdate() {
q.updWhere = append(q.updWhere, f)
} else {
q.where = append(q.where, f)
}
}
func (q *Query) Join(join string, params ...interface{}) *Query {
q.joins = append(q.joins, queryParamsAppender{join, params})
return q
}
func (q *Query) Group(columns ...string) *Query {
for _, column := range columns {
q.group = append(q.group, fieldAppender{column})
}
return q
}
func (q *Query) GroupExpr(group string, params ...interface{}) *Query {
q.group = append(q.group, queryParamsAppender{group, params})
return q
}
func (q *Query) Having(having string, params ...interface{}) *Query {
q.having = append(q.having, queryParamsAppender{having, params})
return q
}
// Order adds sort order to the Query quoting column name.
// OrderExpr can be used to bypass quoting restriction.
func (q *Query) Order(orders ...string) *Query {
loop:
for _, order := range orders {
ind := strings.Index(order, " ")
if ind != -1 {
field := order[:ind]
sort := order[ind+1:]
switch internal.ToUpper(sort) {
case "ASC", "DESC", "ASC NULLS FIRST", "DESC NULLS FIRST",
"ASC NULLS LAST", "DESC NULLS LAST":
q = q.OrderExpr("? ?", types.F(field), types.Q(sort))
continue loop
}
}
q.order = append(q.order, fieldAppender{order})
}
return q
}
// Order adds sort order to the Query.
func (q *Query) OrderExpr(order string, params ...interface{}) *Query {
q.order = append(q.order, queryParamsAppender{order, params})
return q
}
func (q *Query) Limit(n int) *Query {
q.limit = n
return q
}
func (q *Query) Offset(n int) *Query {
q.offset = n
return q
}
func (q *Query) OnConflict(s string, params ...interface{}) *Query {
q.onConflict = &queryParamsAppender{s, params}
return q
}
func (q *Query) onConflictDoUpdate() bool {
return q.onConflict != nil &&
strings.HasSuffix(q.onConflict.query, "DO UPDATE")
}
func (q *Query) Returning(s string, params ...interface{}) *Query {
q.returning = append(q.returning, queryParamsAppender{s, params})
return q
}
func (q *Query) For(s string, params ...interface{}) *Query {
q.selFor = queryParamsAppender{s, params}
return q
}
// Apply calls the fn passing the Query as an argument.
func (q *Query) Apply(fn func(*Query) (*Query, error)) *Query {
qq, err := fn(q)
if err != nil {
q.err(err)
return q
}
return qq
}
// Count returns number of rows matching the query using count aggregate function.
func (q *Query) Count() (int, error) {
if q.stickyErr != nil {
return 0, q.stickyErr
}
var count int
_, err := q.db.QueryOne(
Scan(&count),
q.countSelectQuery("count(*)"),
q.model,
)
return count, err
}
func (q *Query) countSelectQuery(column string) selectQuery {
return selectQuery{
q: q,
count: column,
}
}
// First selects the first row.
func (q *Query) First() error {
err := q.model.Table().checkPKs()
if err != nil {
return err
}
b := columns(nil, q.model.Table().Alias, "", q.model.Table().PKs)
return q.OrderExpr(internal.BytesToString(b)).Limit(1).Select()
}
// Last selects the last row.
func (q *Query) Last() error {
err := q.model.Table().checkPKs()
if err != nil {
return err
}
b := columns(nil, q.model.Table().Alias, "", q.model.Table().PKs)
b = append(b, " DESC"...)
return q.OrderExpr(internal.BytesToString(b)).Limit(1).Select()
}
// Select selects the model.
func (q *Query) Select(values ...interface{}) error {
if q.stickyErr != nil {
return q.stickyErr
}
model, err := q.newModel(values...)
if err != nil {
return err
}
res, err := q.query(model, selectQuery{q: q})
if err != nil {
return err
}
if res.RowsReturned() > 0 {
if q.model != nil {
if err := q.selectJoins(q.model.GetJoins()); err != nil {
return err
}
}
if err := model.AfterSelect(q.db); err != nil {
return err
}
}
return nil
}
func (q *Query) newModel(values ...interface{}) (Model, error) {
if len(values) > 0 {
return NewModel(values...)
}
return q.model, nil
}
func (q *Query) query(model Model, query interface{}) (Result, error) {
if _, ok := model.(useQueryOne); ok {
return q.db.QueryOne(model, query, q.model)
}
return q.db.Query(model, query, q.model)
}
// SelectAndCount runs Select and Count in two goroutines,
// waits for them to finish and returns the result.
func (q *Query) SelectAndCount(values ...interface{}) (count int, err error) {
if q.stickyErr != nil {
return 0, q.stickyErr
}
var wg sync.WaitGroup
wg.Add(2)
var mu sync.Mutex
go func() {
defer wg.Done()
if e := q.Select(values...); e != nil {
mu.Lock()
err = e
mu.Unlock()
}
}()
go func() {
defer wg.Done()
var e error
count, e = q.Count()
if e != nil {
mu.Lock()
err = e
mu.Unlock()
}
}()
wg.Wait()
return count, err
}
func (q *Query) forEachHasOneJoin(fn func(*join)) {
if q.model == nil {
return
}
q._forEachHasOneJoin(fn, q.model.GetJoins())
}
func (q *Query) _forEachHasOneJoin(fn func(*join), joins []join) {
for i := range joins {
j := &joins[i]
switch j.Rel.Type {
case HasOneRelation, BelongsToRelation:
fn(j)
q._forEachHasOneJoin(fn, j.JoinModel.GetJoins())
}
}
}
func (q *Query) selectJoins(joins []join) error {
var err error
for i := range joins {
j := &joins[i]
if j.Rel.Type == HasOneRelation || j.Rel.Type == BelongsToRelation {
err = q.selectJoins(j.JoinModel.GetJoins())
} else {
err = j.Select(q.db)
}
if err != nil {
return err
}
}
return nil
}
// Insert inserts the model.
func (q *Query) Insert(values ...interface{}) (Result, error) {
if q.stickyErr != nil {
return nil, q.stickyErr
}
model, err := q.newModel(values...)
if err != nil {
return nil, err
}
if q.model != nil {
if err := q.model.BeforeInsert(q.db); err != nil {
return nil, err
}
}
res, err := q.db.Query(model, insertQuery{q: q}, q.model)
if err != nil {
return nil, err
}
if q.model != nil {
if err := q.model.AfterInsert(q.db); err != nil {
return nil, err
}
}
return res, nil
}
// SelectOrInsert selects the model inserting one if it does not exist.
func (q *Query) SelectOrInsert(values ...interface{}) (inserted bool, err error) {
if q.stickyErr != nil {
return false, q.stickyErr
}
var insertErr error
for i := 0; i < 5; i++ {
if i >= 2 {
time.Sleep(internal.RetryBackoff(i-2, 250*time.Millisecond, 4*time.Second))
}
err := q.Select(values...)
if err == nil {
return false, nil
}
if err != internal.ErrNoRows {
return false, err
}
res, err := q.Insert(values...)
if err != nil {
insertErr = err
if pgErr, ok := err.(internal.PGError); ok {
if pgErr.IntegrityViolation() {
continue
}
if pgErr.Field('C') == "55000" {
// Retry on "#55000 attempted to delete invisible tuple".
continue
}
}
return false, err
}
if res.RowsAffected() == 1 {
return true, nil
}
}
err = fmt.Errorf(
"pg: SelectOrInsert: select returns no rows (insert fails with err=%q)",
insertErr,
)
return false, err
}
// Update updates the model.
func (q *Query) Update(values ...interface{}) (Result, error) {
if q.stickyErr != nil {
return nil, q.stickyErr
}
model, err := q.newModel(values...)
if err != nil {
return nil, err
}
if q.model != nil {
if err := q.model.BeforeUpdate(q.db); err != nil {
return nil, err
}
}
res, err := q.db.Query(model, updateQuery{q}, q.model)
if err != nil {
return nil, err
}
if q.model != nil {
if err := q.model.AfterUpdate(q.db); err != nil {
return nil, err
}
}
return res, nil
}
// Delete deletes the model.
func (q *Query) Delete(values ...interface{}) (Result, error) {
if q.stickyErr != nil {
return nil, q.stickyErr
}
model, err := q.newModel(values...)
if err != nil {
return nil, err
}
if q.model != nil {
if err := q.model.BeforeDelete(q.db); err != nil {
return nil, err
}
}
res, err := q.db.Query(model, deleteQuery{q}, q.model)
if err != nil {
return nil, err
}
if q.model != nil {
if err := q.model.AfterDelete(q.db); err != nil {
return nil, err
}
}
return res, nil
}
func (q *Query) CreateTable(opt *CreateTableOptions) (Result, error) {
if q.stickyErr != nil {
return nil, q.stickyErr
}
return q.db.Exec(createTableQuery{
q: q,
opt: opt,
})
}
func (q *Query) DropTable(opt *DropTableOptions) (Result, error) {
if q.stickyErr != nil {
return nil, q.stickyErr
}
return q.db.Exec(dropTableQuery{
q: q,
opt: opt,
})
}
// Exec is an alias for DB.Exec.
func (q *Query) Exec(query interface{}, params ...interface{}) (Result, error) {
params = append(params, q.model)
return q.db.Exec(query, params...)
}
// ExecOne is an alias for DB.ExecOne.
func (q *Query) ExecOne(query interface{}, params ...interface{}) (Result, error) {
params = append(params, q.model)
return q.db.ExecOne(query, params...)
}
// Query is an alias for DB.Query.
func (q *Query) Query(model, query interface{}, params ...interface{}) (Result, error) {
params = append(params, q.model)
return q.db.Query(model, query, params...)
}
// QueryOne is an alias for DB.QueryOne.
func (q *Query) QueryOne(model, query interface{}, params ...interface{}) (Result, error) {
params = append(params, q.model)
return q.db.QueryOne(model, query, params...)
}
// CopyFrom is an alias from DB.CopyFrom.
func (q *Query) CopyFrom(r io.Reader, query interface{}, params ...interface{}) (Result, error) {
params = append(params, q.model)
return q.db.CopyFrom(r, query, params...)
}
// CopyTo is an alias from DB.CopyTo.
func (q *Query) CopyTo(w io.Writer, query interface{}, params ...interface{}) (Result, error) {
params = append(params, q.model)
return q.db.CopyTo(w, query, params...)
}
func (q *Query) FormatQuery(b []byte, query string, params ...interface{}) []byte {
params = append(params, q.model)
if q.db != nil {
return q.db.FormatQuery(b, query, params...)
}
return formatter.Append(b, query, params...)
}
func (q *Query) hasModel() bool {
return !q.ignoreModel && q.model != nil
}
func (q *Query) hasTables() bool {
return q.hasModel() || len(q.tables) > 0
}
func (q *Query) appendTableName(b []byte) []byte {
return q.FormatQuery(b, string(q.model.Table().Name))
}
func (q *Query) appendTableNameWithAlias(b []byte) []byte {
b = q.appendTableName(b)
b = append(b, " AS "...)
b = append(b, q.model.Table().Alias...)
return b
}
func (q *Query) appendFirstTable(b []byte) []byte {
if q.hasModel() {
return q.appendTableName(b)
}
if len(q.tables) > 0 {
b = q.tables[0].AppendFormat(b, q)
}
return b
}
func (q *Query) appendFirstTableWithAlias(b []byte) []byte {
if q.hasModel() {
return q.appendTableNameWithAlias(b)
}
if len(q.tables) > 0 {
b = q.tables[0].AppendFormat(b, q)
}
return b
}
func (q *Query) appendTables(b []byte) []byte {
if q.hasModel() {
b = q.appendTableNameWithAlias(b)
if len(q.tables) > 0 {
b = append(b, ", "...)
}
}
for i, f := range q.tables {
if i > 0 {
b = append(b, ", "...)
}
b = f.AppendFormat(b, q)
}
return b
}
func (q *Query) hasOtherTables() bool {
if q.hasModel() {
return len(q.tables) > 0
}
return len(q.tables) > 1
}
func (q *Query) modelHasData() bool {
if !q.hasModel() {
return false
}
v := q.model.Value()
return v.Kind() == reflect.Slice && v.Len() > 0
}
func (q *Query) appendOtherTables(b []byte) []byte {
tables := q.tables
if !q.hasModel() {
tables = tables[1:]
}
for i, f := range tables {
if i > 0 {
b = append(b, ", "...)
}
b = f.AppendFormat(b, q)
}
return b
}
func (q *Query) appendColumns(b []byte) []byte {
for i, f := range q.columns {
if i > 0 {
b = append(b, ", "...)
}
b = f.AppendFormat(b, q)
}
return b
}
func (q *Query) mustAppendWhere(b []byte) ([]byte, error) {
if len(q.where) > 0 {
b = q.appendWhere(b)
return b, nil
}
if q.model == nil {
return nil, errors.New("pg: Model is nil")
}
if err := q.model.Table().checkPKs(); err != nil {
return nil, err
}
b = append(b, " WHERE "...)
return wherePKQuery{q}.AppendFormat(b, nil), nil
}
func (q *Query) appendWhere(b []byte) []byte {
return q._appendWhere(b, q.where)
}
func (q *Query) appendUpdWhere(b []byte) []byte {
return q._appendWhere(b, q.updWhere)
}
func (q *Query) _appendWhere(b []byte, where []sepFormatAppender) []byte {
b = append(b, " WHERE "...)
for i, f := range where {
if i > 0 {
b = append(b, ' ')
b = f.AppendSep(b)
b = append(b, ' ')
}
b = f.AppendFormat(b, q)
}
return b
}
func (q *Query) appendSet(b []byte) []byte {
b = append(b, " SET "...)
for i, f := range q.set {
if i > 0 {
b = append(b, ", "...)
}
b = f.AppendFormat(b, q)
}
return b
}
func (q *Query) appendReturning(b []byte) []byte {
b = append(b, " RETURNING "...)
for i, f := range q.returning {
if i > 0 {
b = append(b, ", "...)
}
b = f.AppendFormat(b, q)
}
return b
}
func (q *Query) appendWith(b []byte) ([]byte, error) {
var err error
b = append(b, "WITH "...)
for i, with := range q.with {
if i > 0 {
b = append(b, ", "...)
}
b = types.AppendField(b, with.name, 1)
b = append(b, " AS ("...)
b, err = selectQuery{q: with.query}.AppendQuery(b)
if err != nil {
return nil, err
}
b = append(b, ')')
}
b = append(b, ' ')
return b, nil
}
//------------------------------------------------------------------------------
type wherePKQuery struct {
*Query
}
func (wherePKQuery) AppendSep(b []byte) []byte {
return append(b, "AND"...)
}
func (q wherePKQuery) AppendFormat(b []byte, f QueryFormatter) []byte {
table := q.model.Table()
value := q.model.Value()
if value.Kind() == reflect.Struct {
return appendColumnAndValue(b, value, table.Alias, table.PKs)
} else {
return appendColumnAndColumn(b, value, table.Alias, table.PKs)
}
}
func appendColumnAndValue(b []byte, v reflect.Value, alias types.Q, fields []*Field) []byte {
for i, f := range fields {
if i > 0 {
b = append(b, " AND "...)
}
b = append(b, alias...)
b = append(b, '.')
b = append(b, f.Column...)
b = append(b, " = "...)
b = f.AppendValue(b, v, 1)
}
return b
}
func appendColumnAndColumn(b []byte, v reflect.Value, alias types.Q, fields []*Field) []byte {
for i, f := range fields {
if i > 0 {
b = append(b, " AND "...)
}
b = append(b, alias...)
b = append(b, '.')
b = append(b, f.Column...)
b = append(b, " = _data."...)
b = append(b, f.Column...)
}
return b
}

61
vendor/github.com/go-pg/pg/orm/query_test.go generated vendored Normal file
View file

@ -0,0 +1,61 @@
package orm_test
import (
"testing"
"unsafe"
"github.com/go-pg/pg/orm"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
func TestQuerySize(t *testing.T) {
size := int(unsafe.Sizeof(orm.Query{}))
wanted := 360
if size != wanted {
t.Fatalf("got %d, wanted %d", size, wanted)
}
}
func TestQueryFormatQuery(t *testing.T) {
type FormatModel struct {
Foo string
Bar string
}
q := orm.NewQuery(nil, &FormatModel{"foo", "bar"})
params := &struct {
Foo string
}{
"not_foo",
}
b := q.FormatQuery(nil, "?foo ?TableName ?TableAlias ?Columns", params)
wanted := `'not_foo' "format_models" "format_model" "foo", "bar"`
if string(b) != wanted {
t.Fatalf("got `%s`, wanted `%s`", string(b), wanted)
}
}
var _ = Describe("NewQuery", func() {
It("works with nil db", func() {
q := orm.NewQuery(nil)
b, err := q.AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal("SELECT *"))
})
It("works with nil model", func() {
type Model struct {
Id int
}
q := orm.NewQuery(nil, (*Model)(nil))
b, err := q.AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`SELECT "model"."id" FROM "models" AS "model"`))
})
})

23
vendor/github.com/go-pg/pg/orm/relation.go generated vendored Normal file
View file

@ -0,0 +1,23 @@
package orm
import "github.com/go-pg/pg/types"
const (
HasOneRelation = 1 << iota
BelongsToRelation
HasManyRelation
Many2ManyRelation
)
type Relation struct {
Type int
Polymorphic bool
Field *Field
JoinTable *Table
FKs []*Field
M2MTableName types.Q
M2MTableAlias types.Q
BasePrefix string
JoinPrefix string
}

14
vendor/github.com/go-pg/pg/orm/result.go generated vendored Normal file
View file

@ -0,0 +1,14 @@
package orm
// A Result summarizes an executed SQL command.
type Result interface {
Model() Model
// RowsAffected returns the number of rows affected by SELECT, INSERT, UPDATE,
// or DELETE queries. It returns -1 if query can't possibly affect any rows,
// e.g. in case of CREATE or SHOW queries.
RowsAffected() int
// RowsReturned returns the number of rows returned by the query.
RowsReturned() int
}

188
vendor/github.com/go-pg/pg/orm/select.go generated vendored Normal file
View file

@ -0,0 +1,188 @@
package orm
import (
"strconv"
"strings"
)
func Select(db DB, model interface{}) error {
q := NewQuery(db, model)
if err := q.model.Table().checkPKs(); err != nil {
return err
}
q.where = append(q.where, wherePKQuery{q})
return q.Select()
}
type selectQuery struct {
q *Query
count string
}
var _ QueryAppender = (*selectQuery)(nil)
func (q selectQuery) Copy() QueryAppender {
return selectQuery{
q: q.q.Copy(),
count: q.count,
}
}
func (q selectQuery) Query() *Query {
return q.q
}
func (q selectQuery) AppendQuery(b []byte) ([]byte, error) {
if q.q.stickyErr != nil {
return nil, q.q.stickyErr
}
var err error
cteCount := q.count != "" && (len(q.q.group) > 0 || q.isDistinct())
if cteCount {
b = append(b, `WITH "_count_wrapper" AS (`...)
}
if len(q.q.with) > 0 {
b, err = q.q.appendWith(b)
if err != nil {
return nil, err
}
}
b = append(b, "SELECT "...)
if q.count != "" && !cteCount {
b = append(b, q.count...)
} else {
b = q.appendColumns(b)
}
if q.q.hasTables() {
b = append(b, " FROM "...)
b = q.q.appendTables(b)
}
q.q.forEachHasOneJoin(func(j *join) {
b = append(b, ' ')
b = j.appendHasOneJoin(q.q.db, b)
})
if len(q.q.joins) > 0 {
for _, f := range q.q.joins {
b = append(b, ' ')
b = f.AppendFormat(b, q.q)
}
}
if len(q.q.where) > 0 {
b = q.q.appendWhere(b)
}
if len(q.q.group) > 0 {
b = append(b, " GROUP BY "...)
for i, f := range q.q.group {
if i > 0 {
b = append(b, ", "...)
}
b = f.AppendFormat(b, q.q)
}
}
if len(q.q.having) > 0 {
b = append(b, " HAVING "...)
for i, f := range q.q.having {
if i > 0 {
b = append(b, " AND "...)
}
b = append(b, '(')
b = f.AppendFormat(b, q.q)
b = append(b, ')')
}
}
if q.count == "" {
if len(q.q.order) > 0 {
b = append(b, " ORDER BY "...)
for i, f := range q.q.order {
if i > 0 {
b = append(b, ", "...)
}
b = f.AppendFormat(b, q.q)
}
}
if q.q.limit != 0 {
b = append(b, " LIMIT "...)
b = strconv.AppendInt(b, int64(q.q.limit), 10)
}
if q.q.offset != 0 {
b = append(b, " OFFSET "...)
b = strconv.AppendInt(b, int64(q.q.offset), 10)
}
if q.q.selFor != nil {
b = append(b, " FOR "...)
b = q.q.selFor.AppendFormat(b, q.q)
}
} else if cteCount {
b = append(b, `) SELECT `...)
b = append(b, q.count...)
b = append(b, ` FROM "_count_wrapper"`...)
}
return b, nil
}
func (q selectQuery) appendColumns(b []byte) []byte {
start := len(b)
if q.q.columns != nil {
b = q.q.appendColumns(b)
} else if q.q.hasModel() {
b = q.appendTableColumns(b, q.q.model.Table())
} else {
b = append(b, '*')
}
q.q.forEachHasOneJoin(func(j *join) {
if len(b) != start {
b = append(b, ", "...)
start = len(b)
}
b = j.appendHasOneColumns(b)
if len(b) == start {
b = b[:len(b)-2]
}
})
return b
}
func (q selectQuery) appendTableColumns(b []byte, table *Table) []byte {
for i, f := range table.Fields {
if i > 0 {
b = append(b, ", "...)
}
b = append(b, table.Alias...)
b = append(b, '.')
b = append(b, f.Column...)
}
return b
}
func (q selectQuery) isDistinct() bool {
for _, column := range q.q.columns {
column, ok := column.(queryParamsAppender)
if ok {
if strings.Contains(column.query, "DISTINCT") ||
strings.Contains(column.query, "distinct") {
return true
}
}
}
return false
}

242
vendor/github.com/go-pg/pg/orm/select_test.go generated vendored Normal file
View file

@ -0,0 +1,242 @@
package orm
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
type User struct {
tableName struct{} `sql:"user"`
}
type SelectModel struct {
Id int
Name string
HasOne *HasOneModel
HasOneId int
HasMany []HasManyModel
}
type HasOneModel struct {
Id int
}
type HasManyModel struct {
Id int
SelectModelId int
}
var _ = Describe("Select", func() {
It("works with User model", func() {
q := NewQuery(nil, &User{})
b, err := selectQuery{q: q}.AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`SELECT FROM "user" AS "user"`))
})
It("copies query", func() {
q1 := NewQuery(nil).Where("1 = 1").Where("2 = 2").Where("3 = 3")
q2 := q1.Copy().Where("q2 = ?", "v2")
_ = q1.Where("q1 = ?", "v1")
b, err := selectQuery{q: q2}.AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal("SELECT * WHERE (1 = 1) AND (2 = 2) AND (3 = 3) AND (q2 = 'v2')"))
})
It("specifies all columns", func() {
q := NewQuery(nil, &SelectModel{})
b, err := selectQuery{q: q}.AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`SELECT "select_model"."id", "select_model"."name", "select_model"."has_one_id" FROM "select_models" AS "select_model"`))
})
It("omits columns in main query", func() {
q := NewQuery(nil, &SelectModel{}).Column("_", "HasOne")
b, err := selectQuery{q: q}.AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`SELECT "has_one"."id" AS "has_one__id" FROM "select_models" AS "select_model" LEFT JOIN "has_one_models" AS "has_one" ON "has_one"."id" = "select_model"."has_one_id"`))
})
It("omits columns in join query", func() {
q := NewQuery(nil, &SelectModel{}).Column("HasOne._")
b, err := selectQuery{q: q}.AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`SELECT "select_model"."id", "select_model"."name", "select_model"."has_one_id" FROM "select_models" AS "select_model" LEFT JOIN "has_one_models" AS "has_one" ON "has_one"."id" = "select_model"."has_one_id"`))
})
It("specifies all columns for has one", func() {
q := NewQuery(nil, &SelectModel{Id: 1}).Column("HasOne")
b, err := selectQuery{q: q}.AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`SELECT "select_model"."id", "select_model"."name", "select_model"."has_one_id", "has_one"."id" AS "has_one__id" FROM "select_models" AS "select_model" LEFT JOIN "has_one_models" AS "has_one" ON "has_one"."id" = "select_model"."has_one_id"`))
})
It("specifies all columns for has many", func() {
q := NewQuery(nil, &SelectModel{Id: 1}).Column("HasMany")
q, err := q.model.GetJoin("HasMany").manyQuery(nil)
Expect(err).NotTo(HaveOccurred())
b, err := selectQuery{q: q}.AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`SELECT "has_many_model"."id", "has_many_model"."select_model_id" FROM "has_many_models" AS "has_many_model" WHERE (("has_many_model"."select_model_id") IN ((1)))`))
})
It("supports multiple groups", func() {
q := NewQuery(nil).Group("one").Group("two")
b, err := selectQuery{q: q}.AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`SELECT * GROUP BY "one", "two"`))
})
It("WhereOr", func() {
q := NewQuery(nil).Where("1 = 1").WhereOr("1 = 2")
b, err := selectQuery{q: q}.AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`SELECT * WHERE (1 = 1) OR (1 = 2)`))
})
It("supports subqueries", func() {
subq := NewQuery(nil, &SelectModel{}).Column("id").Where("name IS NOT NULL")
q := NewQuery(nil).Where("id IN (?)", subq)
b, err := selectQuery{q: q}.AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`SELECT * WHERE (id IN (SELECT "id" FROM "select_models" AS "select_model" WHERE (name IS NOT NULL)))`))
})
It("supports locking", func() {
q := NewQuery(nil).For("UPDATE SKIP LOCKED")
b, err := selectQuery{q: q}.AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`SELECT * FOR UPDATE SKIP LOCKED`))
})
It("supports WhereGroup", func() {
q := NewQuery(nil).Where("TRUE").WhereGroup(func(q *Query) (*Query, error) {
q = q.Where("FALSE").WhereOr("TRUE")
return q, nil
})
b, err := selectQuery{q: q}.AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`SELECT * WHERE (TRUE) AND ((FALSE) OR (TRUE))`))
})
It("supports WhereOrGroup", func() {
q := NewQuery(nil).Where("TRUE").WhereOrGroup(func(q *Query) (*Query, error) {
q = q.Where("FALSE").Where("TRUE")
return q, nil
})
b, err := selectQuery{q: q}.AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`SELECT * WHERE (TRUE) OR ((FALSE) AND (TRUE))`))
})
})
var _ = Describe("Count", func() {
It("removes LIMIT, OFFSET, and ORDER", func() {
q := NewQuery(nil).Order("order").Limit(1).Offset(2)
b, err := q.countSelectQuery("count(*)").AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`SELECT count(*)`))
})
It("does not remove LIMIT, OFFSET, and ORDER from CTE", func() {
q := NewQuery(nil).
Column("col1", "col2").
Order("order").
Limit(1).
Offset(2).
WrapWith("wrapper").
Table("wrapper").
Order("order").
Limit(1).
Offset(2)
b, err := q.countSelectQuery("count(*)").AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`WITH "wrapper" AS (SELECT "col1", "col2" ORDER BY "order" LIMIT 1 OFFSET 2) SELECT count(*) FROM "wrapper"`))
})
It("includes has one joins", func() {
q := NewQuery(nil, &SelectModel{Id: 1}).Column("HasOne")
b, err := q.countSelectQuery("count(*)").AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`SELECT count(*) FROM "select_models" AS "select_model" LEFT JOIN "has_one_models" AS "has_one" ON "has_one"."id" = "select_model"."has_one_id"`))
})
It("uses CTE when query contains GROUP BY", func() {
q := NewQuery(nil).Group("one")
b, err := q.countSelectQuery("count(*)").AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`WITH "_count_wrapper" AS (SELECT * GROUP BY "one") SELECT count(*) FROM "_count_wrapper"`))
})
It("uses CTE when column contains DISTINCT", func() {
q := NewQuery(nil).ColumnExpr("DISTINCT group_id")
b, err := q.countSelectQuery("count(*)").AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`WITH "_count_wrapper" AS (SELECT DISTINCT group_id) SELECT count(*) FROM "_count_wrapper"`))
})
})
var _ = Describe("With", func() {
It("WrapWith wraps query in CTE", func() {
q := NewQuery(nil, &SelectModel{}).
Where("cond1").
WrapWith("wrapper").
Table("wrapper").
Where("cond2")
b, err := selectQuery{q: q}.AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`WITH "wrapper" AS (SELECT "select_model"."id", "select_model"."name", "select_model"."has_one_id" FROM "select_models" AS "select_model" WHERE (cond1)) SELECT * FROM "wrapper" WHERE (cond2)`))
})
It("generates nested CTE", func() {
q1 := NewQuery(nil).Table("q1")
q2 := NewQuery(nil).With("q1", q1).Table("q2", "q1")
q3 := NewQuery(nil).With("q2", q2).Table("q3", "q2")
b, err := selectQuery{q: q3}.AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`WITH "q2" AS (WITH "q1" AS (SELECT * FROM "q1") SELECT * FROM "q2", "q1") SELECT * FROM "q3", "q2"`))
})
})
type orderTest struct {
order string
query string
}
var _ = Describe("Select Order", func() {
orderTests := []orderTest{
{"id", `"id"`},
{"id asc", `"id" asc`},
{"id desc", `"id" desc`},
{"id ASC", `"id" ASC`},
{"id DESC", `"id" DESC`},
{"id ASC NULLS FIRST", `"id" ASC NULLS FIRST`},
}
It("sets order", func() {
for _, test := range orderTests {
q := NewQuery(nil).Order(test.order)
b, err := selectQuery{q: q}.AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`SELECT * ORDER BY ` + test.query))
}
})
})

568
vendor/github.com/go-pg/pg/orm/table.go generated vendored Normal file
View file

@ -0,0 +1,568 @@
package orm
import (
"bytes"
"database/sql"
"encoding/json"
"fmt"
"net"
"reflect"
"strings"
"time"
"github.com/go-pg/pg/internal"
"github.com/go-pg/pg/types"
)
var timeType = reflect.TypeOf((*time.Time)(nil)).Elem()
var ipType = reflect.TypeOf((*net.IP)(nil)).Elem()
var ipNetType = reflect.TypeOf((*net.IPNet)(nil)).Elem()
var scannerType = reflect.TypeOf((*sql.Scanner)(nil)).Elem()
var nullBoolType = reflect.TypeOf((*sql.NullBool)(nil)).Elem()
var nullFloatType = reflect.TypeOf((*sql.NullFloat64)(nil)).Elem()
var nullIntType = reflect.TypeOf((*sql.NullInt64)(nil)).Elem()
var nullStringType = reflect.TypeOf((*sql.NullString)(nil)).Elem()
type Table struct {
Type reflect.Type
zeroStruct reflect.Value
TypeName string
Name types.Q
Alias types.Q
ModelName string
Fields []*Field
PKs []*Field
Columns []*Field
FieldsMap map[string]*Field
Methods map[string]*Method
Relations map[string]*Relation
flags uint8
}
func (t *Table) SetFlag(flag uint8) {
t.flags |= flag
}
func (t *Table) HasFlag(flag uint8) bool {
if t == nil {
return false
}
return t.flags&flag != 0
}
func (t *Table) HasField(field string) bool {
_, err := t.GetField(field)
return err == nil
}
func (t *Table) checkPKs() error {
if len(t.PKs) == 0 {
return fmt.Errorf("model=%s does not have primary keys", t.Type.Name())
}
return nil
}
func (t *Table) AddField(field *Field) {
t.Fields = append(t.Fields, field)
if field.HasFlag(PrimaryKeyFlag) {
t.PKs = append(t.PKs, field)
} else {
t.Columns = append(t.Columns, field)
}
t.FieldsMap[field.SQLName] = field
}
func (t *Table) GetField(fieldName string) (*Field, error) {
field, ok := t.FieldsMap[fieldName]
if !ok {
return nil, fmt.Errorf("can't find column=%s in table=%s", fieldName, t.Name)
}
return field, nil
}
func (t *Table) AppendParam(b []byte, strct reflect.Value, name string) ([]byte, bool) {
if field, ok := t.FieldsMap[name]; ok {
b = field.AppendValue(b, strct, 1)
return b, true
}
if method, ok := t.Methods[name]; ok {
b = method.AppendValue(b, strct.Addr(), 1)
return b, true
}
return b, false
}
func (t *Table) addRelation(rel *Relation) {
if t.Relations == nil {
t.Relations = make(map[string]*Relation)
}
t.Relations[rel.Field.GoName] = rel
}
func newTable(typ reflect.Type) *Table {
table, ok := Tables.tables[typ]
if ok {
return table
}
modelName := internal.Underscore(typ.Name())
table = &Table{
Type: typ,
zeroStruct: reflect.Zero(typ),
TypeName: internal.ToExported(typ.Name()),
Name: types.Q(types.AppendField(nil, tableNameInflector(modelName), 1)),
Alias: types.Q(types.AppendField(nil, modelName, 1)),
ModelName: modelName,
Fields: make([]*Field, 0, typ.NumField()),
FieldsMap: make(map[string]*Field, typ.NumField()),
}
Tables.tables[typ] = table
table.addFields(typ, nil)
typ = reflect.PtrTo(typ)
if typ.Implements(afterQueryHookType) {
table.SetFlag(AfterQueryHookFlag)
}
if typ.Implements(afterSelectHookType) {
table.SetFlag(AfterSelectHookFlag)
}
if typ.Implements(beforeInsertHookType) {
table.SetFlag(BeforeInsertHookFlag)
}
if typ.Implements(afterInsertHookType) {
table.SetFlag(AfterInsertHookFlag)
}
if typ.Implements(beforeUpdateHookType) {
table.SetFlag(BeforeUpdateHookFlag)
}
if typ.Implements(afterUpdateHookType) {
table.SetFlag(AfterUpdateHookFlag)
}
if typ.Implements(beforeDeleteHookType) {
table.SetFlag(BeforeDeleteHookFlag)
}
if typ.Implements(afterDeleteHookType) {
table.SetFlag(AfterDeleteHookFlag)
}
if table.Methods == nil {
table.Methods = make(map[string]*Method)
}
for i := 0; i < typ.NumMethod(); i++ {
m := typ.Method(i)
if m.PkgPath != "" {
continue
}
if m.Type.NumIn() > 1 {
continue
}
if m.Type.NumOut() != 1 {
continue
}
retType := m.Type.Out(0)
method := Method{
Index: m.Index,
appender: types.Appender(retType),
}
table.Methods[m.Name] = &method
}
return table
}
func (t *Table) addFields(typ reflect.Type, baseIndex []int) {
for i := 0; i < typ.NumField(); i++ {
f := typ.Field(i)
// Make a copy so slice is not shared between fields.
var index []int
index = append(index, baseIndex...)
if f.Anonymous {
embeddedTable := newTable(indirectType(f.Type))
pgTag := parseTag(f.Tag.Get("pg"))
if _, ok := pgTag.Options["override"]; ok {
t.TypeName = embeddedTable.TypeName
t.Name = embeddedTable.Name
t.Alias = embeddedTable.Alias
t.ModelName = embeddedTable.ModelName
}
t.addFields(embeddedTable.Type, append(index, f.Index...))
continue
}
field := t.newField(f, index)
if field != nil {
t.AddField(field)
}
}
}
func (t *Table) getField(name string) *Field {
for _, f := range t.Fields {
if f.GoName == name {
return f
}
}
f, ok := t.Type.FieldByName(name)
if !ok {
return nil
}
return t.newField(f, nil)
}
func (t *Table) newField(f reflect.StructField, index []int) *Field {
sqlTag := parseTag(f.Tag.Get("sql"))
switch f.Name {
case "tableName", "TableName":
if index != nil {
return nil
}
if sqlTag.Name != "" {
if isPostgresKeyword(sqlTag.Name) {
sqlTag.Name = `"` + sqlTag.Name + `"`
}
t.Name = types.Q(sqlTag.Name)
}
if alias, ok := sqlTag.Options["alias"]; ok {
t.Alias = types.Q(alias)
}
return nil
}
if f.PkgPath != "" {
return nil
}
skip := sqlTag.Name == "-"
if skip || sqlTag.Name == "" {
sqlTag.Name = internal.Underscore(f.Name)
}
if field, ok := t.FieldsMap[sqlTag.Name]; ok {
if field.GoName == f.Name {
return field
}
}
field := Field{
Type: indirectType(f.Type),
GoName: f.Name,
SQLName: sqlTag.Name,
Column: types.Q(types.AppendField(nil, sqlTag.Name, 1)),
Index: append(index, f.Index...),
}
if _, ok := sqlTag.Options["notnull"]; ok {
field.SetFlag(NotNullFlag)
}
if _, ok := sqlTag.Options["unique"]; ok {
field.SetFlag(UniqueFlag)
}
if v, ok := sqlTag.Options["default"]; ok {
v, ok = unquote(v)
if ok {
field.Default = types.Q(types.AppendString(nil, v, 1))
} else {
field.Default = types.Q(v)
}
}
if len(t.PKs) == 0 && (field.SQLName == "id" || field.SQLName == "uuid") {
field.SetFlag(PrimaryKeyFlag)
} else if _, ok := sqlTag.Options["pk"]; ok {
field.SetFlag(PrimaryKeyFlag)
} else if strings.HasSuffix(field.SQLName, "_id") ||
strings.HasSuffix(field.SQLName, "_uuid") {
field.SetFlag(ForeignKeyFlag)
}
pgTag := parseTag(f.Tag.Get("pg"))
if _, ok := pgTag.Options["array"]; ok {
field.SetFlag(ArrayFlag)
}
field.SQLType = fieldSQLType(&field, sqlTag)
if strings.HasSuffix(field.SQLType, "[]") {
field.SetFlag(ArrayFlag)
}
if _, ok := pgTag.Options["json_use_number"]; ok {
field.append = types.Appender(f.Type)
field.scan = scanJSONValue
} else if field.HasFlag(ArrayFlag) {
field.append = types.ArrayAppender(f.Type)
field.scan = types.ArrayScanner(f.Type)
} else if _, ok := pgTag.Options["hstore"]; ok {
field.append = types.HstoreAppender(f.Type)
field.scan = types.HstoreScanner(f.Type)
} else {
field.append = types.Appender(f.Type)
field.scan = types.Scanner(f.Type)
}
field.isZero = isZeroFunc(f.Type)
if !skip && isColumn(f.Type) {
return &field
}
switch field.Type.Kind() {
case reflect.Slice:
elemType := indirectType(field.Type.Elem())
if elemType.Kind() != reflect.Struct {
break
}
joinTable := newTable(elemType)
fk, ok := pgTag.Options["fk"]
if !ok {
fk = t.TypeName
}
if m2mTable, _ := pgTag.Options["many2many"]; m2mTable != "" {
m2mTableAlias := m2mTable
if ind := strings.IndexByte(m2mTable, '.'); ind >= 0 {
m2mTableAlias = m2mTable[ind+1:]
}
joinFK, ok := pgTag.Options["joinFK"]
if !ok {
joinFK = joinTable.TypeName
}
t.addRelation(&Relation{
Type: Many2ManyRelation,
Field: &field,
JoinTable: joinTable,
M2MTableName: types.Q(m2mTable),
M2MTableAlias: types.Q(m2mTableAlias),
BasePrefix: internal.Underscore(fk + "_"),
JoinPrefix: internal.Underscore(joinFK + "_"),
})
return nil
}
s, polymorphic := pgTag.Options["polymorphic"]
if polymorphic {
fk = s
}
fks := foreignKeys(t, joinTable, fk, t.TypeName)
if len(fks) > 0 {
t.addRelation(&Relation{
Type: HasManyRelation,
Polymorphic: polymorphic,
Field: &field,
FKs: fks,
JoinTable: joinTable,
BasePrefix: internal.Underscore(fk + "_"),
})
return nil
}
case reflect.Struct:
joinTable := newTable(field.Type)
if len(joinTable.Fields) == 0 {
break
}
for _, ff := range joinTable.FieldsMap {
ff = ff.Copy()
ff.SQLName = field.SQLName + "__" + ff.SQLName
ff.Column = types.Q(types.AppendField(nil, ff.SQLName, 1))
ff.Index = append(field.Index, ff.Index...)
if _, ok := t.FieldsMap[ff.SQLName]; !ok {
t.FieldsMap[ff.SQLName] = ff
}
}
if t.tryHasOne(joinTable, &field, pgTag) ||
t.tryBelongsToOne(joinTable, &field, pgTag) {
t.FieldsMap[field.SQLName] = &field
return nil
}
}
if skip {
t.FieldsMap[field.SQLName] = &field
return nil
}
return &field
}
func isPostgresKeyword(s string) bool {
switch s {
case "user":
return true
}
return false
}
func isColumn(typ reflect.Type) bool {
return typ.Implements(scannerType) || reflect.PtrTo(typ).Implements(scannerType)
}
func fieldSQLType(field *Field, sqlTag *tag) string {
if v, ok := sqlTag.Options["type"]; ok {
field.SetFlag(customTypeFlag)
v, _ := unquote(v)
return v
}
if field.HasFlag(ArrayFlag) {
sqlType := sqlType(field.Type.Elem())
return sqlType + "[]"
}
sqlType := sqlType(field.Type)
if field.HasFlag(PrimaryKeyFlag) {
switch sqlType {
case "smallint":
return "smallserial"
case "integer":
return "serial"
case "bigint":
return "bigserial"
}
}
return sqlType
}
func sqlType(typ reflect.Type) string {
switch typ {
case timeType:
return "timestamptz"
case ipType:
return "inet"
case ipNetType:
return "cidr"
case nullBoolType:
return "boolean"
case nullFloatType:
return "double precision"
case nullIntType:
return "bigint"
case nullStringType:
return "text"
}
switch typ.Kind() {
case reflect.Int8, reflect.Uint8, reflect.Int16:
return "smallint"
case reflect.Uint16, reflect.Int32:
return "integer"
case reflect.Uint32, reflect.Int64, reflect.Int:
return "bigint"
case reflect.Uint, reflect.Uint64:
return "decimal"
case reflect.Float32:
return "real"
case reflect.Float64:
return "double precision"
case reflect.Bool:
return "boolean"
case reflect.String:
return "text"
case reflect.Map, reflect.Struct:
return "jsonb"
case reflect.Array, reflect.Slice:
if typ.Elem().Kind() == reflect.Uint8 {
return "bytea"
}
return "jsonb"
default:
return typ.Kind().String()
}
}
func foreignKeys(base, join *Table, fk, fieldName string) []*Field {
var fks []*Field
for _, pk := range base.PKs {
fkName := fk + pk.GoName
if f := join.getField(fkName); f != nil {
fks = append(fks, f)
}
}
if len(fks) > 0 {
return fks
}
if fk != "" && fk != fieldName {
if f := join.getField(fk); f != nil {
fks = append(fks, f)
}
}
return fks
}
func (t *Table) tryHasOne(joinTable *Table, field *Field, tag *tag) bool {
fk, ok := tag.Options["fk"]
if !ok {
fk = field.GoName
}
fks := foreignKeys(joinTable, t, fk, field.GoName)
if len(fks) > 0 {
t.addRelation(&Relation{
Type: HasOneRelation,
Field: field,
FKs: fks,
JoinTable: joinTable,
})
return true
}
return false
}
func (t *Table) tryBelongsToOne(joinTable *Table, field *Field, tag *tag) bool {
fk, ok := tag.Options["fk"]
if !ok {
fk = t.TypeName
}
fks := foreignKeys(t, joinTable, fk, t.TypeName)
if len(fks) > 0 {
t.addRelation(&Relation{
Type: BelongsToRelation,
Field: field,
FKs: fks,
JoinTable: joinTable,
})
return true
}
return false
}
func scanJSONValue(v reflect.Value, b []byte) error {
if !v.CanSet() {
return fmt.Errorf("pg: Scan(non-pointer %s)", v.Type())
}
if b == nil {
v.Set(reflect.New(v.Type()).Elem())
return nil
}
dec := json.NewDecoder(bytes.NewReader(b))
dec.UseNumber()
return dec.Decode(v.Addr().Interface())
}

29
vendor/github.com/go-pg/pg/orm/table_params.go generated vendored Normal file
View file

@ -0,0 +1,29 @@
package orm
import "reflect"
type tableParams struct {
table *Table
strct reflect.Value
}
func newTableParams(strct interface{}) (*tableParams, bool) {
v := reflect.ValueOf(strct)
if !v.IsValid() {
return nil, false
}
v = reflect.Indirect(v)
if v.Kind() != reflect.Struct {
return nil, false
}
return &tableParams{
table: Tables.Get(v.Type()),
strct: v,
}, true
}
func (m tableParams) AppendParam(b []byte, f QueryFormatter, name string) ([]byte, bool) {
return m.table.AppendParam(b, m.strct, name)
}

168
vendor/github.com/go-pg/pg/orm/table_test.go generated vendored Normal file
View file

@ -0,0 +1,168 @@
package orm_test
import (
"reflect"
"github.com/go-pg/pg/orm"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
type A struct {
Id int
}
func (A) Method() int {
return 10
}
type B struct {
A
}
var _ = Describe("embedded Model", func() {
var strct reflect.Value
var table *orm.Table
BeforeEach(func() {
strct = reflect.ValueOf(B{A: A{Id: 1}})
table = orm.Tables.Get(strct.Type())
})
It("has fields", func() {
Expect(table.Fields).To(HaveLen(1))
Expect(table.FieldsMap).To(HaveLen(1))
id, ok := table.FieldsMap["id"]
Expect(ok).To(BeTrue())
Expect(id.GoName).To(Equal("Id"))
Expect(id.SQLName).To(Equal("id"))
Expect(string(id.Column)).To(Equal(`"id"`))
Expect(id.HasFlag(orm.PrimaryKeyFlag)).To(BeTrue())
Expect(string(id.AppendValue(nil, strct, 1))).To(Equal("1"))
Expect(table.PKs).To(HaveLen(1))
Expect(table.PKs[0]).To(Equal(id))
})
It("has methods", func() {
Expect(table.Methods).To(HaveLen(1))
m, ok := table.Methods["Method"]
Expect(ok).To(BeTrue())
Expect(m.Index).To(Equal(0))
Expect(string(m.AppendValue(nil, strct, 1))).To(Equal("10"))
})
})
type C struct {
Name int `sql:",pk"`
Id int
UUID int
}
var _ = Describe("primary key annotation", func() {
var table *orm.Table
BeforeEach(func() {
strct := reflect.ValueOf(C{})
table = orm.Tables.Get(strct.Type())
})
It("has precedence over auto-detection", func() {
Expect(table.PKs).To(HaveLen(1))
Expect(table.PKs[0].GoName).To(Equal("Name"))
})
})
type D struct {
UUID int
}
var _ = Describe("uuid field", func() {
var table *orm.Table
BeforeEach(func() {
strct := reflect.ValueOf(D{})
table = orm.Tables.Get(strct.Type())
})
It("is detected as primary key", func() {
Expect(table.PKs).To(HaveLen(1))
Expect(table.PKs[0].GoName).To(Equal("UUID"))
})
})
type E struct {
Id int
StructField struct {
Foo string
Bar string
}
}
var _ = Describe("struct field", func() {
var table *orm.Table
BeforeEach(func() {
strct := reflect.ValueOf(E{})
table = orm.Tables.Get(strct.Type())
})
It("is present in the list", func() {
Expect(table.Fields).To(HaveLen(2))
_, ok := table.FieldsMap["struct_field"]
Expect(ok).To(BeTrue())
})
})
type f struct {
Id int
G *g
}
type g struct {
Id int
FId int
F *f
}
var _ = Describe("unexported types", func() {
It("work with belongs to relation", func() {
strct := reflect.ValueOf(f{})
table := orm.Tables.Get(strct.Type())
rel, ok := table.Relations["G"]
Expect(ok).To(BeTrue())
Expect(rel.Type).To(Equal(orm.BelongsToRelation))
})
It("work with has one relation", func() {
strct := reflect.ValueOf(g{})
table := orm.Tables.Get(strct.Type())
rel, ok := table.Relations["F"]
Expect(ok).To(BeTrue())
Expect(rel.Type).To(Equal(orm.HasOneRelation))
})
})
type H struct {
I *I
}
type I struct {
H *H
}
var _ = Describe("model with circular reference", func() {
It("works", func() {
table := orm.Tables.Get(reflect.TypeOf(H{}))
Expect(table).NotTo(BeNil())
table = orm.Tables.Get(reflect.TypeOf(I{}))
Expect(table).NotTo(BeNil())
})
})

39
vendor/github.com/go-pg/pg/orm/tables.go generated vendored Normal file
View file

@ -0,0 +1,39 @@
package orm
import (
"fmt"
"reflect"
"sync"
)
var Tables = newTables()
type tables struct {
mu sync.RWMutex
tables map[reflect.Type]*Table
}
func newTables() *tables {
return &tables{
tables: make(map[reflect.Type]*Table),
}
}
func (t *tables) Get(typ reflect.Type) *Table {
if typ.Kind() != reflect.Struct {
panic(fmt.Errorf("got %s, wanted %s", typ.Kind(), reflect.Struct))
}
t.mu.RLock()
table, ok := t.tables[typ]
t.mu.RUnlock()
if ok {
return table
}
t.mu.Lock()
table = newTable(typ)
t.mu.Unlock()
return table
}

139
vendor/github.com/go-pg/pg/orm/tag.go generated vendored Normal file
View file

@ -0,0 +1,139 @@
package orm
import (
"github.com/go-pg/pg/internal/parser"
)
type tag struct {
Name string
Options map[string]string
}
func parseTag(s string) *tag {
p := &tagParser{
Parser: parser.NewString(s),
}
p.parseKey()
return &p.tag
}
type tagParser struct {
*parser.Parser
tag tag
key string
}
func (p *tagParser) setTagOption(key, value string) {
if p.tag.Options == nil {
p.tag.Options = make(map[string]string)
if value == "" && p.tag.Name == "" {
p.tag.Name = key
return
}
}
if key != "" {
p.tag.Options[key] = value
}
}
func (p *tagParser) parseKey() {
var b []byte
for p.Valid() {
c := p.Read()
switch c {
case ',':
p.Skip(' ')
p.setTagOption(string(b), "")
p.parseKey()
return
case ':':
p.key = string(b)
p.parseValue()
return
default:
b = append(b, c)
}
}
if len(b) > 0 {
p.setTagOption(string(b), "")
}
}
func (p *tagParser) parseValue() {
const quote = '\''
c := p.Peek()
if c == quote {
p.parseQuotedValue()
return
}
var b []byte
for p.Valid() {
c = p.Read()
switch c {
case '\\':
c = p.Read()
b = append(b, c)
case ',':
p.Skip(' ')
p.setTagOption(p.key, string(b))
p.parseKey()
return
default:
b = append(b, c)
}
}
if len(b) > 0 {
p.setTagOption(p.key, string(b))
}
}
func (p *tagParser) parseQuotedValue() {
const quote = '\''
if !p.Skip(quote) {
panic("not reached")
}
var b []byte
b = append(b, quote)
for p.Valid() {
bb, ok := p.ReadSep(quote)
if !ok {
b = append(b, bb...)
break
}
if len(bb) > 0 && bb[len(bb)-1] == '\\' {
b = append(b, bb[:len(bb)-1]...)
b = append(b, quote)
continue
}
b = append(b, bb...)
b = append(b, quote)
p.setTagOption(p.key, string(b))
p.parseKey()
return
}
if len(b) > 0 {
p.setTagOption(p.key, string(b))
}
}
func unquote(s string) (string, bool) {
const quote = '\''
if len(s) < 2 {
return s, false
}
if s[0] == quote && s[len(s)-1] == quote {
return s[1 : len(s)-1], true
}
return s, false
}

42
vendor/github.com/go-pg/pg/orm/tag_test.go generated vendored Normal file
View file

@ -0,0 +1,42 @@
package orm
import (
"testing"
)
var tagTests = []struct {
tag string
name string
opts map[string]string
}{
{"", "", nil},
{"hello", "hello", nil},
{",hello", "", map[string]string{"hello": ""}},
{"hello:world", "", map[string]string{"hello": "world"}},
{"hello:world,foo:bar", "", map[string]string{"hello": "world", "foo": "bar"}},
{"hello:'world1,world2'", "", map[string]string{"hello": "'world1,world2'"}},
{`hello:'D\'Angelo', foo:bar`, "", map[string]string{"hello": "'D'Angelo'", "foo": "bar"}},
}
func TestTagParser(t *testing.T) {
for _, test := range tagTests {
tag := parseTag(test.tag)
if tag.Name != test.name {
t.Fatalf("got %q, wanted %q (tag=%q)", tag.Name, test.name, test.tag)
}
if len(tag.Options) != len(test.opts) {
t.Fatalf(
"got %#v options, wanted %#v (tag=%q)",
tag.Options, test.opts, test.tag,
)
}
for k, v := range test.opts {
if tag.Options[k] != v {
t.Fatalf("got %s=%q, wanted %q (tag=%q)", k, tag.Options[k], v, test.tag)
}
}
}
}

206
vendor/github.com/go-pg/pg/orm/update.go generated vendored Normal file
View file

@ -0,0 +1,206 @@
package orm
import (
"errors"
"reflect"
"github.com/go-pg/pg/internal"
)
func Update(db DB, model ...interface{}) error {
res, err := NewQuery(db, model...).Update()
if err != nil {
return err
}
return internal.AssertOneRow(res.RowsAffected())
}
type updateQuery struct {
q *Query
}
var _ QueryAppender = (*updateQuery)(nil)
func (q updateQuery) Copy() QueryAppender {
return updateQuery{
q: q.q.Copy(),
}
}
func (q updateQuery) Query() *Query {
return q.q
}
func (q updateQuery) AppendQuery(b []byte) ([]byte, error) {
if q.q.stickyErr != nil {
return nil, q.q.stickyErr
}
var err error
if len(q.q.with) > 0 {
b, err = q.q.appendWith(b)
if err != nil {
return nil, err
}
}
b = append(b, "UPDATE "...)
b = q.q.appendFirstTableWithAlias(b)
b, err = q.mustAppendSet(b)
if err != nil {
return nil, err
}
if q.q.hasOtherTables() || q.q.modelHasData() {
b = append(b, " FROM "...)
b = q.q.appendOtherTables(b)
b, err = q.appendModelData(b)
if err != nil {
return nil, err
}
}
b, err = q.q.mustAppendWhere(b)
if err != nil {
return nil, err
}
if len(q.q.returning) > 0 {
b = q.q.appendReturning(b)
}
return b, nil
}
func (q updateQuery) mustAppendSet(b []byte) ([]byte, error) {
if len(q.q.set) > 0 {
b = q.q.appendSet(b)
return b, nil
}
if q.q.model == nil {
return nil, errors.New("pg: Model is nil")
}
b = append(b, " SET "...)
value := q.q.model.Value()
var err error
if value.Kind() == reflect.Struct {
b, err = q.appendSetStruct(b, value)
} else {
b, err = q.appendSetSlice(b, value)
}
if err != nil {
return nil, err
}
return b, nil
}
func (q updateQuery) appendSetStruct(b []byte, strct reflect.Value) ([]byte, error) {
fields, err := q.q.getFields()
if err != nil {
return nil, err
}
if len(fields) == 0 {
fields = q.q.model.Table().Columns
}
for i, f := range fields {
if i > 0 {
b = append(b, ", "...)
}
b = append(b, f.Column...)
b = append(b, " = "...)
b = f.AppendValue(b, strct, 1)
}
return b, nil
}
func (q updateQuery) appendSetSlice(b []byte, slice reflect.Value) ([]byte, error) {
fields, err := q.q.getFields()
if err != nil {
return nil, err
}
if len(fields) == 0 {
fields = q.q.model.Table().Columns
}
for i, f := range fields {
if i > 0 {
b = append(b, ", "...)
}
b = append(b, f.Column...)
b = append(b, " = "...)
b = append(b, "_data."...)
b = append(b, f.Column...)
}
return b, nil
}
func (q updateQuery) appendModelData(b []byte) ([]byte, error) {
if !q.q.hasModel() {
return b, nil
}
v := q.q.model.Value()
if v.Kind() != reflect.Slice || v.Len() == 0 {
return b, nil
}
columns, err := q.q.getDataFields()
if err != nil {
return nil, err
}
if len(columns) > 0 {
columns = append(columns, q.q.model.Table().PKs...)
} else {
columns = q.q.model.Table().Fields
}
return appendSliceValues(b, columns, v), nil
}
func appendSliceValues(b []byte, fields []*Field, slice reflect.Value) []byte {
b = append(b, "(VALUES ("...)
for i := 0; i < slice.Len(); i++ {
el := slice.Index(i)
if el.Kind() == reflect.Interface {
el = el.Elem()
}
b = appendValues(b, fields, reflect.Indirect(el))
if i != slice.Len()-1 {
b = append(b, "), ("...)
}
}
b = append(b, ")) AS _data("...)
b = appendColumns(b, fields)
b = append(b, ")"...)
return b
}
func appendValues(b []byte, fields []*Field, v reflect.Value) []byte {
for i, f := range fields {
if i > 0 {
b = append(b, ", "...)
}
if f.OmitZero(v) {
b = append(b, "NULL"...)
} else {
b = f.AppendValue(b, v, 1)
}
if f.HasFlag(customTypeFlag) {
b = append(b, "::"...)
b = append(b, f.SQLType...)
}
}
return b
}

39
vendor/github.com/go-pg/pg/orm/update_test.go generated vendored Normal file
View file

@ -0,0 +1,39 @@
package orm
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
type UpdateTest struct {
Id int
Value string `sql:"type:mytype"`
}
var _ = Describe("Update", func() {
It("bulk updates", func() {
q := NewQuery(nil, &UpdateTest{}).
Model(&UpdateTest{
Id: 1,
Value: "hello",
}, &UpdateTest{
Id: 2,
})
b, err := updateQuery{q}.AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`UPDATE "update_tests" AS "update_test" SET "value" = _data."value" FROM (VALUES (1, 'hello'::mytype), (2, NULL::mytype)) AS _data("id", "value") WHERE "update_test"."id" = _data."id"`))
})
It("supports WITH", func() {
q := NewQuery(nil, &UpdateTest{}).
WrapWith("wrapper").
Model(&UpdateTest{}).
Table("wrapper").
Where("update_test.id = wrapper.id")
b, err := updateQuery{q}.AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(`WITH "wrapper" AS (SELECT "update_test"."id", "update_test"."value" FROM "update_tests" AS "update_test") UPDATE "update_tests" AS "update_test" SET "value" = NULL FROM "wrapper" WHERE (update_test.id = wrapper.id)`))
})
})

185
vendor/github.com/go-pg/pg/orm/url_values.go generated vendored Normal file
View file

@ -0,0 +1,185 @@
package orm
import (
"fmt"
"net/url"
"strconv"
"strings"
"github.com/go-pg/pg/types"
)
// URLFilters is used with Query.Apply to add WHERE clauses from the URL values:
// - ?foo=bar - Where(`"foo" = 'bar'`)
// - ?foo=hello&foo=world - Where(`"foo" IN ('hello','world')`)
// - ?foo__exclude=bar - Where(`"foo" != 'bar'`)
// - ?foo__ieq=bar - Where(`"foo" ILIKE 'bar'`)
// - ?foo__match=bar - Where(`"foo" SIMILAR TO 'bar'`)
// - ?foo__gt=42 - Where(`"foo" > 42`)
// - ?foo__gte=42 - Where(`"foo" >= 42`)
// - ?foo__lt=42 - Where(`"foo" < 42`)
// - ?foo__lte=42 - Where(`"foo" <= 42`)
func URLFilters(urlValues url.Values) func(*Query) (*Query, error) {
return func(q *Query) (*Query, error) {
for fieldName, values := range urlValues {
var operation string
if i := strings.Index(fieldName, "__"); i != -1 {
fieldName, operation = fieldName[:i], fieldName[i+2:]
}
if q.model.Table().HasField(fieldName) {
q = addOperator(q, fieldName, operation, values)
}
}
return q, nil
}
}
func addOperator(q *Query, fieldName, operator string, values []string) *Query {
switch operator {
case "gt":
q = forEachValue(q, fieldName, values, "? > ?")
case "gte":
q = forEachValue(q, fieldName, values, "? >= ?")
case "lt":
q = forEachValue(q, fieldName, values, "? < ?")
case "lte":
q = forEachValue(q, fieldName, values, "? <= ?")
case "ieq":
q = forEachValue(q, fieldName, values, "? ILIKE ?")
case "match":
q = forEachValue(q, fieldName, values, "? SIMILAR TO ?")
case "exclude":
q = forAllValues(q, fieldName, values, "? != ?", "? NOT IN (?)")
case "", "include":
q = forAllValues(q, fieldName, values, "? = ?", "? IN (?)")
}
return q
}
func forEachValue(q *Query, fieldName string, values []string, queryTemplate string) *Query {
for _, value := range values {
q = q.Where(queryTemplate, types.F(fieldName), value)
}
return q
}
func forAllValues(q *Query, fieldName string, values []string, queryTemplate, queryArrayTemplate string) *Query {
if len(values) > 1 {
q = q.Where(queryArrayTemplate, types.F(fieldName), types.In(values))
} else {
q = q.Where(queryTemplate, types.F(fieldName), values[0])
}
return q
}
type Pager struct {
Limit int
Offset int
// Default max limit is 1000.
MaxLimit int
// Default max offset is 1000000.
MaxOffset int
stickyErr error
}
func NewPager(values url.Values) *Pager {
p := &Pager{}
p.SetURLValues(values)
return p
}
func (p *Pager) SetURLValues(values url.Values) {
limit, err := intParam(values, "limit")
if err != nil {
p.stickyErr = err
return
}
p.Limit = limit
page, err := intParam(values, "page")
if err != nil {
p.stickyErr = err
return
}
if page > 0 {
p.SetPage(page)
}
}
func (p *Pager) maxLimit() int {
if p.MaxLimit > 0 {
return p.MaxLimit
}
return 1000
}
func (p *Pager) maxOffset() int {
if p.MaxOffset > 0 {
return p.MaxOffset
}
return 1000000
}
func (p *Pager) GetLimit() int {
const defaultLimit = 100
if p.Limit <= 0 {
return defaultLimit
}
if p.Limit > p.maxLimit() {
return p.maxLimit()
}
return p.Limit
}
func (p *Pager) GetOffset() int {
if p.Offset > p.maxOffset() {
return p.maxOffset()
}
if p.Offset > 0 {
return p.Offset
}
return 0
}
func (p *Pager) SetPage(page int) {
p.Offset = (page - 1) * p.GetLimit()
}
func (p *Pager) GetPage() int {
return (p.GetOffset() / p.GetLimit()) + 1
}
func (p *Pager) Paginate(q *Query) (*Query, error) {
if p.stickyErr != nil {
return nil, p.stickyErr
}
q = q.Limit(p.GetLimit()).
Offset(p.GetOffset())
return q, nil
}
// Pagination is used with Query.Apply to set LIMIT and OFFSET from the URL values:
// - ?limit=10 - sets q.Limit(10), max limit is 1000.
// - ?page=5 - sets q.Offset((page - 1) * limit), max offset is 1000000.
func Pagination(values url.Values) func(*Query) (*Query, error) {
return NewPager(values).Paginate
}
func intParam(urlValues url.Values, paramName string) (int, error) {
values, ok := urlValues[paramName]
if !ok {
return 0, nil
}
value, err := strconv.Atoi(values[0])
if err != nil {
return 0, fmt.Errorf("param=%s value=%s is invalid: %s", paramName, values[0], err)
}
return value, nil
}

117
vendor/github.com/go-pg/pg/orm/url_values_test.go generated vendored Normal file
View file

@ -0,0 +1,117 @@
package orm
import (
"net/http"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
type URLValuesModel struct {
Id int
Name string
}
type urlValuesTest struct {
url string
query string
}
var _ = Describe("URLValues", func() {
query := `SELECT "url_values_model"."id", "url_values_model"."name" FROM "url_values_models" AS "url_values_model"`
urlValuesTests := []urlValuesTest{
{
url: "http://localhost:8000/test?id__gt=1",
query: query + ` WHERE ("id" > '1')`,
},
{
url: "http://localhost:8000/test?name__gte=Michael",
query: query + ` WHERE ("name" >= 'Michael')`,
},
{
url: "http://localhost:8000/test?id__lt=10",
query: query + ` WHERE ("id" < '10')`,
},
{
url: "http://localhost:8000/test?name__lte=Peter",
query: query + ` WHERE ("name" <= 'Peter')`,
},
{
url: "http://localhost:8000/test?name__exclude=Peter",
query: query + ` WHERE ("name" != 'Peter')`,
},
{
url: "http://localhost:8000/test?name__exclude=Mike&name__exclude=Peter",
query: query + ` WHERE ("name" NOT IN ('Mike','Peter'))`,
},
{
url: "http://localhost:8000/test?name=Mike",
query: query + ` WHERE ("name" = 'Mike')`,
},
{
url: "http://localhost:8000/test?name__ieq=mik_",
query: query + ` WHERE ("name" ILIKE 'mik_')`,
},
{
url: "http://localhost:8000/test?name__match=(m|p).*",
query: query + ` WHERE ("name" SIMILAR TO '(m|p).*')`,
},
{
url: "http://localhost:8000/test?name__include=Peter&name__include=Mike",
query: query + ` WHERE ("name" IN ('Peter','Mike'))`,
},
{
url: "http://localhost:8000/test?name=Mike&name=Peter",
query: query + ` WHERE ("name" IN ('Mike','Peter'))`,
},
{
url: "http://localhost:8000/test?invalid_field=1",
query: query,
},
}
It("adds conditions to the query", func() {
for _, urlValuesTest := range urlValuesTests {
req, _ := http.NewRequest("GET", urlValuesTest.url, nil)
q := NewQuery(nil, &URLValuesModel{})
q = q.Apply(URLFilters(req.URL.Query()))
b, err := selectQuery{q: q}.AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(urlValuesTest.query))
}
})
})
var _ = Describe("Pager", func() {
query := `SELECT "url_values_model"."id", "url_values_model"."name" FROM "url_values_models" AS "url_values_model"`
urlValuesTests := []urlValuesTest{
{
url: "http://localhost:8000/test?limit=10",
query: query + " LIMIT 10",
},
{
url: "http://localhost:8000/test?page=5",
query: query + ` LIMIT 100 OFFSET 400`,
},
{
url: "http://localhost:8000/test?page=5&limit=20",
query: query + ` LIMIT 20 OFFSET 80`,
},
}
It("adds limit and offset to the query", func() {
for _, urlValuesTest := range urlValuesTests {
req, _ := http.NewRequest("GET", urlValuesTest.url, nil)
q := NewQuery(nil, &URLValuesModel{})
q = q.Apply(Pagination(req.URL.Query()))
b, err := selectQuery{q: q}.AppendQuery(nil)
Expect(err).NotTo(HaveOccurred())
Expect(string(b)).To(Equal(urlValuesTest.query))
}
})
})

155
vendor/github.com/go-pg/pg/orm/util.go generated vendored Normal file
View file

@ -0,0 +1,155 @@
package orm
import (
"reflect"
"github.com/go-pg/pg/types"
)
func indirectType(t reflect.Type) reflect.Type {
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
return t
}
func sliceElemType(v reflect.Value) reflect.Type {
elemType := v.Type().Elem()
if elemType.Kind() == reflect.Interface && v.Len() > 0 {
return reflect.Indirect(v.Index(0).Elem()).Type()
} else {
return indirectType(elemType)
}
}
func typeByIndex(t reflect.Type, index []int) reflect.Type {
for _, x := range index {
switch t.Kind() {
case reflect.Ptr:
t = t.Elem()
case reflect.Slice:
t = indirectType(t.Elem())
}
t = t.Field(x).Type
}
return indirectType(t)
}
func fieldByIndex(v reflect.Value, index []int) reflect.Value {
for i, x := range index {
if i > 0 {
v = indirectNew(v)
}
v = v.Field(x)
}
return v
}
func indirectNew(v reflect.Value) reflect.Value {
if v.Kind() == reflect.Ptr {
if v.IsNil() {
v.Set(reflect.New(v.Type().Elem()))
}
v = v.Elem()
}
return v
}
func columns(b []byte, table types.Q, prefix string, fields []*Field) []byte {
for i, f := range fields {
if i > 0 {
b = append(b, ", "...)
}
if len(table) > 0 {
b = append(b, table...)
b = append(b, '.')
}
b = types.AppendField(b, prefix+f.SQLName, 1)
}
return b
}
func walk(v reflect.Value, index []int, fn func(reflect.Value)) {
v = reflect.Indirect(v)
switch v.Kind() {
case reflect.Slice:
for i := 0; i < v.Len(); i++ {
visitField(v.Index(i), index, fn)
}
default:
visitField(v, index, fn)
}
}
func visitField(v reflect.Value, index []int, fn func(reflect.Value)) {
v = reflect.Indirect(v)
if len(index) > 0 {
v = v.Field(index[0])
walk(v, index[1:], fn)
} else {
fn(v)
}
}
func appendChildValues(b []byte, v reflect.Value, index []int, fields []*Field) []byte {
seen := make(map[string]struct{})
walk(v, index, func(v reflect.Value) {
start := len(b)
b = append(b, '(')
for i, f := range fields {
if i > 0 {
b = append(b, ", "...)
}
b = f.AppendValue(b, v, 1)
}
b = append(b, "), "...)
if _, ok := seen[string(b[start:])]; ok {
b = b[:start]
} else {
seen[string(b[start:])] = struct{}{}
}
})
if len(seen) > 0 {
b = b[:len(b)-2] // trim ", "
}
return b
}
func dstValues(model tableModel, fields []*Field) map[string][]reflect.Value {
mp := make(map[string][]reflect.Value)
var id []byte
walk(model.Root(), model.ParentIndex(), func(v reflect.Value) {
id = modelId(id[:0], v, fields)
mp[string(id)] = append(mp[string(id)], v.FieldByIndex(model.Relation().Field.Index))
})
return mp
}
func modelId(b []byte, v reflect.Value, fields []*Field) []byte {
for _, f := range fields {
b = f.AppendValue(b, v, 0)
b = append(b, ',')
}
return b
}
func modelIdMap(b []byte, m map[string]string, prefix string, fields []*Field) []byte {
for _, f := range fields {
b = append(b, m[prefix+f.SQLName]...)
b = append(b, ',')
}
return b
}
func appendColumns(b []byte, fields []*Field) []byte {
for i, f := range fields {
if i > 0 {
b = append(b, ", "...)
}
b = append(b, f.Column...)
}
return b
}

122
vendor/github.com/go-pg/pg/orm/zero.go generated vendored Normal file
View file

@ -0,0 +1,122 @@
package orm
import (
"database/sql/driver"
"reflect"
"github.com/go-pg/pg/types"
)
var driverValuerType = reflect.TypeOf((*driver.Valuer)(nil)).Elem()
var appenderType = reflect.TypeOf((*types.ValueAppender)(nil)).Elem()
var isZeroerType = reflect.TypeOf((*isZeroer)(nil)).Elem()
type isZeroer interface {
IsZero() bool
}
func isZeroFunc(typ reflect.Type) func(reflect.Value) bool {
if typ.Implements(isZeroerType) {
return isZero
}
switch typ.Kind() {
case reflect.Array:
if typ.Elem().Kind() == reflect.Uint8 {
return isZeroBytes
}
return isZeroLen
case reflect.Map, reflect.Slice, reflect.String:
return isZeroLen
case reflect.Bool:
return isZeroBool
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return isZeroInt
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return isZeroUint
case reflect.Float32, reflect.Float64:
return isZeroFloat
case reflect.Interface, reflect.Ptr:
return isZeroNil
}
if typ.Implements(appenderType) {
return isZeroAppenderValue
}
if typ.Implements(driverValuerType) {
return isZeroDriverValue
}
return isZeroFalse
}
func isZero(v reflect.Value) bool {
if v.Kind() == reflect.Ptr {
return v.IsNil()
}
return v.Interface().(isZeroer).IsZero()
}
func isZeroAppenderValue(v reflect.Value) bool {
if v.Kind() == reflect.Ptr {
return v.IsNil()
}
appender := v.Interface().(types.ValueAppender)
value, err := appender.AppendValue(nil, 0)
if err != nil {
return false
}
return value == nil
}
func isZeroDriverValue(v reflect.Value) bool {
if v.Kind() == reflect.Ptr {
return v.IsNil()
}
valuer := v.Interface().(driver.Valuer)
value, err := valuer.Value()
if err != nil {
return false
}
return value == nil
}
func isZeroLen(v reflect.Value) bool {
return v.Len() == 0
}
func isZeroNil(v reflect.Value) bool {
return v.IsNil()
}
func isZeroBool(v reflect.Value) bool {
return !v.Bool()
}
func isZeroInt(v reflect.Value) bool {
return v.Int() == 0
}
func isZeroUint(v reflect.Value) bool {
return v.Uint() == 0
}
func isZeroFloat(v reflect.Value) bool {
return v.Float() == 0
}
func isZeroBytes(v reflect.Value) bool {
b := v.Slice(0, v.Len()).Bytes()
for _, c := range b {
if c != 0 {
return false
}
}
return true
}
func isZeroFalse(v reflect.Value) bool {
return false
}