DB Migrations (#67)
This commit is contained in:
37
vendor/github.com/go-xorm/builder/.drone.yml
generated
vendored
Normal file
37
vendor/github.com/go-xorm/builder/.drone.yml
generated
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
workspace:
|
||||
base: /go
|
||||
path: src/github.com/go-xorm/builder
|
||||
|
||||
clone:
|
||||
git:
|
||||
image: plugins/git:next
|
||||
depth: 50
|
||||
tags: true
|
||||
|
||||
matrix:
|
||||
GO_VERSION:
|
||||
- 1.8
|
||||
- 1.9
|
||||
- 1.10
|
||||
- 1.11
|
||||
|
||||
pipeline:
|
||||
test:
|
||||
image: golang:${GO_VERSION}
|
||||
commands:
|
||||
- go get -u github.com/golang/lint/golint
|
||||
- go get -u github.com/stretchr/testify/assert
|
||||
- go get -u github.com/go-xorm/sqlfiddle
|
||||
- golint ./...
|
||||
- go test -v -race -coverprofile=coverage.txt -covermode=atomic
|
||||
when:
|
||||
event: [ push, tag, pull_request ]
|
||||
|
||||
codecov:
|
||||
image: robertstettner/drone-codecov
|
||||
group: build
|
||||
secrets: [ codecov_token ]
|
||||
files:
|
||||
- coverage.txt
|
||||
when:
|
||||
event: [ push, pull_request ]
|
39
vendor/github.com/go-xorm/builder/README.md
generated
vendored
39
vendor/github.com/go-xorm/builder/README.md
generated
vendored
@ -1,26 +1,47 @@
|
||||
# SQL builder
|
||||
|
||||
[](https://circleci.com/gh/go-xorm/builder/tree/master)
|
||||
[](https://gitci.cn/go-xorm/builder) [](https://codecov.io/gh/go-xorm/builder)
|
||||
[](https://goreportcard.com/report/github.com/go-xorm/builder)
|
||||
|
||||
Package builder is a lightweight and fast SQL builder for Go and XORM.
|
||||
|
||||
Make sure you have installed Go 1.1+ and then:
|
||||
Make sure you have installed Go 1.8+ and then:
|
||||
|
||||
go get github.com/go-xorm/builder
|
||||
|
||||
# Insert
|
||||
|
||||
```Go
|
||||
sql, args, err := Insert(Eq{"c": 1, "d": 2}).Into("table1").ToSQL()
|
||||
sql, args, err := builder.Insert(Eq{"c": 1, "d": 2}).Into("table1").ToSQL()
|
||||
|
||||
// INSERT INTO table1 SELECT * FROM table2
|
||||
sql, err := builder.Insert().Into("table1").Select().From("table2").ToBoundSQL()
|
||||
|
||||
// INSERT INTO table1 (a, b) SELECT b, c FROM table2
|
||||
sql, err = builder.Insert("a, b").Into("table1").Select("b, c").From("table2").ToBoundSQL()
|
||||
```
|
||||
|
||||
# Select
|
||||
|
||||
```Go
|
||||
// Simple Query
|
||||
sql, args, err := Select("c, d").From("table1").Where(Eq{"a": 1}).ToSQL()
|
||||
|
||||
// With join
|
||||
sql, args, err = Select("c, d").From("table1").LeftJoin("table2", Eq{"table1.id": 1}.And(Lt{"table2.id": 3})).
|
||||
RightJoin("table3", "table2.id = table3.tid").Where(Eq{"a": 1}).ToSQL()
|
||||
// From sub query
|
||||
sql, args, err := Select("sub.id").From(Select("c").From("table1").Where(Eq{"a": 1}), "sub").Where(Eq{"b": 1}).ToSQL()
|
||||
// From union query
|
||||
sql, args, err = Select("sub.id").From(
|
||||
Select("id").From("table1").Where(Eq{"a": 1}).Union("all", Select("id").From("table1").Where(Eq{"a": 2})),"sub").
|
||||
Where(Eq{"b": 1}).ToSQL()
|
||||
// With order by
|
||||
sql, args, err = Select("a", "b", "c").From("table1").Where(Eq{"f1": "v1", "f2": "v2"}).
|
||||
OrderBy("a ASC").ToSQL()
|
||||
// With limit.
|
||||
// Be careful! You should set up specific dialect for builder before performing a query with LIMIT
|
||||
sql, args, err = Dialect(MYSQL).Select("a", "b", "c").From("table1").OrderBy("a ASC").
|
||||
Limit(5, 10).ToSQL()
|
||||
```
|
||||
|
||||
# Update
|
||||
@ -35,6 +56,16 @@ sql, args, err := Update(Eq{"a": 2}).From("table1").Where(Eq{"a": 1}).ToSQL()
|
||||
sql, args, err := Delete(Eq{"a": 1}).From("table1").ToSQL()
|
||||
```
|
||||
|
||||
# Union
|
||||
|
||||
```Go
|
||||
sql, args, err := Select("*").From("a").Where(Eq{"status": "1"}).
|
||||
Union("all", Select("*").From("a").Where(Eq{"status": "2"})).
|
||||
Union("distinct", Select("*").From("a").Where(Eq{"status": "3"})).
|
||||
Union("", Select("*").From("a").Where(Eq{"status": "4"})).
|
||||
ToSQL()
|
||||
```
|
||||
|
||||
# Conditions
|
||||
|
||||
* `Eq` is a redefine of a map, you can give one or more conditions to `Eq`
|
||||
|
273
vendor/github.com/go-xorm/builder/builder.go
generated
vendored
273
vendor/github.com/go-xorm/builder/builder.go
generated
vendored
@ -4,6 +4,12 @@
|
||||
|
||||
package builder
|
||||
|
||||
import (
|
||||
sql2 "database/sql"
|
||||
"fmt"
|
||||
"sort"
|
||||
)
|
||||
|
||||
type optype byte
|
||||
|
||||
const (
|
||||
@ -12,6 +18,15 @@ const (
|
||||
insertType // insert
|
||||
updateType // update
|
||||
deleteType // delete
|
||||
unionType // union
|
||||
)
|
||||
|
||||
const (
|
||||
POSTGRES = "postgres"
|
||||
SQLITE = "sqlite3"
|
||||
MYSQL = "mysql"
|
||||
MSSQL = "mssql"
|
||||
ORACLE = "oracle"
|
||||
)
|
||||
|
||||
type join struct {
|
||||
@ -20,60 +35,115 @@ type join struct {
|
||||
joinCond Cond
|
||||
}
|
||||
|
||||
type union struct {
|
||||
unionType string
|
||||
builder *Builder
|
||||
}
|
||||
|
||||
type limit struct {
|
||||
limitN int
|
||||
offset int
|
||||
}
|
||||
|
||||
// Builder describes a SQL statement
|
||||
type Builder struct {
|
||||
optype
|
||||
tableName string
|
||||
cond Cond
|
||||
selects []string
|
||||
joins []join
|
||||
inserts Eq
|
||||
updates []Eq
|
||||
dialect string
|
||||
isNested bool
|
||||
into string
|
||||
from string
|
||||
subQuery *Builder
|
||||
cond Cond
|
||||
selects []string
|
||||
joins []join
|
||||
unions []union
|
||||
limitation *limit
|
||||
insertCols []string
|
||||
insertVals []interface{}
|
||||
updates []Eq
|
||||
orderBy string
|
||||
groupBy string
|
||||
having string
|
||||
}
|
||||
|
||||
// Select creates a select Builder
|
||||
func Select(cols ...string) *Builder {
|
||||
builder := &Builder{cond: NewCond()}
|
||||
return builder.Select(cols...)
|
||||
// Dialect sets the db dialect of Builder.
|
||||
func Dialect(dialect string) *Builder {
|
||||
builder := &Builder{cond: NewCond(), dialect: dialect}
|
||||
return builder
|
||||
}
|
||||
|
||||
// Insert creates an insert Builder
|
||||
func Insert(eq Eq) *Builder {
|
||||
builder := &Builder{cond: NewCond()}
|
||||
return builder.Insert(eq)
|
||||
// MySQL is shortcut of Dialect(MySQL)
|
||||
func MySQL() *Builder {
|
||||
return Dialect(MYSQL)
|
||||
}
|
||||
|
||||
// Update creates an update Builder
|
||||
func Update(updates ...Eq) *Builder {
|
||||
builder := &Builder{cond: NewCond()}
|
||||
return builder.Update(updates...)
|
||||
// MsSQL is shortcut of Dialect(MsSQL)
|
||||
func MsSQL() *Builder {
|
||||
return Dialect(MSSQL)
|
||||
}
|
||||
|
||||
// Delete creates a delete Builder
|
||||
func Delete(conds ...Cond) *Builder {
|
||||
builder := &Builder{cond: NewCond()}
|
||||
return builder.Delete(conds...)
|
||||
// Oracle is shortcut of Dialect(Oracle)
|
||||
func Oracle() *Builder {
|
||||
return Dialect(ORACLE)
|
||||
}
|
||||
|
||||
// Postgres is shortcut of Dialect(Postgres)
|
||||
func Postgres() *Builder {
|
||||
return Dialect(POSTGRES)
|
||||
}
|
||||
|
||||
// SQLite is shortcut of Dialect(SQLITE)
|
||||
func SQLite() *Builder {
|
||||
return Dialect(SQLITE)
|
||||
}
|
||||
|
||||
// Where sets where SQL
|
||||
func (b *Builder) Where(cond Cond) *Builder {
|
||||
b.cond = b.cond.And(cond)
|
||||
if b.cond.IsValid() {
|
||||
b.cond = b.cond.And(cond)
|
||||
} else {
|
||||
b.cond = cond
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// From sets the table name
|
||||
func (b *Builder) From(tableName string) *Builder {
|
||||
b.tableName = tableName
|
||||
// From sets from subject(can be a table name in string or a builder pointer) and its alias
|
||||
func (b *Builder) From(subject interface{}, alias ...string) *Builder {
|
||||
switch subject.(type) {
|
||||
case *Builder:
|
||||
b.subQuery = subject.(*Builder)
|
||||
|
||||
if len(alias) > 0 {
|
||||
b.from = alias[0]
|
||||
} else {
|
||||
b.isNested = true
|
||||
}
|
||||
case string:
|
||||
b.from = subject.(string)
|
||||
|
||||
if len(alias) > 0 {
|
||||
b.from = b.from + " " + alias[0]
|
||||
}
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// TableName returns the table name
|
||||
func (b *Builder) TableName() string {
|
||||
if b.optype == insertType {
|
||||
return b.into
|
||||
}
|
||||
return b.from
|
||||
}
|
||||
|
||||
// Into sets insert table name
|
||||
func (b *Builder) Into(tableName string) *Builder {
|
||||
b.tableName = tableName
|
||||
b.into = tableName
|
||||
return b
|
||||
}
|
||||
|
||||
// Join sets join table and contions
|
||||
// Join sets join table and conditions
|
||||
func (b *Builder) Join(joinType, joinTable string, joinCond interface{}) *Builder {
|
||||
switch joinCond.(type) {
|
||||
case Cond:
|
||||
@ -85,6 +155,50 @@ func (b *Builder) Join(joinType, joinTable string, joinCond interface{}) *Builde
|
||||
return b
|
||||
}
|
||||
|
||||
// Union sets union conditions
|
||||
func (b *Builder) Union(unionTp string, unionCond *Builder) *Builder {
|
||||
var builder *Builder
|
||||
if b.optype != unionType {
|
||||
builder = &Builder{cond: NewCond()}
|
||||
builder.optype = unionType
|
||||
builder.dialect = b.dialect
|
||||
builder.selects = b.selects
|
||||
|
||||
currentUnions := b.unions
|
||||
// erase sub unions (actually append to new Builder.unions)
|
||||
b.unions = nil
|
||||
|
||||
for e := range currentUnions {
|
||||
currentUnions[e].builder.dialect = b.dialect
|
||||
}
|
||||
|
||||
builder.unions = append(append(builder.unions, union{"", b}), currentUnions...)
|
||||
} else {
|
||||
builder = b
|
||||
}
|
||||
|
||||
if unionCond != nil {
|
||||
if unionCond.dialect == "" && builder.dialect != "" {
|
||||
unionCond.dialect = builder.dialect
|
||||
}
|
||||
|
||||
builder.unions = append(builder.unions, union{unionTp, unionCond})
|
||||
}
|
||||
|
||||
return builder
|
||||
}
|
||||
|
||||
// Limit sets limitN condition
|
||||
func (b *Builder) Limit(limitN int, offset ...int) *Builder {
|
||||
b.limitation = &limit{limitN: limitN}
|
||||
|
||||
if len(offset) > 0 {
|
||||
b.limitation.offset = offset[0]
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// InnerJoin sets inner join
|
||||
func (b *Builder) InnerJoin(joinTable string, joinCond interface{}) *Builder {
|
||||
return b.Join("INNER", joinTable, joinCond)
|
||||
@ -113,7 +227,9 @@ func (b *Builder) FullJoin(joinTable string, joinCond interface{}) *Builder {
|
||||
// Select sets select SQL
|
||||
func (b *Builder) Select(cols ...string) *Builder {
|
||||
b.selects = cols
|
||||
b.optype = selectType
|
||||
if b.optype == condType {
|
||||
b.optype = selectType
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
@ -130,15 +246,52 @@ func (b *Builder) Or(cond Cond) *Builder {
|
||||
}
|
||||
|
||||
// Insert sets insert SQL
|
||||
func (b *Builder) Insert(eq Eq) *Builder {
|
||||
b.inserts = eq
|
||||
func (b *Builder) Insert(eq ...interface{}) *Builder {
|
||||
if len(eq) > 0 {
|
||||
var paramType = -1
|
||||
for _, e := range eq {
|
||||
switch t := e.(type) {
|
||||
case Eq:
|
||||
if paramType == -1 {
|
||||
paramType = 0
|
||||
}
|
||||
if paramType != 0 {
|
||||
break
|
||||
}
|
||||
for k, v := range t {
|
||||
b.insertCols = append(b.insertCols, k)
|
||||
b.insertVals = append(b.insertVals, v)
|
||||
}
|
||||
case string:
|
||||
if paramType == -1 {
|
||||
paramType = 1
|
||||
}
|
||||
if paramType != 1 {
|
||||
break
|
||||
}
|
||||
b.insertCols = append(b.insertCols, t)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(b.insertCols) == len(b.insertVals) {
|
||||
sort.Slice(b.insertVals, func(i, j int) bool {
|
||||
return b.insertCols[i] < b.insertCols[j]
|
||||
})
|
||||
sort.Strings(b.insertCols)
|
||||
}
|
||||
b.optype = insertType
|
||||
return b
|
||||
}
|
||||
|
||||
// Update sets update SQL
|
||||
func (b *Builder) Update(updates ...Eq) *Builder {
|
||||
b.updates = updates
|
||||
b.updates = make([]Eq, 0, len(updates))
|
||||
for _, update := range updates {
|
||||
if update.IsValid() {
|
||||
b.updates = append(b.updates, update)
|
||||
}
|
||||
}
|
||||
b.optype = updateType
|
||||
return b
|
||||
}
|
||||
@ -153,8 +306,8 @@ func (b *Builder) Delete(conds ...Cond) *Builder {
|
||||
// WriteTo implements Writer interface
|
||||
func (b *Builder) WriteTo(w Writer) error {
|
||||
switch b.optype {
|
||||
case condType:
|
||||
return b.cond.WriteTo(w)
|
||||
/*case condType:
|
||||
return b.cond.WriteTo(w)*/
|
||||
case selectType:
|
||||
return b.selectWriteTo(w)
|
||||
case insertType:
|
||||
@ -163,6 +316,8 @@ func (b *Builder) WriteTo(w Writer) error {
|
||||
return b.updateWriteTo(w)
|
||||
case deleteType:
|
||||
return b.deleteWriteTo(w)
|
||||
case unionType:
|
||||
return b.unionWriteTo(w)
|
||||
}
|
||||
|
||||
return ErrNotSupportType
|
||||
@ -175,16 +330,48 @@ func (b *Builder) ToSQL() (string, []interface{}, error) {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
return w.writer.String(), w.args, nil
|
||||
// in case of sql.NamedArg in args
|
||||
for e := range w.args {
|
||||
if namedArg, ok := w.args[e].(sql2.NamedArg); ok {
|
||||
w.args[e] = namedArg.Value
|
||||
}
|
||||
}
|
||||
|
||||
var sql = w.writer.String()
|
||||
var err error
|
||||
|
||||
switch b.dialect {
|
||||
case ORACLE, MSSQL:
|
||||
// This is for compatibility with different sql drivers
|
||||
for e := range w.args {
|
||||
w.args[e] = sql2.Named(fmt.Sprintf("p%d", e+1), w.args[e])
|
||||
}
|
||||
|
||||
var prefix string
|
||||
if b.dialect == ORACLE {
|
||||
prefix = ":p"
|
||||
} else {
|
||||
prefix = "@p"
|
||||
}
|
||||
|
||||
if sql, err = ConvertPlaceholder(sql, prefix); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
case POSTGRES:
|
||||
if sql, err = ConvertPlaceholder(sql, "$"); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return sql, w.args, nil
|
||||
}
|
||||
|
||||
// ToSQL convert a builder or condtions to SQL and args
|
||||
func ToSQL(cond interface{}) (string, []interface{}, error) {
|
||||
switch cond.(type) {
|
||||
case Cond:
|
||||
return condToSQL(cond.(Cond))
|
||||
case *Builder:
|
||||
return cond.(*Builder).ToSQL()
|
||||
// ToBoundSQL
|
||||
func (b *Builder) ToBoundSQL() (string, error) {
|
||||
w := NewWriter()
|
||||
if err := b.WriteTo(w); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return "", nil, ErrNotSupportType
|
||||
|
||||
return ConvertToBoundSQL(w.writer.String(), w.args)
|
||||
}
|
||||
|
13
vendor/github.com/go-xorm/builder/builder_delete.go
generated
vendored
13
vendor/github.com/go-xorm/builder/builder_delete.go
generated
vendored
@ -5,16 +5,21 @@
|
||||
package builder
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Delete creates a delete Builder
|
||||
func Delete(conds ...Cond) *Builder {
|
||||
builder := &Builder{cond: NewCond()}
|
||||
return builder.Delete(conds...)
|
||||
}
|
||||
|
||||
func (b *Builder) deleteWriteTo(w Writer) error {
|
||||
if len(b.tableName) <= 0 {
|
||||
return errors.New("no table indicated")
|
||||
if len(b.from) <= 0 {
|
||||
return ErrNoTableName
|
||||
}
|
||||
|
||||
if _, err := fmt.Fprintf(w, "DELETE FROM %s WHERE ", b.tableName); err != nil {
|
||||
if _, err := fmt.Fprintf(w, "DELETE FROM %s WHERE ", b.from); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
51
vendor/github.com/go-xorm/builder/builder_insert.go
generated
vendored
51
vendor/github.com/go-xorm/builder/builder_insert.go
generated
vendored
@ -6,37 +6,63 @@ package builder
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func (b *Builder) insertWriteTo(w Writer) error {
|
||||
if len(b.tableName) <= 0 {
|
||||
return errors.New("no table indicated")
|
||||
}
|
||||
if len(b.inserts) <= 0 {
|
||||
return errors.New("no column to be update")
|
||||
// Insert creates an insert Builder
|
||||
func Insert(eq ...interface{}) *Builder {
|
||||
builder := &Builder{cond: NewCond()}
|
||||
return builder.Insert(eq...)
|
||||
}
|
||||
|
||||
func (b *Builder) insertSelectWriteTo(w Writer) error {
|
||||
if _, err := fmt.Fprintf(w, "INSERT INTO %s ", b.into); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := fmt.Fprintf(w, "INSERT INTO %s (", b.tableName); err != nil {
|
||||
if len(b.insertCols) > 0 {
|
||||
fmt.Fprintf(w, "(")
|
||||
for _, col := range b.insertCols {
|
||||
fmt.Fprintf(w, col)
|
||||
}
|
||||
fmt.Fprintf(w, ") ")
|
||||
}
|
||||
|
||||
return b.selectWriteTo(w)
|
||||
}
|
||||
|
||||
func (b *Builder) insertWriteTo(w Writer) error {
|
||||
if len(b.into) <= 0 {
|
||||
return ErrNoTableName
|
||||
}
|
||||
if len(b.insertCols) <= 0 && b.from == "" {
|
||||
return ErrNoColumnToInsert
|
||||
}
|
||||
|
||||
if b.into != "" && b.from != "" {
|
||||
return b.insertSelectWriteTo(w)
|
||||
}
|
||||
|
||||
if _, err := fmt.Fprintf(w, "INSERT INTO %s (", b.into); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var args = make([]interface{}, 0)
|
||||
var bs []byte
|
||||
var valBuffer = bytes.NewBuffer(bs)
|
||||
var i = 0
|
||||
for col, value := range b.inserts {
|
||||
|
||||
for i, col := range b.insertCols {
|
||||
value := b.insertVals[i]
|
||||
fmt.Fprint(w, col)
|
||||
if e, ok := value.(expr); ok {
|
||||
fmt.Fprint(valBuffer, e.sql)
|
||||
fmt.Fprintf(valBuffer, "(%s)", e.sql)
|
||||
args = append(args, e.args...)
|
||||
} else {
|
||||
fmt.Fprint(valBuffer, "?")
|
||||
args = append(args, value)
|
||||
}
|
||||
|
||||
if i != len(b.inserts)-1 {
|
||||
if i != len(b.insertCols)-1 {
|
||||
if _, err := fmt.Fprint(w, ","); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -44,7 +70,6 @@ func (b *Builder) insertWriteTo(w Writer) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
i = i + 1
|
||||
}
|
||||
|
||||
if _, err := fmt.Fprint(w, ") Values ("); err != nil {
|
||||
|
100
vendor/github.com/go-xorm/builder/builder_limit.go
generated
vendored
Normal file
100
vendor/github.com/go-xorm/builder/builder_limit.go
generated
vendored
Normal file
@ -0,0 +1,100 @@
|
||||
// Copyright 2018 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (b *Builder) limitWriteTo(w Writer) error {
|
||||
if strings.TrimSpace(b.dialect) == "" {
|
||||
return ErrDialectNotSetUp
|
||||
}
|
||||
|
||||
if b.limitation != nil {
|
||||
limit := b.limitation
|
||||
if limit.offset < 0 || limit.limitN <= 0 {
|
||||
return ErrInvalidLimitation
|
||||
}
|
||||
// erase limit condition
|
||||
b.limitation = nil
|
||||
ow := w.(*BytesWriter)
|
||||
|
||||
switch strings.ToLower(strings.TrimSpace(b.dialect)) {
|
||||
case ORACLE:
|
||||
if len(b.selects) == 0 {
|
||||
b.selects = append(b.selects, "*")
|
||||
}
|
||||
|
||||
var final *Builder
|
||||
selects := b.selects
|
||||
b.selects = append(selects, "ROWNUM RN")
|
||||
|
||||
var wb *Builder
|
||||
if b.optype == unionType {
|
||||
wb = Dialect(b.dialect).Select("at.*", "ROWNUM RN").
|
||||
From(b, "at")
|
||||
} else {
|
||||
wb = b
|
||||
}
|
||||
|
||||
if limit.offset == 0 {
|
||||
final = Dialect(b.dialect).Select(selects...).From(wb, "at").
|
||||
Where(Lte{"at.RN": limit.limitN})
|
||||
} else {
|
||||
sub := Dialect(b.dialect).Select("*").
|
||||
From(b, "at").Where(Lte{"at.RN": limit.offset + limit.limitN})
|
||||
|
||||
final = Dialect(b.dialect).Select(selects...).From(sub, "att").
|
||||
Where(Gt{"att.RN": limit.offset})
|
||||
}
|
||||
|
||||
return final.WriteTo(ow)
|
||||
case SQLITE, MYSQL, POSTGRES:
|
||||
// if type UNION, we need to write previous content back to current writer
|
||||
if b.optype == unionType {
|
||||
if err := b.WriteTo(ow); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if limit.offset == 0 {
|
||||
fmt.Fprint(ow, " LIMIT ", limit.limitN)
|
||||
} else {
|
||||
fmt.Fprintf(ow, " LIMIT %v OFFSET %v", limit.limitN, limit.offset)
|
||||
}
|
||||
case MSSQL:
|
||||
if len(b.selects) == 0 {
|
||||
b.selects = append(b.selects, "*")
|
||||
}
|
||||
|
||||
var final *Builder
|
||||
selects := b.selects
|
||||
b.selects = append(append([]string{fmt.Sprintf("TOP %d %v", limit.limitN+limit.offset, b.selects[0])},
|
||||
b.selects[1:]...), "ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS RN")
|
||||
|
||||
var wb *Builder
|
||||
if b.optype == unionType {
|
||||
wb = Dialect(b.dialect).Select("*", "ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS RN").
|
||||
From(b, "at")
|
||||
} else {
|
||||
wb = b
|
||||
}
|
||||
|
||||
if limit.offset == 0 {
|
||||
final = Dialect(b.dialect).Select(selects...).From(wb, "at")
|
||||
} else {
|
||||
final = Dialect(b.dialect).Select(selects...).From(wb, "at").Where(Gt{"at.RN": limit.offset})
|
||||
}
|
||||
|
||||
return final.WriteTo(ow)
|
||||
default:
|
||||
return ErrNotSupportType
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
110
vendor/github.com/go-xorm/builder/builder_select.go
generated
vendored
110
vendor/github.com/go-xorm/builder/builder_select.go
generated
vendored
@ -5,13 +5,24 @@
|
||||
package builder
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Select creates a select Builder
|
||||
func Select(cols ...string) *Builder {
|
||||
builder := &Builder{cond: NewCond()}
|
||||
return builder.Select(cols...)
|
||||
}
|
||||
|
||||
func (b *Builder) selectWriteTo(w Writer) error {
|
||||
if len(b.tableName) <= 0 {
|
||||
return errors.New("no table indicated")
|
||||
if len(b.from) <= 0 && !b.isNested {
|
||||
return ErrNoTableName
|
||||
}
|
||||
|
||||
// perform limit before writing to writer when b.dialect between ORACLE and MSSQL
|
||||
// this avoid a duplicate writing problem in simple limit query
|
||||
if b.limitation != nil && (b.dialect == ORACLE || b.dialect == MSSQL) {
|
||||
return b.limitWriteTo(w)
|
||||
}
|
||||
|
||||
if _, err := fmt.Fprint(w, "SELECT "); err != nil {
|
||||
@ -34,20 +45,101 @@ func (b *Builder) selectWriteTo(w Writer) error {
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := fmt.Fprintf(w, " FROM %s", b.tableName); err != nil {
|
||||
return err
|
||||
if b.subQuery == nil {
|
||||
if _, err := fmt.Fprint(w, " FROM ", b.from); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if b.cond.IsValid() && len(b.from) <= 0 {
|
||||
return ErrUnnamedDerivedTable
|
||||
}
|
||||
if b.subQuery.dialect != "" && b.dialect != b.subQuery.dialect {
|
||||
return ErrInconsistentDialect
|
||||
}
|
||||
|
||||
// dialect of sub-query will inherit from the main one (if not set up)
|
||||
if b.dialect != "" && b.subQuery.dialect == "" {
|
||||
b.subQuery.dialect = b.dialect
|
||||
}
|
||||
|
||||
switch b.subQuery.optype {
|
||||
case selectType, unionType:
|
||||
fmt.Fprint(w, " FROM (")
|
||||
if err := b.subQuery.WriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(b.from) == 0 {
|
||||
fmt.Fprintf(w, ")")
|
||||
} else {
|
||||
fmt.Fprintf(w, ") %v", b.from)
|
||||
}
|
||||
default:
|
||||
return ErrUnexpectedSubQuery
|
||||
}
|
||||
}
|
||||
|
||||
for _, v := range b.joins {
|
||||
fmt.Fprintf(w, " %s JOIN %s ON ", v.joinType, v.joinTable)
|
||||
if _, err := fmt.Fprintf(w, " %s JOIN %s ON ", v.joinType, v.joinTable); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := v.joinCond.WriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := fmt.Fprint(w, " WHERE "); err != nil {
|
||||
return err
|
||||
if b.cond.IsValid() {
|
||||
if _, err := fmt.Fprint(w, " WHERE "); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := b.cond.WriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return b.cond.WriteTo(w)
|
||||
if len(b.groupBy) > 0 {
|
||||
if _, err := fmt.Fprint(w, " GROUP BY ", b.groupBy); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(b.having) > 0 {
|
||||
if _, err := fmt.Fprint(w, " HAVING ", b.having); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(b.orderBy) > 0 {
|
||||
if _, err := fmt.Fprint(w, " ORDER BY ", b.orderBy); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if b.limitation != nil {
|
||||
if err := b.limitWriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// OrderBy orderBy SQL
|
||||
func (b *Builder) OrderBy(orderBy string) *Builder {
|
||||
b.orderBy = orderBy
|
||||
return b
|
||||
}
|
||||
|
||||
// GroupBy groupby SQL
|
||||
func (b *Builder) GroupBy(groupby string) *Builder {
|
||||
b.groupBy = groupby
|
||||
return b
|
||||
}
|
||||
|
||||
// Having having SQL
|
||||
func (b *Builder) Having(having string) *Builder {
|
||||
b.having = having
|
||||
return b
|
||||
}
|
||||
|
47
vendor/github.com/go-xorm/builder/builder_union.go
generated
vendored
Normal file
47
vendor/github.com/go-xorm/builder/builder_union.go
generated
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
// Copyright 2018 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (b *Builder) unionWriteTo(w Writer) error {
|
||||
if b.limitation != nil || b.cond.IsValid() ||
|
||||
b.orderBy != "" || b.having != "" || b.groupBy != "" {
|
||||
return ErrNotUnexpectedUnionConditions
|
||||
}
|
||||
|
||||
for idx, u := range b.unions {
|
||||
current := u.builder
|
||||
if current.optype != selectType {
|
||||
return ErrUnsupportedUnionMembers
|
||||
}
|
||||
|
||||
if len(b.unions) == 1 {
|
||||
if err := current.selectWriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if b.dialect != "" && b.dialect != current.dialect {
|
||||
return ErrInconsistentDialect
|
||||
}
|
||||
|
||||
if idx != 0 {
|
||||
fmt.Fprint(w, fmt.Sprintf(" UNION %v ", strings.ToUpper(u.unionType)))
|
||||
}
|
||||
fmt.Fprint(w, "(")
|
||||
|
||||
if err := current.selectWriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Fprint(w, ")")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
15
vendor/github.com/go-xorm/builder/builder_update.go
generated
vendored
15
vendor/github.com/go-xorm/builder/builder_update.go
generated
vendored
@ -5,19 +5,24 @@
|
||||
package builder
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Update creates an update Builder
|
||||
func Update(updates ...Eq) *Builder {
|
||||
builder := &Builder{cond: NewCond()}
|
||||
return builder.Update(updates...)
|
||||
}
|
||||
|
||||
func (b *Builder) updateWriteTo(w Writer) error {
|
||||
if len(b.tableName) <= 0 {
|
||||
return errors.New("no table indicated")
|
||||
if len(b.from) <= 0 {
|
||||
return ErrNoTableName
|
||||
}
|
||||
if len(b.updates) <= 0 {
|
||||
return errors.New("no column to be update")
|
||||
return ErrNoColumnToUpdate
|
||||
}
|
||||
|
||||
if _, err := fmt.Fprintf(w, "UPDATE %s SET ", b.tableName); err != nil {
|
||||
if _, err := fmt.Fprintf(w, "UPDATE %s SET ", b.from); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
12
vendor/github.com/go-xorm/builder/circle.yml
generated
vendored
12
vendor/github.com/go-xorm/builder/circle.yml
generated
vendored
@ -1,12 +0,0 @@
|
||||
dependencies:
|
||||
override:
|
||||
# './...' is a relative pattern which means all subdirectories
|
||||
- go get -t -d -v ./...
|
||||
- go build -v
|
||||
- go get -u github.com/golang/lint/golint
|
||||
|
||||
test:
|
||||
override:
|
||||
# './...' is a relative pattern which means all subdirectories
|
||||
- golint ./...
|
||||
- go test -v -race
|
21
vendor/github.com/go-xorm/builder/cond.go
generated
vendored
21
vendor/github.com/go-xorm/builder/cond.go
generated
vendored
@ -5,7 +5,6 @@
|
||||
package builder
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
)
|
||||
|
||||
@ -19,15 +18,15 @@ var _ Writer = NewWriter()
|
||||
|
||||
// BytesWriter implments Writer and save SQL in bytes.Buffer
|
||||
type BytesWriter struct {
|
||||
writer *bytes.Buffer
|
||||
buffer []byte
|
||||
writer *StringBuilder
|
||||
args []interface{}
|
||||
}
|
||||
|
||||
// NewWriter creates a new string writer
|
||||
func NewWriter() *BytesWriter {
|
||||
w := &BytesWriter{}
|
||||
w.writer = bytes.NewBuffer(w.buffer)
|
||||
w := &BytesWriter{
|
||||
writer: &StringBuilder{},
|
||||
}
|
||||
return w
|
||||
}
|
||||
|
||||
@ -73,15 +72,3 @@ func (condEmpty) Or(conds ...Cond) Cond {
|
||||
func (condEmpty) IsValid() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func condToSQL(cond Cond) (string, []interface{}, error) {
|
||||
if cond == nil || !cond.IsValid() {
|
||||
return "", nil, nil
|
||||
}
|
||||
|
||||
w := NewWriter()
|
||||
if err := cond.WriteTo(w); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
return w.writer.String(), w.args, nil
|
||||
}
|
||||
|
6
vendor/github.com/go-xorm/builder/cond_and.go
generated
vendored
6
vendor/github.com/go-xorm/builder/cond_and.go
generated
vendored
@ -25,7 +25,9 @@ func And(conds ...Cond) Cond {
|
||||
func (and condAnd) WriteTo(w Writer) error {
|
||||
for i, cond := range and {
|
||||
_, isOr := cond.(condOr)
|
||||
if isOr {
|
||||
_, isExpr := cond.(expr)
|
||||
wrap := isOr || isExpr
|
||||
if wrap {
|
||||
fmt.Fprint(w, "(")
|
||||
}
|
||||
|
||||
@ -34,7 +36,7 @@ func (and condAnd) WriteTo(w Writer) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if isOr {
|
||||
if wrap {
|
||||
fmt.Fprint(w, ")")
|
||||
}
|
||||
|
||||
|
29
vendor/github.com/go-xorm/builder/cond_between.go
generated
vendored
29
vendor/github.com/go-xorm/builder/cond_between.go
generated
vendored
@ -17,10 +17,35 @@ var _ Cond = Between{}
|
||||
|
||||
// WriteTo write data to Writer
|
||||
func (between Between) WriteTo(w Writer) error {
|
||||
if _, err := fmt.Fprintf(w, "%s BETWEEN ? AND ?", between.Col); err != nil {
|
||||
if _, err := fmt.Fprintf(w, "%s BETWEEN ", between.Col); err != nil {
|
||||
return err
|
||||
}
|
||||
w.Append(between.LessVal, between.MoreVal)
|
||||
if lv, ok := between.LessVal.(expr); ok {
|
||||
if err := lv.WriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if _, err := fmt.Fprint(w, "?"); err != nil {
|
||||
return err
|
||||
}
|
||||
w.Append(between.LessVal)
|
||||
}
|
||||
|
||||
if _, err := fmt.Fprint(w, " AND "); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if mv, ok := between.MoreVal.(expr); ok {
|
||||
if err := mv.WriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if _, err := fmt.Fprint(w, "?"); err != nil {
|
||||
return err
|
||||
}
|
||||
w.Append(between.MoreVal)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
8
vendor/github.com/go-xorm/builder/cond_compare.go
generated
vendored
8
vendor/github.com/go-xorm/builder/cond_compare.go
generated
vendored
@ -10,7 +10,13 @@ import "fmt"
|
||||
func WriteMap(w Writer, data map[string]interface{}, op string) error {
|
||||
var args = make([]interface{}, 0, len(data))
|
||||
var i = 0
|
||||
for k, v := range data {
|
||||
keys := make([]string, 0, len(data))
|
||||
for k := range data {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
|
||||
for _, k := range keys {
|
||||
v := data[k]
|
||||
switch v.(type) {
|
||||
case expr:
|
||||
if _, err := fmt.Fprintf(w, "%s%s(", k, op); err != nil {
|
||||
|
20
vendor/github.com/go-xorm/builder/cond_eq.go
generated
vendored
20
vendor/github.com/go-xorm/builder/cond_eq.go
generated
vendored
@ -4,7 +4,10 @@
|
||||
|
||||
package builder
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// Incr implements a type used by Eq
|
||||
type Incr int
|
||||
@ -19,7 +22,8 @@ var _ Cond = Eq{}
|
||||
|
||||
func (eq Eq) opWriteTo(op string, w Writer) error {
|
||||
var i = 0
|
||||
for k, v := range eq {
|
||||
for _, k := range eq.sortedKeys() {
|
||||
v := eq[k]
|
||||
switch v.(type) {
|
||||
case []int, []int64, []string, []int32, []int16, []int8, []uint, []uint64, []uint32, []uint16, []interface{}:
|
||||
if err := In(k, v).WriteTo(w); err != nil {
|
||||
@ -94,3 +98,15 @@ func (eq Eq) Or(conds ...Cond) Cond {
|
||||
func (eq Eq) IsValid() bool {
|
||||
return len(eq) > 0
|
||||
}
|
||||
|
||||
// sortedKeys returns all keys of this Eq sorted with sort.Strings.
|
||||
// It is used internally for consistent ordering when generating
|
||||
// SQL, see https://github.com/go-xorm/builder/issues/10
|
||||
func (eq Eq) sortedKeys() []string {
|
||||
keys := make([]string, 0, len(eq))
|
||||
for key := range eq {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
return keys
|
||||
}
|
||||
|
2
vendor/github.com/go-xorm/builder/cond_like.go
generated
vendored
2
vendor/github.com/go-xorm/builder/cond_like.go
generated
vendored
@ -16,7 +16,7 @@ func (like Like) WriteTo(w Writer) error {
|
||||
if _, err := fmt.Fprintf(w, "%s LIKE ?", like[0]); err != nil {
|
||||
return err
|
||||
}
|
||||
// FIXME: if use other regular express, this will be failed. but for compitable, keep this
|
||||
// FIXME: if use other regular express, this will be failed. but for compatible, keep this
|
||||
if like[1][0] == '%' || like[1][len(like[1])-1] == '%' {
|
||||
w.Append(like[1])
|
||||
} else {
|
||||
|
20
vendor/github.com/go-xorm/builder/cond_neq.go
generated
vendored
20
vendor/github.com/go-xorm/builder/cond_neq.go
generated
vendored
@ -4,7 +4,10 @@
|
||||
|
||||
package builder
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// Neq defines not equal conditions
|
||||
type Neq map[string]interface{}
|
||||
@ -15,7 +18,8 @@ var _ Cond = Neq{}
|
||||
func (neq Neq) WriteTo(w Writer) error {
|
||||
var args = make([]interface{}, 0, len(neq))
|
||||
var i = 0
|
||||
for k, v := range neq {
|
||||
for _, k := range neq.sortedKeys() {
|
||||
v := neq[k]
|
||||
switch v.(type) {
|
||||
case []int, []int64, []string, []int32, []int16, []int8:
|
||||
if err := NotIn(k, v).WriteTo(w); err != nil {
|
||||
@ -76,3 +80,15 @@ func (neq Neq) Or(conds ...Cond) Cond {
|
||||
func (neq Neq) IsValid() bool {
|
||||
return len(neq) > 0
|
||||
}
|
||||
|
||||
// sortedKeys returns all keys of this Neq sorted with sort.Strings.
|
||||
// It is used internally for consistent ordering when generating
|
||||
// SQL, see https://github.com/go-xorm/builder/issues/10
|
||||
func (neq Neq) sortedKeys() []string {
|
||||
keys := make([]string, 0, len(neq))
|
||||
for key := range neq {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
return keys
|
||||
}
|
||||
|
24
vendor/github.com/go-xorm/builder/cond_not.go
generated
vendored
24
vendor/github.com/go-xorm/builder/cond_not.go
generated
vendored
@ -21,6 +21,18 @@ func (not Not) WriteTo(w Writer) error {
|
||||
if _, err := fmt.Fprint(w, "("); err != nil {
|
||||
return err
|
||||
}
|
||||
case Eq:
|
||||
if len(not[0].(Eq)) > 1 {
|
||||
if _, err := fmt.Fprint(w, "("); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case Neq:
|
||||
if len(not[0].(Neq)) > 1 {
|
||||
if _, err := fmt.Fprint(w, "("); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := not[0].WriteTo(w); err != nil {
|
||||
@ -32,6 +44,18 @@ func (not Not) WriteTo(w Writer) error {
|
||||
if _, err := fmt.Fprint(w, ")"); err != nil {
|
||||
return err
|
||||
}
|
||||
case Eq:
|
||||
if len(not[0].(Eq)) > 1 {
|
||||
if _, err := fmt.Fprint(w, ")"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case Neq:
|
||||
if len(not[0].(Neq)) > 1 {
|
||||
if _, err := fmt.Fprint(w, ")"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
4
vendor/github.com/go-xorm/builder/cond_or.go
generated
vendored
4
vendor/github.com/go-xorm/builder/cond_or.go
generated
vendored
@ -27,10 +27,12 @@ func (o condOr) WriteTo(w Writer) error {
|
||||
for i, cond := range o {
|
||||
var needQuote bool
|
||||
switch cond.(type) {
|
||||
case condAnd:
|
||||
case condAnd, expr:
|
||||
needQuote = true
|
||||
case Eq:
|
||||
needQuote = (len(cond.(Eq)) > 1)
|
||||
case Neq:
|
||||
needQuote = (len(cond.(Neq)) > 1)
|
||||
}
|
||||
|
||||
if needQuote {
|
||||
|
26
vendor/github.com/go-xorm/builder/error.go
generated
vendored
26
vendor/github.com/go-xorm/builder/error.go
generated
vendored
@ -8,9 +8,33 @@ import "errors"
|
||||
|
||||
var (
|
||||
// ErrNotSupportType not supported SQL type error
|
||||
ErrNotSupportType = errors.New("not supported SQL type")
|
||||
ErrNotSupportType = errors.New("Not supported SQL type")
|
||||
// ErrNoNotInConditions no NOT IN params error
|
||||
ErrNoNotInConditions = errors.New("No NOT IN conditions")
|
||||
// ErrNoInConditions no IN params error
|
||||
ErrNoInConditions = errors.New("No IN conditions")
|
||||
// ErrNeedMoreArguments need more arguments
|
||||
ErrNeedMoreArguments = errors.New("Need more sql arguments")
|
||||
// ErrNoTableName no table name
|
||||
ErrNoTableName = errors.New("No table indicated")
|
||||
// ErrNoColumnToInsert no column to update
|
||||
ErrNoColumnToUpdate = errors.New("No column(s) to update")
|
||||
// ErrNoColumnToInsert no column to update
|
||||
ErrNoColumnToInsert = errors.New("No column(s) to insert")
|
||||
// ErrNotSupportDialectType not supported dialect type error
|
||||
ErrNotSupportDialectType = errors.New("Not supported dialect type")
|
||||
// ErrNotUnexpectedUnionConditions using union in a wrong way
|
||||
ErrNotUnexpectedUnionConditions = errors.New("Unexpected conditional fields in UNION query")
|
||||
// ErrUnsupportedUnionMembers unexpected members in UNION query
|
||||
ErrUnsupportedUnionMembers = errors.New("Unexpected members in UNION query")
|
||||
// ErrUnexpectedSubQuery Unexpected sub-query in SELECT query
|
||||
ErrUnexpectedSubQuery = errors.New("Unexpected sub-query in SELECT query")
|
||||
// ErrDialectNotSetUp dialect is not setup yet
|
||||
ErrDialectNotSetUp = errors.New("Dialect is not setup yet, try to use `Dialect(dbType)` at first")
|
||||
// ErrInvalidLimitation offset or limit is not correct
|
||||
ErrInvalidLimitation = errors.New("Offset or limit is not correct")
|
||||
// ErrUnnamedDerivedTable Every derived table must have its own alias
|
||||
ErrUnnamedDerivedTable = errors.New("Every derived table must have its own alias")
|
||||
// ErrInconsistentDialect Inconsistent dialect in same builder
|
||||
ErrInconsistentDialect = errors.New("Inconsistent dialect in same builder")
|
||||
)
|
||||
|
1
vendor/github.com/go-xorm/builder/go.mod
generated
vendored
Normal file
1
vendor/github.com/go-xorm/builder/go.mod
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
module "github.com/go-xorm/builder"
|
156
vendor/github.com/go-xorm/builder/sql.go
generated
vendored
Normal file
156
vendor/github.com/go-xorm/builder/sql.go
generated
vendored
Normal file
@ -0,0 +1,156 @@
|
||||
// Copyright 2018 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
import (
|
||||
sql2 "database/sql"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
func condToSQL(cond Cond) (string, []interface{}, error) {
|
||||
if cond == nil || !cond.IsValid() {
|
||||
return "", nil, nil
|
||||
}
|
||||
|
||||
w := NewWriter()
|
||||
if err := cond.WriteTo(w); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
return w.writer.String(), w.args, nil
|
||||
}
|
||||
|
||||
func condToBoundSQL(cond Cond) (string, error) {
|
||||
if cond == nil || !cond.IsValid() {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
w := NewWriter()
|
||||
if err := cond.WriteTo(w); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return ConvertToBoundSQL(w.writer.String(), w.args)
|
||||
}
|
||||
|
||||
// ToSQL convert a builder or conditions to SQL and args
|
||||
func ToSQL(cond interface{}) (string, []interface{}, error) {
|
||||
switch cond.(type) {
|
||||
case Cond:
|
||||
return condToSQL(cond.(Cond))
|
||||
case *Builder:
|
||||
return cond.(*Builder).ToSQL()
|
||||
}
|
||||
return "", nil, ErrNotSupportType
|
||||
}
|
||||
|
||||
// ToBoundSQL convert a builder or conditions to parameters bound SQL
|
||||
func ToBoundSQL(cond interface{}) (string, error) {
|
||||
switch cond.(type) {
|
||||
case Cond:
|
||||
return condToBoundSQL(cond.(Cond))
|
||||
case *Builder:
|
||||
return cond.(*Builder).ToBoundSQL()
|
||||
}
|
||||
return "", ErrNotSupportType
|
||||
}
|
||||
|
||||
func noSQLQuoteNeeded(a interface{}) bool {
|
||||
switch a.(type) {
|
||||
case int, int8, int16, int32, int64:
|
||||
return true
|
||||
case uint, uint8, uint16, uint32, uint64:
|
||||
return true
|
||||
case float32, float64:
|
||||
return true
|
||||
case bool:
|
||||
return true
|
||||
case string:
|
||||
return false
|
||||
case time.Time, *time.Time:
|
||||
return false
|
||||
}
|
||||
|
||||
t := reflect.TypeOf(a)
|
||||
switch t.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return true
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return true
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return true
|
||||
case reflect.Bool:
|
||||
return true
|
||||
case reflect.String:
|
||||
return false
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// ConvertToBoundSQL will convert SQL and args to a bound SQL
|
||||
func ConvertToBoundSQL(sql string, args []interface{}) (string, error) {
|
||||
buf := StringBuilder{}
|
||||
var i, j, start int
|
||||
for ; i < len(sql); i++ {
|
||||
if sql[i] == '?' {
|
||||
_, err := buf.WriteString(sql[start:i])
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
start = i + 1
|
||||
|
||||
if len(args) == j {
|
||||
return "", ErrNeedMoreArguments
|
||||
}
|
||||
|
||||
arg := args[j]
|
||||
if namedArg, ok := arg.(sql2.NamedArg); ok {
|
||||
arg = namedArg.Value
|
||||
}
|
||||
|
||||
if noSQLQuoteNeeded(arg) {
|
||||
_, err = fmt.Fprint(&buf, arg)
|
||||
} else {
|
||||
_, err = fmt.Fprintf(&buf, "'%v'", arg)
|
||||
}
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
j = j + 1
|
||||
}
|
||||
}
|
||||
_, err := buf.WriteString(sql[start:])
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
// ConvertPlaceholder replaces ? to $1, $2 ... or :1, :2 ... according prefix
|
||||
func ConvertPlaceholder(sql, prefix string) (string, error) {
|
||||
buf := StringBuilder{}
|
||||
var i, j, start int
|
||||
for ; i < len(sql); i++ {
|
||||
if sql[i] == '?' {
|
||||
if _, err := buf.WriteString(sql[start:i]); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
start = i + 1
|
||||
j = j + 1
|
||||
|
||||
if _, err := buf.WriteString(fmt.Sprintf("%v%d", prefix, j)); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := buf.WriteString(sql[start:]); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return buf.String(), nil
|
||||
}
|
119
vendor/github.com/go-xorm/builder/string_builder.go
generated
vendored
Normal file
119
vendor/github.com/go-xorm/builder/string_builder.go
generated
vendored
Normal file
@ -0,0 +1,119 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
import (
|
||||
"unicode/utf8"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// A StringBuilder is used to efficiently build a string using Write methods.
|
||||
// It minimizes memory copying. The zero value is ready to use.
|
||||
// Do not copy a non-zero Builder.
|
||||
type StringBuilder struct {
|
||||
addr *StringBuilder // of receiver, to detect copies by value
|
||||
buf []byte
|
||||
}
|
||||
|
||||
// noescape hides a pointer from escape analysis. noescape is
|
||||
// the identity function but escape analysis doesn't think the
|
||||
// output depends on the input. noescape is inlined and currently
|
||||
// compiles down to zero instructions.
|
||||
// USE CAREFULLY!
|
||||
// This was copied from the runtime; see issues 23382 and 7921.
|
||||
//go:nosplit
|
||||
func noescape(p unsafe.Pointer) unsafe.Pointer {
|
||||
x := uintptr(p)
|
||||
return unsafe.Pointer(x ^ 0)
|
||||
}
|
||||
|
||||
func (b *StringBuilder) copyCheck() {
|
||||
if b.addr == nil {
|
||||
// This hack works around a failing of Go's escape analysis
|
||||
// that was causing b to escape and be heap allocated.
|
||||
// See issue 23382.
|
||||
// TODO: once issue 7921 is fixed, this should be reverted to
|
||||
// just "b.addr = b".
|
||||
b.addr = (*StringBuilder)(noescape(unsafe.Pointer(b)))
|
||||
} else if b.addr != b {
|
||||
panic("strings: illegal use of non-zero Builder copied by value")
|
||||
}
|
||||
}
|
||||
|
||||
// String returns the accumulated string.
|
||||
func (b *StringBuilder) String() string {
|
||||
return *(*string)(unsafe.Pointer(&b.buf))
|
||||
}
|
||||
|
||||
// Len returns the number of accumulated bytes; b.Len() == len(b.String()).
|
||||
func (b *StringBuilder) Len() int { return len(b.buf) }
|
||||
|
||||
// Reset resets the Builder to be empty.
|
||||
func (b *StringBuilder) Reset() {
|
||||
b.addr = nil
|
||||
b.buf = nil
|
||||
}
|
||||
|
||||
// grow copies the buffer to a new, larger buffer so that there are at least n
|
||||
// bytes of capacity beyond len(b.buf).
|
||||
func (b *StringBuilder) grow(n int) {
|
||||
buf := make([]byte, len(b.buf), 2*cap(b.buf)+n)
|
||||
copy(buf, b.buf)
|
||||
b.buf = buf
|
||||
}
|
||||
|
||||
// Grow grows b's capacity, if necessary, to guarantee space for
|
||||
// another n bytes. After Grow(n), at least n bytes can be written to b
|
||||
// without another allocation. If n is negative, Grow panics.
|
||||
func (b *StringBuilder) Grow(n int) {
|
||||
b.copyCheck()
|
||||
if n < 0 {
|
||||
panic("strings.Builder.Grow: negative count")
|
||||
}
|
||||
if cap(b.buf)-len(b.buf) < n {
|
||||
b.grow(n)
|
||||
}
|
||||
}
|
||||
|
||||
// Write appends the contents of p to b's buffer.
|
||||
// Write always returns len(p), nil.
|
||||
func (b *StringBuilder) Write(p []byte) (int, error) {
|
||||
b.copyCheck()
|
||||
b.buf = append(b.buf, p...)
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
// WriteByte appends the byte c to b's buffer.
|
||||
// The returned error is always nil.
|
||||
func (b *StringBuilder) WriteByte(c byte) error {
|
||||
b.copyCheck()
|
||||
b.buf = append(b.buf, c)
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteRune appends the UTF-8 encoding of Unicode code point r to b's buffer.
|
||||
// It returns the length of r and a nil error.
|
||||
func (b *StringBuilder) WriteRune(r rune) (int, error) {
|
||||
b.copyCheck()
|
||||
if r < utf8.RuneSelf {
|
||||
b.buf = append(b.buf, byte(r))
|
||||
return 1, nil
|
||||
}
|
||||
l := len(b.buf)
|
||||
if cap(b.buf)-l < utf8.UTFMax {
|
||||
b.grow(utf8.UTFMax)
|
||||
}
|
||||
n := utf8.EncodeRune(b.buf[l:l+utf8.UTFMax], r)
|
||||
b.buf = b.buf[:l+n]
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// WriteString appends the contents of s to b's buffer.
|
||||
// It returns the length of s and a nil error.
|
||||
func (b *StringBuilder) WriteString(s string) (int, error) {
|
||||
b.copyCheck()
|
||||
b.buf = append(b.buf, s...)
|
||||
return len(s), nil
|
||||
}
|
4
vendor/github.com/go-xorm/core/column.go
generated
vendored
4
vendor/github.com/go-xorm/core/column.go
generated
vendored
@ -147,12 +147,12 @@ func (col *Column) ValueOfV(dataStruct *reflect.Value) (*reflect.Value, error) {
|
||||
}
|
||||
fieldValue = fieldValue.Elem().FieldByName(fieldPath[i+1])
|
||||
} else {
|
||||
return nil, fmt.Errorf("field %v is not valid", col.FieldName)
|
||||
return nil, fmt.Errorf("field %v is not valid", col.FieldName)
|
||||
}
|
||||
}
|
||||
|
||||
if !fieldValue.IsValid() {
|
||||
return nil, fmt.Errorf("field %v is not valid", col.FieldName)
|
||||
return nil, fmt.Errorf("field %v is not valid", col.FieldName)
|
||||
}
|
||||
|
||||
return &fieldValue, nil
|
||||
|
2
vendor/github.com/go-xorm/core/table.go
generated
vendored
2
vendor/github.com/go-xorm/core/table.go
generated
vendored
@ -49,7 +49,6 @@ func NewTable(name string, t reflect.Type) *Table {
|
||||
}
|
||||
|
||||
func (table *Table) columnsByName(name string) []*Column {
|
||||
|
||||
n := len(name)
|
||||
|
||||
for k := range table.columnsMap {
|
||||
@ -75,7 +74,6 @@ func (table *Table) GetColumn(name string) *Column {
|
||||
}
|
||||
|
||||
func (table *Table) GetColumnIdx(name string, idx int) *Column {
|
||||
|
||||
cols := table.columnsByName(name)
|
||||
|
||||
if cols != nil && idx < len(cols) {
|
||||
|
4
vendor/github.com/go-xorm/core/type.go
generated
vendored
4
vendor/github.com/go-xorm/core/type.go
generated
vendored
@ -74,6 +74,7 @@ var (
|
||||
NVarchar = "NVARCHAR"
|
||||
TinyText = "TINYTEXT"
|
||||
Text = "TEXT"
|
||||
NText = "NTEXT"
|
||||
Clob = "CLOB"
|
||||
MediumText = "MEDIUMTEXT"
|
||||
LongText = "LONGTEXT"
|
||||
@ -130,6 +131,7 @@ var (
|
||||
NVarchar: TEXT_TYPE,
|
||||
TinyText: TEXT_TYPE,
|
||||
Text: TEXT_TYPE,
|
||||
NText: TEXT_TYPE,
|
||||
MediumText: TEXT_TYPE,
|
||||
LongText: TEXT_TYPE,
|
||||
Uuid: TEXT_TYPE,
|
||||
@ -293,7 +295,7 @@ func SQLType2Type(st SQLType) reflect.Type {
|
||||
return reflect.TypeOf(float32(1))
|
||||
case Double:
|
||||
return reflect.TypeOf(float64(1))
|
||||
case Char, Varchar, NVarchar, TinyText, Text, MediumText, LongText, Enum, Set, Uuid, Clob, SysName:
|
||||
case Char, Varchar, NVarchar, TinyText, Text, NText, MediumText, LongText, Enum, Set, Uuid, Clob, SysName:
|
||||
return reflect.TypeOf("")
|
||||
case TinyBlob, Blob, LongBlob, Bytea, Binary, MediumBlob, VarBinary, UniqueIdentifier:
|
||||
return reflect.TypeOf([]byte{})
|
||||
|
125
vendor/github.com/go-xorm/xorm/.drone.yml
generated
vendored
Normal file
125
vendor/github.com/go-xorm/xorm/.drone.yml
generated
vendored
Normal file
@ -0,0 +1,125 @@
|
||||
workspace:
|
||||
base: /go
|
||||
path: src/github.com/go-xorm/xorm
|
||||
|
||||
clone:
|
||||
git:
|
||||
image: plugins/git:next
|
||||
depth: 50
|
||||
tags: true
|
||||
|
||||
services:
|
||||
mysql:
|
||||
image: mysql:5.7
|
||||
environment:
|
||||
- MYSQL_DATABASE=xorm_test
|
||||
- MYSQL_ALLOW_EMPTY_PASSWORD=yes
|
||||
when:
|
||||
event: [ push, tag, pull_request ]
|
||||
|
||||
pgsql:
|
||||
image: postgres:9.5
|
||||
environment:
|
||||
- POSTGRES_USER=postgres
|
||||
- POSTGRES_DB=xorm_test
|
||||
when:
|
||||
event: [ push, tag, pull_request ]
|
||||
|
||||
#mssql:
|
||||
# image: microsoft/mssql-server-linux:2017-CU11
|
||||
# environment:
|
||||
# - ACCEPT_EULA=Y
|
||||
# - SA_PASSWORD=yourStrong(!)Password
|
||||
# - MSSQL_PID=Developer
|
||||
# commands:
|
||||
# - echo 'CREATE DATABASE xorm_test' > create.sql
|
||||
# - /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P yourStrong(!)Password -i "create.sql"
|
||||
|
||||
matrix:
|
||||
GO_VERSION:
|
||||
- 1.8
|
||||
- 1.9
|
||||
- 1.10
|
||||
- 1.11
|
||||
|
||||
pipeline:
|
||||
init_postgres:
|
||||
image: postgres:9.5
|
||||
commands:
|
||||
# wait for postgres service to become available
|
||||
- |
|
||||
until psql -U postgres -d xorm_test -h pgsql \
|
||||
-c "SELECT 1;" >/dev/null 2>&1; do sleep 1; done
|
||||
# query the database
|
||||
- |
|
||||
psql -U postgres -d xorm_test -h pgsql \
|
||||
-c "create schema xorm;"
|
||||
|
||||
build:
|
||||
image: golang:${GO_VERSION}
|
||||
commands:
|
||||
- go get -t -d -v ./...
|
||||
- go get -u github.com/go-xorm/core
|
||||
- go get -u github.com/go-xorm/builder
|
||||
- go build -v
|
||||
when:
|
||||
event: [ push, pull_request ]
|
||||
|
||||
test-sqlite:
|
||||
image: golang:${GO_VERSION}
|
||||
commands:
|
||||
- go get -u github.com/wadey/gocovmerge
|
||||
- go test -v -race -db="sqlite3" -conn_str="./test.db" -coverprofile=coverage1-1.txt -covermode=atomic
|
||||
- go test -v -race -db="sqlite3" -conn_str="./test.db" -cache=true -coverprofile=coverage1-2.txt -covermode=atomic
|
||||
when:
|
||||
event: [ push, pull_request ]
|
||||
|
||||
test-mysql:
|
||||
image: golang:${GO_VERSION}
|
||||
commands:
|
||||
- go test -v -race -db="mysql" -conn_str="root:@tcp(mysql)/xorm_test" -coverprofile=coverage2-1.txt -covermode=atomic
|
||||
- go test -v -race -db="mysql" -conn_str="root:@tcp(mysql)/xorm_test" -cache=true -coverprofile=coverage2-2.txt -covermode=atomic
|
||||
when:
|
||||
event: [ push, pull_request ]
|
||||
|
||||
test-mysql-utf8mb4:
|
||||
image: golang:${GO_VERSION}
|
||||
commands:
|
||||
- go test -v -race -db="mysql" -conn_str="root:@tcp(mysql)/xorm_test?charset=utf8mb4" -coverprofile=coverage2.1-1.txt -covermode=atomic
|
||||
- go test -v -race -db="mysql" -conn_str="root:@tcp(mysql)/xorm_test?charset=utf8mb4" -cache=true -coverprofile=coverage2.1-2.txt -covermode=atomic
|
||||
when:
|
||||
event: [ push, pull_request ]
|
||||
|
||||
test-mymysql:
|
||||
image: golang:${GO_VERSION}
|
||||
commands:
|
||||
- go test -v -race -db="mymysql" -conn_str="tcp:mysql:3306*xorm_test/root/" -coverprofile=coverage3-1.txt -covermode=atomic
|
||||
- go test -v -race -db="mymysql" -conn_str="tcp:mysql:3306*xorm_test/root/" -cache=true -coverprofile=coverage3-2.txt -covermode=atomic
|
||||
when:
|
||||
event: [ push, pull_request ]
|
||||
|
||||
test-postgres:
|
||||
image: golang:${GO_VERSION}
|
||||
commands:
|
||||
- go test -v -race -db="postgres" -conn_str="postgres://postgres:@pgsql/xorm_test?sslmode=disable" -coverprofile=coverage4-1.txt -covermode=atomic
|
||||
- go test -v -race -db="postgres" -conn_str="postgres://postgres:@pgsql/xorm_test?sslmode=disable" -cache=true -coverprofile=coverage4-2.txt -covermode=atomic
|
||||
when:
|
||||
event: [ push, pull_request ]
|
||||
|
||||
test-postgres-schema:
|
||||
image: golang:${GO_VERSION}
|
||||
commands:
|
||||
- go test -v -race -db="postgres" -conn_str="postgres://postgres:@pgsql/xorm_test?sslmode=disable" -schema=xorm -coverprofile=coverage5-1.txt -covermode=atomic
|
||||
- go test -v -race -db="postgres" -conn_str="postgres://postgres:@pgsql/xorm_test?sslmode=disable" -schema=xorm -cache=true -coverprofile=coverage5-2.txt -covermode=atomic
|
||||
- gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage2.1-1.txt coverage2.1-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt > coverage.txt
|
||||
when:
|
||||
event: [ push, pull_request ]
|
||||
|
||||
#coverage:
|
||||
# image: robertstettner/drone-codecov
|
||||
# secrets: [ codecov_token ]
|
||||
# files:
|
||||
# - coverage.txt
|
||||
# when:
|
||||
# event: [ push, pull_request ]
|
||||
# branch: [ master ]
|
3
vendor/github.com/go-xorm/xorm/.gitignore
generated
vendored
3
vendor/github.com/go-xorm/xorm/.gitignore
generated
vendored
@ -28,3 +28,6 @@ temp_test.go
|
||||
.vscode
|
||||
xorm.test
|
||||
*.sqlite3
|
||||
test.db.sql
|
||||
|
||||
.idea/
|
||||
|
9
vendor/github.com/go-xorm/xorm/CONTRIBUTING.md
generated
vendored
9
vendor/github.com/go-xorm/xorm/CONTRIBUTING.md
generated
vendored
@ -32,13 +32,10 @@ proposed functionality.
|
||||
We appreciate any bug reports, but especially ones with self-contained
|
||||
(doesn't depend on code outside of xorm), minimal (can't be simplified
|
||||
further) test cases. It's especially helpful if you can submit a pull
|
||||
request with just the failing test case (you'll probably want to
|
||||
pattern it after the tests in
|
||||
[base.go](https://github.com/go-xorm/tests/blob/master/base.go) AND
|
||||
[benchmark.go](https://github.com/go-xorm/tests/blob/master/benchmark.go).
|
||||
request with just the failing test case(you can find some example test file like [session_get_test.go](https://github.com/go-xorm/xorm/blob/master/session_get_test.go)).
|
||||
|
||||
If you implements a new database interface, you maybe need to add a <databasename>_test.go file.
|
||||
For example, [mysql_test.go](https://github.com/go-xorm/tests/blob/master/mysql/mysql_test.go)
|
||||
If you implements a new database interface, you maybe need to add a test_<databasename>.sh file.
|
||||
For example, [mysql_test.go](https://github.com/go-xorm/xorm/blob/master/test_mysql.sh)
|
||||
|
||||
### New functionality
|
||||
|
||||
|
301
vendor/github.com/go-xorm/xorm/README.md
generated
vendored
301
vendor/github.com/go-xorm/xorm/README.md
generated
vendored
@ -1,3 +1,5 @@
|
||||
# xorm
|
||||
|
||||
[中文](https://github.com/go-xorm/xorm/blob/master/README_CN.md)
|
||||
|
||||
Xorm is a simple and powerful ORM for Go.
|
||||
@ -6,7 +8,7 @@ Xorm is a simple and powerful ORM for Go.
|
||||
[](https://goreportcard.com/report/github.com/go-xorm/xorm)
|
||||
[](https://discord.gg/HuR2CF3)
|
||||
|
||||
# Features
|
||||
## Features
|
||||
|
||||
* Struct <-> Table Mapping Support
|
||||
|
||||
@ -28,7 +30,13 @@ Xorm is a simple and powerful ORM for Go.
|
||||
|
||||
* SQL Builder support via [github.com/go-xorm/builder](https://github.com/go-xorm/builder)
|
||||
|
||||
# Drivers Support
|
||||
* Automatical Read/Write seperatelly
|
||||
|
||||
* Postgres schema support
|
||||
|
||||
* Context Cache support
|
||||
|
||||
## Drivers Support
|
||||
|
||||
Drivers for Go's sql package which currently support database/sql includes:
|
||||
|
||||
@ -46,43 +54,17 @@ Drivers for Go's sql package which currently support database/sql includes:
|
||||
|
||||
* Oracle: [github.com/mattn/go-oci8](https://github.com/mattn/go-oci8) (experiment)
|
||||
|
||||
# Changelog
|
||||
|
||||
* **v0.6.3**
|
||||
* merge tests to main project
|
||||
* add `Exist` function
|
||||
* add `SumInt` function
|
||||
* Mysql now support read and create column comment.
|
||||
* fix time related bugs.
|
||||
* fix some other bugs.
|
||||
|
||||
* **v0.6.2**
|
||||
* refactor tag parse methods
|
||||
* add Scan features to Get
|
||||
* add QueryString method
|
||||
|
||||
* **v0.6.0**
|
||||
* remove support for ql
|
||||
* add query condition builder support via [github.com/go-xorm/builder](https://github.com/go-xorm/builder), so `Where`, `And`, `Or`
|
||||
methods can use `builder.Cond` as parameter
|
||||
* add Sum, SumInt, SumInt64 and NotIn methods
|
||||
* some bugs fixed
|
||||
|
||||
[More changes ...](https://github.com/go-xorm/manual-en-US/tree/master/chapter-16)
|
||||
|
||||
# Installation
|
||||
## Installation
|
||||
|
||||
go get github.com/go-xorm/xorm
|
||||
|
||||
# Documents
|
||||
## Documents
|
||||
|
||||
* [Manual](http://xorm.io/docs)
|
||||
|
||||
* [GoDoc](http://godoc.org/github.com/go-xorm/xorm)
|
||||
|
||||
* [GoWalker](http://gowalker.org/github.com/go-xorm/xorm)
|
||||
|
||||
# Quick Start
|
||||
## Quick Start
|
||||
|
||||
* Create Engine
|
||||
|
||||
@ -106,15 +88,36 @@ type User struct {
|
||||
err := engine.Sync2(new(User))
|
||||
```
|
||||
|
||||
* `Query` runs a SQL string, the returned results is `[]map[string][]byte`, `QueryString` returns `[]map[string]string`.
|
||||
* Create Engine Group
|
||||
|
||||
```Go
|
||||
dataSourceNameSlice := []string{masterDataSourceName, slave1DataSourceName, slave2DataSourceName}
|
||||
engineGroup, err := xorm.NewEngineGroup(driverName, dataSourceNameSlice)
|
||||
```
|
||||
|
||||
```Go
|
||||
masterEngine, err := xorm.NewEngine(driverName, masterDataSourceName)
|
||||
slave1Engine, err := xorm.NewEngine(driverName, slave1DataSourceName)
|
||||
slave2Engine, err := xorm.NewEngine(driverName, slave2DataSourceName)
|
||||
engineGroup, err := xorm.NewEngineGroup(masterEngine, []*Engine{slave1Engine, slave2Engine})
|
||||
```
|
||||
|
||||
Then all place where `engine` you can just use `engineGroup`.
|
||||
|
||||
* `Query` runs a SQL string, the returned results is `[]map[string][]byte`, `QueryString` returns `[]map[string]string`, `QueryInterface` returns `[]map[string]interface{}`.
|
||||
|
||||
```Go
|
||||
results, err := engine.Query("select * from user")
|
||||
results, err := engine.Where("a = 1").Query()
|
||||
|
||||
results, err := engine.QueryString("select * from user")
|
||||
results, err := engine.Where("a = 1").QueryString()
|
||||
|
||||
results, err := engine.QueryInterface("select * from user")
|
||||
results, err := engine.Where("a = 1").QueryInterface()
|
||||
```
|
||||
|
||||
* `Execute` runs a SQL string, it returns `affected` and `error`
|
||||
* `Exec` runs a SQL string, it returns `affected` and `error`
|
||||
|
||||
```Go
|
||||
affected, err := engine.Exec("update user set age = ? where name = ?", age, name)
|
||||
@ -125,62 +128,76 @@ affected, err := engine.Exec("update user set age = ? where name = ?", age, name
|
||||
```Go
|
||||
affected, err := engine.Insert(&user)
|
||||
// INSERT INTO struct () values ()
|
||||
|
||||
affected, err := engine.Insert(&user1, &user2)
|
||||
// INSERT INTO struct1 () values ()
|
||||
// INSERT INTO struct2 () values ()
|
||||
|
||||
affected, err := engine.Insert(&users)
|
||||
// INSERT INTO struct () values (),(),()
|
||||
|
||||
affected, err := engine.Insert(&user1, &users)
|
||||
// INSERT INTO struct1 () values ()
|
||||
// INSERT INTO struct2 () values (),(),()
|
||||
```
|
||||
|
||||
* Query one record from database
|
||||
* `Get` query one record from database
|
||||
|
||||
```Go
|
||||
has, err := engine.Get(&user)
|
||||
// SELECT * FROM user LIMIT 1
|
||||
|
||||
has, err := engine.Where("name = ?", name).Desc("id").Get(&user)
|
||||
// SELECT * FROM user WHERE name = ? ORDER BY id DESC LIMIT 1
|
||||
|
||||
var name string
|
||||
has, err := engine.Where("id = ?", id).Cols("name").Get(&name)
|
||||
// SELECT name FROM user WHERE id = ?
|
||||
|
||||
var id int64
|
||||
has, err := engine.Where("name = ?", name).Cols("id").Get(&id)
|
||||
has, err := engine.SQL("select id from user").Get(&id)
|
||||
// SELECT id FROM user WHERE name = ?
|
||||
|
||||
var valuesMap = make(map[string]string)
|
||||
has, err := engine.Where("id = ?", id).Get(&valuesMap)
|
||||
// SELECT * FROM user WHERE id = ?
|
||||
|
||||
var valuesSlice = make([]interface{}, len(cols))
|
||||
has, err := engine.Where("id = ?", id).Cols(cols...).Get(&valuesSlice)
|
||||
// SELECT col1, col2, col3 FROM user WHERE id = ?
|
||||
```
|
||||
|
||||
* Check if one record exist on table
|
||||
* `Exist` check if one record exist on table
|
||||
|
||||
```Go
|
||||
has, err := testEngine.Exist(new(RecordExist))
|
||||
// SELECT * FROM record_exist LIMIT 1
|
||||
|
||||
has, err = testEngine.Exist(&RecordExist{
|
||||
Name: "test1",
|
||||
})
|
||||
// SELECT * FROM record_exist WHERE name = ? LIMIT 1
|
||||
|
||||
has, err = testEngine.Where("name = ?", "test1").Exist(&RecordExist{})
|
||||
// SELECT * FROM record_exist WHERE name = ? LIMIT 1
|
||||
|
||||
has, err = testEngine.SQL("select * from record_exist where name = ?", "test1").Exist()
|
||||
// select * from record_exist where name = ?
|
||||
|
||||
has, err = testEngine.Table("record_exist").Exist()
|
||||
// SELECT * FROM record_exist LIMIT 1
|
||||
|
||||
has, err = testEngine.Table("record_exist").Where("name = ?", "test1").Exist()
|
||||
// SELECT * FROM record_exist WHERE name = ? LIMIT 1
|
||||
```
|
||||
|
||||
* Query multiple records from database, also you can use join and extends
|
||||
* `Find` query multiple records from database, also you can use join and extends
|
||||
|
||||
```Go
|
||||
var users []User
|
||||
err := engine.Where("name = ?", name).And("age > 10").Limit(10, 0).Find(&users)
|
||||
// SELECT * FROM user WHERE name = ? AND age > 10 limit 0 offset 10
|
||||
// SELECT * FROM user WHERE name = ? AND age > 10 limit 10 offset 0
|
||||
|
||||
type Detail struct {
|
||||
Id int64
|
||||
@ -193,14 +210,14 @@ type UserDetail struct {
|
||||
}
|
||||
|
||||
var users []UserDetail
|
||||
err := engine.Table("user").Select("user.*, detail.*")
|
||||
err := engine.Table("user").Select("user.*, detail.*").
|
||||
Join("INNER", "detail", "detail.user_id = user.id").
|
||||
Where("user.name = ?", name).Limit(10, 0).
|
||||
Find(&users)
|
||||
// SELECT user.*, detail.* FROM user INNER JOIN detail WHERE user.name = ? limit 0 offset 10
|
||||
// SELECT user.*, detail.* FROM user INNER JOIN detail WHERE user.name = ? limit 10 offset 0
|
||||
```
|
||||
|
||||
* Query multiple records and record by record handle, there are two methods Iterate and Rows
|
||||
* `Iterate` and `Rows` query multiple records and record by record handle, there are two methods Iterate and Rows
|
||||
|
||||
```Go
|
||||
err := engine.Iterate(&User{Name:name}, func(idx int, bean interface{}) error {
|
||||
@ -209,6 +226,13 @@ err := engine.Iterate(&User{Name:name}, func(idx int, bean interface{}) error {
|
||||
})
|
||||
// SELECT * FROM user
|
||||
|
||||
err := engine.BufferSize(100).Iterate(&User{Name:name}, func(idx int, bean interface{}) error {
|
||||
user := bean.(*User)
|
||||
return nil
|
||||
})
|
||||
// SELECT * FROM user Limit 0, 100
|
||||
// SELECT * FROM user Limit 101, 100
|
||||
|
||||
rows, err := engine.Rows(&User{Name:name})
|
||||
// SELECT * FROM user
|
||||
defer rows.Close()
|
||||
@ -218,10 +242,10 @@ for rows.Next() {
|
||||
}
|
||||
```
|
||||
|
||||
* Update one or more records, default will update non-empty and non-zero fields except when you use Cols, AllCols and so on.
|
||||
* `Update` update one or more records, default will update non-empty and non-zero fields except when you use Cols, AllCols and so on.
|
||||
|
||||
```Go
|
||||
affected, err := engine.Id(1).Update(&user)
|
||||
affected, err := engine.ID(1).Update(&user)
|
||||
// UPDATE user SET ... Where id = ?
|
||||
|
||||
affected, err := engine.Update(&user, &User{Name:name})
|
||||
@ -232,32 +256,50 @@ affected, err := engine.In("id", ids).Update(&user)
|
||||
// UPDATE user SET ... Where id IN (?, ?, ?)
|
||||
|
||||
// force update indicated columns by Cols
|
||||
affected, err := engine.Id(1).Cols("age").Update(&User{Name:name, Age: 12})
|
||||
affected, err := engine.ID(1).Cols("age").Update(&User{Name:name, Age: 12})
|
||||
// UPDATE user SET age = ?, updated=? Where id = ?
|
||||
|
||||
// force NOT update indicated columns by Omit
|
||||
affected, err := engine.Id(1).Omit("name").Update(&User{Name:name, Age: 12})
|
||||
affected, err := engine.ID(1).Omit("name").Update(&User{Name:name, Age: 12})
|
||||
// UPDATE user SET age = ?, updated=? Where id = ?
|
||||
|
||||
affected, err := engine.Id(1).AllCols().Update(&user)
|
||||
affected, err := engine.ID(1).AllCols().Update(&user)
|
||||
// UPDATE user SET name=?,age=?,salt=?,passwd=?,updated=? Where id = ?
|
||||
```
|
||||
|
||||
* Delete one or more records, Delete MUST have condition
|
||||
* `Delete` delete one or more records, Delete MUST have condition
|
||||
|
||||
```Go
|
||||
affected, err := engine.Where(...).Delete(&user)
|
||||
// DELETE FROM user Where ...
|
||||
affected, err := engine.Id(2).Delete(&user)
|
||||
|
||||
affected, err := engine.ID(2).Delete(&user)
|
||||
// DELETE FROM user Where id = ?
|
||||
```
|
||||
|
||||
* Count records
|
||||
* `Count` count records
|
||||
|
||||
```Go
|
||||
counts, err := engine.Count(&user)
|
||||
// SELECT count(*) AS total FROM user
|
||||
```
|
||||
|
||||
* `Sum` sum functions
|
||||
|
||||
```Go
|
||||
agesFloat64, err := engine.Sum(&user, "age")
|
||||
// SELECT sum(age) AS total FROM user
|
||||
|
||||
agesInt64, err := engine.SumInt(&user, "age")
|
||||
// SELECT sum(age) AS total FROM user
|
||||
|
||||
sumFloat64Slice, err := engine.Sums(&user, "age", "score")
|
||||
// SELECT sum(age), sum(score) FROM user
|
||||
|
||||
sumInt64Slice, err := engine.SumsInt(&user, "age", "score")
|
||||
// SELECT sum(age), sum(score) FROM user
|
||||
```
|
||||
|
||||
* Query conditions builder
|
||||
|
||||
```Go
|
||||
@ -265,7 +307,155 @@ err := engine.Where(builder.NotIn("a", 1, 2).And(builder.In("b", "c", "d", "e"))
|
||||
// SELECT id, name ... FROM user WHERE a NOT IN (?, ?) AND b IN (?, ?, ?)
|
||||
```
|
||||
|
||||
# Cases
|
||||
* Multiple operations in one go routine, no transation here but resue session memory
|
||||
|
||||
```Go
|
||||
session := engine.NewSession()
|
||||
defer session.Close()
|
||||
|
||||
user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
|
||||
if _, err := session.Insert(&user1); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
user2 := Userinfo{Username: "yyy"}
|
||||
if _, err := session.Where("id = ?", 2).Update(&user2); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
```
|
||||
|
||||
* Transation should on one go routine. There is transaction and resue session memory
|
||||
|
||||
```Go
|
||||
session := engine.NewSession()
|
||||
defer session.Close()
|
||||
|
||||
// add Begin() before any action
|
||||
if err := session.Begin(); err != nil {
|
||||
// if returned then will rollback automatically
|
||||
return err
|
||||
}
|
||||
|
||||
user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
|
||||
if _, err := session.Insert(&user1); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
user2 := Userinfo{Username: "yyy"}
|
||||
if _, err := session.Where("id = ?", 2).Update(&user2); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// add Commit() after all actions
|
||||
return session.Commit()
|
||||
```
|
||||
|
||||
* Or you can use `Transaction` to replace above codes.
|
||||
|
||||
```Go
|
||||
res, err := engine.Transaction(func(sess *xorm.Session) (interface{}, error) {
|
||||
user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
|
||||
if _, err := session.Insert(&user1); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
user2 := Userinfo{Username: "yyy"}
|
||||
if _, err := session.Where("id = ?", 2).Update(&user2); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, nil
|
||||
})
|
||||
```
|
||||
|
||||
* Context Cache, if enabled, current query result will be cached on session and be used by next same statement on the same session.
|
||||
|
||||
```Go
|
||||
sess := engine.NewSession()
|
||||
defer sess.Close()
|
||||
|
||||
var context = xorm.NewMemoryContextCache()
|
||||
|
||||
var c2 ContextGetStruct
|
||||
has, err := sess.ID(1).ContextCache(context).Get(&c2)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
assert.EqualValues(t, 1, c2.Id)
|
||||
assert.EqualValues(t, "1", c2.Name)
|
||||
sql, args := sess.LastSQL()
|
||||
assert.True(t, len(sql) > 0)
|
||||
assert.True(t, len(args) > 0)
|
||||
|
||||
var c3 ContextGetStruct
|
||||
has, err = sess.ID(1).ContextCache(context).Get(&c3)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
assert.EqualValues(t, 1, c3.Id)
|
||||
assert.EqualValues(t, "1", c3.Name)
|
||||
sql, args = sess.LastSQL()
|
||||
assert.True(t, len(sql) == 0)
|
||||
assert.True(t, len(args) == 0)
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
If you want to pull request, please see [CONTRIBUTING](https://github.com/go-xorm/xorm/blob/master/CONTRIBUTING.md). And we also provide [Xorm on Google Groups](https://groups.google.com/forum/#!forum/xorm) to discuss.
|
||||
|
||||
## Credits
|
||||
|
||||
### Contributors
|
||||
|
||||
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
|
||||
<a href="graphs/contributors"><img src="https://opencollective.com/xorm/contributors.svg?width=890&button=false" /></a>
|
||||
|
||||
### Backers
|
||||
|
||||
Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/xorm#backer)]
|
||||
|
||||
<a href="https://opencollective.com/xorm#backers" target="_blank"><img src="https://opencollective.com/xorm/backers.svg?width=890"></a>
|
||||
|
||||
### Sponsors
|
||||
|
||||
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/xorm#sponsor)]
|
||||
|
||||
## Changelog
|
||||
|
||||
* **v0.7.0**
|
||||
* Some bugs fixed
|
||||
|
||||
* **v0.6.6**
|
||||
* Some bugs fixed
|
||||
|
||||
* **v0.6.5**
|
||||
* Postgres schema support
|
||||
* vgo support
|
||||
* Add FindAndCount
|
||||
* Database special params support via NewEngineWithParams
|
||||
* Some bugs fixed
|
||||
|
||||
* **v0.6.4**
|
||||
* Automatical Read/Write seperatelly
|
||||
* Query/QueryString/QueryInterface and action with Where/And
|
||||
* Get support non-struct variables
|
||||
* BufferSize on Iterate
|
||||
* fix some other bugs.
|
||||
|
||||
[More changes ...](https://github.com/go-xorm/manual-en-US/tree/master/chapter-16)
|
||||
|
||||
## Cases
|
||||
|
||||
* [studygolang](http://studygolang.com/) - [github.com/studygolang/studygolang](https://github.com/studygolang/studygolang)
|
||||
|
||||
@ -301,15 +491,6 @@ err := engine.Where(builder.NotIn("a", 1, 2).And(builder.In("b", "c", "d", "e"))
|
||||
|
||||
* [go-blog](http://wangcheng.me) - [github.com/easykoo/go-blog](https://github.com/easykoo/go-blog)
|
||||
|
||||
# Discuss
|
||||
## LICENSE
|
||||
|
||||
Please visit [Xorm on Google Groups](https://groups.google.com/forum/#!forum/xorm)
|
||||
|
||||
# Contributing
|
||||
|
||||
If you want to pull request, please see [CONTRIBUTING](https://github.com/go-xorm/xorm/blob/master/CONTRIBUTING.md)
|
||||
|
||||
# LICENSE
|
||||
|
||||
BSD License
|
||||
[http://creativecommons.org/licenses/BSD/](http://creativecommons.org/licenses/BSD/)
|
||||
BSD License [http://creativecommons.org/licenses/BSD/](http://creativecommons.org/licenses/BSD/)
|
275
vendor/github.com/go-xorm/xorm/README_CN.md
generated
vendored
275
vendor/github.com/go-xorm/xorm/README_CN.md
generated
vendored
@ -22,6 +22,8 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作
|
||||
|
||||
* 支持级联加载Struct
|
||||
|
||||
* Schema支持(仅Postgres)
|
||||
|
||||
* 支持缓存
|
||||
|
||||
* 支持根据数据库自动生成xorm的结构体
|
||||
@ -30,6 +32,8 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作
|
||||
|
||||
* 内置SQL Builder支持
|
||||
|
||||
* 上下文缓存支持
|
||||
|
||||
## 驱动支持
|
||||
|
||||
目前支持的Go数据库驱动和对应的数据库如下:
|
||||
@ -50,35 +54,6 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作
|
||||
|
||||
* Oracle: [github.com/mattn/go-oci8](https://github.com/mattn/go-oci8) (试验性支持)
|
||||
|
||||
## 更新日志
|
||||
|
||||
* **v0.6.3**
|
||||
* 合并单元测试到主工程
|
||||
* 新增`Exist`方法
|
||||
* 新增`SumInt`方法
|
||||
* Mysql新增读取和创建字段注释支持
|
||||
* 新增`SetConnMaxLifetime`方法
|
||||
* 修正了时间相关的Bug
|
||||
* 修复了一些其它Bug
|
||||
|
||||
* **v0.6.2**
|
||||
* 重构Tag解析方式
|
||||
* Get方法新增类似Scan的特性
|
||||
* 新增 QueryString 方法
|
||||
|
||||
* **v0.6.0**
|
||||
* 去除对 ql 的支持
|
||||
* 新增条件查询分析器 [github.com/go-xorm/builder](https://github.com/go-xorm/builder), 从因此 `Where, And, Or` 函数
|
||||
将可以用 `builder.Cond` 作为条件组合
|
||||
* 新增 Sum, SumInt, SumInt64 和 NotIn 函数
|
||||
* Bug修正
|
||||
|
||||
* **v0.5.0**
|
||||
* logging接口进行不兼容改变
|
||||
* Bug修正
|
||||
|
||||
[更多更新日志...](https://github.com/go-xorm/manual-zh-CN/tree/master/chapter-16)
|
||||
|
||||
## 安装
|
||||
|
||||
go get github.com/go-xorm/xorm
|
||||
@ -115,12 +90,33 @@ type User struct {
|
||||
err := engine.Sync2(new(User))
|
||||
```
|
||||
|
||||
* `Query` 最原始的也支持SQL语句查询,返回的结果类型为 []map[string][]byte。`QueryString` 返回 []map[string]string
|
||||
* 创建Engine组
|
||||
|
||||
```Go
|
||||
dataSourceNameSlice := []string{masterDataSourceName, slave1DataSourceName, slave2DataSourceName}
|
||||
engineGroup, err := xorm.NewEngineGroup(driverName, dataSourceNameSlice)
|
||||
```
|
||||
|
||||
```Go
|
||||
masterEngine, err := xorm.NewEngine(driverName, masterDataSourceName)
|
||||
slave1Engine, err := xorm.NewEngine(driverName, slave1DataSourceName)
|
||||
slave2Engine, err := xorm.NewEngine(driverName, slave2DataSourceName)
|
||||
engineGroup, err := xorm.NewEngineGroup(masterEngine, []*Engine{slave1Engine, slave2Engine})
|
||||
```
|
||||
|
||||
所有使用 `engine` 都可以简单的用 `engineGroup` 来替换。
|
||||
|
||||
* `Query` 最原始的也支持SQL语句查询,返回的结果类型为 []map[string][]byte。`QueryString` 返回 []map[string]string, `QueryInterface` 返回 `[]map[string]interface{}`.
|
||||
|
||||
```Go
|
||||
results, err := engine.Query("select * from user")
|
||||
results, err := engine.Where("a = 1").Query()
|
||||
|
||||
results, err := engine.QueryString("select * from user")
|
||||
results, err := engine.Where("a = 1").QueryString()
|
||||
|
||||
results, err := engine.QueryInterface("select * from user")
|
||||
results, err := engine.Where("a = 1").QueryInterface()
|
||||
```
|
||||
|
||||
* `Exec` 执行一个SQL语句
|
||||
@ -129,67 +125,81 @@ results, err := engine.QueryString("select * from user")
|
||||
affected, err := engine.Exec("update user set age = ? where name = ?", age, name)
|
||||
```
|
||||
|
||||
* 插入一条或者多条记录
|
||||
* `Insert` 插入一条或者多条记录
|
||||
|
||||
```Go
|
||||
affected, err := engine.Insert(&user)
|
||||
// INSERT INTO struct () values ()
|
||||
|
||||
affected, err := engine.Insert(&user1, &user2)
|
||||
// INSERT INTO struct1 () values ()
|
||||
// INSERT INTO struct2 () values ()
|
||||
|
||||
affected, err := engine.Insert(&users)
|
||||
// INSERT INTO struct () values (),(),()
|
||||
|
||||
affected, err := engine.Insert(&user1, &users)
|
||||
// INSERT INTO struct1 () values ()
|
||||
// INSERT INTO struct2 () values (),(),()
|
||||
```
|
||||
|
||||
* 查询单条记录
|
||||
* `Get` 查询单条记录
|
||||
|
||||
```Go
|
||||
has, err := engine.Get(&user)
|
||||
// SELECT * FROM user LIMIT 1
|
||||
|
||||
has, err := engine.Where("name = ?", name).Desc("id").Get(&user)
|
||||
// SELECT * FROM user WHERE name = ? ORDER BY id DESC LIMIT 1
|
||||
|
||||
var name string
|
||||
has, err := engine.Where("id = ?", id).Cols("name").Get(&name)
|
||||
// SELECT name FROM user WHERE id = ?
|
||||
|
||||
var id int64
|
||||
has, err := engine.Where("name = ?", name).Cols("id").Get(&id)
|
||||
has, err := engine.SQL("select id from user").Get(&id)
|
||||
// SELECT id FROM user WHERE name = ?
|
||||
|
||||
var valuesMap = make(map[string]string)
|
||||
has, err := engine.Where("id = ?", id).Get(&valuesMap)
|
||||
// SELECT * FROM user WHERE id = ?
|
||||
|
||||
var valuesSlice = make([]interface{}, len(cols))
|
||||
has, err := engine.Where("id = ?", id).Cols(cols...).Get(&valuesSlice)
|
||||
// SELECT col1, col2, col3 FROM user WHERE id = ?
|
||||
```
|
||||
|
||||
* 检测记录是否存在
|
||||
* `Exist` 检测记录是否存在
|
||||
|
||||
```Go
|
||||
has, err := testEngine.Exist(new(RecordExist))
|
||||
// SELECT * FROM record_exist LIMIT 1
|
||||
|
||||
has, err = testEngine.Exist(&RecordExist{
|
||||
Name: "test1",
|
||||
})
|
||||
// SELECT * FROM record_exist WHERE name = ? LIMIT 1
|
||||
|
||||
has, err = testEngine.Where("name = ?", "test1").Exist(&RecordExist{})
|
||||
// SELECT * FROM record_exist WHERE name = ? LIMIT 1
|
||||
|
||||
has, err = testEngine.SQL("select * from record_exist where name = ?", "test1").Exist()
|
||||
// select * from record_exist where name = ?
|
||||
|
||||
has, err = testEngine.Table("record_exist").Exist()
|
||||
// SELECT * FROM record_exist LIMIT 1
|
||||
|
||||
has, err = testEngine.Table("record_exist").Where("name = ?", "test1").Exist()
|
||||
// SELECT * FROM record_exist WHERE name = ? LIMIT 1
|
||||
```
|
||||
|
||||
* 查询多条记录,当然可以使用Join和extends来组合使用
|
||||
* `Find` 查询多条记录,当然可以使用Join和extends来组合使用
|
||||
|
||||
```Go
|
||||
var users []User
|
||||
err := engine.Where("name = ?", name).And("age > 10").Limit(10, 0).Find(&users)
|
||||
// SELECT * FROM user WHERE name = ? AND age > 10 limit 0 offset 10
|
||||
// SELECT * FROM user WHERE name = ? AND age > 10 limit 10 offset 0
|
||||
|
||||
type Detail struct {
|
||||
Id int64
|
||||
@ -206,10 +216,10 @@ err := engine.Table("user").Select("user.*, detail.*")
|
||||
Join("INNER", "detail", "detail.user_id = user.id").
|
||||
Where("user.name = ?", name).Limit(10, 0).
|
||||
Find(&users)
|
||||
// SELECT user.*, detail.* FROM user INNER JOIN detail WHERE user.name = ? limit 0 offset 10
|
||||
// SELECT user.*, detail.* FROM user INNER JOIN detail WHERE user.name = ? limit 10 offset 0
|
||||
```
|
||||
|
||||
* 根据条件遍历数据库,可以有两种方式: Iterate and Rows
|
||||
* `Iterate` 和 `Rows` 根据条件遍历数据库,可以有两种方式: Iterate and Rows
|
||||
|
||||
```Go
|
||||
err := engine.Iterate(&User{Name:name}, func(idx int, bean interface{}) error {
|
||||
@ -218,6 +228,13 @@ err := engine.Iterate(&User{Name:name}, func(idx int, bean interface{}) error {
|
||||
})
|
||||
// SELECT * FROM user
|
||||
|
||||
err := engine.BufferSize(100).Iterate(&User{Name:name}, func(idx int, bean interface{}) error {
|
||||
user := bean.(*User)
|
||||
return nil
|
||||
})
|
||||
// SELECT * FROM user Limit 0, 100
|
||||
// SELECT * FROM user Limit 101, 100
|
||||
|
||||
rows, err := engine.Rows(&User{Name:name})
|
||||
// SELECT * FROM user
|
||||
defer rows.Close()
|
||||
@ -227,10 +244,10 @@ for rows.Next() {
|
||||
}
|
||||
```
|
||||
|
||||
* 更新数据,除非使用Cols,AllCols函数指明,默认只更新非空和非0的字段
|
||||
* `Update` 更新数据,除非使用Cols,AllCols函数指明,默认只更新非空和非0的字段
|
||||
|
||||
```Go
|
||||
affected, err := engine.Id(1).Update(&user)
|
||||
affected, err := engine.ID(1).Update(&user)
|
||||
// UPDATE user SET ... Where id = ?
|
||||
|
||||
affected, err := engine.Update(&user, &User{Name:name})
|
||||
@ -241,31 +258,50 @@ affected, err := engine.In(ids).Update(&user)
|
||||
// UPDATE user SET ... Where id IN (?, ?, ?)
|
||||
|
||||
// force update indicated columns by Cols
|
||||
affected, err := engine.Id(1).Cols("age").Update(&User{Name:name, Age: 12})
|
||||
affected, err := engine.ID(1).Cols("age").Update(&User{Name:name, Age: 12})
|
||||
// UPDATE user SET age = ?, updated=? Where id = ?
|
||||
|
||||
// force NOT update indicated columns by Omit
|
||||
affected, err := engine.Id(1).Omit("name").Update(&User{Name:name, Age: 12})
|
||||
affected, err := engine.ID(1).Omit("name").Update(&User{Name:name, Age: 12})
|
||||
// UPDATE user SET age = ?, updated=? Where id = ?
|
||||
|
||||
affected, err := engine.Id(1).AllCols().Update(&user)
|
||||
affected, err := engine.ID(1).AllCols().Update(&user)
|
||||
// UPDATE user SET name=?,age=?,salt=?,passwd=?,updated=? Where id = ?
|
||||
```
|
||||
|
||||
* 删除记录,需要注意,删除必须至少有一个条件,否则会报错。要清空数据库可以用EmptyTable
|
||||
* `Delete` 删除记录,需要注意,删除必须至少有一个条件,否则会报错。要清空数据库可以用EmptyTable
|
||||
|
||||
```Go
|
||||
affected, err := engine.Where(...).Delete(&user)
|
||||
// DELETE FROM user Where ...
|
||||
|
||||
affected, err := engine.ID(2).Delete(&user)
|
||||
// DELETE FROM user Where id = ?
|
||||
```
|
||||
|
||||
* 获取记录条数
|
||||
* `Count` 获取记录条数
|
||||
|
||||
```Go
|
||||
counts, err := engine.Count(&user)
|
||||
// SELECT count(*) AS total FROM user
|
||||
```
|
||||
|
||||
* `Sum` 求和函数
|
||||
|
||||
```Go
|
||||
agesFloat64, err := engine.Sum(&user, "age")
|
||||
// SELECT sum(age) AS total FROM user
|
||||
|
||||
agesInt64, err := engine.SumInt(&user, "age")
|
||||
// SELECT sum(age) AS total FROM user
|
||||
|
||||
sumFloat64Slice, err := engine.Sums(&user, "age", "score")
|
||||
// SELECT sum(age), sum(score) FROM user
|
||||
|
||||
sumInt64Slice, err := engine.SumsInt(&user, "age", "score")
|
||||
// SELECT sum(age), sum(score) FROM user
|
||||
```
|
||||
|
||||
* 条件编辑器
|
||||
|
||||
```Go
|
||||
@ -273,6 +309,132 @@ err := engine.Where(builder.NotIn("a", 1, 2).And(builder.In("b", "c", "d", "e"))
|
||||
// SELECT id, name ... FROM user WHERE a NOT IN (?, ?) AND b IN (?, ?, ?)
|
||||
```
|
||||
|
||||
* 在一个Go程中多次操作数据库,但没有事务
|
||||
|
||||
```Go
|
||||
session := engine.NewSession()
|
||||
defer session.Close()
|
||||
|
||||
user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
|
||||
if _, err := session.Insert(&user1); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
user2 := Userinfo{Username: "yyy"}
|
||||
if _, err := session.Where("id = ?", 2).Update(&user2); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
```
|
||||
|
||||
* 在一个Go程中有事务
|
||||
|
||||
```Go
|
||||
session := engine.NewSession()
|
||||
defer session.Close()
|
||||
|
||||
// add Begin() before any action
|
||||
if err := session.Begin(); err != nil {
|
||||
// if returned then will rollback automatically
|
||||
return err
|
||||
}
|
||||
|
||||
user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
|
||||
if _, err := session.Insert(&user1); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
user2 := Userinfo{Username: "yyy"}
|
||||
if _, err := session.Where("id = ?", 2).Update(&user2); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// add Commit() after all actions
|
||||
return session.Commit()
|
||||
```
|
||||
|
||||
* 事物的简写方法
|
||||
|
||||
```Go
|
||||
res, err := engine.Transaction(func(sess *xorm.Session) (interface{}, error) {
|
||||
user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
|
||||
if _, err := session.Insert(&user1); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
user2 := Userinfo{Username: "yyy"}
|
||||
if _, err := session.Where("id = ?", 2).Update(&user2); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, nil
|
||||
})
|
||||
```
|
||||
|
||||
* Context Cache, if enabled, current query result will be cached on session and be used by next same statement on the same session.
|
||||
|
||||
```Go
|
||||
sess := engine.NewSession()
|
||||
defer sess.Close()
|
||||
|
||||
var context = xorm.NewMemoryContextCache()
|
||||
|
||||
var c2 ContextGetStruct
|
||||
has, err := sess.ID(1).ContextCache(context).Get(&c2)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
assert.EqualValues(t, 1, c2.Id)
|
||||
assert.EqualValues(t, "1", c2.Name)
|
||||
sql, args := sess.LastSQL()
|
||||
assert.True(t, len(sql) > 0)
|
||||
assert.True(t, len(args) > 0)
|
||||
|
||||
var c3 ContextGetStruct
|
||||
has, err = sess.ID(1).ContextCache(context).Get(&c3)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
assert.EqualValues(t, 1, c3.Id)
|
||||
assert.EqualValues(t, "1", c3.Name)
|
||||
sql, args = sess.LastSQL()
|
||||
assert.True(t, len(sql) == 0)
|
||||
assert.True(t, len(args) == 0)
|
||||
```
|
||||
|
||||
## 贡献
|
||||
|
||||
如果您也想为Xorm贡献您的力量,请查看 [CONTRIBUTING](https://github.com/go-xorm/xorm/blob/master/CONTRIBUTING.md)。您也可以加入QQ群 技术帮助和讨论。
|
||||
群一:280360085 (已满)
|
||||
群二:795010183
|
||||
|
||||
## Credits
|
||||
|
||||
### Contributors
|
||||
|
||||
感谢所有的贡献者. [[Contribute](CONTRIBUTING.md)].
|
||||
<a href="graphs/contributors"><img src="https://opencollective.com/xorm/contributors.svg?width=890&button=false" /></a>
|
||||
|
||||
### Backers
|
||||
|
||||
感谢我们所有的 backers! 🙏 [[成为 backer](https://opencollective.com/xorm#backer)]
|
||||
|
||||
<a href="https://opencollective.com/xorm#backers" target="_blank"><img src="https://opencollective.com/xorm/backers.svg?width=890"></a>
|
||||
|
||||
### Sponsors
|
||||
|
||||
成为 sponsor 来支持 xorm。您的 logo 将会被显示并被链接到您的网站。 [[成为 sponsor](https://opencollective.com/xorm#sponsor)]
|
||||
|
||||
# 案例
|
||||
|
||||
* [Go语言中文网](http://studygolang.com/) - [github.com/studygolang/studygolang](https://github.com/studygolang/studygolang)
|
||||
@ -307,13 +469,30 @@ err := engine.Where(builder.NotIn("a", 1, 2).And(builder.In("b", "c", "d", "e"))
|
||||
|
||||
* [go-blog](http://wangcheng.me) - [github.com/easykoo/go-blog](https://github.com/easykoo/go-blog)
|
||||
|
||||
## 讨论
|
||||
|
||||
请加入QQ群:280360085 进行讨论。
|
||||
## 更新日志
|
||||
|
||||
## 贡献
|
||||
* **v0.7.0**
|
||||
* 修正部分Bug
|
||||
|
||||
如果您也想为Xorm贡献您的力量,请查看 [CONTRIBUTING](https://github.com/go-xorm/xorm/blob/master/CONTRIBUTING.md)
|
||||
* **v0.6.6**
|
||||
* 修正部分Bug
|
||||
|
||||
* **v0.6.5**
|
||||
* 通过 engine.SetSchema 来支持 schema,当前仅支持Postgres
|
||||
* vgo 支持
|
||||
* 新增 `FindAndCount` 函数
|
||||
* 通过 `NewEngineWithParams` 支持数据库特别参数
|
||||
* 修正部分Bug
|
||||
|
||||
* **v0.6.4**
|
||||
* 自动读写分离支持
|
||||
* Query/QueryString/QueryInterface 支持与 Where/And 合用
|
||||
* `Get` 支持获取非结构体变量
|
||||
* `Iterate` 支持 `BufferSize`
|
||||
* 修正部分Bug
|
||||
|
||||
[更多更新日志...](https://github.com/go-xorm/manual-zh-CN/tree/master/chapter-16)
|
||||
|
||||
## LICENSE
|
||||
|
||||
|
7
vendor/github.com/go-xorm/xorm/circle.yml
generated
vendored
7
vendor/github.com/go-xorm/xorm/circle.yml
generated
vendored
@ -17,11 +17,12 @@ database:
|
||||
- createdb -p 5432 -e -U postgres xorm_test1
|
||||
- createdb -p 5432 -e -U postgres xorm_test2
|
||||
- createdb -p 5432 -e -U postgres xorm_test3
|
||||
- psql xorm_test postgres -c "create schema xorm"
|
||||
|
||||
test:
|
||||
override:
|
||||
# './...' is a relative pattern which means all subdirectories
|
||||
- go get -u github.com/wadey/gocovmerge;
|
||||
- go get -u github.com/wadey/gocovmerge
|
||||
- go test -v -race -db="sqlite3" -conn_str="./test.db" -coverprofile=coverage1-1.txt -covermode=atomic
|
||||
- go test -v -race -db="sqlite3" -conn_str="./test.db" -cache=true -coverprofile=coverage1-2.txt -covermode=atomic
|
||||
- go test -v -race -db="mysql" -conn_str="root:@/xorm_test" -coverprofile=coverage2-1.txt -covermode=atomic
|
||||
@ -30,7 +31,9 @@ test:
|
||||
- go test -v -race -db="mymysql" -conn_str="xorm_test/root/" -cache=true -coverprofile=coverage3-2.txt -covermode=atomic
|
||||
- go test -v -race -db="postgres" -conn_str="dbname=xorm_test sslmode=disable" -coverprofile=coverage4-1.txt -covermode=atomic
|
||||
- go test -v -race -db="postgres" -conn_str="dbname=xorm_test sslmode=disable" -cache=true -coverprofile=coverage4-2.txt -covermode=atomic
|
||||
- gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt > coverage.txt
|
||||
- go test -v -race -db="postgres" -conn_str="dbname=xorm_test sslmode=disable" -schema=xorm -coverprofile=coverage5-1.txt -covermode=atomic
|
||||
- go test -v -race -db="postgres" -conn_str="dbname=xorm_test sslmode=disable" -schema=xorm -cache=true -coverprofile=coverage5-2.txt -covermode=atomic
|
||||
- gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt > coverage.txt
|
||||
- cd /home/ubuntu/.go_workspace/src/github.com/go-xorm/tests && ./sqlite3.sh
|
||||
- cd /home/ubuntu/.go_workspace/src/github.com/go-xorm/tests && ./mysql.sh
|
||||
- cd /home/ubuntu/.go_workspace/src/github.com/go-xorm/tests && ./postgres.sh
|
||||
|
26
vendor/github.com/go-xorm/xorm/context.go
generated
vendored
Normal file
26
vendor/github.com/go-xorm/xorm/context.go
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright 2017 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build go1.8
|
||||
|
||||
package xorm
|
||||
|
||||
import "context"
|
||||
|
||||
// PingContext tests if database is alive
|
||||
func (engine *Engine) PingContext(ctx context.Context) error {
|
||||
session := engine.NewSession()
|
||||
defer session.Close()
|
||||
return session.PingContext(ctx)
|
||||
}
|
||||
|
||||
// PingContext test if database is ok
|
||||
func (session *Session) PingContext(ctx context.Context) error {
|
||||
if session.isAutoClose {
|
||||
defer session.Close()
|
||||
}
|
||||
|
||||
session.engine.logger.Infof("PING DATABASE %v", session.engine.DriverName())
|
||||
return session.DB().PingContext(ctx)
|
||||
}
|
30
vendor/github.com/go-xorm/xorm/context_cache.go
generated
vendored
Normal file
30
vendor/github.com/go-xorm/xorm/context_cache.go
generated
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright 2018 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
// ContextCache is the interface that operates the cache data.
|
||||
type ContextCache interface {
|
||||
// Put puts value into cache with key.
|
||||
Put(key string, val interface{})
|
||||
// Get gets cached value by given key.
|
||||
Get(key string) interface{}
|
||||
}
|
||||
|
||||
type memoryContextCache map[string]interface{}
|
||||
|
||||
// NewMemoryContextCache return memoryContextCache
|
||||
func NewMemoryContextCache() memoryContextCache {
|
||||
return make(map[string]interface{})
|
||||
}
|
||||
|
||||
// Put puts value into cache with key.
|
||||
func (m memoryContextCache) Put(key string, val interface{}) {
|
||||
m[key] = val
|
||||
}
|
||||
|
||||
// Get gets cached value by given key.
|
||||
func (m memoryContextCache) Get(key string) interface{} {
|
||||
return m[key]
|
||||
}
|
6
vendor/github.com/go-xorm/xorm/convert.go
generated
vendored
6
vendor/github.com/go-xorm/xorm/convert.go
generated
vendored
@ -209,10 +209,10 @@ func convertAssign(dest, src interface{}) error {
|
||||
if src == nil {
|
||||
dv.Set(reflect.Zero(dv.Type()))
|
||||
return nil
|
||||
} else {
|
||||
dv.Set(reflect.New(dv.Type().Elem()))
|
||||
return convertAssign(dv.Interface(), src)
|
||||
}
|
||||
|
||||
dv.Set(reflect.New(dv.Type().Elem()))
|
||||
return convertAssign(dv.Interface(), src)
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
s := asString(src)
|
||||
i64, err := strconv.ParseInt(s, 10, dv.Type().Bits())
|
||||
|
77
vendor/github.com/go-xorm/xorm/dialect_mysql.go
generated
vendored
77
vendor/github.com/go-xorm/xorm/dialect_mysql.go
generated
vendored
@ -172,12 +172,33 @@ type mysql struct {
|
||||
allowAllFiles bool
|
||||
allowOldPasswords bool
|
||||
clientFoundRows bool
|
||||
rowFormat string
|
||||
}
|
||||
|
||||
func (db *mysql) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error {
|
||||
return db.Base.Init(d, db, uri, drivername, dataSourceName)
|
||||
}
|
||||
|
||||
func (db *mysql) SetParams(params map[string]string) {
|
||||
rowFormat, ok := params["rowFormat"]
|
||||
if ok {
|
||||
var t = strings.ToUpper(rowFormat)
|
||||
switch t {
|
||||
case "COMPACT":
|
||||
fallthrough
|
||||
case "REDUNDANT":
|
||||
fallthrough
|
||||
case "DYNAMIC":
|
||||
fallthrough
|
||||
case "COMPRESSED":
|
||||
db.rowFormat = t
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (db *mysql) SqlType(c *core.Column) string {
|
||||
var res string
|
||||
switch t := c.SQLType.Name; t {
|
||||
@ -487,6 +508,62 @@ func (db *mysql) GetIndexes(tableName string) (map[string]*core.Index, error) {
|
||||
return indexes, nil
|
||||
}
|
||||
|
||||
func (db *mysql) CreateTableSql(table *core.Table, tableName, storeEngine, charset string) string {
|
||||
var sql string
|
||||
sql = "CREATE TABLE IF NOT EXISTS "
|
||||
if tableName == "" {
|
||||
tableName = table.Name
|
||||
}
|
||||
|
||||
sql += db.Quote(tableName)
|
||||
sql += " ("
|
||||
|
||||
if len(table.ColumnsSeq()) > 0 {
|
||||
pkList := table.PrimaryKeys
|
||||
|
||||
for _, colName := range table.ColumnsSeq() {
|
||||
col := table.GetColumn(colName)
|
||||
if col.IsPrimaryKey && len(pkList) == 1 {
|
||||
sql += col.String(db)
|
||||
} else {
|
||||
sql += col.StringNoPk(db)
|
||||
}
|
||||
sql = strings.TrimSpace(sql)
|
||||
if len(col.Comment) > 0 {
|
||||
sql += " COMMENT '" + col.Comment + "'"
|
||||
}
|
||||
sql += ", "
|
||||
}
|
||||
|
||||
if len(pkList) > 1 {
|
||||
sql += "PRIMARY KEY ( "
|
||||
sql += db.Quote(strings.Join(pkList, db.Quote(",")))
|
||||
sql += " ), "
|
||||
}
|
||||
|
||||
sql = sql[:len(sql)-2]
|
||||
}
|
||||
sql += ")"
|
||||
|
||||
if storeEngine != "" {
|
||||
sql += " ENGINE=" + storeEngine
|
||||
}
|
||||
|
||||
if len(charset) == 0 {
|
||||
charset = db.URI().Charset
|
||||
}
|
||||
if len(charset) != 0 {
|
||||
sql += " DEFAULT CHARSET " + charset
|
||||
}
|
||||
|
||||
|
||||
|
||||
if db.rowFormat != "" {
|
||||
sql += " ROW_FORMAT=" + db.rowFormat
|
||||
}
|
||||
return sql
|
||||
}
|
||||
|
||||
func (db *mysql) Filters() []core.Filter {
|
||||
return []core.Filter{&core.IdFilter{}}
|
||||
}
|
||||
|
174
vendor/github.com/go-xorm/xorm/dialect_postgres.go
generated
vendored
174
vendor/github.com/go-xorm/xorm/dialect_postgres.go
generated
vendored
@ -8,7 +8,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@ -765,14 +764,26 @@ var (
|
||||
"YES": true,
|
||||
"ZONE": true,
|
||||
}
|
||||
|
||||
// DefaultPostgresSchema default postgres schema
|
||||
DefaultPostgresSchema = "public"
|
||||
)
|
||||
|
||||
const postgresPublicSchema = "public"
|
||||
|
||||
type postgres struct {
|
||||
core.Base
|
||||
}
|
||||
|
||||
func (db *postgres) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error {
|
||||
return db.Base.Init(d, db, uri, drivername, dataSourceName)
|
||||
err := db.Base.Init(d, db, uri, drivername, dataSourceName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if db.Schema == "" {
|
||||
db.Schema = DefaultPostgresSchema
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *postgres) SqlType(c *core.Column) string {
|
||||
@ -869,32 +880,42 @@ func (db *postgres) IndexOnTable() bool {
|
||||
}
|
||||
|
||||
func (db *postgres) IndexCheckSql(tableName, idxName string) (string, []interface{}) {
|
||||
args := []interface{}{tableName, idxName}
|
||||
if len(db.Schema) == 0 {
|
||||
args := []interface{}{tableName, idxName}
|
||||
return `SELECT indexname FROM pg_indexes WHERE tablename = ? AND indexname = ?`, args
|
||||
}
|
||||
|
||||
args := []interface{}{db.Schema, tableName, idxName}
|
||||
return `SELECT indexname FROM pg_indexes ` +
|
||||
`WHERE tablename = ? AND indexname = ?`, args
|
||||
`WHERE schemaname = ? AND tablename = ? AND indexname = ?`, args
|
||||
}
|
||||
|
||||
func (db *postgres) TableCheckSql(tableName string) (string, []interface{}) {
|
||||
args := []interface{}{tableName}
|
||||
return `SELECT tablename FROM pg_tables WHERE tablename = ?`, args
|
||||
if len(db.Schema) == 0 {
|
||||
args := []interface{}{tableName}
|
||||
return `SELECT tablename FROM pg_tables WHERE tablename = ?`, args
|
||||
}
|
||||
|
||||
args := []interface{}{db.Schema, tableName}
|
||||
return `SELECT tablename FROM pg_tables WHERE schemaname = ? AND tablename = ?`, args
|
||||
}
|
||||
|
||||
/*func (db *postgres) ColumnCheckSql(tableName, colName string) (string, []interface{}) {
|
||||
args := []interface{}{tableName, colName}
|
||||
return "SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = ?" +
|
||||
" AND column_name = ?", args
|
||||
}*/
|
||||
|
||||
func (db *postgres) ModifyColumnSql(tableName string, col *core.Column) string {
|
||||
return fmt.Sprintf("alter table %s ALTER COLUMN %s TYPE %s",
|
||||
tableName, col.Name, db.SqlType(col))
|
||||
if len(db.Schema) == 0 {
|
||||
return fmt.Sprintf("alter table %s ALTER COLUMN %s TYPE %s",
|
||||
tableName, col.Name, db.SqlType(col))
|
||||
}
|
||||
return fmt.Sprintf("alter table %s.%s ALTER COLUMN %s TYPE %s",
|
||||
db.Schema, tableName, col.Name, db.SqlType(col))
|
||||
}
|
||||
|
||||
func (db *postgres) DropIndexSql(tableName string, index *core.Index) string {
|
||||
//var unique string
|
||||
quote := db.Quote
|
||||
idxName := index.Name
|
||||
|
||||
tableName = strings.Replace(tableName, `"`, "", -1)
|
||||
tableName = strings.Replace(tableName, `.`, "_", -1)
|
||||
|
||||
if !strings.HasPrefix(idxName, "UQE_") &&
|
||||
!strings.HasPrefix(idxName, "IDX_") {
|
||||
if index.Type == core.UniqueType {
|
||||
@ -903,13 +924,21 @@ func (db *postgres) DropIndexSql(tableName string, index *core.Index) string {
|
||||
idxName = fmt.Sprintf("IDX_%v_%v", tableName, index.Name)
|
||||
}
|
||||
}
|
||||
if db.Uri.Schema != "" {
|
||||
idxName = db.Uri.Schema + "." + idxName
|
||||
}
|
||||
return fmt.Sprintf("DROP INDEX %v", quote(idxName))
|
||||
}
|
||||
|
||||
func (db *postgres) IsColumnExist(tableName, colName string) (bool, error) {
|
||||
args := []interface{}{tableName, colName}
|
||||
query := "SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = $1" +
|
||||
" AND column_name = $2"
|
||||
args := []interface{}{db.Schema, tableName, colName}
|
||||
query := "SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = $1 AND table_name = $2" +
|
||||
" AND column_name = $3"
|
||||
if len(db.Schema) == 0 {
|
||||
args = []interface{}{tableName, colName}
|
||||
query = "SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = $1" +
|
||||
" AND column_name = $2"
|
||||
}
|
||||
db.LogSQL(query, args)
|
||||
|
||||
rows, err := db.DB().Query(query, args...)
|
||||
@ -922,8 +951,7 @@ func (db *postgres) IsColumnExist(tableName, colName string) (bool, error) {
|
||||
}
|
||||
|
||||
func (db *postgres) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
|
||||
// FIXME: the schema should be replaced by user custom's
|
||||
args := []interface{}{tableName, "public"}
|
||||
args := []interface{}{tableName}
|
||||
s := `SELECT column_name, column_default, is_nullable, data_type, character_maximum_length, numeric_precision, numeric_precision_radix ,
|
||||
CASE WHEN p.contype = 'p' THEN true ELSE false END AS primarykey,
|
||||
CASE WHEN p.contype = 'u' THEN true ELSE false END AS uniquekey
|
||||
@ -934,7 +962,15 @@ FROM pg_attribute f
|
||||
LEFT JOIN pg_constraint p ON p.conrelid = c.oid AND f.attnum = ANY (p.conkey)
|
||||
LEFT JOIN pg_class AS g ON p.confrelid = g.oid
|
||||
LEFT JOIN INFORMATION_SCHEMA.COLUMNS s ON s.column_name=f.attname AND c.relname=s.table_name
|
||||
WHERE c.relkind = 'r'::char AND c.relname = $1 AND s.table_schema = $2 AND f.attnum > 0 ORDER BY f.attnum;`
|
||||
WHERE c.relkind = 'r'::char AND c.relname = $1%s AND f.attnum > 0 ORDER BY f.attnum;`
|
||||
|
||||
var f string
|
||||
if len(db.Schema) != 0 {
|
||||
args = append(args, db.Schema)
|
||||
f = " AND s.table_schema = $2"
|
||||
}
|
||||
s = fmt.Sprintf(s, f)
|
||||
|
||||
db.LogSQL(s, args)
|
||||
|
||||
rows, err := db.DB().Query(s, args...)
|
||||
@ -1024,9 +1060,13 @@ WHERE c.relkind = 'r'::char AND c.relname = $1 AND s.table_schema = $2 AND f.att
|
||||
}
|
||||
|
||||
func (db *postgres) GetTables() ([]*core.Table, error) {
|
||||
// FIXME: replace public to user customrize schema
|
||||
args := []interface{}{"public"}
|
||||
s := fmt.Sprintf("SELECT tablename FROM pg_tables WHERE schemaname = $1")
|
||||
args := []interface{}{}
|
||||
s := "SELECT tablename FROM pg_tables"
|
||||
if len(db.Schema) != 0 {
|
||||
args = append(args, db.Schema)
|
||||
s = s + " WHERE schemaname = $1"
|
||||
}
|
||||
|
||||
db.LogSQL(s, args)
|
||||
|
||||
rows, err := db.DB().Query(s, args...)
|
||||
@ -1050,9 +1090,12 @@ func (db *postgres) GetTables() ([]*core.Table, error) {
|
||||
}
|
||||
|
||||
func (db *postgres) GetIndexes(tableName string) (map[string]*core.Index, error) {
|
||||
// FIXME: replace the public schema to user specify schema
|
||||
args := []interface{}{"public", tableName}
|
||||
s := fmt.Sprintf("SELECT indexname, indexdef FROM pg_indexes WHERE schemaname=$1 AND tablename=$2")
|
||||
args := []interface{}{tableName}
|
||||
s := fmt.Sprintf("SELECT indexname, indexdef FROM pg_indexes WHERE tablename=$1")
|
||||
if len(db.Schema) != 0 {
|
||||
args = append(args, db.Schema)
|
||||
s = s + " AND schemaname=$2"
|
||||
}
|
||||
db.LogSQL(s, args)
|
||||
|
||||
rows, err := db.DB().Query(s, args...)
|
||||
@ -1117,10 +1160,6 @@ func (vs values) Get(k string) (v string) {
|
||||
return vs[k]
|
||||
}
|
||||
|
||||
func errorf(s string, args ...interface{}) {
|
||||
panic(fmt.Errorf("pq: %s", fmt.Sprintf(s, args...)))
|
||||
}
|
||||
|
||||
func parseURL(connstr string) (string, error) {
|
||||
u, err := url.Parse(connstr)
|
||||
if err != nil {
|
||||
@ -1131,46 +1170,18 @@ func parseURL(connstr string) (string, error) {
|
||||
return "", fmt.Errorf("invalid connection protocol: %s", u.Scheme)
|
||||
}
|
||||
|
||||
var kvs []string
|
||||
escaper := strings.NewReplacer(` `, `\ `, `'`, `\'`, `\`, `\\`)
|
||||
accrue := func(k, v string) {
|
||||
if v != "" {
|
||||
kvs = append(kvs, k+"="+escaper.Replace(v))
|
||||
}
|
||||
}
|
||||
|
||||
if u.User != nil {
|
||||
v := u.User.Username()
|
||||
accrue("user", v)
|
||||
|
||||
v, _ = u.User.Password()
|
||||
accrue("password", v)
|
||||
}
|
||||
|
||||
i := strings.Index(u.Host, ":")
|
||||
if i < 0 {
|
||||
accrue("host", u.Host)
|
||||
} else {
|
||||
accrue("host", u.Host[:i])
|
||||
accrue("port", u.Host[i+1:])
|
||||
}
|
||||
|
||||
if u.Path != "" {
|
||||
accrue("dbname", u.Path[1:])
|
||||
return escaper.Replace(u.Path[1:]), nil
|
||||
}
|
||||
|
||||
q := u.Query()
|
||||
for k := range q {
|
||||
accrue(k, q.Get(k))
|
||||
}
|
||||
|
||||
sort.Strings(kvs) // Makes testing easier (not a performance concern)
|
||||
return strings.Join(kvs, " "), nil
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func parseOpts(name string, o values) {
|
||||
func parseOpts(name string, o values) error {
|
||||
if len(name) == 0 {
|
||||
return
|
||||
return fmt.Errorf("invalid options: %s", name)
|
||||
}
|
||||
|
||||
name = strings.TrimSpace(name)
|
||||
@ -1179,31 +1190,48 @@ func parseOpts(name string, o values) {
|
||||
for _, p := range ps {
|
||||
kv := strings.Split(p, "=")
|
||||
if len(kv) < 2 {
|
||||
errorf("invalid option: %q", p)
|
||||
return fmt.Errorf("invalid option: %q", p)
|
||||
}
|
||||
o.Set(kv[0], kv[1])
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *pqDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
|
||||
db := &core.Uri{DbType: core.POSTGRES}
|
||||
o := make(values)
|
||||
var err error
|
||||
|
||||
if strings.HasPrefix(dataSourceName, "postgresql://") || strings.HasPrefix(dataSourceName, "postgres://") {
|
||||
dataSourceName, err = parseURL(dataSourceName)
|
||||
db.DbName, err = parseURL(dataSourceName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
o := make(values)
|
||||
err = parseOpts(dataSourceName, o)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
parseOpts(dataSourceName, o)
|
||||
|
||||
db.DbName = o.Get("dbname")
|
||||
db.DbName = o.Get("dbname")
|
||||
}
|
||||
|
||||
if db.DbName == "" {
|
||||
return nil, errors.New("dbname is empty")
|
||||
}
|
||||
/*db.Schema = o.Get("schema")
|
||||
if len(db.Schema) == 0 {
|
||||
db.Schema = "public"
|
||||
}*/
|
||||
|
||||
return db, nil
|
||||
}
|
||||
|
||||
type pqDriverPgx struct {
|
||||
pqDriver
|
||||
}
|
||||
|
||||
func (pgx *pqDriverPgx) Parse(driverName, dataSourceName string) (*core.Uri, error) {
|
||||
// Remove the leading characters for driver to work
|
||||
if len(dataSourceName) >= 9 && dataSourceName[0] == 0 {
|
||||
dataSourceName = dataSourceName[9:]
|
||||
}
|
||||
return pgx.pqDriver.Parse(driverName, dataSourceName)
|
||||
}
|
||||
|
6
vendor/github.com/go-xorm/xorm/dialect_sqlite3.go
generated
vendored
6
vendor/github.com/go-xorm/xorm/dialect_sqlite3.go
generated
vendored
@ -233,7 +233,7 @@ func (db *sqlite3) TableCheckSql(tableName string) (string, []interface{}) {
|
||||
}
|
||||
|
||||
func (db *sqlite3) DropIndexSql(tableName string, index *core.Index) string {
|
||||
//var unique string
|
||||
// var unique string
|
||||
quote := db.Quote
|
||||
idxName := index.Name
|
||||
|
||||
@ -452,5 +452,9 @@ type sqlite3Driver struct {
|
||||
}
|
||||
|
||||
func (p *sqlite3Driver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
|
||||
if strings.Contains(dataSourceName, "?") {
|
||||
dataSourceName = dataSourceName[:strings.Index(dataSourceName, "?")]
|
||||
}
|
||||
|
||||
return &core.Uri{DbType: core.SQLITE, DbName: dataSourceName}, nil
|
||||
}
|
||||
|
305
vendor/github.com/go-xorm/xorm/engine.go
generated
vendored
305
vendor/github.com/go-xorm/xorm/engine.go
generated
vendored
@ -47,6 +47,52 @@ type Engine struct {
|
||||
disableGlobalCache bool
|
||||
|
||||
tagHandlers map[string]tagHandler
|
||||
|
||||
engineGroup *EngineGroup
|
||||
|
||||
cachers map[string]core.Cacher
|
||||
cacherLock sync.RWMutex
|
||||
}
|
||||
|
||||
func (engine *Engine) setCacher(tableName string, cacher core.Cacher) {
|
||||
engine.cacherLock.Lock()
|
||||
engine.cachers[tableName] = cacher
|
||||
engine.cacherLock.Unlock()
|
||||
}
|
||||
|
||||
func (engine *Engine) SetCacher(tableName string, cacher core.Cacher) {
|
||||
engine.setCacher(tableName, cacher)
|
||||
}
|
||||
|
||||
func (engine *Engine) getCacher(tableName string) core.Cacher {
|
||||
var cacher core.Cacher
|
||||
var ok bool
|
||||
engine.cacherLock.RLock()
|
||||
cacher, ok = engine.cachers[tableName]
|
||||
engine.cacherLock.RUnlock()
|
||||
if !ok && !engine.disableGlobalCache {
|
||||
cacher = engine.Cacher
|
||||
}
|
||||
return cacher
|
||||
}
|
||||
|
||||
func (engine *Engine) GetCacher(tableName string) core.Cacher {
|
||||
return engine.getCacher(tableName)
|
||||
}
|
||||
|
||||
// BufferSize sets buffer size for iterate
|
||||
func (engine *Engine) BufferSize(size int) *Session {
|
||||
session := engine.NewSession()
|
||||
session.isAutoClose = true
|
||||
return session.BufferSize(size)
|
||||
}
|
||||
|
||||
// CondDeleted returns the conditions whether a record is soft deleted.
|
||||
func (engine *Engine) CondDeleted(colName string) builder.Cond {
|
||||
if engine.dialect.DBType() == core.MSSQL {
|
||||
return builder.IsNull{colName}
|
||||
}
|
||||
return builder.IsNull{colName}.Or(builder.Eq{colName: zeroTime1})
|
||||
}
|
||||
|
||||
// ShowSQL show SQL statement or not on logger if log level is great than INFO
|
||||
@ -79,6 +125,11 @@ func (engine *Engine) SetLogger(logger core.ILogger) {
|
||||
engine.dialect.SetLogger(logger)
|
||||
}
|
||||
|
||||
// SetLogLevel sets the logger level
|
||||
func (engine *Engine) SetLogLevel(level core.LogLevel) {
|
||||
engine.logger.SetLevel(level)
|
||||
}
|
||||
|
||||
// SetDisableGlobalCache disable global cache or not
|
||||
func (engine *Engine) SetDisableGlobalCache(disable bool) {
|
||||
if engine.disableGlobalCache != disable {
|
||||
@ -126,6 +177,14 @@ func (engine *Engine) QuoteStr() string {
|
||||
return engine.dialect.QuoteStr()
|
||||
}
|
||||
|
||||
func (engine *Engine) quoteColumns(columnStr string) string {
|
||||
columns := strings.Split(columnStr, ",")
|
||||
for i := 0; i < len(columns); i++ {
|
||||
columns[i] = engine.Quote(strings.TrimSpace(columns[i]))
|
||||
}
|
||||
return strings.Join(columns, ",")
|
||||
}
|
||||
|
||||
// Quote Use QuoteStr quote the string sql
|
||||
func (engine *Engine) Quote(value string) string {
|
||||
value = strings.TrimSpace(value)
|
||||
@ -143,7 +202,7 @@ func (engine *Engine) Quote(value string) string {
|
||||
}
|
||||
|
||||
// QuoteTo quotes string and writes into the buffer
|
||||
func (engine *Engine) QuoteTo(buf *bytes.Buffer, value string) {
|
||||
func (engine *Engine) QuoteTo(buf *builder.StringBuilder, value string) {
|
||||
if buf == nil {
|
||||
return
|
||||
}
|
||||
@ -186,6 +245,11 @@ func (engine *Engine) AutoIncrStr() string {
|
||||
return engine.dialect.AutoIncrStr()
|
||||
}
|
||||
|
||||
// SetConnMaxLifetime sets the maximum amount of time a connection may be reused.
|
||||
func (engine *Engine) SetConnMaxLifetime(d time.Duration) {
|
||||
engine.db.SetConnMaxLifetime(d)
|
||||
}
|
||||
|
||||
// SetMaxOpenConns is only available for go 1.2+
|
||||
func (engine *Engine) SetMaxOpenConns(conns int) {
|
||||
engine.db.SetMaxOpenConns(conns)
|
||||
@ -201,6 +265,11 @@ func (engine *Engine) SetDefaultCacher(cacher core.Cacher) {
|
||||
engine.Cacher = cacher
|
||||
}
|
||||
|
||||
// GetDefaultCacher returns the default cacher
|
||||
func (engine *Engine) GetDefaultCacher() core.Cacher {
|
||||
return engine.Cacher
|
||||
}
|
||||
|
||||
// NoCache If you has set default cacher, and you want temporilly stop use cache,
|
||||
// you can use NoCache()
|
||||
func (engine *Engine) NoCache() *Session {
|
||||
@ -218,13 +287,7 @@ func (engine *Engine) NoCascade() *Session {
|
||||
|
||||
// MapCacher Set a table use a special cacher
|
||||
func (engine *Engine) MapCacher(bean interface{}, cacher core.Cacher) error {
|
||||
v := rValue(bean)
|
||||
tb, err := engine.autoMapType(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tb.Cacher = cacher
|
||||
engine.setCacher(engine.TableName(bean, true), cacher)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -509,33 +572,6 @@ func (engine *Engine) dumpTables(tables []*core.Table, w io.Writer, tp ...core.D
|
||||
return nil
|
||||
}
|
||||
|
||||
func (engine *Engine) tableName(beanOrTableName interface{}) (string, error) {
|
||||
v := rValue(beanOrTableName)
|
||||
if v.Type().Kind() == reflect.String {
|
||||
return beanOrTableName.(string), nil
|
||||
} else if v.Type().Kind() == reflect.Struct {
|
||||
return engine.tbName(v), nil
|
||||
}
|
||||
return "", errors.New("bean should be a struct or struct's point")
|
||||
}
|
||||
|
||||
func (engine *Engine) tbName(v reflect.Value) string {
|
||||
if tb, ok := v.Interface().(TableName); ok {
|
||||
return tb.TableName()
|
||||
}
|
||||
|
||||
if v.Type().Kind() == reflect.Ptr {
|
||||
if tb, ok := reflect.Indirect(v).Interface().(TableName); ok {
|
||||
return tb.TableName()
|
||||
}
|
||||
} else if v.CanAddr() {
|
||||
if tb, ok := v.Addr().Interface().(TableName); ok {
|
||||
return tb.TableName()
|
||||
}
|
||||
}
|
||||
return engine.TableMapper.Obj2Table(reflect.Indirect(v).Type().Name())
|
||||
}
|
||||
|
||||
// Cascade use cascade or not
|
||||
func (engine *Engine) Cascade(trueOrFalse ...bool) *Session {
|
||||
session := engine.NewSession()
|
||||
@ -736,6 +772,13 @@ func (engine *Engine) OrderBy(order string) *Session {
|
||||
return session.OrderBy(order)
|
||||
}
|
||||
|
||||
// Prepare enables prepare statement
|
||||
func (engine *Engine) Prepare() *Session {
|
||||
session := engine.NewSession()
|
||||
session.isAutoClose = true
|
||||
return session.Prepare()
|
||||
}
|
||||
|
||||
// Join the join_operator should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN
|
||||
func (engine *Engine) Join(joinOperator string, tablename interface{}, condition string, args ...interface{}) *Session {
|
||||
session := engine.NewSession()
|
||||
@ -757,7 +800,8 @@ func (engine *Engine) Having(conditions string) *Session {
|
||||
return session.Having(conditions)
|
||||
}
|
||||
|
||||
func (engine *Engine) unMapType(t reflect.Type) {
|
||||
// UnMapType removes the datbase mapper of a type
|
||||
func (engine *Engine) UnMapType(t reflect.Type) {
|
||||
engine.mutex.Lock()
|
||||
defer engine.mutex.Unlock()
|
||||
delete(engine.Tables, t)
|
||||
@ -811,7 +855,7 @@ func (engine *Engine) TableInfo(bean interface{}) *Table {
|
||||
if err != nil {
|
||||
engine.logger.Error(err)
|
||||
}
|
||||
return &Table{tb, engine.tbName(v)}
|
||||
return &Table{tb, engine.TableName(bean)}
|
||||
}
|
||||
|
||||
func addIndex(indexName string, table *core.Table, col *core.Column, indexType int) {
|
||||
@ -826,15 +870,6 @@ func addIndex(indexName string, table *core.Table, col *core.Column, indexType i
|
||||
}
|
||||
}
|
||||
|
||||
func (engine *Engine) newTable() *core.Table {
|
||||
table := core.NewEmptyTable()
|
||||
|
||||
if !engine.disableGlobalCache {
|
||||
table.Cacher = engine.Cacher
|
||||
}
|
||||
return table
|
||||
}
|
||||
|
||||
// TableName table name interface to define customerize table name
|
||||
type TableName interface {
|
||||
TableName() string
|
||||
@ -846,21 +881,9 @@ var (
|
||||
|
||||
func (engine *Engine) mapType(v reflect.Value) (*core.Table, error) {
|
||||
t := v.Type()
|
||||
table := engine.newTable()
|
||||
if tb, ok := v.Interface().(TableName); ok {
|
||||
table.Name = tb.TableName()
|
||||
} else {
|
||||
if v.CanAddr() {
|
||||
if tb, ok = v.Addr().Interface().(TableName); ok {
|
||||
table.Name = tb.TableName()
|
||||
}
|
||||
}
|
||||
if table.Name == "" {
|
||||
table.Name = engine.TableMapper.Obj2Table(t.Name())
|
||||
}
|
||||
}
|
||||
|
||||
table := core.NewEmptyTable()
|
||||
table.Type = t
|
||||
table.Name = engine.tbNameForMap(v)
|
||||
|
||||
var idFieldColName string
|
||||
var hasCacheTag, hasNoCacheTag bool
|
||||
@ -914,7 +937,7 @@ func (engine *Engine) mapType(v reflect.Value) (*core.Table, error) {
|
||||
}
|
||||
if pStart > -1 {
|
||||
if !strings.HasSuffix(k, ")") {
|
||||
return nil, errors.New("cannot match ) charactor")
|
||||
return nil, fmt.Errorf("field %s tag %s cannot match ) charactor", col.FieldName, key)
|
||||
}
|
||||
|
||||
ctx.tagName = k[:pStart]
|
||||
@ -1014,15 +1037,15 @@ func (engine *Engine) mapType(v reflect.Value) (*core.Table, error) {
|
||||
if hasCacheTag {
|
||||
if engine.Cacher != nil { // !nash! use engine's cacher if provided
|
||||
engine.logger.Info("enable cache on table:", table.Name)
|
||||
table.Cacher = engine.Cacher
|
||||
engine.setCacher(table.Name, engine.Cacher)
|
||||
} else {
|
||||
engine.logger.Info("enable LRU cache on table:", table.Name)
|
||||
table.Cacher = NewLRUCacher2(NewMemoryStore(), time.Hour, 10000) // !nashtsai! HACK use LRU cacher for now
|
||||
engine.setCacher(table.Name, NewLRUCacher2(NewMemoryStore(), time.Hour, 10000))
|
||||
}
|
||||
}
|
||||
if hasNoCacheTag {
|
||||
engine.logger.Info("no cache on table:", table.Name)
|
||||
table.Cacher = nil
|
||||
engine.logger.Info("disable cache on table:", table.Name)
|
||||
engine.setCacher(table.Name, nil)
|
||||
}
|
||||
|
||||
return table, nil
|
||||
@ -1081,7 +1104,25 @@ func (engine *Engine) idOfV(rv reflect.Value) (core.PK, error) {
|
||||
pk := make([]interface{}, len(table.PrimaryKeys))
|
||||
for i, col := range table.PKColumns() {
|
||||
var err error
|
||||
pkField := v.FieldByName(col.FieldName)
|
||||
|
||||
fieldName := col.FieldName
|
||||
for {
|
||||
parts := strings.SplitN(fieldName, ".", 2)
|
||||
if len(parts) == 1 {
|
||||
break
|
||||
}
|
||||
|
||||
v = v.FieldByName(parts[0])
|
||||
if v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
}
|
||||
if v.Kind() != reflect.Struct {
|
||||
return nil, ErrUnSupportedType
|
||||
}
|
||||
fieldName = parts[1]
|
||||
}
|
||||
|
||||
pkField := v.FieldByName(fieldName)
|
||||
switch pkField.Kind() {
|
||||
case reflect.String:
|
||||
pk[i], err = engine.idTypeAssertion(col, pkField.String())
|
||||
@ -1127,26 +1168,10 @@ func (engine *Engine) CreateUniques(bean interface{}) error {
|
||||
return session.CreateUniques(bean)
|
||||
}
|
||||
|
||||
func (engine *Engine) getCacher2(table *core.Table) core.Cacher {
|
||||
return table.Cacher
|
||||
}
|
||||
|
||||
// ClearCacheBean if enabled cache, clear the cache bean
|
||||
func (engine *Engine) ClearCacheBean(bean interface{}, id string) error {
|
||||
v := rValue(bean)
|
||||
t := v.Type()
|
||||
if t.Kind() != reflect.Struct {
|
||||
return errors.New("error params")
|
||||
}
|
||||
tableName := engine.tbName(v)
|
||||
table, err := engine.autoMapType(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cacher := table.Cacher
|
||||
if cacher == nil {
|
||||
cacher = engine.Cacher
|
||||
}
|
||||
tableName := engine.TableName(bean)
|
||||
cacher := engine.getCacher(tableName)
|
||||
if cacher != nil {
|
||||
cacher.ClearIds(tableName)
|
||||
cacher.DelBean(tableName, id)
|
||||
@ -1157,21 +1182,8 @@ func (engine *Engine) ClearCacheBean(bean interface{}, id string) error {
|
||||
// ClearCache if enabled cache, clear some tables' cache
|
||||
func (engine *Engine) ClearCache(beans ...interface{}) error {
|
||||
for _, bean := range beans {
|
||||
v := rValue(bean)
|
||||
t := v.Type()
|
||||
if t.Kind() != reflect.Struct {
|
||||
return errors.New("error params")
|
||||
}
|
||||
tableName := engine.tbName(v)
|
||||
table, err := engine.autoMapType(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cacher := table.Cacher
|
||||
if cacher == nil {
|
||||
cacher = engine.Cacher
|
||||
}
|
||||
tableName := engine.TableName(bean)
|
||||
cacher := engine.getCacher(tableName)
|
||||
if cacher != nil {
|
||||
cacher.ClearIds(tableName)
|
||||
cacher.ClearBeans(tableName)
|
||||
@ -1189,13 +1201,13 @@ func (engine *Engine) Sync(beans ...interface{}) error {
|
||||
|
||||
for _, bean := range beans {
|
||||
v := rValue(bean)
|
||||
tableName := engine.tbName(v)
|
||||
tableNameNoSchema := engine.TableName(bean)
|
||||
table, err := engine.autoMapType(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
isExist, err := session.Table(bean).isTableExist(tableName)
|
||||
isExist, err := session.Table(bean).isTableExist(tableNameNoSchema)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -1221,12 +1233,12 @@ func (engine *Engine) Sync(beans ...interface{}) error {
|
||||
}
|
||||
} else {
|
||||
for _, col := range table.Columns() {
|
||||
isExist, err := engine.dialect.IsColumnExist(tableName, col.Name)
|
||||
isExist, err := engine.dialect.IsColumnExist(tableNameNoSchema, col.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !isExist {
|
||||
if err := session.statement.setRefValue(v); err != nil {
|
||||
if err := session.statement.setRefBean(bean); err != nil {
|
||||
return err
|
||||
}
|
||||
err = session.addColumn(col.Name)
|
||||
@ -1237,35 +1249,35 @@ func (engine *Engine) Sync(beans ...interface{}) error {
|
||||
}
|
||||
|
||||
for name, index := range table.Indexes {
|
||||
if err := session.statement.setRefValue(v); err != nil {
|
||||
if err := session.statement.setRefBean(bean); err != nil {
|
||||
return err
|
||||
}
|
||||
if index.Type == core.UniqueType {
|
||||
isExist, err := session.isIndexExist2(tableName, index.Cols, true)
|
||||
isExist, err := session.isIndexExist2(tableNameNoSchema, index.Cols, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !isExist {
|
||||
if err := session.statement.setRefValue(v); err != nil {
|
||||
if err := session.statement.setRefBean(bean); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = session.addUnique(tableName, name)
|
||||
err = session.addUnique(tableNameNoSchema, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else if index.Type == core.IndexType {
|
||||
isExist, err := session.isIndexExist2(tableName, index.Cols, false)
|
||||
isExist, err := session.isIndexExist2(tableNameNoSchema, index.Cols, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !isExist {
|
||||
if err := session.statement.setRefValue(v); err != nil {
|
||||
if err := session.statement.setRefBean(bean); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = session.addIndex(tableName, name)
|
||||
err = session.addIndex(tableNameNoSchema, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -1334,31 +1346,31 @@ func (engine *Engine) DropIndexes(bean interface{}) error {
|
||||
}
|
||||
|
||||
// Exec raw sql
|
||||
func (engine *Engine) Exec(sql string, args ...interface{}) (sql.Result, error) {
|
||||
func (engine *Engine) Exec(sqlorArgs ...interface{}) (sql.Result, error) {
|
||||
session := engine.NewSession()
|
||||
defer session.Close()
|
||||
return session.Exec(sql, args...)
|
||||
return session.Exec(sqlorArgs...)
|
||||
}
|
||||
|
||||
// Query a raw sql and return records as []map[string][]byte
|
||||
func (engine *Engine) Query(sql string, paramStr ...interface{}) (resultsSlice []map[string][]byte, err error) {
|
||||
func (engine *Engine) Query(sqlorArgs ...interface{}) (resultsSlice []map[string][]byte, err error) {
|
||||
session := engine.NewSession()
|
||||
defer session.Close()
|
||||
return session.Query(sql, paramStr...)
|
||||
return session.Query(sqlorArgs...)
|
||||
}
|
||||
|
||||
// QueryString runs a raw sql and return records as []map[string]string
|
||||
func (engine *Engine) QueryString(sqlStr string, args ...interface{}) ([]map[string]string, error) {
|
||||
func (engine *Engine) QueryString(sqlorArgs ...interface{}) ([]map[string]string, error) {
|
||||
session := engine.NewSession()
|
||||
defer session.Close()
|
||||
return session.QueryString(sqlStr, args...)
|
||||
return session.QueryString(sqlorArgs...)
|
||||
}
|
||||
|
||||
// QueryInterface runs a raw sql and return records as []map[string]interface{}
|
||||
func (engine *Engine) QueryInterface(sqlStr string, args ...interface{}) ([]map[string]interface{}, error) {
|
||||
func (engine *Engine) QueryInterface(sqlorArgs ...interface{}) ([]map[string]interface{}, error) {
|
||||
session := engine.NewSession()
|
||||
defer session.Close()
|
||||
return session.QueryInterface(sqlStr, args...)
|
||||
return session.QueryInterface(sqlorArgs...)
|
||||
}
|
||||
|
||||
// Insert one or more records
|
||||
@ -1418,6 +1430,13 @@ func (engine *Engine) Find(beans interface{}, condiBeans ...interface{}) error {
|
||||
return session.Find(beans, condiBeans...)
|
||||
}
|
||||
|
||||
// FindAndCount find the results and also return the counts
|
||||
func (engine *Engine) FindAndCount(rowsSlicePtr interface{}, condiBean ...interface{}) (int64, error) {
|
||||
session := engine.NewSession()
|
||||
defer session.Close()
|
||||
return session.FindAndCount(rowsSlicePtr, condiBean...)
|
||||
}
|
||||
|
||||
// Iterate record by record handle records from table, bean's non-empty fields
|
||||
// are conditions.
|
||||
func (engine *Engine) Iterate(bean interface{}, fun IterFunc) error {
|
||||
@ -1564,24 +1583,44 @@ func (engine *Engine) formatTime(sqlTypeName string, t time.Time) (v interface{}
|
||||
return
|
||||
}
|
||||
|
||||
// GetColumnMapper returns the column name mapper
|
||||
func (engine *Engine) GetColumnMapper() core.IMapper {
|
||||
return engine.ColumnMapper
|
||||
}
|
||||
|
||||
// GetTableMapper returns the table name mapper
|
||||
func (engine *Engine) GetTableMapper() core.IMapper {
|
||||
return engine.TableMapper
|
||||
}
|
||||
|
||||
// GetTZLocation returns time zone of the application
|
||||
func (engine *Engine) GetTZLocation() *time.Location {
|
||||
return engine.TZLocation
|
||||
}
|
||||
|
||||
// SetTZLocation sets time zone of the application
|
||||
func (engine *Engine) SetTZLocation(tz *time.Location) {
|
||||
engine.TZLocation = tz
|
||||
}
|
||||
|
||||
// GetTZDatabase returns time zone of the database
|
||||
func (engine *Engine) GetTZDatabase() *time.Location {
|
||||
return engine.DatabaseTZ
|
||||
}
|
||||
|
||||
// SetTZDatabase sets time zone of the database
|
||||
func (engine *Engine) SetTZDatabase(tz *time.Location) {
|
||||
engine.DatabaseTZ = tz
|
||||
}
|
||||
|
||||
// SetSchema sets the schema of database
|
||||
func (engine *Engine) SetSchema(schema string) {
|
||||
engine.dialect.URI().Schema = schema
|
||||
}
|
||||
|
||||
// Unscoped always disable struct tag "deleted"
|
||||
func (engine *Engine) Unscoped() *Session {
|
||||
session := engine.NewSession()
|
||||
session.isAutoClose = true
|
||||
return session.Unscoped()
|
||||
}
|
||||
|
||||
// CondDeleted returns the conditions whether a record is soft deleted.
|
||||
func (engine *Engine) CondDeleted(colName string) builder.Cond {
|
||||
if engine.dialect.DBType() == core.MSSQL {
|
||||
return builder.IsNull{colName}
|
||||
}
|
||||
return builder.IsNull{colName}.Or(builder.Eq{colName: zeroTime1})
|
||||
}
|
||||
|
||||
// BufferSize sets buffer size for iterate
|
||||
func (engine *Engine) BufferSize(size int) *Session {
|
||||
session := engine.NewSession()
|
||||
session.isAutoClose = true
|
||||
return session.BufferSize(size)
|
||||
}
|
||||
|
5
vendor/github.com/go-xorm/xorm/engine_cond.go
generated
vendored
5
vendor/github.com/go-xorm/xorm/engine_cond.go
generated
vendored
@ -9,6 +9,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-xorm/builder"
|
||||
@ -51,7 +52,9 @@ func (engine *Engine) buildConds(table *core.Table, bean interface{},
|
||||
|
||||
fieldValuePtr, err := col.ValueOf(bean)
|
||||
if err != nil {
|
||||
engine.logger.Error(err)
|
||||
if !strings.Contains(err.Error(), "is not valid") {
|
||||
engine.logger.Warn(err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
|
204
vendor/github.com/go-xorm/xorm/engine_group.go
generated
vendored
Normal file
204
vendor/github.com/go-xorm/xorm/engine_group.go
generated
vendored
Normal file
@ -0,0 +1,204 @@
|
||||
// Copyright 2017 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/go-xorm/core"
|
||||
)
|
||||
|
||||
// EngineGroup defines an engine group
|
||||
type EngineGroup struct {
|
||||
*Engine
|
||||
slaves []*Engine
|
||||
policy GroupPolicy
|
||||
}
|
||||
|
||||
// NewEngineGroup creates a new engine group
|
||||
func NewEngineGroup(args1 interface{}, args2 interface{}, policies ...GroupPolicy) (*EngineGroup, error) {
|
||||
var eg EngineGroup
|
||||
if len(policies) > 0 {
|
||||
eg.policy = policies[0]
|
||||
} else {
|
||||
eg.policy = RoundRobinPolicy()
|
||||
}
|
||||
|
||||
driverName, ok1 := args1.(string)
|
||||
conns, ok2 := args2.([]string)
|
||||
if ok1 && ok2 {
|
||||
engines := make([]*Engine, len(conns))
|
||||
for i, conn := range conns {
|
||||
engine, err := NewEngine(driverName, conn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
engine.engineGroup = &eg
|
||||
engines[i] = engine
|
||||
}
|
||||
|
||||
eg.Engine = engines[0]
|
||||
eg.slaves = engines[1:]
|
||||
return &eg, nil
|
||||
}
|
||||
|
||||
master, ok3 := args1.(*Engine)
|
||||
slaves, ok4 := args2.([]*Engine)
|
||||
if ok3 && ok4 {
|
||||
master.engineGroup = &eg
|
||||
for i := 0; i < len(slaves); i++ {
|
||||
slaves[i].engineGroup = &eg
|
||||
}
|
||||
eg.Engine = master
|
||||
eg.slaves = slaves
|
||||
return &eg, nil
|
||||
}
|
||||
return nil, ErrParamsType
|
||||
}
|
||||
|
||||
// Close the engine
|
||||
func (eg *EngineGroup) Close() error {
|
||||
err := eg.Engine.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < len(eg.slaves); i++ {
|
||||
err := eg.slaves[i].Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Master returns the master engine
|
||||
func (eg *EngineGroup) Master() *Engine {
|
||||
return eg.Engine
|
||||
}
|
||||
|
||||
// Ping tests if database is alive
|
||||
func (eg *EngineGroup) Ping() error {
|
||||
if err := eg.Engine.Ping(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, slave := range eg.slaves {
|
||||
if err := slave.Ping(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetColumnMapper set the column name mapping rule
|
||||
func (eg *EngineGroup) SetColumnMapper(mapper core.IMapper) {
|
||||
eg.Engine.ColumnMapper = mapper
|
||||
for i := 0; i < len(eg.slaves); i++ {
|
||||
eg.slaves[i].ColumnMapper = mapper
|
||||
}
|
||||
}
|
||||
|
||||
// SetConnMaxLifetime sets the maximum amount of time a connection may be reused.
|
||||
func (eg *EngineGroup) SetConnMaxLifetime(d time.Duration) {
|
||||
eg.Engine.SetConnMaxLifetime(d)
|
||||
for i := 0; i < len(eg.slaves); i++ {
|
||||
eg.slaves[i].SetConnMaxLifetime(d)
|
||||
}
|
||||
}
|
||||
|
||||
// SetDefaultCacher set the default cacher
|
||||
func (eg *EngineGroup) SetDefaultCacher(cacher core.Cacher) {
|
||||
eg.Engine.SetDefaultCacher(cacher)
|
||||
for i := 0; i < len(eg.slaves); i++ {
|
||||
eg.slaves[i].SetDefaultCacher(cacher)
|
||||
}
|
||||
}
|
||||
|
||||
// SetLogger set the new logger
|
||||
func (eg *EngineGroup) SetLogger(logger core.ILogger) {
|
||||
eg.Engine.SetLogger(logger)
|
||||
for i := 0; i < len(eg.slaves); i++ {
|
||||
eg.slaves[i].SetLogger(logger)
|
||||
}
|
||||
}
|
||||
|
||||
// SetLogLevel sets the logger level
|
||||
func (eg *EngineGroup) SetLogLevel(level core.LogLevel) {
|
||||
eg.Engine.SetLogLevel(level)
|
||||
for i := 0; i < len(eg.slaves); i++ {
|
||||
eg.slaves[i].SetLogLevel(level)
|
||||
}
|
||||
}
|
||||
|
||||
// SetMapper set the name mapping rules
|
||||
func (eg *EngineGroup) SetMapper(mapper core.IMapper) {
|
||||
eg.Engine.SetMapper(mapper)
|
||||
for i := 0; i < len(eg.slaves); i++ {
|
||||
eg.slaves[i].SetMapper(mapper)
|
||||
}
|
||||
}
|
||||
|
||||
// SetMaxIdleConns set the max idle connections on pool, default is 2
|
||||
func (eg *EngineGroup) SetMaxIdleConns(conns int) {
|
||||
eg.Engine.db.SetMaxIdleConns(conns)
|
||||
for i := 0; i < len(eg.slaves); i++ {
|
||||
eg.slaves[i].db.SetMaxIdleConns(conns)
|
||||
}
|
||||
}
|
||||
|
||||
// SetMaxOpenConns is only available for go 1.2+
|
||||
func (eg *EngineGroup) SetMaxOpenConns(conns int) {
|
||||
eg.Engine.db.SetMaxOpenConns(conns)
|
||||
for i := 0; i < len(eg.slaves); i++ {
|
||||
eg.slaves[i].db.SetMaxOpenConns(conns)
|
||||
}
|
||||
}
|
||||
|
||||
// SetPolicy set the group policy
|
||||
func (eg *EngineGroup) SetPolicy(policy GroupPolicy) *EngineGroup {
|
||||
eg.policy = policy
|
||||
return eg
|
||||
}
|
||||
|
||||
// SetTableMapper set the table name mapping rule
|
||||
func (eg *EngineGroup) SetTableMapper(mapper core.IMapper) {
|
||||
eg.Engine.TableMapper = mapper
|
||||
for i := 0; i < len(eg.slaves); i++ {
|
||||
eg.slaves[i].TableMapper = mapper
|
||||
}
|
||||
}
|
||||
|
||||
// ShowExecTime show SQL statement and execute time or not on logger if log level is great than INFO
|
||||
func (eg *EngineGroup) ShowExecTime(show ...bool) {
|
||||
eg.Engine.ShowExecTime(show...)
|
||||
for i := 0; i < len(eg.slaves); i++ {
|
||||
eg.slaves[i].ShowExecTime(show...)
|
||||
}
|
||||
}
|
||||
|
||||
// ShowSQL show SQL statement or not on logger if log level is great than INFO
|
||||
func (eg *EngineGroup) ShowSQL(show ...bool) {
|
||||
eg.Engine.ShowSQL(show...)
|
||||
for i := 0; i < len(eg.slaves); i++ {
|
||||
eg.slaves[i].ShowSQL(show...)
|
||||
}
|
||||
}
|
||||
|
||||
// Slave returns one of the physical databases which is a slave according the policy
|
||||
func (eg *EngineGroup) Slave() *Engine {
|
||||
switch len(eg.slaves) {
|
||||
case 0:
|
||||
return eg.Engine
|
||||
case 1:
|
||||
return eg.slaves[0]
|
||||
}
|
||||
return eg.policy.Slave(eg)
|
||||
}
|
||||
|
||||
// Slaves returns all the slaves
|
||||
func (eg *EngineGroup) Slaves() []*Engine {
|
||||
return eg.slaves
|
||||
}
|
116
vendor/github.com/go-xorm/xorm/engine_group_policy.go
generated
vendored
Normal file
116
vendor/github.com/go-xorm/xorm/engine_group_policy.go
generated
vendored
Normal file
@ -0,0 +1,116 @@
|
||||
// Copyright 2017 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// GroupPolicy is be used by chosing the current slave from slaves
|
||||
type GroupPolicy interface {
|
||||
Slave(*EngineGroup) *Engine
|
||||
}
|
||||
|
||||
// GroupPolicyHandler should be used when a function is a GroupPolicy
|
||||
type GroupPolicyHandler func(*EngineGroup) *Engine
|
||||
|
||||
// Slave implements the chosen of slaves
|
||||
func (h GroupPolicyHandler) Slave(eg *EngineGroup) *Engine {
|
||||
return h(eg)
|
||||
}
|
||||
|
||||
// RandomPolicy implmentes randomly chose the slave of slaves
|
||||
func RandomPolicy() GroupPolicyHandler {
|
||||
var r = rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
return func(g *EngineGroup) *Engine {
|
||||
return g.Slaves()[r.Intn(len(g.Slaves()))]
|
||||
}
|
||||
}
|
||||
|
||||
// WeightRandomPolicy implmentes randomly chose the slave of slaves
|
||||
func WeightRandomPolicy(weights []int) GroupPolicyHandler {
|
||||
var rands = make([]int, 0, len(weights))
|
||||
for i := 0; i < len(weights); i++ {
|
||||
for n := 0; n < weights[i]; n++ {
|
||||
rands = append(rands, i)
|
||||
}
|
||||
}
|
||||
var r = rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
|
||||
return func(g *EngineGroup) *Engine {
|
||||
var slaves = g.Slaves()
|
||||
idx := rands[r.Intn(len(rands))]
|
||||
if idx >= len(slaves) {
|
||||
idx = len(slaves) - 1
|
||||
}
|
||||
return slaves[idx]
|
||||
}
|
||||
}
|
||||
|
||||
func RoundRobinPolicy() GroupPolicyHandler {
|
||||
var pos = -1
|
||||
var lock sync.Mutex
|
||||
return func(g *EngineGroup) *Engine {
|
||||
var slaves = g.Slaves()
|
||||
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
pos++
|
||||
if pos >= len(slaves) {
|
||||
pos = 0
|
||||
}
|
||||
|
||||
return slaves[pos]
|
||||
}
|
||||
}
|
||||
|
||||
func WeightRoundRobinPolicy(weights []int) GroupPolicyHandler {
|
||||
var rands = make([]int, 0, len(weights))
|
||||
for i := 0; i < len(weights); i++ {
|
||||
for n := 0; n < weights[i]; n++ {
|
||||
rands = append(rands, i)
|
||||
}
|
||||
}
|
||||
var pos = -1
|
||||
var lock sync.Mutex
|
||||
|
||||
return func(g *EngineGroup) *Engine {
|
||||
var slaves = g.Slaves()
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
pos++
|
||||
if pos >= len(rands) {
|
||||
pos = 0
|
||||
}
|
||||
|
||||
idx := rands[pos]
|
||||
if idx >= len(slaves) {
|
||||
idx = len(slaves) - 1
|
||||
}
|
||||
return slaves[idx]
|
||||
}
|
||||
}
|
||||
|
||||
// LeastConnPolicy implements GroupPolicy, every time will get the least connections slave
|
||||
func LeastConnPolicy() GroupPolicyHandler {
|
||||
return func(g *EngineGroup) *Engine {
|
||||
var slaves = g.Slaves()
|
||||
connections := 0
|
||||
idx := 0
|
||||
for i := 0; i < len(slaves); i++ {
|
||||
openConnections := slaves[i].DB().Stats().OpenConnections
|
||||
if i == 0 {
|
||||
connections = openConnections
|
||||
idx = i
|
||||
} else if openConnections <= connections {
|
||||
connections = openConnections
|
||||
idx = i
|
||||
}
|
||||
}
|
||||
return slaves[idx]
|
||||
}
|
||||
}
|
14
vendor/github.com/go-xorm/xorm/engine_maxlife.go
generated
vendored
14
vendor/github.com/go-xorm/xorm/engine_maxlife.go
generated
vendored
@ -1,14 +0,0 @@
|
||||
// Copyright 2017 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build go1.6
|
||||
|
||||
package xorm
|
||||
|
||||
import "time"
|
||||
|
||||
// SetConnMaxLifetime sets the maximum amount of time a connection may be reused.
|
||||
func (engine *Engine) SetConnMaxLifetime(d time.Duration) {
|
||||
engine.db.SetConnMaxLifetime(d)
|
||||
}
|
113
vendor/github.com/go-xorm/xorm/engine_table.go
generated
vendored
Normal file
113
vendor/github.com/go-xorm/xorm/engine_table.go
generated
vendored
Normal file
@ -0,0 +1,113 @@
|
||||
// Copyright 2018 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/go-xorm/core"
|
||||
)
|
||||
|
||||
// TableNameWithSchema will automatically add schema prefix on table name
|
||||
func (engine *Engine) tbNameWithSchema(v string) string {
|
||||
// Add schema name as prefix of table name.
|
||||
// Only for postgres database.
|
||||
if engine.dialect.DBType() == core.POSTGRES &&
|
||||
engine.dialect.URI().Schema != "" &&
|
||||
engine.dialect.URI().Schema != postgresPublicSchema &&
|
||||
strings.Index(v, ".") == -1 {
|
||||
return engine.dialect.URI().Schema + "." + v
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// TableName returns table name with schema prefix if has
|
||||
func (engine *Engine) TableName(bean interface{}, includeSchema ...bool) string {
|
||||
tbName := engine.tbNameNoSchema(bean)
|
||||
if len(includeSchema) > 0 && includeSchema[0] {
|
||||
tbName = engine.tbNameWithSchema(tbName)
|
||||
}
|
||||
|
||||
return tbName
|
||||
}
|
||||
|
||||
// tbName get some table's table name
|
||||
func (session *Session) tbNameNoSchema(table *core.Table) string {
|
||||
if len(session.statement.AltTableName) > 0 {
|
||||
return session.statement.AltTableName
|
||||
}
|
||||
|
||||
return table.Name
|
||||
}
|
||||
|
||||
func (engine *Engine) tbNameForMap(v reflect.Value) string {
|
||||
if v.Type().Implements(tpTableName) {
|
||||
return v.Interface().(TableName).TableName()
|
||||
}
|
||||
if v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
if v.Type().Implements(tpTableName) {
|
||||
return v.Interface().(TableName).TableName()
|
||||
}
|
||||
}
|
||||
|
||||
return engine.TableMapper.Obj2Table(v.Type().Name())
|
||||
}
|
||||
|
||||
func (engine *Engine) tbNameNoSchema(tablename interface{}) string {
|
||||
switch tablename.(type) {
|
||||
case []string:
|
||||
t := tablename.([]string)
|
||||
if len(t) > 1 {
|
||||
return fmt.Sprintf("%v AS %v", engine.Quote(t[0]), engine.Quote(t[1]))
|
||||
} else if len(t) == 1 {
|
||||
return engine.Quote(t[0])
|
||||
}
|
||||
case []interface{}:
|
||||
t := tablename.([]interface{})
|
||||
l := len(t)
|
||||
var table string
|
||||
if l > 0 {
|
||||
f := t[0]
|
||||
switch f.(type) {
|
||||
case string:
|
||||
table = f.(string)
|
||||
case TableName:
|
||||
table = f.(TableName).TableName()
|
||||
default:
|
||||
v := rValue(f)
|
||||
t := v.Type()
|
||||
if t.Kind() == reflect.Struct {
|
||||
table = engine.tbNameForMap(v)
|
||||
} else {
|
||||
table = engine.Quote(fmt.Sprintf("%v", f))
|
||||
}
|
||||
}
|
||||
}
|
||||
if l > 1 {
|
||||
return fmt.Sprintf("%v AS %v", engine.Quote(table),
|
||||
engine.Quote(fmt.Sprintf("%v", t[1])))
|
||||
} else if l == 1 {
|
||||
return engine.Quote(table)
|
||||
}
|
||||
case TableName:
|
||||
return tablename.(TableName).TableName()
|
||||
case string:
|
||||
return tablename.(string)
|
||||
case reflect.Value:
|
||||
v := tablename.(reflect.Value)
|
||||
return engine.tbNameForMap(v)
|
||||
default:
|
||||
v := rValue(tablename)
|
||||
t := v.Type()
|
||||
if t.Kind() == reflect.Struct {
|
||||
return engine.tbNameForMap(v)
|
||||
}
|
||||
return engine.Quote(fmt.Sprintf("%v", tablename))
|
||||
}
|
||||
return ""
|
||||
}
|
31
vendor/github.com/go-xorm/xorm/error.go
generated
vendored
31
vendor/github.com/go-xorm/xorm/error.go
generated
vendored
@ -6,21 +6,44 @@ package xorm
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrParamsType params error
|
||||
ErrParamsType = errors.New("Params type error")
|
||||
// ErrTableNotFound table not found error
|
||||
ErrTableNotFound = errors.New("Not found table")
|
||||
ErrTableNotFound = errors.New("Table not found")
|
||||
// ErrUnSupportedType unsupported error
|
||||
ErrUnSupportedType = errors.New("Unsupported type error")
|
||||
// ErrNotExist record is not exist error
|
||||
ErrNotExist = errors.New("Not exist error")
|
||||
// ErrNotExist record does not exist error
|
||||
ErrNotExist = errors.New("Record does not exist")
|
||||
// ErrCacheFailed cache failed error
|
||||
ErrCacheFailed = errors.New("Cache failed")
|
||||
// ErrNeedDeletedCond delete needs less one condition error
|
||||
ErrNeedDeletedCond = errors.New("Delete need at least one condition")
|
||||
ErrNeedDeletedCond = errors.New("Delete action needs at least one condition")
|
||||
// ErrNotImplemented not implemented
|
||||
ErrNotImplemented = errors.New("Not implemented")
|
||||
// ErrConditionType condition type unsupported
|
||||
ErrConditionType = errors.New("Unsupported condition type")
|
||||
)
|
||||
|
||||
// ErrFieldIsNotExist columns does not exist
|
||||
type ErrFieldIsNotExist struct {
|
||||
FieldName string
|
||||
TableName string
|
||||
}
|
||||
|
||||
func (e ErrFieldIsNotExist) Error() string {
|
||||
return fmt.Sprintf("field %s is not valid on table %s", e.FieldName, e.TableName)
|
||||
}
|
||||
|
||||
// ErrFieldIsNotValid is not valid
|
||||
type ErrFieldIsNotValid struct {
|
||||
FieldName string
|
||||
TableName string
|
||||
}
|
||||
|
||||
func (e ErrFieldIsNotValid) Error() string {
|
||||
return fmt.Sprintf("field %s is not valid on table %s", e.FieldName, e.TableName)
|
||||
}
|
||||
|
24
vendor/github.com/go-xorm/xorm/go.mod
generated
vendored
Normal file
24
vendor/github.com/go-xorm/xorm/go.mod
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
module github.com/go-xorm/xorm
|
||||
|
||||
require (
|
||||
github.com/cockroachdb/apd v1.1.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20181014144952-4e0d7dc8888f
|
||||
github.com/go-sql-driver/mysql v1.4.0
|
||||
github.com/go-xorm/builder v0.3.2
|
||||
github.com/go-xorm/core v0.6.0
|
||||
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a // indirect
|
||||
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 // indirect
|
||||
github.com/jackc/pgx v3.2.0+incompatible
|
||||
github.com/kr/pretty v0.1.0 // indirect
|
||||
github.com/lib/pq v1.0.0
|
||||
github.com/mattn/go-sqlite3 v1.9.0
|
||||
github.com/pkg/errors v0.8.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/satori/go.uuid v1.2.0 // indirect
|
||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 // indirect
|
||||
github.com/stretchr/testify v1.2.2
|
||||
github.com/ziutek/mymysql v1.5.4
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
|
||||
gopkg.in/stretchr/testify.v1 v1.2.2
|
||||
)
|
43
vendor/github.com/go-xorm/xorm/go.sum
generated
vendored
Normal file
43
vendor/github.com/go-xorm/xorm/go.sum
generated
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
|
||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20181014144952-4e0d7dc8888f h1:WH0w/R4Yoey+04HhFxqZ6VX6I0d7RMyw5aXQ9UTvQPs=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20181014144952-4e0d7dc8888f/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc=
|
||||
github.com/go-sql-driver/mysql v1.4.0 h1:7LxgVwFb2hIQtMm87NdgAVfXjnt4OePseqT1tKx+opk=
|
||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-xorm/builder v0.3.2 h1:pSsZQRRzJNapKEAEhigw3xLmiLPeAYv5GFlpYZ8+a5I=
|
||||
github.com/go-xorm/builder v0.3.2/go.mod h1:v8mE3MFBgtL+RGFNfUnAMUqqfk/Y4W5KuwCFQIEpQLk=
|
||||
github.com/go-xorm/core v0.6.0 h1:tp6hX+ku4OD9khFZS8VGBDRY3kfVCtelPfmkgCyHxL0=
|
||||
github.com/go-xorm/core v0.6.0/go.mod h1:d8FJ9Br8OGyQl12MCclmYBuBqqxsyeedpXciV5Myih8=
|
||||
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y=
|
||||
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM=
|
||||
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc=
|
||||
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ=
|
||||
github.com/jackc/pgx v3.2.0+incompatible h1:0Vihzu20St42/UDsvZGdNE6jak7oi/UOeMzwMPHkgFY=
|
||||
github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4=
|
||||
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 h1:pntxY8Ary0t43dCZ5dqY4YTJCObLY1kIXl0uzMv+7DE=
|
||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
|
||||
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/stretchr/testify.v1 v1.2.2 h1:yhQC6Uy5CqibAIlk1wlusa/MJ3iAN49/BsR/dCCKz3M=
|
||||
gopkg.in/stretchr/testify.v1 v1.2.2/go.mod h1:QI5V/q6UbPmuhtm10CaFZxED9NreB8PnFYN9JcR6TxU=
|
162
vendor/github.com/go-xorm/xorm/helpers.go
generated
vendored
162
vendor/github.com/go-xorm/xorm/helpers.go
generated
vendored
@ -11,7 +11,6 @@ import (
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-xorm/core"
|
||||
)
|
||||
@ -293,19 +292,6 @@ func structName(v reflect.Type) string {
|
||||
return v.Name()
|
||||
}
|
||||
|
||||
func col2NewCols(columns ...string) []string {
|
||||
newColumns := make([]string, 0, len(columns))
|
||||
for _, col := range columns {
|
||||
col = strings.Replace(col, "`", "", -1)
|
||||
col = strings.Replace(col, `"`, "", -1)
|
||||
ccols := strings.Split(col, ",")
|
||||
for _, c := range ccols {
|
||||
newColumns = append(newColumns, strings.TrimSpace(c))
|
||||
}
|
||||
}
|
||||
return newColumns
|
||||
}
|
||||
|
||||
func sliceEq(left, right []string) bool {
|
||||
if len(left) != len(right) {
|
||||
return false
|
||||
@ -320,154 +306,6 @@ func sliceEq(left, right []string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func setColumnInt(bean interface{}, col *core.Column, t int64) {
|
||||
v, err := col.ValueOf(bean)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if v.CanSet() {
|
||||
switch v.Type().Kind() {
|
||||
case reflect.Int, reflect.Int64, reflect.Int32:
|
||||
v.SetInt(t)
|
||||
case reflect.Uint, reflect.Uint64, reflect.Uint32:
|
||||
v.SetUint(uint64(t))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setColumnTime(bean interface{}, col *core.Column, t time.Time) {
|
||||
v, err := col.ValueOf(bean)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if v.CanSet() {
|
||||
switch v.Type().Kind() {
|
||||
case reflect.Struct:
|
||||
v.Set(reflect.ValueOf(t).Convert(v.Type()))
|
||||
case reflect.Int, reflect.Int64, reflect.Int32:
|
||||
v.SetInt(t.Unix())
|
||||
case reflect.Uint, reflect.Uint64, reflect.Uint32:
|
||||
v.SetUint(uint64(t.Unix()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func genCols(table *core.Table, session *Session, bean interface{}, useCol bool, includeQuote bool) ([]string, []interface{}, error) {
|
||||
colNames := make([]string, 0, len(table.ColumnsSeq()))
|
||||
args := make([]interface{}, 0, len(table.ColumnsSeq()))
|
||||
|
||||
for _, col := range table.Columns() {
|
||||
if useCol && !col.IsVersion && !col.IsCreated && !col.IsUpdated {
|
||||
if _, ok := getFlagForColumn(session.statement.columnMap, col); !ok {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if col.MapType == core.ONLYFROMDB {
|
||||
continue
|
||||
}
|
||||
|
||||
fieldValuePtr, err := col.ValueOf(bean)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
fieldValue := *fieldValuePtr
|
||||
|
||||
if col.IsAutoIncrement {
|
||||
switch fieldValue.Type().Kind() {
|
||||
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int, reflect.Int64:
|
||||
if fieldValue.Int() == 0 {
|
||||
continue
|
||||
}
|
||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint, reflect.Uint64:
|
||||
if fieldValue.Uint() == 0 {
|
||||
continue
|
||||
}
|
||||
case reflect.String:
|
||||
if len(fieldValue.String()) == 0 {
|
||||
continue
|
||||
}
|
||||
case reflect.Ptr:
|
||||
if fieldValue.Pointer() == 0 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if col.IsDeleted {
|
||||
continue
|
||||
}
|
||||
|
||||
if session.statement.ColumnStr != "" {
|
||||
if _, ok := getFlagForColumn(session.statement.columnMap, col); !ok {
|
||||
continue
|
||||
} else if _, ok := session.statement.incrColumns[col.Name]; ok {
|
||||
continue
|
||||
} else if _, ok := session.statement.decrColumns[col.Name]; ok {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if session.statement.OmitStr != "" {
|
||||
if _, ok := getFlagForColumn(session.statement.columnMap, col); ok {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// !evalphobia! set fieldValue as nil when column is nullable and zero-value
|
||||
if _, ok := getFlagForColumn(session.statement.nullableMap, col); ok {
|
||||
if col.Nullable && isZero(fieldValue.Interface()) {
|
||||
var nilValue *int
|
||||
fieldValue = reflect.ValueOf(nilValue)
|
||||
}
|
||||
}
|
||||
|
||||
if (col.IsCreated || col.IsUpdated) && session.statement.UseAutoTime /*&& isZero(fieldValue.Interface())*/ {
|
||||
// if time is non-empty, then set to auto time
|
||||
val, t := session.engine.nowTime(col)
|
||||
args = append(args, val)
|
||||
|
||||
var colName = col.Name
|
||||
session.afterClosures = append(session.afterClosures, func(bean interface{}) {
|
||||
col := table.GetColumn(colName)
|
||||
setColumnTime(bean, col, t)
|
||||
})
|
||||
} else if col.IsVersion && session.statement.checkVersion {
|
||||
args = append(args, 1)
|
||||
} else {
|
||||
arg, err := session.value2Interface(col, fieldValue)
|
||||
if err != nil {
|
||||
return colNames, args, err
|
||||
}
|
||||
args = append(args, arg)
|
||||
}
|
||||
|
||||
if includeQuote {
|
||||
colNames = append(colNames, session.engine.Quote(col.Name)+" = ?")
|
||||
} else {
|
||||
colNames = append(colNames, col.Name)
|
||||
}
|
||||
}
|
||||
return colNames, args, nil
|
||||
}
|
||||
|
||||
func indexName(tableName, idxName string) string {
|
||||
return fmt.Sprintf("IDX_%v_%v", tableName, idxName)
|
||||
}
|
||||
|
||||
func getFlagForColumn(m map[string]bool, col *core.Column) (val bool, has bool) {
|
||||
if len(m) == 0 {
|
||||
return false, false
|
||||
}
|
||||
|
||||
n := len(col.Name)
|
||||
|
||||
for mk := range m {
|
||||
if len(mk) != n {
|
||||
continue
|
||||
}
|
||||
if strings.EqualFold(mk, col.Name) {
|
||||
return m[mk], true
|
||||
}
|
||||
}
|
||||
|
||||
return false, false
|
||||
}
|
||||
|
116
vendor/github.com/go-xorm/xorm/interface.go
generated
vendored
Normal file
116
vendor/github.com/go-xorm/xorm/interface.go
generated
vendored
Normal file
@ -0,0 +1,116 @@
|
||||
// Copyright 2017 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/go-xorm/core"
|
||||
)
|
||||
|
||||
// Interface defines the interface which Engine, EngineGroup and Session will implementate.
|
||||
type Interface interface {
|
||||
AllCols() *Session
|
||||
Alias(alias string) *Session
|
||||
Asc(colNames ...string) *Session
|
||||
BufferSize(size int) *Session
|
||||
Cols(columns ...string) *Session
|
||||
Count(...interface{}) (int64, error)
|
||||
CreateIndexes(bean interface{}) error
|
||||
CreateUniques(bean interface{}) error
|
||||
Decr(column string, arg ...interface{}) *Session
|
||||
Desc(...string) *Session
|
||||
Delete(interface{}) (int64, error)
|
||||
Distinct(columns ...string) *Session
|
||||
DropIndexes(bean interface{}) error
|
||||
Exec(sqlOrAgrs ...interface{}) (sql.Result, error)
|
||||
Exist(bean ...interface{}) (bool, error)
|
||||
Find(interface{}, ...interface{}) error
|
||||
FindAndCount(interface{}, ...interface{}) (int64, error)
|
||||
Get(interface{}) (bool, error)
|
||||
GroupBy(keys string) *Session
|
||||
ID(interface{}) *Session
|
||||
In(string, ...interface{}) *Session
|
||||
Incr(column string, arg ...interface{}) *Session
|
||||
Insert(...interface{}) (int64, error)
|
||||
InsertOne(interface{}) (int64, error)
|
||||
IsTableEmpty(bean interface{}) (bool, error)
|
||||
IsTableExist(beanOrTableName interface{}) (bool, error)
|
||||
Iterate(interface{}, IterFunc) error
|
||||
Limit(int, ...int) *Session
|
||||
MustCols(columns ...string) *Session
|
||||
NoAutoCondition(...bool) *Session
|
||||
NotIn(string, ...interface{}) *Session
|
||||
Join(joinOperator string, tablename interface{}, condition string, args ...interface{}) *Session
|
||||
Omit(columns ...string) *Session
|
||||
OrderBy(order string) *Session
|
||||
Ping() error
|
||||
Query(sqlOrAgrs ...interface{}) (resultsSlice []map[string][]byte, err error)
|
||||
QueryInterface(sqlorArgs ...interface{}) ([]map[string]interface{}, error)
|
||||
QueryString(sqlorArgs ...interface{}) ([]map[string]string, error)
|
||||
Rows(bean interface{}) (*Rows, error)
|
||||
SetExpr(string, string) *Session
|
||||
SQL(interface{}, ...interface{}) *Session
|
||||
Sum(bean interface{}, colName string) (float64, error)
|
||||
SumInt(bean interface{}, colName string) (int64, error)
|
||||
Sums(bean interface{}, colNames ...string) ([]float64, error)
|
||||
SumsInt(bean interface{}, colNames ...string) ([]int64, error)
|
||||
Table(tableNameOrBean interface{}) *Session
|
||||
Unscoped() *Session
|
||||
Update(bean interface{}, condiBeans ...interface{}) (int64, error)
|
||||
UseBool(...string) *Session
|
||||
Where(interface{}, ...interface{}) *Session
|
||||
}
|
||||
|
||||
// EngineInterface defines the interface which Engine, EngineGroup will implementate.
|
||||
type EngineInterface interface {
|
||||
Interface
|
||||
|
||||
Before(func(interface{})) *Session
|
||||
Charset(charset string) *Session
|
||||
ClearCache(...interface{}) error
|
||||
CreateTables(...interface{}) error
|
||||
DBMetas() ([]*core.Table, error)
|
||||
Dialect() core.Dialect
|
||||
DropTables(...interface{}) error
|
||||
DumpAllToFile(fp string, tp ...core.DbType) error
|
||||
GetCacher(string) core.Cacher
|
||||
GetColumnMapper() core.IMapper
|
||||
GetDefaultCacher() core.Cacher
|
||||
GetTableMapper() core.IMapper
|
||||
GetTZDatabase() *time.Location
|
||||
GetTZLocation() *time.Location
|
||||
MapCacher(interface{}, core.Cacher) error
|
||||
NewSession() *Session
|
||||
NoAutoTime() *Session
|
||||
Quote(string) string
|
||||
SetCacher(string, core.Cacher)
|
||||
SetConnMaxLifetime(time.Duration)
|
||||
SetDefaultCacher(core.Cacher)
|
||||
SetLogger(logger core.ILogger)
|
||||
SetLogLevel(core.LogLevel)
|
||||
SetMapper(core.IMapper)
|
||||
SetMaxOpenConns(int)
|
||||
SetMaxIdleConns(int)
|
||||
SetSchema(string)
|
||||
SetTZDatabase(tz *time.Location)
|
||||
SetTZLocation(tz *time.Location)
|
||||
ShowExecTime(...bool)
|
||||
ShowSQL(show ...bool)
|
||||
Sync(...interface{}) error
|
||||
Sync2(...interface{}) error
|
||||
StoreEngine(storeEngine string) *Session
|
||||
TableInfo(bean interface{}) *Table
|
||||
TableName(interface{}, ...bool) string
|
||||
UnMapType(reflect.Type)
|
||||
}
|
||||
|
||||
var (
|
||||
_ Interface = &Session{}
|
||||
_ EngineInterface = &Engine{}
|
||||
_ EngineInterface = &EngineGroup{}
|
||||
)
|
6
vendor/github.com/go-xorm/xorm/rows.go
generated
vendored
6
vendor/github.com/go-xorm/xorm/rows.go
generated
vendored
@ -32,7 +32,7 @@ func newRows(session *Session, bean interface{}) (*Rows, error) {
|
||||
var args []interface{}
|
||||
var err error
|
||||
|
||||
if err = rows.session.statement.setRefValue(rValue(bean)); err != nil {
|
||||
if err = rows.session.statement.setRefBean(bean); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -94,8 +94,7 @@ func (rows *Rows) Scan(bean interface{}) error {
|
||||
return fmt.Errorf("scan arg is incompatible type to [%v]", rows.beanType)
|
||||
}
|
||||
|
||||
dataStruct := rValue(bean)
|
||||
if err := rows.session.statement.setRefValue(dataStruct); err != nil {
|
||||
if err := rows.session.statement.setRefBean(bean); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -104,6 +103,7 @@ func (rows *Rows) Scan(bean interface{}) error {
|
||||
return err
|
||||
}
|
||||
|
||||
dataStruct := rValue(bean)
|
||||
_, err = rows.session.slice2Bean(scanResults, rows.fields, bean, &dataStruct, rows.session.statement.RefTable)
|
||||
if err != nil {
|
||||
return err
|
||||
|
768
vendor/github.com/go-xorm/xorm/session.go
generated
vendored
768
vendor/github.com/go-xorm/xorm/session.go
generated
vendored
@ -76,6 +76,7 @@ func (session *Session) Init() {
|
||||
session.afterDeleteBeans = make(map[interface{}]*[]func(interface{}), 0)
|
||||
session.beforeClosures = make([]func(interface{}), 0)
|
||||
session.afterClosures = make([]func(interface{}), 0)
|
||||
session.stmtCache = make(map[uint32]*core.Stmt)
|
||||
|
||||
session.afterProcessors = make([]executedProcessor, 0)
|
||||
|
||||
@ -101,6 +102,12 @@ func (session *Session) Close() {
|
||||
}
|
||||
}
|
||||
|
||||
// ContextCache enable context cache or not
|
||||
func (session *Session) ContextCache(context ContextCache) *Session {
|
||||
session.statement.context = context
|
||||
return session
|
||||
}
|
||||
|
||||
// IsClosed returns if session is closed
|
||||
func (session *Session) IsClosed() bool {
|
||||
return session.db == nil
|
||||
@ -262,13 +269,13 @@ func (session *Session) canCache() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (session *Session) doPrepare(sqlStr string) (stmt *core.Stmt, err error) {
|
||||
func (session *Session) doPrepare(db *core.DB, sqlStr string) (stmt *core.Stmt, err error) {
|
||||
crc := crc32.ChecksumIEEE([]byte(sqlStr))
|
||||
// TODO try hash(sqlStr+len(sqlStr))
|
||||
var has bool
|
||||
stmt, has = session.stmtCache[crc]
|
||||
if !has {
|
||||
stmt, err = session.DB().Prepare(sqlStr)
|
||||
stmt, err = db.Prepare(sqlStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -277,24 +284,22 @@ func (session *Session) doPrepare(sqlStr string) (stmt *core.Stmt, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (session *Session) getField(dataStruct *reflect.Value, key string, table *core.Table, idx int) *reflect.Value {
|
||||
func (session *Session) getField(dataStruct *reflect.Value, key string, table *core.Table, idx int) (*reflect.Value, error) {
|
||||
var col *core.Column
|
||||
if col = table.GetColumnIdx(key, idx); col == nil {
|
||||
//session.engine.logger.Warnf("table %v has no column %v. %v", table.Name, key, table.ColumnsSeq())
|
||||
return nil
|
||||
return nil, ErrFieldIsNotExist{key, table.Name}
|
||||
}
|
||||
|
||||
fieldValue, err := col.ValueOfV(dataStruct)
|
||||
if err != nil {
|
||||
session.engine.logger.Error(err)
|
||||
return nil
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !fieldValue.IsValid() || !fieldValue.CanSet() {
|
||||
session.engine.logger.Warnf("table %v's column %v is not valid or cannot set", table.Name, key)
|
||||
return nil
|
||||
return nil, ErrFieldIsNotValid{key, table.Name}
|
||||
}
|
||||
return fieldValue
|
||||
|
||||
return fieldValue, nil
|
||||
}
|
||||
|
||||
// Cell cell is a result of one column field
|
||||
@ -406,405 +411,417 @@ func (session *Session) slice2Bean(scanResults []interface{}, fields []string, b
|
||||
}
|
||||
tempMap[lKey] = idx
|
||||
|
||||
if fieldValue := session.getField(dataStruct, key, table, idx); fieldValue != nil {
|
||||
rawValue := reflect.Indirect(reflect.ValueOf(scanResults[ii]))
|
||||
|
||||
// if row is null then ignore
|
||||
if rawValue.Interface() == nil {
|
||||
continue
|
||||
fieldValue, err := session.getField(dataStruct, key, table, idx)
|
||||
if err != nil {
|
||||
if !strings.Contains(err.Error(), "is not valid") {
|
||||
session.engine.logger.Warn(err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if fieldValue == nil {
|
||||
continue
|
||||
}
|
||||
rawValue := reflect.Indirect(reflect.ValueOf(scanResults[ii]))
|
||||
|
||||
if fieldValue.CanAddr() {
|
||||
if structConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok {
|
||||
if data, err := value2Bytes(&rawValue); err == nil {
|
||||
if err := structConvert.FromDB(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
// if row is null then ignore
|
||||
if rawValue.Interface() == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if fieldValue.CanAddr() {
|
||||
if structConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok {
|
||||
if data, err := value2Bytes(&rawValue); err == nil {
|
||||
if err := structConvert.FromDB(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if _, ok := fieldValue.Interface().(core.Conversion); ok {
|
||||
if data, err := value2Bytes(&rawValue); err == nil {
|
||||
if fieldValue.Kind() == reflect.Ptr && fieldValue.IsNil() {
|
||||
fieldValue.Set(reflect.New(fieldValue.Type().Elem()))
|
||||
}
|
||||
fieldValue.Interface().(core.Conversion).FromDB(data)
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
rawValueType := reflect.TypeOf(rawValue.Interface())
|
||||
vv := reflect.ValueOf(rawValue.Interface())
|
||||
col := table.GetColumnIdx(key, idx)
|
||||
if col.IsPrimaryKey {
|
||||
pk = append(pk, rawValue.Interface())
|
||||
if _, ok := fieldValue.Interface().(core.Conversion); ok {
|
||||
if data, err := value2Bytes(&rawValue); err == nil {
|
||||
if fieldValue.Kind() == reflect.Ptr && fieldValue.IsNil() {
|
||||
fieldValue.Set(reflect.New(fieldValue.Type().Elem()))
|
||||
}
|
||||
fieldValue.Interface().(core.Conversion).FromDB(data)
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
fieldType := fieldValue.Type()
|
||||
hasAssigned := false
|
||||
continue
|
||||
}
|
||||
|
||||
if col.SQLType.IsJson() {
|
||||
var bs []byte
|
||||
if rawValueType.Kind() == reflect.String {
|
||||
bs = []byte(vv.String())
|
||||
} else if rawValueType.ConvertibleTo(core.BytesType) {
|
||||
bs = vv.Bytes()
|
||||
rawValueType := reflect.TypeOf(rawValue.Interface())
|
||||
vv := reflect.ValueOf(rawValue.Interface())
|
||||
col := table.GetColumnIdx(key, idx)
|
||||
if col.IsPrimaryKey {
|
||||
pk = append(pk, rawValue.Interface())
|
||||
}
|
||||
fieldType := fieldValue.Type()
|
||||
hasAssigned := false
|
||||
|
||||
if col.SQLType.IsJson() {
|
||||
var bs []byte
|
||||
if rawValueType.Kind() == reflect.String {
|
||||
bs = []byte(vv.String())
|
||||
} else if rawValueType.ConvertibleTo(core.BytesType) {
|
||||
bs = vv.Bytes()
|
||||
} else {
|
||||
return nil, fmt.Errorf("unsupported database data type: %s %v", key, rawValueType.Kind())
|
||||
}
|
||||
|
||||
hasAssigned = true
|
||||
|
||||
if len(bs) > 0 {
|
||||
if fieldType.Kind() == reflect.String {
|
||||
fieldValue.SetString(string(bs))
|
||||
continue
|
||||
}
|
||||
if fieldValue.CanAddr() {
|
||||
err := json.Unmarshal(bs, fieldValue.Addr().Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
return nil, fmt.Errorf("unsupported database data type: %s %v", key, rawValueType.Kind())
|
||||
}
|
||||
|
||||
hasAssigned = true
|
||||
|
||||
if len(bs) > 0 {
|
||||
if fieldValue.CanAddr() {
|
||||
err := json.Unmarshal(bs, fieldValue.Addr().Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
x := reflect.New(fieldType)
|
||||
err := json.Unmarshal(bs, x.Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fieldValue.Set(x.Elem())
|
||||
x := reflect.New(fieldType)
|
||||
err := json.Unmarshal(bs, x.Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fieldValue.Set(x.Elem())
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
switch fieldType.Kind() {
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
// TODO: reimplement this
|
||||
var bs []byte
|
||||
if rawValueType.Kind() == reflect.String {
|
||||
bs = []byte(vv.String())
|
||||
} else if rawValueType.ConvertibleTo(core.BytesType) {
|
||||
bs = vv.Bytes()
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
hasAssigned = true
|
||||
if len(bs) > 0 {
|
||||
if fieldValue.CanAddr() {
|
||||
err := json.Unmarshal(bs, fieldValue.Addr().Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
x := reflect.New(fieldType)
|
||||
err := json.Unmarshal(bs, x.Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fieldValue.Set(x.Elem())
|
||||
switch fieldType.Kind() {
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
// TODO: reimplement this
|
||||
var bs []byte
|
||||
if rawValueType.Kind() == reflect.String {
|
||||
bs = []byte(vv.String())
|
||||
} else if rawValueType.ConvertibleTo(core.BytesType) {
|
||||
bs = vv.Bytes()
|
||||
}
|
||||
|
||||
hasAssigned = true
|
||||
if len(bs) > 0 {
|
||||
if fieldValue.CanAddr() {
|
||||
err := json.Unmarshal(bs, fieldValue.Addr().Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
x := reflect.New(fieldType)
|
||||
err := json.Unmarshal(bs, x.Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fieldValue.Set(x.Elem())
|
||||
}
|
||||
}
|
||||
case reflect.Slice, reflect.Array:
|
||||
switch rawValueType.Kind() {
|
||||
case reflect.Slice, reflect.Array:
|
||||
switch rawValueType.Kind() {
|
||||
case reflect.Slice, reflect.Array:
|
||||
switch rawValueType.Elem().Kind() {
|
||||
case reflect.Uint8:
|
||||
if fieldType.Elem().Kind() == reflect.Uint8 {
|
||||
hasAssigned = true
|
||||
if col.SQLType.IsText() {
|
||||
x := reflect.New(fieldType)
|
||||
err := json.Unmarshal(vv.Bytes(), x.Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fieldValue.Set(x.Elem())
|
||||
} else {
|
||||
if fieldValue.Len() > 0 {
|
||||
for i := 0; i < fieldValue.Len(); i++ {
|
||||
if i < vv.Len() {
|
||||
fieldValue.Index(i).Set(vv.Index(i))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < vv.Len(); i++ {
|
||||
fieldValue.Set(reflect.Append(*fieldValue, vv.Index(i)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case reflect.String:
|
||||
if rawValueType.Kind() == reflect.String {
|
||||
hasAssigned = true
|
||||
fieldValue.SetString(vv.String())
|
||||
}
|
||||
case reflect.Bool:
|
||||
if rawValueType.Kind() == reflect.Bool {
|
||||
hasAssigned = true
|
||||
fieldValue.SetBool(vv.Bool())
|
||||
}
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
switch rawValueType.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
hasAssigned = true
|
||||
fieldValue.SetInt(vv.Int())
|
||||
}
|
||||
case reflect.Float32, reflect.Float64:
|
||||
switch rawValueType.Kind() {
|
||||
case reflect.Float32, reflect.Float64:
|
||||
hasAssigned = true
|
||||
fieldValue.SetFloat(vv.Float())
|
||||
}
|
||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
|
||||
switch rawValueType.Kind() {
|
||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
|
||||
hasAssigned = true
|
||||
fieldValue.SetUint(vv.Uint())
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
hasAssigned = true
|
||||
fieldValue.SetUint(uint64(vv.Int()))
|
||||
}
|
||||
case reflect.Struct:
|
||||
if fieldType.ConvertibleTo(core.TimeType) {
|
||||
dbTZ := session.engine.DatabaseTZ
|
||||
if col.TimeZone != nil {
|
||||
dbTZ = col.TimeZone
|
||||
}
|
||||
|
||||
if rawValueType == core.TimeType {
|
||||
switch rawValueType.Elem().Kind() {
|
||||
case reflect.Uint8:
|
||||
if fieldType.Elem().Kind() == reflect.Uint8 {
|
||||
hasAssigned = true
|
||||
|
||||
t := vv.Convert(core.TimeType).Interface().(time.Time)
|
||||
|
||||
z, _ := t.Zone()
|
||||
// set new location if database don't save timezone or give an incorrect timezone
|
||||
if len(z) == 0 || t.Year() == 0 || t.Location().String() != dbTZ.String() { // !nashtsai! HACK tmp work around for lib/pq doesn't properly time with location
|
||||
session.engine.logger.Debugf("empty zone key[%v] : %v | zone: %v | location: %+v\n", key, t, z, *t.Location())
|
||||
t = time.Date(t.Year(), t.Month(), t.Day(), t.Hour(),
|
||||
t.Minute(), t.Second(), t.Nanosecond(), dbTZ)
|
||||
}
|
||||
|
||||
t = t.In(session.engine.TZLocation)
|
||||
fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
|
||||
} else if rawValueType == core.IntType || rawValueType == core.Int64Type ||
|
||||
rawValueType == core.Int32Type {
|
||||
hasAssigned = true
|
||||
|
||||
t := time.Unix(vv.Int(), 0).In(session.engine.TZLocation)
|
||||
fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
|
||||
} else {
|
||||
if d, ok := vv.Interface().([]uint8); ok {
|
||||
hasAssigned = true
|
||||
t, err := session.byte2Time(col, d)
|
||||
if err != nil {
|
||||
session.engine.logger.Error("byte2Time error:", err.Error())
|
||||
hasAssigned = false
|
||||
} else {
|
||||
fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
|
||||
}
|
||||
} else if d, ok := vv.Interface().(string); ok {
|
||||
hasAssigned = true
|
||||
t, err := session.str2Time(col, d)
|
||||
if err != nil {
|
||||
session.engine.logger.Error("byte2Time error:", err.Error())
|
||||
hasAssigned = false
|
||||
} else {
|
||||
fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
|
||||
}
|
||||
} else {
|
||||
return nil, fmt.Errorf("rawValueType is %v, value is %v", rawValueType, vv.Interface())
|
||||
}
|
||||
}
|
||||
} else if nulVal, ok := fieldValue.Addr().Interface().(sql.Scanner); ok {
|
||||
// !<winxxp>! 增加支持sql.Scanner接口的结构,如sql.NullString
|
||||
hasAssigned = true
|
||||
if err := nulVal.Scan(vv.Interface()); err != nil {
|
||||
session.engine.logger.Error("sql.Sanner error:", err.Error())
|
||||
hasAssigned = false
|
||||
}
|
||||
} else if col.SQLType.IsJson() {
|
||||
if rawValueType.Kind() == reflect.String {
|
||||
hasAssigned = true
|
||||
x := reflect.New(fieldType)
|
||||
if len([]byte(vv.String())) > 0 {
|
||||
err := json.Unmarshal([]byte(vv.String()), x.Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fieldValue.Set(x.Elem())
|
||||
}
|
||||
} else if rawValueType.Kind() == reflect.Slice {
|
||||
hasAssigned = true
|
||||
x := reflect.New(fieldType)
|
||||
if len(vv.Bytes()) > 0 {
|
||||
if col.SQLType.IsText() {
|
||||
x := reflect.New(fieldType)
|
||||
err := json.Unmarshal(vv.Bytes(), x.Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fieldValue.Set(x.Elem())
|
||||
}
|
||||
}
|
||||
} else if session.statement.UseCascade {
|
||||
table, err := session.engine.autoMapType(*fieldValue)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hasAssigned = true
|
||||
if len(table.PrimaryKeys) != 1 {
|
||||
return nil, errors.New("unsupported non or composited primary key cascade")
|
||||
}
|
||||
var pk = make(core.PK, len(table.PrimaryKeys))
|
||||
pk[0], err = asKind(vv, rawValueType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !isPKZero(pk) {
|
||||
// !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
|
||||
// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
|
||||
// property to be fetched lazily
|
||||
structInter := reflect.New(fieldValue.Type())
|
||||
has, err := session.ID(pk).NoCascade().get(structInter.Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if has {
|
||||
fieldValue.Set(structInter.Elem())
|
||||
} else {
|
||||
return nil, errors.New("cascade obj is not exist")
|
||||
if fieldValue.Len() > 0 {
|
||||
for i := 0; i < fieldValue.Len(); i++ {
|
||||
if i < vv.Len() {
|
||||
fieldValue.Index(i).Set(vv.Index(i))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < vv.Len(); i++ {
|
||||
fieldValue.Set(reflect.Append(*fieldValue, vv.Index(i)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case reflect.Ptr:
|
||||
// !nashtsai! TODO merge duplicated codes above
|
||||
switch fieldType {
|
||||
// following types case matching ptr's native type, therefore assign ptr directly
|
||||
case core.PtrStringType:
|
||||
if rawValueType.Kind() == reflect.String {
|
||||
x := vv.String()
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.PtrBoolType:
|
||||
if rawValueType.Kind() == reflect.Bool {
|
||||
x := vv.Bool()
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.PtrTimeType:
|
||||
if rawValueType == core.PtrTimeType {
|
||||
hasAssigned = true
|
||||
var x = rawValue.Interface().(time.Time)
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.PtrFloat64Type:
|
||||
if rawValueType.Kind() == reflect.Float64 {
|
||||
x := vv.Float()
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.PtrUint64Type:
|
||||
if rawValueType.Kind() == reflect.Int64 {
|
||||
var x = uint64(vv.Int())
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.PtrInt64Type:
|
||||
if rawValueType.Kind() == reflect.Int64 {
|
||||
x := vv.Int()
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.PtrFloat32Type:
|
||||
if rawValueType.Kind() == reflect.Float64 {
|
||||
var x = float32(vv.Float())
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.PtrIntType:
|
||||
if rawValueType.Kind() == reflect.Int64 {
|
||||
var x = int(vv.Int())
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.PtrInt32Type:
|
||||
if rawValueType.Kind() == reflect.Int64 {
|
||||
var x = int32(vv.Int())
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.PtrInt8Type:
|
||||
if rawValueType.Kind() == reflect.Int64 {
|
||||
var x = int8(vv.Int())
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.PtrInt16Type:
|
||||
if rawValueType.Kind() == reflect.Int64 {
|
||||
var x = int16(vv.Int())
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.PtrUintType:
|
||||
if rawValueType.Kind() == reflect.Int64 {
|
||||
var x = uint(vv.Int())
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.PtrUint32Type:
|
||||
if rawValueType.Kind() == reflect.Int64 {
|
||||
var x = uint32(vv.Int())
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.Uint8Type:
|
||||
if rawValueType.Kind() == reflect.Int64 {
|
||||
var x = uint8(vv.Int())
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.Uint16Type:
|
||||
if rawValueType.Kind() == reflect.Int64 {
|
||||
var x = uint16(vv.Int())
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.Complex64Type:
|
||||
var x complex64
|
||||
if len([]byte(vv.String())) > 0 {
|
||||
err := json.Unmarshal([]byte(vv.String()), &x)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
hasAssigned = true
|
||||
case core.Complex128Type:
|
||||
var x complex128
|
||||
if len([]byte(vv.String())) > 0 {
|
||||
err := json.Unmarshal([]byte(vv.String()), &x)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
hasAssigned = true
|
||||
} // switch fieldType
|
||||
} // switch fieldType.Kind()
|
||||
}
|
||||
case reflect.String:
|
||||
if rawValueType.Kind() == reflect.String {
|
||||
hasAssigned = true
|
||||
fieldValue.SetString(vv.String())
|
||||
}
|
||||
case reflect.Bool:
|
||||
if rawValueType.Kind() == reflect.Bool {
|
||||
hasAssigned = true
|
||||
fieldValue.SetBool(vv.Bool())
|
||||
}
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
switch rawValueType.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
hasAssigned = true
|
||||
fieldValue.SetInt(vv.Int())
|
||||
}
|
||||
case reflect.Float32, reflect.Float64:
|
||||
switch rawValueType.Kind() {
|
||||
case reflect.Float32, reflect.Float64:
|
||||
hasAssigned = true
|
||||
fieldValue.SetFloat(vv.Float())
|
||||
}
|
||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
|
||||
switch rawValueType.Kind() {
|
||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
|
||||
hasAssigned = true
|
||||
fieldValue.SetUint(vv.Uint())
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
hasAssigned = true
|
||||
fieldValue.SetUint(uint64(vv.Int()))
|
||||
}
|
||||
case reflect.Struct:
|
||||
if fieldType.ConvertibleTo(core.TimeType) {
|
||||
dbTZ := session.engine.DatabaseTZ
|
||||
if col.TimeZone != nil {
|
||||
dbTZ = col.TimeZone
|
||||
}
|
||||
|
||||
// !nashtsai! for value can't be assigned directly fallback to convert to []byte then back to value
|
||||
if !hasAssigned {
|
||||
data, err := value2Bytes(&rawValue)
|
||||
if rawValueType == core.TimeType {
|
||||
hasAssigned = true
|
||||
|
||||
t := vv.Convert(core.TimeType).Interface().(time.Time)
|
||||
|
||||
z, _ := t.Zone()
|
||||
// set new location if database don't save timezone or give an incorrect timezone
|
||||
if len(z) == 0 || t.Year() == 0 || t.Location().String() != dbTZ.String() { // !nashtsai! HACK tmp work around for lib/pq doesn't properly time with location
|
||||
session.engine.logger.Debugf("empty zone key[%v] : %v | zone: %v | location: %+v\n", key, t, z, *t.Location())
|
||||
t = time.Date(t.Year(), t.Month(), t.Day(), t.Hour(),
|
||||
t.Minute(), t.Second(), t.Nanosecond(), dbTZ)
|
||||
}
|
||||
|
||||
t = t.In(session.engine.TZLocation)
|
||||
fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
|
||||
} else if rawValueType == core.IntType || rawValueType == core.Int64Type ||
|
||||
rawValueType == core.Int32Type {
|
||||
hasAssigned = true
|
||||
|
||||
t := time.Unix(vv.Int(), 0).In(session.engine.TZLocation)
|
||||
fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
|
||||
} else {
|
||||
if d, ok := vv.Interface().([]uint8); ok {
|
||||
hasAssigned = true
|
||||
t, err := session.byte2Time(col, d)
|
||||
if err != nil {
|
||||
session.engine.logger.Error("byte2Time error:", err.Error())
|
||||
hasAssigned = false
|
||||
} else {
|
||||
fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
|
||||
}
|
||||
} else if d, ok := vv.Interface().(string); ok {
|
||||
hasAssigned = true
|
||||
t, err := session.str2Time(col, d)
|
||||
if err != nil {
|
||||
session.engine.logger.Error("byte2Time error:", err.Error())
|
||||
hasAssigned = false
|
||||
} else {
|
||||
fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
|
||||
}
|
||||
} else {
|
||||
return nil, fmt.Errorf("rawValueType is %v, value is %v", rawValueType, vv.Interface())
|
||||
}
|
||||
}
|
||||
} else if nulVal, ok := fieldValue.Addr().Interface().(sql.Scanner); ok {
|
||||
// !<winxxp>! 增加支持sql.Scanner接口的结构,如sql.NullString
|
||||
hasAssigned = true
|
||||
if err := nulVal.Scan(vv.Interface()); err != nil {
|
||||
session.engine.logger.Error("sql.Sanner error:", err.Error())
|
||||
hasAssigned = false
|
||||
}
|
||||
} else if col.SQLType.IsJson() {
|
||||
if rawValueType.Kind() == reflect.String {
|
||||
hasAssigned = true
|
||||
x := reflect.New(fieldType)
|
||||
if len([]byte(vv.String())) > 0 {
|
||||
err := json.Unmarshal([]byte(vv.String()), x.Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fieldValue.Set(x.Elem())
|
||||
}
|
||||
} else if rawValueType.Kind() == reflect.Slice {
|
||||
hasAssigned = true
|
||||
x := reflect.New(fieldType)
|
||||
if len(vv.Bytes()) > 0 {
|
||||
err := json.Unmarshal(vv.Bytes(), x.Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fieldValue.Set(x.Elem())
|
||||
}
|
||||
}
|
||||
} else if session.statement.UseCascade {
|
||||
table, err := session.engine.autoMapType(*fieldValue)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = session.bytes2Value(col, fieldValue, data); err != nil {
|
||||
hasAssigned = true
|
||||
if len(table.PrimaryKeys) != 1 {
|
||||
return nil, errors.New("unsupported non or composited primary key cascade")
|
||||
}
|
||||
var pk = make(core.PK, len(table.PrimaryKeys))
|
||||
pk[0], err = asKind(vv, rawValueType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !isPKZero(pk) {
|
||||
// !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
|
||||
// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
|
||||
// property to be fetched lazily
|
||||
structInter := reflect.New(fieldValue.Type())
|
||||
has, err := session.ID(pk).NoCascade().get(structInter.Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if has {
|
||||
fieldValue.Set(structInter.Elem())
|
||||
} else {
|
||||
return nil, errors.New("cascade obj is not exist")
|
||||
}
|
||||
}
|
||||
}
|
||||
case reflect.Ptr:
|
||||
// !nashtsai! TODO merge duplicated codes above
|
||||
switch fieldType {
|
||||
// following types case matching ptr's native type, therefore assign ptr directly
|
||||
case core.PtrStringType:
|
||||
if rawValueType.Kind() == reflect.String {
|
||||
x := vv.String()
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.PtrBoolType:
|
||||
if rawValueType.Kind() == reflect.Bool {
|
||||
x := vv.Bool()
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.PtrTimeType:
|
||||
if rawValueType == core.PtrTimeType {
|
||||
hasAssigned = true
|
||||
var x = rawValue.Interface().(time.Time)
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.PtrFloat64Type:
|
||||
if rawValueType.Kind() == reflect.Float64 {
|
||||
x := vv.Float()
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.PtrUint64Type:
|
||||
if rawValueType.Kind() == reflect.Int64 {
|
||||
var x = uint64(vv.Int())
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.PtrInt64Type:
|
||||
if rawValueType.Kind() == reflect.Int64 {
|
||||
x := vv.Int()
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.PtrFloat32Type:
|
||||
if rawValueType.Kind() == reflect.Float64 {
|
||||
var x = float32(vv.Float())
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.PtrIntType:
|
||||
if rawValueType.Kind() == reflect.Int64 {
|
||||
var x = int(vv.Int())
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.PtrInt32Type:
|
||||
if rawValueType.Kind() == reflect.Int64 {
|
||||
var x = int32(vv.Int())
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.PtrInt8Type:
|
||||
if rawValueType.Kind() == reflect.Int64 {
|
||||
var x = int8(vv.Int())
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.PtrInt16Type:
|
||||
if rawValueType.Kind() == reflect.Int64 {
|
||||
var x = int16(vv.Int())
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.PtrUintType:
|
||||
if rawValueType.Kind() == reflect.Int64 {
|
||||
var x = uint(vv.Int())
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.PtrUint32Type:
|
||||
if rawValueType.Kind() == reflect.Int64 {
|
||||
var x = uint32(vv.Int())
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.Uint8Type:
|
||||
if rawValueType.Kind() == reflect.Int64 {
|
||||
var x = uint8(vv.Int())
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.Uint16Type:
|
||||
if rawValueType.Kind() == reflect.Int64 {
|
||||
var x = uint16(vv.Int())
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.Complex64Type:
|
||||
var x complex64
|
||||
if len([]byte(vv.String())) > 0 {
|
||||
err := json.Unmarshal([]byte(vv.String()), &x)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
hasAssigned = true
|
||||
case core.Complex128Type:
|
||||
var x complex128
|
||||
if len([]byte(vv.String())) > 0 {
|
||||
err := json.Unmarshal([]byte(vv.String()), &x)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
hasAssigned = true
|
||||
} // switch fieldType
|
||||
} // switch fieldType.Kind()
|
||||
|
||||
// !nashtsai! for value can't be assigned directly fallback to convert to []byte then back to value
|
||||
if !hasAssigned {
|
||||
data, err := value2Bytes(&rawValue)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = session.bytes2Value(col, fieldValue, data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -823,15 +840,6 @@ func (session *Session) LastSQL() (string, []interface{}) {
|
||||
return session.lastSQL, session.lastSQLArgs
|
||||
}
|
||||
|
||||
// tbName get some table's table name
|
||||
func (session *Session) tbNameNoSchema(table *core.Table) string {
|
||||
if len(session.statement.AltTableName) > 0 {
|
||||
return session.statement.AltTableName
|
||||
}
|
||||
|
||||
return table.Name
|
||||
}
|
||||
|
||||
// Unscoped always disable struct tag "deleted"
|
||||
func (session *Session) Unscoped() *Session {
|
||||
session.statement.Unscoped()
|
||||
|
115
vendor/github.com/go-xorm/xorm/session_cols.go
generated
vendored
115
vendor/github.com/go-xorm/xorm/session_cols.go
generated
vendored
@ -4,6 +4,121 @@
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-xorm/core"
|
||||
)
|
||||
|
||||
type incrParam struct {
|
||||
colName string
|
||||
arg interface{}
|
||||
}
|
||||
|
||||
type decrParam struct {
|
||||
colName string
|
||||
arg interface{}
|
||||
}
|
||||
|
||||
type exprParam struct {
|
||||
colName string
|
||||
expr string
|
||||
}
|
||||
|
||||
type columnMap []string
|
||||
|
||||
func (m columnMap) contain(colName string) bool {
|
||||
if len(m) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
n := len(colName)
|
||||
for _, mk := range m {
|
||||
if len(mk) != n {
|
||||
continue
|
||||
}
|
||||
if strings.EqualFold(mk, colName) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *columnMap) add(colName string) bool {
|
||||
if m.contain(colName) {
|
||||
return false
|
||||
}
|
||||
*m = append(*m, colName)
|
||||
return true
|
||||
}
|
||||
|
||||
func setColumnInt(bean interface{}, col *core.Column, t int64) {
|
||||
v, err := col.ValueOf(bean)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if v.CanSet() {
|
||||
switch v.Type().Kind() {
|
||||
case reflect.Int, reflect.Int64, reflect.Int32:
|
||||
v.SetInt(t)
|
||||
case reflect.Uint, reflect.Uint64, reflect.Uint32:
|
||||
v.SetUint(uint64(t))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setColumnTime(bean interface{}, col *core.Column, t time.Time) {
|
||||
v, err := col.ValueOf(bean)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if v.CanSet() {
|
||||
switch v.Type().Kind() {
|
||||
case reflect.Struct:
|
||||
v.Set(reflect.ValueOf(t).Convert(v.Type()))
|
||||
case reflect.Int, reflect.Int64, reflect.Int32:
|
||||
v.SetInt(t.Unix())
|
||||
case reflect.Uint, reflect.Uint64, reflect.Uint32:
|
||||
v.SetUint(uint64(t.Unix()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getFlagForColumn(m map[string]bool, col *core.Column) (val bool, has bool) {
|
||||
if len(m) == 0 {
|
||||
return false, false
|
||||
}
|
||||
|
||||
n := len(col.Name)
|
||||
|
||||
for mk := range m {
|
||||
if len(mk) != n {
|
||||
continue
|
||||
}
|
||||
if strings.EqualFold(mk, col.Name) {
|
||||
return m[mk], true
|
||||
}
|
||||
}
|
||||
|
||||
return false, false
|
||||
}
|
||||
|
||||
func col2NewCols(columns ...string) []string {
|
||||
newColumns := make([]string, 0, len(columns))
|
||||
for _, col := range columns {
|
||||
col = strings.Replace(col, "`", "", -1)
|
||||
col = strings.Replace(col, `"`, "", -1)
|
||||
ccols := strings.Split(col, ",")
|
||||
for _, c := range ccols {
|
||||
newColumns = append(newColumns, strings.TrimSpace(c))
|
||||
}
|
||||
}
|
||||
return newColumns
|
||||
}
|
||||
|
||||
// Incr provides a query string like "count = count + 1"
|
||||
func (session *Session) Incr(column string, arg ...interface{}) *Session {
|
||||
session.statement.Incr(column, arg...)
|
||||
|
14
vendor/github.com/go-xorm/xorm/session_convert.go
generated
vendored
14
vendor/github.com/go-xorm/xorm/session_convert.go
generated
vendored
@ -34,27 +34,27 @@ func (session *Session) str2Time(col *core.Column, data string) (outTime time.Ti
|
||||
sd, err := strconv.ParseInt(sdata, 10, 64)
|
||||
if err == nil {
|
||||
x = time.Unix(sd, 0)
|
||||
session.engine.logger.Debugf("time(0) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
||||
//session.engine.logger.Debugf("time(0) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
||||
} else {
|
||||
session.engine.logger.Debugf("time(0) err key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
||||
//session.engine.logger.Debugf("time(0) err key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
||||
}
|
||||
} else if len(sdata) > 19 && strings.Contains(sdata, "-") {
|
||||
x, err = time.ParseInLocation(time.RFC3339Nano, sdata, parseLoc)
|
||||
session.engine.logger.Debugf("time(1) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
||||
if err != nil {
|
||||
x, err = time.ParseInLocation("2006-01-02 15:04:05.999999999", sdata, parseLoc)
|
||||
session.engine.logger.Debugf("time(2) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
||||
//session.engine.logger.Debugf("time(2) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
||||
}
|
||||
if err != nil {
|
||||
x, err = time.ParseInLocation("2006-01-02 15:04:05.9999999 Z07:00", sdata, parseLoc)
|
||||
session.engine.logger.Debugf("time(3) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
||||
//session.engine.logger.Debugf("time(3) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
||||
}
|
||||
} else if len(sdata) == 19 && strings.Contains(sdata, "-") {
|
||||
x, err = time.ParseInLocation("2006-01-02 15:04:05", sdata, parseLoc)
|
||||
session.engine.logger.Debugf("time(4) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
||||
//session.engine.logger.Debugf("time(4) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
||||
} else if len(sdata) == 10 && sdata[4] == '-' && sdata[7] == '-' {
|
||||
x, err = time.ParseInLocation("2006-01-02", sdata, parseLoc)
|
||||
session.engine.logger.Debugf("time(5) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
||||
//session.engine.logger.Debugf("time(5) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
||||
} else if col.SQLType.Name == core.Time {
|
||||
if strings.Contains(sdata, " ") {
|
||||
ssd := strings.Split(sdata, " ")
|
||||
@ -68,7 +68,7 @@ func (session *Session) str2Time(col *core.Column, data string) (outTime time.Ti
|
||||
|
||||
st := fmt.Sprintf("2006-01-02 %v", sdata)
|
||||
x, err = time.ParseInLocation("2006-01-02 15:04:05", st, parseLoc)
|
||||
session.engine.logger.Debugf("time(6) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
||||
//session.engine.logger.Debugf("time(6) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
||||
} else {
|
||||
outErr = fmt.Errorf("unsupported time format %v", sdata)
|
||||
return
|
||||
|
6
vendor/github.com/go-xorm/xorm/session_delete.go
generated
vendored
6
vendor/github.com/go-xorm/xorm/session_delete.go
generated
vendored
@ -27,7 +27,7 @@ func (session *Session) cacheDelete(table *core.Table, tableName, sqlStr string,
|
||||
return ErrCacheFailed
|
||||
}
|
||||
|
||||
cacher := session.engine.getCacher2(table)
|
||||
cacher := session.engine.getCacher(tableName)
|
||||
pkColumns := table.PKColumns()
|
||||
ids, err := core.GetCacheSql(cacher, tableName, newsql, args)
|
||||
if err != nil {
|
||||
@ -79,7 +79,7 @@ func (session *Session) Delete(bean interface{}) (int64, error) {
|
||||
defer session.Close()
|
||||
}
|
||||
|
||||
if err := session.statement.setRefValue(rValue(bean)); err != nil {
|
||||
if err := session.statement.setRefBean(bean); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
@ -199,7 +199,7 @@ func (session *Session) Delete(bean interface{}) (int64, error) {
|
||||
})
|
||||
}
|
||||
|
||||
if cacher := session.engine.getCacher2(table); cacher != nil && session.statement.UseCache {
|
||||
if cacher := session.engine.getCacher(tableName); cacher != nil && session.statement.UseCache {
|
||||
session.cacheDelete(table, tableNameNoQuote, deleteSQL, argsForCache...)
|
||||
}
|
||||
|
||||
|
15
vendor/github.com/go-xorm/xorm/session_exist.go
generated
vendored
15
vendor/github.com/go-xorm/xorm/session_exist.go
generated
vendored
@ -10,6 +10,7 @@ import (
|
||||
"reflect"
|
||||
|
||||
"github.com/go-xorm/builder"
|
||||
"github.com/go-xorm/core"
|
||||
)
|
||||
|
||||
// Exist returns true if the record exist otherwise return false
|
||||
@ -35,10 +36,18 @@ func (session *Session) Exist(bean ...interface{}) (bool, error) {
|
||||
return false, err
|
||||
}
|
||||
|
||||
sqlStr = fmt.Sprintf("SELECT * FROM %s WHERE %s LIMIT 1", tableName, condSQL)
|
||||
if session.engine.dialect.DBType() == core.MSSQL {
|
||||
sqlStr = fmt.Sprintf("SELECT top 1 * FROM %s WHERE %s", tableName, condSQL)
|
||||
} else {
|
||||
sqlStr = fmt.Sprintf("SELECT * FROM %s WHERE %s LIMIT 1", tableName, condSQL)
|
||||
}
|
||||
args = condArgs
|
||||
} else {
|
||||
sqlStr = fmt.Sprintf("SELECT * FROM %s LIMIT 1", tableName)
|
||||
if session.engine.dialect.DBType() == core.MSSQL {
|
||||
sqlStr = fmt.Sprintf("SELECT top 1 * FROM %s", tableName)
|
||||
} else {
|
||||
sqlStr = fmt.Sprintf("SELECT * FROM %s LIMIT 1", tableName)
|
||||
}
|
||||
args = []interface{}{}
|
||||
}
|
||||
} else {
|
||||
@ -48,7 +57,7 @@ func (session *Session) Exist(bean ...interface{}) (bool, error) {
|
||||
}
|
||||
|
||||
if beanValue.Elem().Kind() == reflect.Struct {
|
||||
if err := session.statement.setRefValue(beanValue.Elem()); err != nil {
|
||||
if err := session.statement.setRefBean(bean[0]); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
53
vendor/github.com/go-xorm/xorm/session_find.go
generated
vendored
53
vendor/github.com/go-xorm/xorm/session_find.go
generated
vendored
@ -29,6 +29,39 @@ func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{})
|
||||
return session.find(rowsSlicePtr, condiBean...)
|
||||
}
|
||||
|
||||
// FindAndCount find the results and also return the counts
|
||||
func (session *Session) FindAndCount(rowsSlicePtr interface{}, condiBean ...interface{}) (int64, error) {
|
||||
if session.isAutoClose {
|
||||
defer session.Close()
|
||||
}
|
||||
|
||||
session.autoResetStatement = false
|
||||
err := session.find(rowsSlicePtr, condiBean...)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))
|
||||
if sliceValue.Kind() != reflect.Slice && sliceValue.Kind() != reflect.Map {
|
||||
return 0, errors.New("needs a pointer to a slice or a map")
|
||||
}
|
||||
|
||||
sliceElementType := sliceValue.Type().Elem()
|
||||
if sliceElementType.Kind() == reflect.Ptr {
|
||||
sliceElementType = sliceElementType.Elem()
|
||||
}
|
||||
session.autoResetStatement = true
|
||||
|
||||
if session.statement.selectStr != "" {
|
||||
session.statement.selectStr = ""
|
||||
}
|
||||
if session.statement.OrderStr != "" {
|
||||
session.statement.OrderStr = ""
|
||||
}
|
||||
|
||||
return session.Count(reflect.New(sliceElementType).Interface())
|
||||
}
|
||||
|
||||
func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{}) error {
|
||||
sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))
|
||||
if sliceValue.Kind() != reflect.Slice && sliceValue.Kind() != reflect.Map {
|
||||
@ -42,7 +75,7 @@ func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{})
|
||||
if sliceElementType.Kind() == reflect.Ptr {
|
||||
if sliceElementType.Elem().Kind() == reflect.Struct {
|
||||
pv := reflect.New(sliceElementType.Elem())
|
||||
if err := session.statement.setRefValue(pv.Elem()); err != nil {
|
||||
if err := session.statement.setRefValue(pv); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
@ -50,7 +83,7 @@ func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{})
|
||||
}
|
||||
} else if sliceElementType.Kind() == reflect.Struct {
|
||||
pv := reflect.New(sliceElementType)
|
||||
if err := session.statement.setRefValue(pv.Elem()); err != nil {
|
||||
if err := session.statement.setRefValue(pv); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
@ -102,7 +135,7 @@ func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{})
|
||||
if session.statement.JoinStr == "" {
|
||||
if columnStr == "" {
|
||||
if session.statement.GroupByStr != "" {
|
||||
columnStr = session.statement.Engine.Quote(strings.Replace(session.statement.GroupByStr, ",", session.engine.Quote(","), -1))
|
||||
columnStr = session.engine.quoteColumns(session.statement.GroupByStr)
|
||||
} else {
|
||||
columnStr = session.statement.genColumnStr()
|
||||
}
|
||||
@ -110,7 +143,7 @@ func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{})
|
||||
} else {
|
||||
if columnStr == "" {
|
||||
if session.statement.GroupByStr != "" {
|
||||
columnStr = session.statement.Engine.Quote(strings.Replace(session.statement.GroupByStr, ",", session.engine.Quote(","), -1))
|
||||
columnStr = session.engine.quoteColumns(session.statement.GroupByStr)
|
||||
} else {
|
||||
columnStr = "*"
|
||||
}
|
||||
@ -128,7 +161,7 @@ func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{})
|
||||
}
|
||||
|
||||
args = append(session.statement.joinArgs, condArgs...)
|
||||
sqlStr, err = session.statement.genSelectSQL(columnStr, condSQL)
|
||||
sqlStr, err = session.statement.genSelectSQL(columnStr, condSQL, true, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -143,7 +176,7 @@ func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{})
|
||||
}
|
||||
|
||||
if session.canCache() {
|
||||
if cacher := session.engine.getCacher2(table); cacher != nil &&
|
||||
if cacher := session.engine.getCacher(table.Name); cacher != nil &&
|
||||
!session.statement.IsDistinct &&
|
||||
!session.statement.unscoped {
|
||||
err = session.cacheFind(sliceElementType, sqlStr, rowsSlicePtr, args...)
|
||||
@ -288,6 +321,12 @@ func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr in
|
||||
return ErrCacheFailed
|
||||
}
|
||||
|
||||
tableName := session.statement.TableName()
|
||||
cacher := session.engine.getCacher(tableName)
|
||||
if cacher == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, filter := range session.engine.dialect.Filters() {
|
||||
sqlStr = filter.Do(sqlStr, session.engine.dialect, session.statement.RefTable)
|
||||
}
|
||||
@ -297,9 +336,7 @@ func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr in
|
||||
return ErrCacheFailed
|
||||
}
|
||||
|
||||
tableName := session.statement.TableName()
|
||||
table := session.statement.RefTable
|
||||
cacher := session.engine.getCacher2(table)
|
||||
ids, err := core.GetCacheSql(cacher, tableName, newsql, args)
|
||||
if err != nil {
|
||||
rows, err := session.queryRows(newsql, args...)
|
||||
|
42
vendor/github.com/go-xorm/xorm/session_get.go
generated
vendored
42
vendor/github.com/go-xorm/xorm/session_get.go
generated
vendored
@ -5,7 +5,9 @@
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
||||
@ -30,7 +32,7 @@ func (session *Session) get(bean interface{}) (bool, error) {
|
||||
}
|
||||
|
||||
if beanValue.Elem().Kind() == reflect.Struct {
|
||||
if err := session.statement.setRefValue(beanValue.Elem()); err != nil {
|
||||
if err := session.statement.setRefBean(bean); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
@ -56,7 +58,7 @@ func (session *Session) get(bean interface{}) (bool, error) {
|
||||
table := session.statement.RefTable
|
||||
|
||||
if session.canCache() && beanValue.Elem().Kind() == reflect.Struct {
|
||||
if cacher := session.engine.getCacher2(table); cacher != nil &&
|
||||
if cacher := session.engine.getCacher(table.Name); cacher != nil &&
|
||||
!session.statement.unscoped {
|
||||
has, err := session.cacheGet(bean, sqlStr, args...)
|
||||
if err != ErrCacheFailed {
|
||||
@ -65,7 +67,28 @@ func (session *Session) get(bean interface{}) (bool, error) {
|
||||
}
|
||||
}
|
||||
|
||||
return session.nocacheGet(beanValue.Elem().Kind(), table, bean, sqlStr, args...)
|
||||
context := session.statement.context
|
||||
if context != nil {
|
||||
res := context.Get(fmt.Sprintf("%v-%v", sqlStr, args))
|
||||
if res != nil {
|
||||
structValue := reflect.Indirect(reflect.ValueOf(bean))
|
||||
structValue.Set(reflect.Indirect(reflect.ValueOf(res)))
|
||||
session.lastSQL = ""
|
||||
session.lastSQLArgs = nil
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
has, err := session.nocacheGet(beanValue.Elem().Kind(), table, bean, sqlStr, args...)
|
||||
if err != nil || !has {
|
||||
return has, err
|
||||
}
|
||||
|
||||
if context != nil {
|
||||
context.Put(fmt.Sprintf("%v-%v", sqlStr, args), bean)
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (session *Session) nocacheGet(beanKind reflect.Kind, table *core.Table, bean interface{}, sqlStr string, args ...interface{}) (bool, error) {
|
||||
@ -76,9 +99,19 @@ func (session *Session) nocacheGet(beanKind reflect.Kind, table *core.Table, bea
|
||||
defer rows.Close()
|
||||
|
||||
if !rows.Next() {
|
||||
if rows.Err() != nil {
|
||||
return false, rows.Err()
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
switch bean.(type) {
|
||||
case sql.NullInt64, sql.NullBool, sql.NullFloat64, sql.NullString:
|
||||
return true, rows.Scan(&bean)
|
||||
case *sql.NullInt64, *sql.NullBool, *sql.NullFloat64, *sql.NullString:
|
||||
return true, rows.Scan(bean)
|
||||
}
|
||||
|
||||
switch beanKind {
|
||||
case reflect.Struct:
|
||||
fields, err := rows.Columns()
|
||||
@ -126,8 +159,9 @@ func (session *Session) cacheGet(bean interface{}, sqlStr string, args ...interf
|
||||
return false, ErrCacheFailed
|
||||
}
|
||||
|
||||
cacher := session.engine.getCacher2(session.statement.RefTable)
|
||||
tableName := session.statement.TableName()
|
||||
cacher := session.engine.getCacher(tableName)
|
||||
|
||||
session.engine.logger.Debug("[cacheGet] find sql:", newsql, args)
|
||||
table := session.statement.RefTable
|
||||
ids, err := core.GetCacheSql(cacher, tableName, newsql, args)
|
||||
|
172
vendor/github.com/go-xorm/xorm/session_insert.go
generated
vendored
172
vendor/github.com/go-xorm/xorm/session_insert.go
generated
vendored
@ -66,11 +66,12 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error
|
||||
return 0, errors.New("could not insert a empty slice")
|
||||
}
|
||||
|
||||
if err := session.statement.setRefValue(reflect.ValueOf(sliceValue.Index(0).Interface())); err != nil {
|
||||
if err := session.statement.setRefBean(sliceValue.Index(0).Interface()); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if len(session.statement.TableName()) <= 0 {
|
||||
tableName := session.statement.TableName()
|
||||
if len(tableName) <= 0 {
|
||||
return 0, ErrTableNotFound
|
||||
}
|
||||
|
||||
@ -115,15 +116,11 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error
|
||||
if col.IsDeleted {
|
||||
continue
|
||||
}
|
||||
if session.statement.ColumnStr != "" {
|
||||
if _, ok := getFlagForColumn(session.statement.columnMap, col); !ok {
|
||||
continue
|
||||
}
|
||||
if session.statement.omitColumnMap.contain(col.Name) {
|
||||
continue
|
||||
}
|
||||
if session.statement.OmitStr != "" {
|
||||
if _, ok := getFlagForColumn(session.statement.columnMap, col); ok {
|
||||
continue
|
||||
}
|
||||
if len(session.statement.columnMap) > 0 && !session.statement.columnMap.contain(col.Name) {
|
||||
continue
|
||||
}
|
||||
if (col.IsCreated || col.IsUpdated) && session.statement.UseAutoTime {
|
||||
val, t := session.engine.nowTime(col)
|
||||
@ -170,15 +167,11 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error
|
||||
if col.IsDeleted {
|
||||
continue
|
||||
}
|
||||
if session.statement.ColumnStr != "" {
|
||||
if _, ok := getFlagForColumn(session.statement.columnMap, col); !ok {
|
||||
continue
|
||||
}
|
||||
if session.statement.omitColumnMap.contain(col.Name) {
|
||||
continue
|
||||
}
|
||||
if session.statement.OmitStr != "" {
|
||||
if _, ok := getFlagForColumn(session.statement.columnMap, col); ok {
|
||||
continue
|
||||
}
|
||||
if len(session.statement.columnMap) > 0 && !session.statement.columnMap.contain(col.Name) {
|
||||
continue
|
||||
}
|
||||
if (col.IsCreated || col.IsUpdated) && session.statement.UseAutoTime {
|
||||
val, t := session.engine.nowTime(col)
|
||||
@ -211,38 +204,33 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error
|
||||
}
|
||||
cleanupProcessorsClosures(&session.beforeClosures)
|
||||
|
||||
var sql = "INSERT INTO %s (%v%v%v) VALUES (%v)"
|
||||
var statement string
|
||||
var tableName = session.statement.TableName()
|
||||
var sql string
|
||||
if session.engine.dialect.DBType() == core.ORACLE {
|
||||
sql = "INSERT ALL INTO %s (%v%v%v) VALUES (%v) SELECT 1 FROM DUAL"
|
||||
temp := fmt.Sprintf(") INTO %s (%v%v%v) VALUES (",
|
||||
session.engine.Quote(tableName),
|
||||
session.engine.QuoteStr(),
|
||||
strings.Join(colNames, session.engine.QuoteStr()+", "+session.engine.QuoteStr()),
|
||||
session.engine.QuoteStr())
|
||||
statement = fmt.Sprintf(sql,
|
||||
sql = fmt.Sprintf("INSERT ALL INTO %s (%v%v%v) VALUES (%v) SELECT 1 FROM DUAL",
|
||||
session.engine.Quote(tableName),
|
||||
session.engine.QuoteStr(),
|
||||
strings.Join(colNames, session.engine.QuoteStr()+", "+session.engine.QuoteStr()),
|
||||
session.engine.QuoteStr(),
|
||||
strings.Join(colMultiPlaces, temp))
|
||||
} else {
|
||||
statement = fmt.Sprintf(sql,
|
||||
sql = fmt.Sprintf("INSERT INTO %s (%v%v%v) VALUES (%v)",
|
||||
session.engine.Quote(tableName),
|
||||
session.engine.QuoteStr(),
|
||||
strings.Join(colNames, session.engine.QuoteStr()+", "+session.engine.QuoteStr()),
|
||||
session.engine.QuoteStr(),
|
||||
strings.Join(colMultiPlaces, "),("))
|
||||
}
|
||||
res, err := session.exec(statement, args...)
|
||||
res, err := session.exec(sql, args...)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if cacher := session.engine.getCacher2(table); cacher != nil && session.statement.UseCache {
|
||||
session.cacheInsert(table, tableName)
|
||||
}
|
||||
session.cacheInsert(tableName)
|
||||
|
||||
lenAfterClosures := len(session.afterClosures)
|
||||
for i := 0; i < size; i++ {
|
||||
@ -298,7 +286,7 @@ func (session *Session) InsertMulti(rowsSlicePtr interface{}) (int64, error) {
|
||||
}
|
||||
|
||||
func (session *Session) innerInsert(bean interface{}) (int64, error) {
|
||||
if err := session.statement.setRefValue(rValue(bean)); err != nil {
|
||||
if err := session.statement.setRefBean(bean); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if len(session.statement.TableName()) <= 0 {
|
||||
@ -316,8 +304,8 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
|
||||
if processor, ok := interface{}(bean).(BeforeInsertProcessor); ok {
|
||||
processor.BeforeInsert()
|
||||
}
|
||||
// --
|
||||
colNames, args, err := genCols(session.statement.RefTable, session, bean, false, false)
|
||||
|
||||
colNames, args, err := session.genInsertColumns(bean)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@ -400,11 +388,9 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
handleAfterInsertProcessorFunc(bean)
|
||||
defer handleAfterInsertProcessorFunc(bean)
|
||||
|
||||
if cacher := session.engine.getCacher2(table); cacher != nil && session.statement.UseCache {
|
||||
session.cacheInsert(table, tableName)
|
||||
}
|
||||
session.cacheInsert(tableName)
|
||||
|
||||
if table.Version != "" && session.statement.checkVersion {
|
||||
verValue, err := table.VersionColumn().ValueOf(bean)
|
||||
@ -445,11 +431,9 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
handleAfterInsertProcessorFunc(bean)
|
||||
defer handleAfterInsertProcessorFunc(bean)
|
||||
|
||||
if cacher := session.engine.getCacher2(table); cacher != nil && session.statement.UseCache {
|
||||
session.cacheInsert(table, tableName)
|
||||
}
|
||||
session.cacheInsert(tableName)
|
||||
|
||||
if table.Version != "" && session.statement.checkVersion {
|
||||
verValue, err := table.VersionColumn().ValueOf(bean)
|
||||
@ -490,9 +474,7 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
|
||||
|
||||
defer handleAfterInsertProcessorFunc(bean)
|
||||
|
||||
if cacher := session.engine.getCacher2(table); cacher != nil && session.statement.UseCache {
|
||||
session.cacheInsert(table, tableName)
|
||||
}
|
||||
session.cacheInsert(tableName)
|
||||
|
||||
if table.Version != "" && session.statement.checkVersion {
|
||||
verValue, err := table.VersionColumn().ValueOf(bean)
|
||||
@ -539,16 +521,104 @@ func (session *Session) InsertOne(bean interface{}) (int64, error) {
|
||||
return session.innerInsert(bean)
|
||||
}
|
||||
|
||||
func (session *Session) cacheInsert(table *core.Table, tables ...string) error {
|
||||
if table == nil {
|
||||
return ErrCacheFailed
|
||||
func (session *Session) cacheInsert(table string) error {
|
||||
if !session.statement.UseCache {
|
||||
return nil
|
||||
}
|
||||
|
||||
cacher := session.engine.getCacher2(table)
|
||||
for _, t := range tables {
|
||||
session.engine.logger.Debug("[cache] clear sql:", t)
|
||||
cacher.ClearIds(t)
|
||||
cacher := session.engine.getCacher(table)
|
||||
if cacher == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
session.engine.logger.Debug("[cache] clear sql:", table)
|
||||
cacher.ClearIds(table)
|
||||
return nil
|
||||
}
|
||||
|
||||
// genInsertColumns generates insert needed columns
|
||||
func (session *Session) genInsertColumns(bean interface{}) ([]string, []interface{}, error) {
|
||||
table := session.statement.RefTable
|
||||
colNames := make([]string, 0, len(table.ColumnsSeq()))
|
||||
args := make([]interface{}, 0, len(table.ColumnsSeq()))
|
||||
|
||||
for _, col := range table.Columns() {
|
||||
if col.MapType == core.ONLYFROMDB {
|
||||
continue
|
||||
}
|
||||
|
||||
if col.IsDeleted {
|
||||
continue
|
||||
}
|
||||
|
||||
if session.statement.omitColumnMap.contain(col.Name) {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(session.statement.columnMap) > 0 && !session.statement.columnMap.contain(col.Name) {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, ok := session.statement.incrColumns[col.Name]; ok {
|
||||
continue
|
||||
} else if _, ok := session.statement.decrColumns[col.Name]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
fieldValuePtr, err := col.ValueOf(bean)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
fieldValue := *fieldValuePtr
|
||||
|
||||
if col.IsAutoIncrement {
|
||||
switch fieldValue.Type().Kind() {
|
||||
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int, reflect.Int64:
|
||||
if fieldValue.Int() == 0 {
|
||||
continue
|
||||
}
|
||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint, reflect.Uint64:
|
||||
if fieldValue.Uint() == 0 {
|
||||
continue
|
||||
}
|
||||
case reflect.String:
|
||||
if len(fieldValue.String()) == 0 {
|
||||
continue
|
||||
}
|
||||
case reflect.Ptr:
|
||||
if fieldValue.Pointer() == 0 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// !evalphobia! set fieldValue as nil when column is nullable and zero-value
|
||||
if _, ok := getFlagForColumn(session.statement.nullableMap, col); ok {
|
||||
if col.Nullable && isZero(fieldValue.Interface()) {
|
||||
var nilValue *int
|
||||
fieldValue = reflect.ValueOf(nilValue)
|
||||
}
|
||||
}
|
||||
|
||||
if (col.IsCreated || col.IsUpdated) && session.statement.UseAutoTime /*&& isZero(fieldValue.Interface())*/ {
|
||||
// if time is non-empty, then set to auto time
|
||||
val, t := session.engine.nowTime(col)
|
||||
args = append(args, val)
|
||||
|
||||
var colName = col.Name
|
||||
session.afterClosures = append(session.afterClosures, func(bean interface{}) {
|
||||
col := table.GetColumn(colName)
|
||||
setColumnTime(bean, col, t)
|
||||
})
|
||||
} else if col.IsVersion && session.statement.checkVersion {
|
||||
args = append(args, 1)
|
||||
} else {
|
||||
arg, err := session.value2Interface(col, fieldValue)
|
||||
if err != nil {
|
||||
return colNames, args, err
|
||||
}
|
||||
args = append(args, arg)
|
||||
}
|
||||
|
||||
colNames = append(colNames, col.Name)
|
||||
}
|
||||
return colNames, args, nil
|
||||
}
|
||||
|
149
vendor/github.com/go-xorm/xorm/session_query.go
generated
vendored
149
vendor/github.com/go-xorm/xorm/session_query.go
generated
vendored
@ -8,17 +8,86 @@ import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-xorm/builder"
|
||||
"github.com/go-xorm/core"
|
||||
)
|
||||
|
||||
func (session *Session) genQuerySQL(sqlorArgs ...interface{}) (string, []interface{}, error) {
|
||||
if len(sqlorArgs) > 0 {
|
||||
return convertSQLOrArgs(sqlorArgs...)
|
||||
}
|
||||
|
||||
if session.statement.RawSQL != "" {
|
||||
return session.statement.RawSQL, session.statement.RawParams, nil
|
||||
}
|
||||
|
||||
if len(session.statement.TableName()) <= 0 {
|
||||
return "", nil, ErrTableNotFound
|
||||
}
|
||||
|
||||
var columnStr = session.statement.ColumnStr
|
||||
if len(session.statement.selectStr) > 0 {
|
||||
columnStr = session.statement.selectStr
|
||||
} else {
|
||||
if session.statement.JoinStr == "" {
|
||||
if columnStr == "" {
|
||||
if session.statement.GroupByStr != "" {
|
||||
columnStr = session.engine.quoteColumns(session.statement.GroupByStr)
|
||||
} else {
|
||||
columnStr = session.statement.genColumnStr()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if columnStr == "" {
|
||||
if session.statement.GroupByStr != "" {
|
||||
columnStr = session.engine.quoteColumns(session.statement.GroupByStr)
|
||||
} else {
|
||||
columnStr = "*"
|
||||
}
|
||||
}
|
||||
}
|
||||
if columnStr == "" {
|
||||
columnStr = "*"
|
||||
}
|
||||
}
|
||||
|
||||
if err := session.statement.processIDParam(); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
condSQL, condArgs, err := builder.ToSQL(session.statement.cond)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
args := append(session.statement.joinArgs, condArgs...)
|
||||
sqlStr, err := session.statement.genSelectSQL(columnStr, condSQL, true, true)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
// for mssql and use limit
|
||||
qs := strings.Count(sqlStr, "?")
|
||||
if len(args)*2 == qs {
|
||||
args = append(args, args...)
|
||||
}
|
||||
|
||||
return sqlStr, args, nil
|
||||
}
|
||||
|
||||
// Query runs a raw sql and return records as []map[string][]byte
|
||||
func (session *Session) Query(sqlStr string, args ...interface{}) ([]map[string][]byte, error) {
|
||||
func (session *Session) Query(sqlorArgs ...interface{}) ([]map[string][]byte, error) {
|
||||
if session.isAutoClose {
|
||||
defer session.Close()
|
||||
}
|
||||
|
||||
sqlStr, args, err := session.genQuerySQL(sqlorArgs...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return session.queryBytes(sqlStr, args...)
|
||||
}
|
||||
|
||||
@ -97,6 +166,34 @@ func row2mapStr(rows *core.Rows, fields []string) (resultsMap map[string]string,
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func row2sliceStr(rows *core.Rows, fields []string) (results []string, err error) {
|
||||
result := make([]string, 0, len(fields))
|
||||
scanResultContainers := make([]interface{}, len(fields))
|
||||
for i := 0; i < len(fields); i++ {
|
||||
var scanResultContainer interface{}
|
||||
scanResultContainers[i] = &scanResultContainer
|
||||
}
|
||||
if err := rows.Scan(scanResultContainers...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i := 0; i < len(fields); i++ {
|
||||
rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[i]))
|
||||
// if row is null then as empty string
|
||||
if rawValue.Interface() == nil {
|
||||
result = append(result, "")
|
||||
continue
|
||||
}
|
||||
|
||||
if data, err := value2String(&rawValue); err == nil {
|
||||
result = append(result, data)
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func rows2Strings(rows *core.Rows) (resultsSlice []map[string]string, err error) {
|
||||
fields, err := rows.Columns()
|
||||
if err != nil {
|
||||
@ -113,12 +210,33 @@ func rows2Strings(rows *core.Rows) (resultsSlice []map[string]string, err error)
|
||||
return resultsSlice, nil
|
||||
}
|
||||
|
||||
func rows2SliceString(rows *core.Rows) (resultsSlice [][]string, err error) {
|
||||
fields, err := rows.Columns()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for rows.Next() {
|
||||
record, err := row2sliceStr(rows, fields)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resultsSlice = append(resultsSlice, record)
|
||||
}
|
||||
|
||||
return resultsSlice, nil
|
||||
}
|
||||
|
||||
// QueryString runs a raw sql and return records as []map[string]string
|
||||
func (session *Session) QueryString(sqlStr string, args ...interface{}) ([]map[string]string, error) {
|
||||
func (session *Session) QueryString(sqlorArgs ...interface{}) ([]map[string]string, error) {
|
||||
if session.isAutoClose {
|
||||
defer session.Close()
|
||||
}
|
||||
|
||||
sqlStr, args, err := session.genQuerySQL(sqlorArgs...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rows, err := session.queryRows(sqlStr, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -128,6 +246,26 @@ func (session *Session) QueryString(sqlStr string, args ...interface{}) ([]map[s
|
||||
return rows2Strings(rows)
|
||||
}
|
||||
|
||||
// QuerySliceString runs a raw sql and return records as [][]string
|
||||
func (session *Session) QuerySliceString(sqlorArgs ...interface{}) ([][]string, error) {
|
||||
if session.isAutoClose {
|
||||
defer session.Close()
|
||||
}
|
||||
|
||||
sqlStr, args, err := session.genQuerySQL(sqlorArgs...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rows, err := session.queryRows(sqlStr, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
return rows2SliceString(rows)
|
||||
}
|
||||
|
||||
func row2mapInterface(rows *core.Rows, fields []string) (resultsMap map[string]interface{}, err error) {
|
||||
resultsMap = make(map[string]interface{}, len(fields))
|
||||
scanResultContainers := make([]interface{}, len(fields))
|
||||
@ -162,11 +300,16 @@ func rows2Interfaces(rows *core.Rows) (resultsSlice []map[string]interface{}, er
|
||||
}
|
||||
|
||||
// QueryInterface runs a raw sql and return records as []map[string]interface{}
|
||||
func (session *Session) QueryInterface(sqlStr string, args ...interface{}) ([]map[string]interface{}, error) {
|
||||
func (session *Session) QueryInterface(sqlorArgs ...interface{}) ([]map[string]interface{}, error) {
|
||||
if session.isAutoClose {
|
||||
defer session.Close()
|
||||
}
|
||||
|
||||
sqlStr, args, err := session.genQuerySQL(sqlorArgs...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rows, err := session.queryRows(sqlStr, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
39
vendor/github.com/go-xorm/xorm/session_raw.go
generated
vendored
39
vendor/github.com/go-xorm/xorm/session_raw.go
generated
vendored
@ -9,6 +9,7 @@ import (
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/go-xorm/builder"
|
||||
"github.com/go-xorm/core"
|
||||
)
|
||||
|
||||
@ -47,9 +48,16 @@ func (session *Session) queryRows(sqlStr string, args ...interface{}) (*core.Row
|
||||
}
|
||||
|
||||
if session.isAutoCommit {
|
||||
var db *core.DB
|
||||
if session.engine.engineGroup != nil {
|
||||
db = session.engine.engineGroup.Slave().DB()
|
||||
} else {
|
||||
db = session.DB()
|
||||
}
|
||||
|
||||
if session.prepareStmt {
|
||||
// don't clear stmt since session will cache them
|
||||
stmt, err := session.doPrepare(sqlStr)
|
||||
stmt, err := session.doPrepare(db, sqlStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -61,7 +69,7 @@ func (session *Session) queryRows(sqlStr string, args ...interface{}) (*core.Row
|
||||
return rows, nil
|
||||
}
|
||||
|
||||
rows, err := session.DB().Query(sqlStr, args...)
|
||||
rows, err := db.Query(sqlStr, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -171,7 +179,7 @@ func (session *Session) exec(sqlStr string, args ...interface{}) (sql.Result, er
|
||||
}
|
||||
|
||||
if session.prepareStmt {
|
||||
stmt, err := session.doPrepare(sqlStr)
|
||||
stmt, err := session.doPrepare(session.DB(), sqlStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -186,11 +194,34 @@ func (session *Session) exec(sqlStr string, args ...interface{}) (sql.Result, er
|
||||
return session.DB().Exec(sqlStr, args...)
|
||||
}
|
||||
|
||||
func convertSQLOrArgs(sqlorArgs ...interface{}) (string, []interface{}, error) {
|
||||
switch sqlorArgs[0].(type) {
|
||||
case string:
|
||||
return sqlorArgs[0].(string), sqlorArgs[1:], nil
|
||||
case *builder.Builder:
|
||||
return sqlorArgs[0].(*builder.Builder).ToSQL()
|
||||
case builder.Builder:
|
||||
bd := sqlorArgs[0].(builder.Builder)
|
||||
return bd.ToSQL()
|
||||
}
|
||||
|
||||
return "", nil, ErrUnSupportedType
|
||||
}
|
||||
|
||||
// Exec raw sql
|
||||
func (session *Session) Exec(sqlStr string, args ...interface{}) (sql.Result, error) {
|
||||
func (session *Session) Exec(sqlorArgs ...interface{}) (sql.Result, error) {
|
||||
if session.isAutoClose {
|
||||
defer session.Close()
|
||||
}
|
||||
|
||||
if len(sqlorArgs) == 0 {
|
||||
return nil, ErrUnSupportedType
|
||||
}
|
||||
|
||||
sqlStr, args, err := convertSQLOrArgs(sqlorArgs...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return session.exec(sqlStr, args...)
|
||||
}
|
||||
|
87
vendor/github.com/go-xorm/xorm/session_schema.go
generated
vendored
87
vendor/github.com/go-xorm/xorm/session_schema.go
generated
vendored
@ -6,9 +6,7 @@ package xorm
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/go-xorm/core"
|
||||
@ -34,8 +32,7 @@ func (session *Session) CreateTable(bean interface{}) error {
|
||||
}
|
||||
|
||||
func (session *Session) createTable(bean interface{}) error {
|
||||
v := rValue(bean)
|
||||
if err := session.statement.setRefValue(v); err != nil {
|
||||
if err := session.statement.setRefBean(bean); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -54,8 +51,7 @@ func (session *Session) CreateIndexes(bean interface{}) error {
|
||||
}
|
||||
|
||||
func (session *Session) createIndexes(bean interface{}) error {
|
||||
v := rValue(bean)
|
||||
if err := session.statement.setRefValue(v); err != nil {
|
||||
if err := session.statement.setRefBean(bean); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -78,8 +74,7 @@ func (session *Session) CreateUniques(bean interface{}) error {
|
||||
}
|
||||
|
||||
func (session *Session) createUniques(bean interface{}) error {
|
||||
v := rValue(bean)
|
||||
if err := session.statement.setRefValue(v); err != nil {
|
||||
if err := session.statement.setRefBean(bean); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -103,8 +98,7 @@ func (session *Session) DropIndexes(bean interface{}) error {
|
||||
}
|
||||
|
||||
func (session *Session) dropIndexes(bean interface{}) error {
|
||||
v := rValue(bean)
|
||||
if err := session.statement.setRefValue(v); err != nil {
|
||||
if err := session.statement.setRefBean(bean); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -128,11 +122,7 @@ func (session *Session) DropTable(beanOrTableName interface{}) error {
|
||||
}
|
||||
|
||||
func (session *Session) dropTable(beanOrTableName interface{}) error {
|
||||
tableName, err := session.engine.tableName(beanOrTableName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tableName := session.engine.TableName(beanOrTableName)
|
||||
var needDrop = true
|
||||
if !session.engine.dialect.SupportDropIfExists() {
|
||||
sqlStr, args := session.engine.dialect.TableCheckSql(tableName)
|
||||
@ -144,8 +134,8 @@ func (session *Session) dropTable(beanOrTableName interface{}) error {
|
||||
}
|
||||
|
||||
if needDrop {
|
||||
sqlStr := session.engine.Dialect().DropTableSql(tableName)
|
||||
_, err = session.exec(sqlStr)
|
||||
sqlStr := session.engine.Dialect().DropTableSql(session.engine.TableName(tableName, true))
|
||||
_, err := session.exec(sqlStr)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@ -157,10 +147,7 @@ func (session *Session) IsTableExist(beanOrTableName interface{}) (bool, error)
|
||||
defer session.Close()
|
||||
}
|
||||
|
||||
tableName, err := session.engine.tableName(beanOrTableName)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
tableName := session.engine.TableName(beanOrTableName)
|
||||
|
||||
return session.isTableExist(tableName)
|
||||
}
|
||||
@ -173,24 +160,15 @@ func (session *Session) isTableExist(tableName string) (bool, error) {
|
||||
|
||||
// IsTableEmpty if table have any records
|
||||
func (session *Session) IsTableEmpty(bean interface{}) (bool, error) {
|
||||
v := rValue(bean)
|
||||
t := v.Type()
|
||||
|
||||
if t.Kind() == reflect.String {
|
||||
if session.isAutoClose {
|
||||
defer session.Close()
|
||||
}
|
||||
return session.isTableEmpty(bean.(string))
|
||||
} else if t.Kind() == reflect.Struct {
|
||||
rows, err := session.Count(bean)
|
||||
return rows == 0, err
|
||||
if session.isAutoClose {
|
||||
defer session.Close()
|
||||
}
|
||||
return false, errors.New("bean should be a struct or struct's point")
|
||||
return session.isTableEmpty(session.engine.TableName(bean))
|
||||
}
|
||||
|
||||
func (session *Session) isTableEmpty(tableName string) (bool, error) {
|
||||
var total int64
|
||||
sqlStr := fmt.Sprintf("select count(*) from %s", session.engine.Quote(tableName))
|
||||
sqlStr := fmt.Sprintf("select count(*) from %s", session.engine.Quote(session.engine.TableName(tableName, true)))
|
||||
err := session.queryRow(sqlStr).Scan(&total)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
@ -255,6 +233,12 @@ func (session *Session) Sync2(beans ...interface{}) error {
|
||||
return err
|
||||
}
|
||||
|
||||
session.autoResetStatement = false
|
||||
defer func() {
|
||||
session.autoResetStatement = true
|
||||
session.resetStatement()
|
||||
}()
|
||||
|
||||
var structTables []*core.Table
|
||||
|
||||
for _, bean := range beans {
|
||||
@ -264,7 +248,8 @@ func (session *Session) Sync2(beans ...interface{}) error {
|
||||
return err
|
||||
}
|
||||
structTables = append(structTables, table)
|
||||
var tbName = session.tbNameNoSchema(table)
|
||||
tbName := engine.TableName(bean)
|
||||
tbNameWithSchema := engine.TableName(tbName, true)
|
||||
|
||||
var oriTable *core.Table
|
||||
for _, tb := range tables {
|
||||
@ -309,32 +294,32 @@ func (session *Session) Sync2(beans ...interface{}) error {
|
||||
if engine.dialect.DBType() == core.MYSQL ||
|
||||
engine.dialect.DBType() == core.POSTGRES {
|
||||
engine.logger.Infof("Table %s column %s change type from %s to %s\n",
|
||||
tbName, col.Name, curType, expectedType)
|
||||
_, err = session.exec(engine.dialect.ModifyColumnSql(table.Name, col))
|
||||
tbNameWithSchema, col.Name, curType, expectedType)
|
||||
_, err = session.exec(engine.dialect.ModifyColumnSql(tbNameWithSchema, col))
|
||||
} else {
|
||||
engine.logger.Warnf("Table %s column %s db type is %s, struct type is %s\n",
|
||||
tbName, col.Name, curType, expectedType)
|
||||
tbNameWithSchema, col.Name, curType, expectedType)
|
||||
}
|
||||
} else if strings.HasPrefix(curType, core.Varchar) && strings.HasPrefix(expectedType, core.Varchar) {
|
||||
if engine.dialect.DBType() == core.MYSQL {
|
||||
if oriCol.Length < col.Length {
|
||||
engine.logger.Infof("Table %s column %s change type from varchar(%d) to varchar(%d)\n",
|
||||
tbName, col.Name, oriCol.Length, col.Length)
|
||||
_, err = session.exec(engine.dialect.ModifyColumnSql(table.Name, col))
|
||||
tbNameWithSchema, col.Name, oriCol.Length, col.Length)
|
||||
_, err = session.exec(engine.dialect.ModifyColumnSql(tbNameWithSchema, col))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if !(strings.HasPrefix(curType, expectedType) && curType[len(expectedType)] == '(') {
|
||||
engine.logger.Warnf("Table %s column %s db type is %s, struct type is %s",
|
||||
tbName, col.Name, curType, expectedType)
|
||||
tbNameWithSchema, col.Name, curType, expectedType)
|
||||
}
|
||||
}
|
||||
} else if expectedType == core.Varchar {
|
||||
if engine.dialect.DBType() == core.MYSQL {
|
||||
if oriCol.Length < col.Length {
|
||||
engine.logger.Infof("Table %s column %s change type from varchar(%d) to varchar(%d)\n",
|
||||
tbName, col.Name, oriCol.Length, col.Length)
|
||||
_, err = session.exec(engine.dialect.ModifyColumnSql(table.Name, col))
|
||||
tbNameWithSchema, col.Name, oriCol.Length, col.Length)
|
||||
_, err = session.exec(engine.dialect.ModifyColumnSql(tbNameWithSchema, col))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -348,7 +333,7 @@ func (session *Session) Sync2(beans ...interface{}) error {
|
||||
}
|
||||
} else {
|
||||
session.statement.RefTable = table
|
||||
session.statement.tableName = tbName
|
||||
session.statement.tableName = tbNameWithSchema
|
||||
err = session.addColumn(col.Name)
|
||||
}
|
||||
if err != nil {
|
||||
@ -371,7 +356,7 @@ func (session *Session) Sync2(beans ...interface{}) error {
|
||||
|
||||
if oriIndex != nil {
|
||||
if oriIndex.Type != index.Type {
|
||||
sql := engine.dialect.DropIndexSql(tbName, oriIndex)
|
||||
sql := engine.dialect.DropIndexSql(tbNameWithSchema, oriIndex)
|
||||
_, err = session.exec(sql)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -387,7 +372,7 @@ func (session *Session) Sync2(beans ...interface{}) error {
|
||||
|
||||
for name2, index2 := range oriTable.Indexes {
|
||||
if _, ok := foundIndexNames[name2]; !ok {
|
||||
sql := engine.dialect.DropIndexSql(tbName, index2)
|
||||
sql := engine.dialect.DropIndexSql(tbNameWithSchema, index2)
|
||||
_, err = session.exec(sql)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -398,12 +383,12 @@ func (session *Session) Sync2(beans ...interface{}) error {
|
||||
for name, index := range addedNames {
|
||||
if index.Type == core.UniqueType {
|
||||
session.statement.RefTable = table
|
||||
session.statement.tableName = tbName
|
||||
err = session.addUnique(tbName, name)
|
||||
session.statement.tableName = tbNameWithSchema
|
||||
err = session.addUnique(tbNameWithSchema, name)
|
||||
} else if index.Type == core.IndexType {
|
||||
session.statement.RefTable = table
|
||||
session.statement.tableName = tbName
|
||||
err = session.addIndex(tbName, name)
|
||||
session.statement.tableName = tbNameWithSchema
|
||||
err = session.addIndex(tbNameWithSchema, name)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
@ -428,7 +413,7 @@ func (session *Session) Sync2(beans ...interface{}) error {
|
||||
|
||||
for _, colName := range table.ColumnsSeq() {
|
||||
if oriTable.GetColumn(colName) == nil {
|
||||
engine.logger.Warnf("Table %s has column %s but struct has not related field", table.Name, colName)
|
||||
engine.logger.Warnf("Table %s has column %s but struct has not related field", engine.TableName(table.Name, true), colName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
2
vendor/github.com/go-xorm/xorm/session_tx.go
generated
vendored
2
vendor/github.com/go-xorm/xorm/session_tx.go
generated
vendored
@ -24,6 +24,7 @@ func (session *Session) Rollback() error {
|
||||
if !session.isAutoCommit && !session.isCommitedOrRollbacked {
|
||||
session.saveLastSQL(session.engine.dialect.RollBackStr())
|
||||
session.isCommitedOrRollbacked = true
|
||||
session.isAutoCommit = true
|
||||
return session.tx.Rollback()
|
||||
}
|
||||
return nil
|
||||
@ -34,6 +35,7 @@ func (session *Session) Commit() error {
|
||||
if !session.isAutoCommit && !session.isCommitedOrRollbacked {
|
||||
session.saveLastSQL("COMMIT")
|
||||
session.isCommitedOrRollbacked = true
|
||||
session.isAutoCommit = true
|
||||
var err error
|
||||
if err = session.tx.Commit(); err == nil {
|
||||
// handle processors after tx committed
|
||||
|
136
vendor/github.com/go-xorm/xorm/session_update.go
generated
vendored
136
vendor/github.com/go-xorm/xorm/session_update.go
generated
vendored
@ -40,7 +40,7 @@ func (session *Session) cacheUpdate(table *core.Table, tableName, sqlStr string,
|
||||
}
|
||||
}
|
||||
|
||||
cacher := session.engine.getCacher2(table)
|
||||
cacher := session.engine.getCacher(tableName)
|
||||
session.engine.logger.Debug("[cacheUpdate] get cache sql", newsql, args[nStart:])
|
||||
ids, err := core.GetCacheSql(cacher, tableName, newsql, args[nStart:])
|
||||
if err != nil {
|
||||
@ -167,7 +167,7 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
|
||||
var isMap = t.Kind() == reflect.Map
|
||||
var isStruct = t.Kind() == reflect.Struct
|
||||
if isStruct {
|
||||
if err := session.statement.setRefValue(v); err != nil {
|
||||
if err := session.statement.setRefBean(bean); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
@ -176,12 +176,10 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
|
||||
}
|
||||
|
||||
if session.statement.ColumnStr == "" {
|
||||
colNames, args = buildUpdates(session.engine, session.statement.RefTable, bean, false, false,
|
||||
false, false, session.statement.allUseBool, session.statement.useAllCols,
|
||||
session.statement.mustColumnMap, session.statement.nullableMap,
|
||||
session.statement.columnMap, true, session.statement.unscoped)
|
||||
colNames, args = session.statement.buildUpdates(bean, false, false,
|
||||
false, false, true)
|
||||
} else {
|
||||
colNames, args, err = genCols(session.statement.RefTable, session, bean, true, true)
|
||||
colNames, args, err = session.genUpdateColumns(bean)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@ -202,7 +200,8 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
|
||||
table := session.statement.RefTable
|
||||
|
||||
if session.statement.UseAutoTime && table != nil && table.Updated != "" {
|
||||
if _, ok := session.statement.columnMap[strings.ToLower(table.Updated)]; !ok {
|
||||
if !session.statement.columnMap.contain(table.Updated) &&
|
||||
!session.statement.omitColumnMap.contain(table.Updated) {
|
||||
colNames = append(colNames, session.engine.Quote(table.Updated)+" = ?")
|
||||
col := table.UpdatedColumn()
|
||||
val, t := session.engine.nowTime(col)
|
||||
@ -242,10 +241,23 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
|
||||
|
||||
var autoCond builder.Cond
|
||||
if !session.statement.noAutoCondition && len(condiBean) > 0 {
|
||||
var err error
|
||||
autoCond, err = session.statement.buildConds(session.statement.RefTable, condiBean[0], true, true, false, true, false)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
if c, ok := condiBean[0].(map[string]interface{}); ok {
|
||||
autoCond = builder.Eq(c)
|
||||
} else {
|
||||
ct := reflect.TypeOf(condiBean[0])
|
||||
k := ct.Kind()
|
||||
if k == reflect.Ptr {
|
||||
k = ct.Elem().Kind()
|
||||
}
|
||||
if k == reflect.Struct {
|
||||
var err error
|
||||
autoCond, err = session.statement.buildConds(session.statement.RefTable, condiBean[0], true, true, false, true, false)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
} else {
|
||||
return 0, ErrConditionType
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -349,12 +361,11 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
|
||||
}
|
||||
}
|
||||
|
||||
if table != nil {
|
||||
if cacher := session.engine.getCacher2(table); cacher != nil && session.statement.UseCache {
|
||||
//session.cacheUpdate(table, tableName, sqlStr, args...)
|
||||
cacher.ClearIds(tableName)
|
||||
cacher.ClearBeans(tableName)
|
||||
}
|
||||
if cacher := session.engine.getCacher(tableName); cacher != nil && session.statement.UseCache {
|
||||
//session.cacheUpdate(table, tableName, sqlStr, args...)
|
||||
session.engine.logger.Debug("[cacheUpdate] clear table ", tableName)
|
||||
cacher.ClearIds(tableName)
|
||||
cacher.ClearBeans(tableName)
|
||||
}
|
||||
|
||||
// handle after update processors
|
||||
@ -389,3 +400,92 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
|
||||
|
||||
return res.RowsAffected()
|
||||
}
|
||||
|
||||
func (session *Session) genUpdateColumns(bean interface{}) ([]string, []interface{}, error) {
|
||||
table := session.statement.RefTable
|
||||
colNames := make([]string, 0, len(table.ColumnsSeq()))
|
||||
args := make([]interface{}, 0, len(table.ColumnsSeq()))
|
||||
|
||||
for _, col := range table.Columns() {
|
||||
if !col.IsVersion && !col.IsCreated && !col.IsUpdated {
|
||||
if session.statement.omitColumnMap.contain(col.Name) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if col.MapType == core.ONLYFROMDB {
|
||||
continue
|
||||
}
|
||||
|
||||
fieldValuePtr, err := col.ValueOf(bean)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
fieldValue := *fieldValuePtr
|
||||
|
||||
if col.IsAutoIncrement {
|
||||
switch fieldValue.Type().Kind() {
|
||||
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int, reflect.Int64:
|
||||
if fieldValue.Int() == 0 {
|
||||
continue
|
||||
}
|
||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint, reflect.Uint64:
|
||||
if fieldValue.Uint() == 0 {
|
||||
continue
|
||||
}
|
||||
case reflect.String:
|
||||
if len(fieldValue.String()) == 0 {
|
||||
continue
|
||||
}
|
||||
case reflect.Ptr:
|
||||
if fieldValue.Pointer() == 0 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (col.IsDeleted && !session.statement.unscoped) || col.IsCreated {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(session.statement.columnMap) > 0 {
|
||||
if !session.statement.columnMap.contain(col.Name) {
|
||||
continue
|
||||
} else if _, ok := session.statement.incrColumns[col.Name]; ok {
|
||||
continue
|
||||
} else if _, ok := session.statement.decrColumns[col.Name]; ok {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// !evalphobia! set fieldValue as nil when column is nullable and zero-value
|
||||
if _, ok := getFlagForColumn(session.statement.nullableMap, col); ok {
|
||||
if col.Nullable && isZero(fieldValue.Interface()) {
|
||||
var nilValue *int
|
||||
fieldValue = reflect.ValueOf(nilValue)
|
||||
}
|
||||
}
|
||||
|
||||
if col.IsUpdated && session.statement.UseAutoTime /*&& isZero(fieldValue.Interface())*/ {
|
||||
// if time is non-empty, then set to auto time
|
||||
val, t := session.engine.nowTime(col)
|
||||
args = append(args, val)
|
||||
|
||||
var colName = col.Name
|
||||
session.afterClosures = append(session.afterClosures, func(bean interface{}) {
|
||||
col := table.GetColumn(colName)
|
||||
setColumnTime(bean, col, t)
|
||||
})
|
||||
} else if col.IsVersion && session.statement.checkVersion {
|
||||
args = append(args, 1)
|
||||
} else {
|
||||
arg, err := session.value2Interface(col, fieldValue)
|
||||
if err != nil {
|
||||
return colNames, args, err
|
||||
}
|
||||
args = append(args, arg)
|
||||
}
|
||||
|
||||
colNames = append(colNames, session.engine.Quote(col.Name)+" = ?")
|
||||
}
|
||||
return colNames, args, nil
|
||||
}
|
||||
|
298
vendor/github.com/go-xorm/xorm/statement.go
generated
vendored
298
vendor/github.com/go-xorm/xorm/statement.go
generated
vendored
@ -5,7 +5,6 @@
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
@ -18,21 +17,6 @@ import (
|
||||
"github.com/go-xorm/core"
|
||||
)
|
||||
|
||||
type incrParam struct {
|
||||
colName string
|
||||
arg interface{}
|
||||
}
|
||||
|
||||
type decrParam struct {
|
||||
colName string
|
||||
arg interface{}
|
||||
}
|
||||
|
||||
type exprParam struct {
|
||||
colName string
|
||||
expr string
|
||||
}
|
||||
|
||||
// Statement save all the sql info for executing SQL
|
||||
type Statement struct {
|
||||
RefTable *core.Table
|
||||
@ -47,7 +31,6 @@ type Statement struct {
|
||||
HavingStr string
|
||||
ColumnStr string
|
||||
selectStr string
|
||||
columnMap map[string]bool
|
||||
useAllCols bool
|
||||
OmitStr string
|
||||
AltTableName string
|
||||
@ -67,6 +50,8 @@ type Statement struct {
|
||||
allUseBool bool
|
||||
checkVersion bool
|
||||
unscoped bool
|
||||
columnMap columnMap
|
||||
omitColumnMap columnMap
|
||||
mustColumnMap map[string]bool
|
||||
nullableMap map[string]bool
|
||||
incrColumns map[string]incrParam
|
||||
@ -74,6 +59,7 @@ type Statement struct {
|
||||
exprColumns map[string]exprParam
|
||||
cond builder.Cond
|
||||
bufferSize int
|
||||
context ContextCache
|
||||
}
|
||||
|
||||
// Init reset all the statement's fields
|
||||
@ -89,7 +75,8 @@ func (statement *Statement) Init() {
|
||||
statement.HavingStr = ""
|
||||
statement.ColumnStr = ""
|
||||
statement.OmitStr = ""
|
||||
statement.columnMap = make(map[string]bool)
|
||||
statement.columnMap = columnMap{}
|
||||
statement.omitColumnMap = columnMap{}
|
||||
statement.AltTableName = ""
|
||||
statement.tableName = ""
|
||||
statement.idParam = nil
|
||||
@ -113,6 +100,7 @@ func (statement *Statement) Init() {
|
||||
statement.exprColumns = make(map[string]exprParam)
|
||||
statement.cond = builder.NewCond()
|
||||
statement.bufferSize = 0
|
||||
statement.context = nil
|
||||
}
|
||||
|
||||
// NoAutoCondition if you do not want convert bean's field as query condition, then use this function
|
||||
@ -160,6 +148,9 @@ func (statement *Statement) And(query interface{}, args ...interface{}) *Stateme
|
||||
case string:
|
||||
cond := builder.Expr(query.(string), args...)
|
||||
statement.cond = statement.cond.And(cond)
|
||||
case map[string]interface{}:
|
||||
cond := builder.Eq(query.(map[string]interface{}))
|
||||
statement.cond = statement.cond.And(cond)
|
||||
case builder.Cond:
|
||||
cond := query.(builder.Cond)
|
||||
statement.cond = statement.cond.And(cond)
|
||||
@ -181,6 +172,9 @@ func (statement *Statement) Or(query interface{}, args ...interface{}) *Statemen
|
||||
case string:
|
||||
cond := builder.Expr(query.(string), args...)
|
||||
statement.cond = statement.cond.Or(cond)
|
||||
case map[string]interface{}:
|
||||
cond := builder.Eq(query.(map[string]interface{}))
|
||||
statement.cond = statement.cond.Or(cond)
|
||||
case builder.Cond:
|
||||
cond := query.(builder.Cond)
|
||||
statement.cond = statement.cond.Or(cond)
|
||||
@ -215,34 +209,33 @@ func (statement *Statement) setRefValue(v reflect.Value) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
statement.tableName = statement.Engine.tbName(v)
|
||||
statement.tableName = statement.Engine.TableName(v, true)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Table tempororily set table name, the parameter could be a string or a pointer of struct
|
||||
func (statement *Statement) Table(tableNameOrBean interface{}) *Statement {
|
||||
v := rValue(tableNameOrBean)
|
||||
t := v.Type()
|
||||
if t.Kind() == reflect.String {
|
||||
statement.AltTableName = tableNameOrBean.(string)
|
||||
} else if t.Kind() == reflect.Struct {
|
||||
var err error
|
||||
statement.RefTable, err = statement.Engine.autoMapType(v)
|
||||
if err != nil {
|
||||
statement.Engine.logger.Error(err)
|
||||
return statement
|
||||
}
|
||||
statement.AltTableName = statement.Engine.tbName(v)
|
||||
func (statement *Statement) setRefBean(bean interface{}) error {
|
||||
var err error
|
||||
statement.RefTable, err = statement.Engine.autoMapType(rValue(bean))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return statement
|
||||
statement.tableName = statement.Engine.TableName(bean, true)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Auto generating update columnes and values according a struct
|
||||
func buildUpdates(engine *Engine, table *core.Table, bean interface{},
|
||||
includeVersion bool, includeUpdated bool, includeNil bool,
|
||||
includeAutoIncr bool, allUseBool bool, useAllCols bool,
|
||||
mustColumnMap map[string]bool, nullableMap map[string]bool,
|
||||
columnMap map[string]bool, update, unscoped bool) ([]string, []interface{}) {
|
||||
func (statement *Statement) buildUpdates(bean interface{},
|
||||
includeVersion, includeUpdated, includeNil,
|
||||
includeAutoIncr, update bool) ([]string, []interface{}) {
|
||||
engine := statement.Engine
|
||||
table := statement.RefTable
|
||||
allUseBool := statement.allUseBool
|
||||
useAllCols := statement.useAllCols
|
||||
mustColumnMap := statement.mustColumnMap
|
||||
nullableMap := statement.nullableMap
|
||||
columnMap := statement.columnMap
|
||||
omitColumnMap := statement.omitColumnMap
|
||||
unscoped := statement.unscoped
|
||||
|
||||
var colNames = make([]string, 0)
|
||||
var args = make([]interface{}, 0)
|
||||
@ -262,7 +255,14 @@ func buildUpdates(engine *Engine, table *core.Table, bean interface{},
|
||||
if col.IsDeleted && !unscoped {
|
||||
continue
|
||||
}
|
||||
if use, ok := columnMap[strings.ToLower(col.Name)]; ok && !use {
|
||||
if omitColumnMap.contain(col.Name) {
|
||||
continue
|
||||
}
|
||||
if len(columnMap) > 0 && !columnMap.contain(col.Name) {
|
||||
continue
|
||||
}
|
||||
|
||||
if col.MapType == core.ONLYFROMDB {
|
||||
continue
|
||||
}
|
||||
|
||||
@ -598,17 +598,10 @@ func (statement *Statement) col2NewColsWithQuote(columns ...string) []string {
|
||||
}
|
||||
|
||||
func (statement *Statement) colmap2NewColsWithQuote() []string {
|
||||
newColumns := make([]string, 0, len(statement.columnMap))
|
||||
for col := range statement.columnMap {
|
||||
fields := strings.Split(strings.TrimSpace(col), ".")
|
||||
if len(fields) == 1 {
|
||||
newColumns = append(newColumns, statement.Engine.quote(fields[0]))
|
||||
} else if len(fields) == 2 {
|
||||
newColumns = append(newColumns, statement.Engine.quote(fields[0])+"."+
|
||||
statement.Engine.quote(fields[1]))
|
||||
} else {
|
||||
panic(errors.New("unwanted colnames"))
|
||||
}
|
||||
newColumns := make([]string, len(statement.columnMap), len(statement.columnMap))
|
||||
copy(newColumns, statement.columnMap)
|
||||
for i := 0; i < len(statement.columnMap); i++ {
|
||||
newColumns[i] = statement.Engine.Quote(newColumns[i])
|
||||
}
|
||||
return newColumns
|
||||
}
|
||||
@ -636,10 +629,11 @@ func (statement *Statement) Select(str string) *Statement {
|
||||
func (statement *Statement) Cols(columns ...string) *Statement {
|
||||
cols := col2NewCols(columns...)
|
||||
for _, nc := range cols {
|
||||
statement.columnMap[strings.ToLower(nc)] = true
|
||||
statement.columnMap.add(nc)
|
||||
}
|
||||
|
||||
newColumns := statement.colmap2NewColsWithQuote()
|
||||
|
||||
statement.ColumnStr = strings.Join(newColumns, ", ")
|
||||
statement.ColumnStr = strings.Replace(statement.ColumnStr, statement.Engine.quote("*"), "*", -1)
|
||||
return statement
|
||||
@ -674,7 +668,7 @@ func (statement *Statement) UseBool(columns ...string) *Statement {
|
||||
func (statement *Statement) Omit(columns ...string) {
|
||||
newColumns := col2NewCols(columns...)
|
||||
for _, nc := range newColumns {
|
||||
statement.columnMap[strings.ToLower(nc)] = false
|
||||
statement.omitColumnMap = append(statement.omitColumnMap, nc)
|
||||
}
|
||||
statement.OmitStr = statement.Engine.Quote(strings.Join(newColumns, statement.Engine.Quote(", ")))
|
||||
}
|
||||
@ -713,10 +707,9 @@ func (statement *Statement) OrderBy(order string) *Statement {
|
||||
|
||||
// Desc generate `ORDER BY xx DESC`
|
||||
func (statement *Statement) Desc(colNames ...string) *Statement {
|
||||
var buf bytes.Buffer
|
||||
fmt.Fprintf(&buf, statement.OrderStr)
|
||||
var buf builder.StringBuilder
|
||||
if len(statement.OrderStr) > 0 {
|
||||
fmt.Fprint(&buf, ", ")
|
||||
fmt.Fprint(&buf, statement.OrderStr, ", ")
|
||||
}
|
||||
newColNames := statement.col2NewColsWithQuote(colNames...)
|
||||
fmt.Fprintf(&buf, "%v DESC", strings.Join(newColNames, " DESC, "))
|
||||
@ -726,10 +719,9 @@ func (statement *Statement) Desc(colNames ...string) *Statement {
|
||||
|
||||
// Asc provide asc order by query condition, the input parameters are columns.
|
||||
func (statement *Statement) Asc(colNames ...string) *Statement {
|
||||
var buf bytes.Buffer
|
||||
fmt.Fprintf(&buf, statement.OrderStr)
|
||||
var buf builder.StringBuilder
|
||||
if len(statement.OrderStr) > 0 {
|
||||
fmt.Fprint(&buf, ", ")
|
||||
fmt.Fprint(&buf, statement.OrderStr, ", ")
|
||||
}
|
||||
newColNames := statement.col2NewColsWithQuote(colNames...)
|
||||
fmt.Fprintf(&buf, "%v ASC", strings.Join(newColNames, " ASC, "))
|
||||
@ -737,48 +729,35 @@ func (statement *Statement) Asc(colNames ...string) *Statement {
|
||||
return statement
|
||||
}
|
||||
|
||||
// Table tempororily set table name, the parameter could be a string or a pointer of struct
|
||||
func (statement *Statement) Table(tableNameOrBean interface{}) *Statement {
|
||||
v := rValue(tableNameOrBean)
|
||||
t := v.Type()
|
||||
if t.Kind() == reflect.Struct {
|
||||
var err error
|
||||
statement.RefTable, err = statement.Engine.autoMapType(v)
|
||||
if err != nil {
|
||||
statement.Engine.logger.Error(err)
|
||||
return statement
|
||||
}
|
||||
}
|
||||
|
||||
statement.AltTableName = statement.Engine.TableName(tableNameOrBean, true)
|
||||
return statement
|
||||
}
|
||||
|
||||
// Join The joinOP should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN
|
||||
func (statement *Statement) Join(joinOP string, tablename interface{}, condition string, args ...interface{}) *Statement {
|
||||
var buf bytes.Buffer
|
||||
var buf builder.StringBuilder
|
||||
if len(statement.JoinStr) > 0 {
|
||||
fmt.Fprintf(&buf, "%v %v JOIN ", statement.JoinStr, joinOP)
|
||||
} else {
|
||||
fmt.Fprintf(&buf, "%v JOIN ", joinOP)
|
||||
}
|
||||
|
||||
switch tablename.(type) {
|
||||
case []string:
|
||||
t := tablename.([]string)
|
||||
if len(t) > 1 {
|
||||
fmt.Fprintf(&buf, "%v AS %v", statement.Engine.Quote(t[0]), statement.Engine.Quote(t[1]))
|
||||
} else if len(t) == 1 {
|
||||
fmt.Fprintf(&buf, statement.Engine.Quote(t[0]))
|
||||
}
|
||||
case []interface{}:
|
||||
t := tablename.([]interface{})
|
||||
l := len(t)
|
||||
var table string
|
||||
if l > 0 {
|
||||
f := t[0]
|
||||
v := rValue(f)
|
||||
t := v.Type()
|
||||
if t.Kind() == reflect.String {
|
||||
table = f.(string)
|
||||
} else if t.Kind() == reflect.Struct {
|
||||
table = statement.Engine.tbName(v)
|
||||
}
|
||||
}
|
||||
if l > 1 {
|
||||
fmt.Fprintf(&buf, "%v AS %v", statement.Engine.Quote(table),
|
||||
statement.Engine.Quote(fmt.Sprintf("%v", t[1])))
|
||||
} else if l == 1 {
|
||||
fmt.Fprintf(&buf, statement.Engine.Quote(table))
|
||||
}
|
||||
default:
|
||||
fmt.Fprintf(&buf, statement.Engine.Quote(fmt.Sprintf("%v", tablename)))
|
||||
}
|
||||
tbName := statement.Engine.TableName(tablename, true)
|
||||
|
||||
fmt.Fprintf(&buf, " ON %v", condition)
|
||||
fmt.Fprintf(&buf, "%s ON %v", tbName, condition)
|
||||
statement.JoinStr = buf.String()
|
||||
statement.joinArgs = append(statement.joinArgs, args...)
|
||||
return statement
|
||||
@ -803,18 +782,20 @@ func (statement *Statement) Unscoped() *Statement {
|
||||
}
|
||||
|
||||
func (statement *Statement) genColumnStr() string {
|
||||
var buf bytes.Buffer
|
||||
if statement.RefTable == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
var buf builder.StringBuilder
|
||||
columns := statement.RefTable.Columns()
|
||||
|
||||
for _, col := range columns {
|
||||
if statement.OmitStr != "" {
|
||||
if _, ok := getFlagForColumn(statement.columnMap, col); ok {
|
||||
continue
|
||||
}
|
||||
if statement.omitColumnMap.contain(col.Name) {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(statement.columnMap) > 0 && !statement.columnMap.contain(col.Name) {
|
||||
continue
|
||||
}
|
||||
|
||||
if col.MapType == core.ONLYTODB {
|
||||
@ -825,10 +806,6 @@ func (statement *Statement) genColumnStr() string {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
|
||||
if col.IsPrimaryKey && statement.Engine.Dialect().DBType() == "ql" {
|
||||
buf.WriteString("id() AS ")
|
||||
}
|
||||
|
||||
if statement.JoinStr != "" {
|
||||
if statement.TableAlias != "" {
|
||||
buf.WriteString(statement.TableAlias)
|
||||
@ -853,11 +830,13 @@ func (statement *Statement) genCreateTableSQL() string {
|
||||
func (statement *Statement) genIndexSQL() []string {
|
||||
var sqls []string
|
||||
tbName := statement.TableName()
|
||||
quote := statement.Engine.Quote
|
||||
for idxName, index := range statement.RefTable.Indexes {
|
||||
for _, index := range statement.RefTable.Indexes {
|
||||
if index.Type == core.IndexType {
|
||||
sql := fmt.Sprintf("CREATE INDEX %v ON %v (%v);", quote(indexName(tbName, idxName)),
|
||||
quote(tbName), quote(strings.Join(index.Cols, quote(","))))
|
||||
sql := statement.Engine.dialect.CreateIndexSql(tbName, index)
|
||||
/*idxTBName := strings.Replace(tbName, ".", "_", -1)
|
||||
idxTBName = strings.Replace(idxTBName, `"`, "", -1)
|
||||
sql := fmt.Sprintf("CREATE INDEX %v ON %v (%v);", quote(indexName(idxTBName, idxName)),
|
||||
quote(tbName), quote(strings.Join(index.Cols, quote(","))))*/
|
||||
sqls = append(sqls, sql)
|
||||
}
|
||||
}
|
||||
@ -883,16 +862,18 @@ func (statement *Statement) genUniqueSQL() []string {
|
||||
func (statement *Statement) genDelIndexSQL() []string {
|
||||
var sqls []string
|
||||
tbName := statement.TableName()
|
||||
idxPrefixName := strings.Replace(tbName, `"`, "", -1)
|
||||
idxPrefixName = strings.Replace(idxPrefixName, `.`, "_", -1)
|
||||
for idxName, index := range statement.RefTable.Indexes {
|
||||
var rIdxName string
|
||||
if index.Type == core.UniqueType {
|
||||
rIdxName = uniqueName(tbName, idxName)
|
||||
rIdxName = uniqueName(idxPrefixName, idxName)
|
||||
} else if index.Type == core.IndexType {
|
||||
rIdxName = indexName(tbName, idxName)
|
||||
rIdxName = indexName(idxPrefixName, idxName)
|
||||
}
|
||||
sql := fmt.Sprintf("DROP INDEX %v", statement.Engine.Quote(rIdxName))
|
||||
sql := fmt.Sprintf("DROP INDEX %v", statement.Engine.Quote(statement.Engine.TableName(rIdxName, true)))
|
||||
if statement.Engine.dialect.IndexOnTable() {
|
||||
sql += fmt.Sprintf(" ON %v", statement.Engine.Quote(statement.TableName()))
|
||||
sql += fmt.Sprintf(" ON %v", statement.Engine.Quote(tbName))
|
||||
}
|
||||
sqls = append(sqls, sql)
|
||||
}
|
||||
@ -901,8 +882,12 @@ func (statement *Statement) genDelIndexSQL() []string {
|
||||
|
||||
func (statement *Statement) genAddColumnStr(col *core.Column) (string, []interface{}) {
|
||||
quote := statement.Engine.Quote
|
||||
sql := fmt.Sprintf("ALTER TABLE %v ADD %v;", quote(statement.TableName()),
|
||||
sql := fmt.Sprintf("ALTER TABLE %v ADD %v", quote(statement.TableName()),
|
||||
col.String(statement.Engine.dialect))
|
||||
if statement.Engine.dialect.DBType() == core.MYSQL && len(col.Comment) > 0 {
|
||||
sql += " COMMENT '" + col.Comment + "'"
|
||||
}
|
||||
sql += ";"
|
||||
return sql, []interface{}{}
|
||||
}
|
||||
|
||||
@ -939,7 +924,7 @@ func (statement *Statement) genGetSQL(bean interface{}) (string, []interface{},
|
||||
v := rValue(bean)
|
||||
isStruct := v.Kind() == reflect.Struct
|
||||
if isStruct {
|
||||
statement.setRefValue(v)
|
||||
statement.setRefBean(bean)
|
||||
}
|
||||
|
||||
var columnStr = statement.ColumnStr
|
||||
@ -950,7 +935,7 @@ func (statement *Statement) genGetSQL(bean interface{}) (string, []interface{},
|
||||
if len(statement.JoinStr) == 0 {
|
||||
if len(columnStr) == 0 {
|
||||
if len(statement.GroupByStr) > 0 {
|
||||
columnStr = statement.Engine.Quote(strings.Replace(statement.GroupByStr, ",", statement.Engine.Quote(","), -1))
|
||||
columnStr = statement.Engine.quoteColumns(statement.GroupByStr)
|
||||
} else {
|
||||
columnStr = statement.genColumnStr()
|
||||
}
|
||||
@ -958,7 +943,7 @@ func (statement *Statement) genGetSQL(bean interface{}) (string, []interface{},
|
||||
} else {
|
||||
if len(columnStr) == 0 {
|
||||
if len(statement.GroupByStr) > 0 {
|
||||
columnStr = statement.Engine.Quote(strings.Replace(statement.GroupByStr, ",", statement.Engine.Quote(","), -1))
|
||||
columnStr = statement.Engine.quoteColumns(statement.GroupByStr)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -972,13 +957,17 @@ func (statement *Statement) genGetSQL(bean interface{}) (string, []interface{},
|
||||
if err := statement.mergeConds(bean); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
} else {
|
||||
if err := statement.processIDParam(); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
}
|
||||
condSQL, condArgs, err := builder.ToSQL(statement.cond)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
sqlStr, err := statement.genSelectSQL(columnStr, condSQL)
|
||||
sqlStr, err := statement.genSelectSQL(columnStr, condSQL, true, true)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
@ -991,7 +980,7 @@ func (statement *Statement) genCountSQL(beans ...interface{}) (string, []interfa
|
||||
var condArgs []interface{}
|
||||
var err error
|
||||
if len(beans) > 0 {
|
||||
statement.setRefValue(rValue(beans[0]))
|
||||
statement.setRefBean(beans[0])
|
||||
condSQL, condArgs, err = statement.genConds(beans[0])
|
||||
} else {
|
||||
condSQL, condArgs, err = builder.ToSQL(statement.cond)
|
||||
@ -1008,7 +997,7 @@ func (statement *Statement) genCountSQL(beans ...interface{}) (string, []interfa
|
||||
selectSQL = "count(*)"
|
||||
}
|
||||
}
|
||||
sqlStr, err := statement.genSelectSQL(selectSQL, condSQL)
|
||||
sqlStr, err := statement.genSelectSQL(selectSQL, condSQL, false, false)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
@ -1017,7 +1006,7 @@ func (statement *Statement) genCountSQL(beans ...interface{}) (string, []interfa
|
||||
}
|
||||
|
||||
func (statement *Statement) genSumSQL(bean interface{}, columns ...string) (string, []interface{}, error) {
|
||||
statement.setRefValue(rValue(bean))
|
||||
statement.setRefBean(bean)
|
||||
|
||||
var sumStrs = make([]string, 0, len(columns))
|
||||
for _, colName := range columns {
|
||||
@ -1033,7 +1022,7 @@ func (statement *Statement) genSumSQL(bean interface{}, columns ...string) (stri
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
sqlStr, err := statement.genSelectSQL(sumSelect, condSQL)
|
||||
sqlStr, err := statement.genSelectSQL(sumSelect, condSQL, true, true)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
@ -1041,27 +1030,20 @@ func (statement *Statement) genSumSQL(bean interface{}, columns ...string) (stri
|
||||
return sqlStr, append(statement.joinArgs, condArgs...), nil
|
||||
}
|
||||
|
||||
func (statement *Statement) genSelectSQL(columnStr, condSQL string) (a string, err error) {
|
||||
var distinct string
|
||||
func (statement *Statement) genSelectSQL(columnStr, condSQL string, needLimit, needOrderBy bool) (string, error) {
|
||||
var (
|
||||
distinct string
|
||||
dialect = statement.Engine.Dialect()
|
||||
quote = statement.Engine.Quote
|
||||
fromStr = " FROM "
|
||||
top, mssqlCondi, whereStr string
|
||||
)
|
||||
if statement.IsDistinct && !strings.HasPrefix(columnStr, "count") {
|
||||
distinct = "DISTINCT "
|
||||
}
|
||||
|
||||
var dialect = statement.Engine.Dialect()
|
||||
var quote = statement.Engine.Quote
|
||||
var top string
|
||||
var mssqlCondi string
|
||||
|
||||
if err := statement.processIDParam(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if len(condSQL) > 0 {
|
||||
fmt.Fprintf(&buf, " WHERE %v", condSQL)
|
||||
whereStr = " WHERE " + condSQL
|
||||
}
|
||||
var whereStr = buf.String()
|
||||
var fromStr = " FROM "
|
||||
|
||||
if dialect.DBType() == core.MSSQL && strings.Contains(statement.TableName(), "..") {
|
||||
fromStr += statement.TableName()
|
||||
@ -1108,9 +1090,10 @@ func (statement *Statement) genSelectSQL(columnStr, condSQL string) (a string, e
|
||||
}
|
||||
|
||||
var orderStr string
|
||||
if len(statement.OrderStr) > 0 {
|
||||
if needOrderBy && len(statement.OrderStr) > 0 {
|
||||
orderStr = " ORDER BY " + statement.OrderStr
|
||||
}
|
||||
|
||||
var groupStr string
|
||||
if len(statement.GroupByStr) > 0 {
|
||||
groupStr = " GROUP BY " + statement.GroupByStr
|
||||
@ -1120,45 +1103,50 @@ func (statement *Statement) genSelectSQL(columnStr, condSQL string) (a string, e
|
||||
}
|
||||
}
|
||||
|
||||
// !nashtsai! REVIEW Sprintf is considered slowest mean of string concatnation, better to work with builder pattern
|
||||
a = fmt.Sprintf("SELECT %v%v%v%v%v", distinct, top, columnStr, fromStr, whereStr)
|
||||
var buf builder.StringBuilder
|
||||
fmt.Fprintf(&buf, "SELECT %v%v%v%v%v", distinct, top, columnStr, fromStr, whereStr)
|
||||
if len(mssqlCondi) > 0 {
|
||||
if len(whereStr) > 0 {
|
||||
a += " AND " + mssqlCondi
|
||||
fmt.Fprint(&buf, " AND ", mssqlCondi)
|
||||
} else {
|
||||
a += " WHERE " + mssqlCondi
|
||||
fmt.Fprint(&buf, " WHERE ", mssqlCondi)
|
||||
}
|
||||
}
|
||||
|
||||
if statement.GroupByStr != "" {
|
||||
a = fmt.Sprintf("%v GROUP BY %v", a, statement.GroupByStr)
|
||||
fmt.Fprint(&buf, " GROUP BY ", statement.GroupByStr)
|
||||
}
|
||||
if statement.HavingStr != "" {
|
||||
a = fmt.Sprintf("%v %v", a, statement.HavingStr)
|
||||
fmt.Fprint(&buf, " ", statement.HavingStr)
|
||||
}
|
||||
if statement.OrderStr != "" {
|
||||
a = fmt.Sprintf("%v ORDER BY %v", a, statement.OrderStr)
|
||||
if needOrderBy && statement.OrderStr != "" {
|
||||
fmt.Fprint(&buf, " ORDER BY ", statement.OrderStr)
|
||||
}
|
||||
if dialect.DBType() != core.MSSQL && dialect.DBType() != core.ORACLE {
|
||||
if statement.Start > 0 {
|
||||
a = fmt.Sprintf("%v LIMIT %v OFFSET %v", a, statement.LimitN, statement.Start)
|
||||
} else if statement.LimitN > 0 {
|
||||
a = fmt.Sprintf("%v LIMIT %v", a, statement.LimitN)
|
||||
}
|
||||
} else if dialect.DBType() == core.ORACLE {
|
||||
if statement.Start != 0 || statement.LimitN != 0 {
|
||||
a = fmt.Sprintf("SELECT %v FROM (SELECT %v,ROWNUM RN FROM (%v) at WHERE ROWNUM <= %d) aat WHERE RN > %d", columnStr, columnStr, a, statement.Start+statement.LimitN, statement.Start)
|
||||
if needLimit {
|
||||
if dialect.DBType() != core.MSSQL && dialect.DBType() != core.ORACLE {
|
||||
if statement.Start > 0 {
|
||||
fmt.Fprintf(&buf, " LIMIT %v OFFSET %v", statement.LimitN, statement.Start)
|
||||
} else if statement.LimitN > 0 {
|
||||
fmt.Fprint(&buf, " LIMIT ", statement.LimitN)
|
||||
}
|
||||
} else if dialect.DBType() == core.ORACLE {
|
||||
if statement.Start != 0 || statement.LimitN != 0 {
|
||||
oldString := buf.String()
|
||||
buf.Reset()
|
||||
fmt.Fprintf(&buf, "SELECT %v FROM (SELECT %v,ROWNUM RN FROM (%v) at WHERE ROWNUM <= %d) aat WHERE RN > %d",
|
||||
columnStr, columnStr, oldString, statement.Start+statement.LimitN, statement.Start)
|
||||
}
|
||||
}
|
||||
}
|
||||
if statement.IsForUpdate {
|
||||
a = dialect.ForUpdateSql(a)
|
||||
return dialect.ForUpdateSql(buf.String()), nil
|
||||
}
|
||||
|
||||
return
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
func (statement *Statement) processIDParam() error {
|
||||
if statement.idParam == nil {
|
||||
if statement.idParam == nil || statement.RefTable == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
26
vendor/github.com/go-xorm/xorm/transaction.go
generated
vendored
Normal file
26
vendor/github.com/go-xorm/xorm/transaction.go
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright 2018 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
// Transaction Execute sql wrapped in a transaction(abbr as tx), tx will automatic commit if no errors occurred
|
||||
func (engine *Engine) Transaction(f func(*Session) (interface{}, error)) (interface{}, error) {
|
||||
session := engine.NewSession()
|
||||
defer session.Close()
|
||||
|
||||
if err := session.Begin(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result, err := f(session)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := session.Commit(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
14
vendor/github.com/go-xorm/xorm/xorm.go
generated
vendored
14
vendor/github.com/go-xorm/xorm/xorm.go
generated
vendored
@ -2,6 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build go1.8
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
@ -17,7 +19,7 @@ import (
|
||||
|
||||
const (
|
||||
// Version show the xorm's version
|
||||
Version string = "0.6.4.0910"
|
||||
Version string = "0.7.0.0504"
|
||||
)
|
||||
|
||||
func regDrvsNDialects() bool {
|
||||
@ -31,7 +33,7 @@ func regDrvsNDialects() bool {
|
||||
"mysql": {"mysql", func() core.Driver { return &mysqlDriver{} }, func() core.Dialect { return &mysql{} }},
|
||||
"mymysql": {"mysql", func() core.Driver { return &mymysqlDriver{} }, func() core.Dialect { return &mysql{} }},
|
||||
"postgres": {"postgres", func() core.Driver { return &pqDriver{} }, func() core.Dialect { return &postgres{} }},
|
||||
"pgx": {"postgres", func() core.Driver { return &pqDriver{} }, func() core.Dialect { return &postgres{} }},
|
||||
"pgx": {"postgres", func() core.Driver { return &pqDriverPgx{} }, func() core.Dialect { return &postgres{} }},
|
||||
"sqlite3": {"sqlite3", func() core.Driver { return &sqlite3Driver{} }, func() core.Dialect { return &sqlite3{} }},
|
||||
"oci8": {"oracle", func() core.Driver { return &oci8Driver{} }, func() core.Dialect { return &oracle{} }},
|
||||
"goracle": {"oracle", func() core.Driver { return &goracleDriver{} }, func() core.Dialect { return &oracle{} }},
|
||||
@ -90,6 +92,7 @@ func NewEngine(driverName string, dataSourceName string) (*Engine, error) {
|
||||
TagIdentifier: "xorm",
|
||||
TZLocation: time.Local,
|
||||
tagHandlers: defaultTagHandlers,
|
||||
cachers: make(map[string]core.Cacher),
|
||||
}
|
||||
|
||||
if uri.DbType == core.SQLITE {
|
||||
@ -108,6 +111,13 @@ func NewEngine(driverName string, dataSourceName string) (*Engine, error) {
|
||||
return engine, nil
|
||||
}
|
||||
|
||||
// NewEngineWithParams new a db manager with params. The params will be passed to dialect.
|
||||
func NewEngineWithParams(driverName string, dataSourceName string, params map[string]string) (*Engine, error) {
|
||||
engine, err := NewEngine(driverName, dataSourceName)
|
||||
engine.dialect.SetParams(params)
|
||||
return engine, err
|
||||
}
|
||||
|
||||
// Clone clone an engine
|
||||
func (engine *Engine) Clone() (*Engine, error) {
|
||||
return NewEngine(engine.DriverName(), engine.DataSourceName())
|
||||
|
8
vendor/github.com/mattn/go-runewidth/.travis.yml
generated
vendored
Normal file
8
vendor/github.com/mattn/go-runewidth/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
language: go
|
||||
go:
|
||||
- tip
|
||||
before_install:
|
||||
- go get github.com/mattn/goveralls
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
script:
|
||||
- $HOME/gopath/bin/goveralls -repotoken lAKAWPzcGsD3A8yBX3BGGtRUdJ6CaGERL
|
21
vendor/github.com/mattn/go-runewidth/LICENSE
generated
vendored
Normal file
21
vendor/github.com/mattn/go-runewidth/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Yasuhiro Matsumoto
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
27
vendor/github.com/mattn/go-runewidth/README.mkd
generated
vendored
Normal file
27
vendor/github.com/mattn/go-runewidth/README.mkd
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
go-runewidth
|
||||
============
|
||||
|
||||
[](https://travis-ci.org/mattn/go-runewidth)
|
||||
[](https://coveralls.io/r/mattn/go-runewidth?branch=HEAD)
|
||||
[](http://godoc.org/github.com/mattn/go-runewidth)
|
||||
[](https://goreportcard.com/report/github.com/mattn/go-runewidth)
|
||||
|
||||
Provides functions to get fixed width of the character or string.
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
```go
|
||||
runewidth.StringWidth("つのだ☆HIRO") == 12
|
||||
```
|
||||
|
||||
|
||||
Author
|
||||
------
|
||||
|
||||
Yasuhiro Matsumoto
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
under the MIT License: http://mattn.mit-license.org/2013
|
977
vendor/github.com/mattn/go-runewidth/runewidth.go
generated
vendored
Normal file
977
vendor/github.com/mattn/go-runewidth/runewidth.go
generated
vendored
Normal file
@ -0,0 +1,977 @@
|
||||
package runewidth
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
var (
|
||||
// EastAsianWidth will be set true if the current locale is CJK
|
||||
EastAsianWidth bool
|
||||
|
||||
// ZeroWidthJoiner is flag to set to use UTR#51 ZWJ
|
||||
ZeroWidthJoiner bool
|
||||
|
||||
// DefaultCondition is a condition in current locale
|
||||
DefaultCondition = &Condition{}
|
||||
)
|
||||
|
||||
func init() {
|
||||
handleEnv()
|
||||
}
|
||||
|
||||
func handleEnv() {
|
||||
env := os.Getenv("RUNEWIDTH_EASTASIAN")
|
||||
if env == "" {
|
||||
EastAsianWidth = IsEastAsian()
|
||||
} else {
|
||||
EastAsianWidth = env == "1"
|
||||
}
|
||||
// update DefaultCondition
|
||||
DefaultCondition.EastAsianWidth = EastAsianWidth
|
||||
DefaultCondition.ZeroWidthJoiner = ZeroWidthJoiner
|
||||
}
|
||||
|
||||
type interval struct {
|
||||
first rune
|
||||
last rune
|
||||
}
|
||||
|
||||
type table []interval
|
||||
|
||||
func inTables(r rune, ts ...table) bool {
|
||||
for _, t := range ts {
|
||||
if inTable(r, t) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func inTable(r rune, t table) bool {
|
||||
// func (t table) IncludesRune(r rune) bool {
|
||||
if r < t[0].first {
|
||||
return false
|
||||
}
|
||||
|
||||
bot := 0
|
||||
top := len(t) - 1
|
||||
for top >= bot {
|
||||
mid := (bot + top) >> 1
|
||||
|
||||
switch {
|
||||
case t[mid].last < r:
|
||||
bot = mid + 1
|
||||
case t[mid].first > r:
|
||||
top = mid - 1
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
var private = table{
|
||||
{0x00E000, 0x00F8FF}, {0x0F0000, 0x0FFFFD}, {0x100000, 0x10FFFD},
|
||||
}
|
||||
|
||||
var nonprint = table{
|
||||
{0x0000, 0x001F}, {0x007F, 0x009F}, {0x00AD, 0x00AD},
|
||||
{0x070F, 0x070F}, {0x180B, 0x180E}, {0x200B, 0x200F},
|
||||
{0x2028, 0x202E}, {0x206A, 0x206F}, {0xD800, 0xDFFF},
|
||||
{0xFEFF, 0xFEFF}, {0xFFF9, 0xFFFB}, {0xFFFE, 0xFFFF},
|
||||
}
|
||||
|
||||
var combining = table{
|
||||
{0x0300, 0x036F}, {0x0483, 0x0489}, {0x0591, 0x05BD},
|
||||
{0x05BF, 0x05BF}, {0x05C1, 0x05C2}, {0x05C4, 0x05C5},
|
||||
{0x05C7, 0x05C7}, {0x0610, 0x061A}, {0x064B, 0x065F},
|
||||
{0x0670, 0x0670}, {0x06D6, 0x06DC}, {0x06DF, 0x06E4},
|
||||
{0x06E7, 0x06E8}, {0x06EA, 0x06ED}, {0x0711, 0x0711},
|
||||
{0x0730, 0x074A}, {0x07A6, 0x07B0}, {0x07EB, 0x07F3},
|
||||
{0x0816, 0x0819}, {0x081B, 0x0823}, {0x0825, 0x0827},
|
||||
{0x0829, 0x082D}, {0x0859, 0x085B}, {0x08D4, 0x08E1},
|
||||
{0x08E3, 0x0903}, {0x093A, 0x093C}, {0x093E, 0x094F},
|
||||
{0x0951, 0x0957}, {0x0962, 0x0963}, {0x0981, 0x0983},
|
||||
{0x09BC, 0x09BC}, {0x09BE, 0x09C4}, {0x09C7, 0x09C8},
|
||||
{0x09CB, 0x09CD}, {0x09D7, 0x09D7}, {0x09E2, 0x09E3},
|
||||
{0x0A01, 0x0A03}, {0x0A3C, 0x0A3C}, {0x0A3E, 0x0A42},
|
||||
{0x0A47, 0x0A48}, {0x0A4B, 0x0A4D}, {0x0A51, 0x0A51},
|
||||
{0x0A70, 0x0A71}, {0x0A75, 0x0A75}, {0x0A81, 0x0A83},
|
||||
{0x0ABC, 0x0ABC}, {0x0ABE, 0x0AC5}, {0x0AC7, 0x0AC9},
|
||||
{0x0ACB, 0x0ACD}, {0x0AE2, 0x0AE3}, {0x0B01, 0x0B03},
|
||||
{0x0B3C, 0x0B3C}, {0x0B3E, 0x0B44}, {0x0B47, 0x0B48},
|
||||
{0x0B4B, 0x0B4D}, {0x0B56, 0x0B57}, {0x0B62, 0x0B63},
|
||||
{0x0B82, 0x0B82}, {0x0BBE, 0x0BC2}, {0x0BC6, 0x0BC8},
|
||||
{0x0BCA, 0x0BCD}, {0x0BD7, 0x0BD7}, {0x0C00, 0x0C03},
|
||||
{0x0C3E, 0x0C44}, {0x0C46, 0x0C48}, {0x0C4A, 0x0C4D},
|
||||
{0x0C55, 0x0C56}, {0x0C62, 0x0C63}, {0x0C81, 0x0C83},
|
||||
{0x0CBC, 0x0CBC}, {0x0CBE, 0x0CC4}, {0x0CC6, 0x0CC8},
|
||||
{0x0CCA, 0x0CCD}, {0x0CD5, 0x0CD6}, {0x0CE2, 0x0CE3},
|
||||
{0x0D01, 0x0D03}, {0x0D3E, 0x0D44}, {0x0D46, 0x0D48},
|
||||
{0x0D4A, 0x0D4D}, {0x0D57, 0x0D57}, {0x0D62, 0x0D63},
|
||||
{0x0D82, 0x0D83}, {0x0DCA, 0x0DCA}, {0x0DCF, 0x0DD4},
|
||||
{0x0DD6, 0x0DD6}, {0x0DD8, 0x0DDF}, {0x0DF2, 0x0DF3},
|
||||
{0x0E31, 0x0E31}, {0x0E34, 0x0E3A}, {0x0E47, 0x0E4E},
|
||||
{0x0EB1, 0x0EB1}, {0x0EB4, 0x0EB9}, {0x0EBB, 0x0EBC},
|
||||
{0x0EC8, 0x0ECD}, {0x0F18, 0x0F19}, {0x0F35, 0x0F35},
|
||||
{0x0F37, 0x0F37}, {0x0F39, 0x0F39}, {0x0F3E, 0x0F3F},
|
||||
{0x0F71, 0x0F84}, {0x0F86, 0x0F87}, {0x0F8D, 0x0F97},
|
||||
{0x0F99, 0x0FBC}, {0x0FC6, 0x0FC6}, {0x102B, 0x103E},
|
||||
{0x1056, 0x1059}, {0x105E, 0x1060}, {0x1062, 0x1064},
|
||||
{0x1067, 0x106D}, {0x1071, 0x1074}, {0x1082, 0x108D},
|
||||
{0x108F, 0x108F}, {0x109A, 0x109D}, {0x135D, 0x135F},
|
||||
{0x1712, 0x1714}, {0x1732, 0x1734}, {0x1752, 0x1753},
|
||||
{0x1772, 0x1773}, {0x17B4, 0x17D3}, {0x17DD, 0x17DD},
|
||||
{0x180B, 0x180D}, {0x1885, 0x1886}, {0x18A9, 0x18A9},
|
||||
{0x1920, 0x192B}, {0x1930, 0x193B}, {0x1A17, 0x1A1B},
|
||||
{0x1A55, 0x1A5E}, {0x1A60, 0x1A7C}, {0x1A7F, 0x1A7F},
|
||||
{0x1AB0, 0x1ABE}, {0x1B00, 0x1B04}, {0x1B34, 0x1B44},
|
||||
{0x1B6B, 0x1B73}, {0x1B80, 0x1B82}, {0x1BA1, 0x1BAD},
|
||||
{0x1BE6, 0x1BF3}, {0x1C24, 0x1C37}, {0x1CD0, 0x1CD2},
|
||||
{0x1CD4, 0x1CE8}, {0x1CED, 0x1CED}, {0x1CF2, 0x1CF4},
|
||||
{0x1CF8, 0x1CF9}, {0x1DC0, 0x1DF5}, {0x1DFB, 0x1DFF},
|
||||
{0x20D0, 0x20F0}, {0x2CEF, 0x2CF1}, {0x2D7F, 0x2D7F},
|
||||
{0x2DE0, 0x2DFF}, {0x302A, 0x302F}, {0x3099, 0x309A},
|
||||
{0xA66F, 0xA672}, {0xA674, 0xA67D}, {0xA69E, 0xA69F},
|
||||
{0xA6F0, 0xA6F1}, {0xA802, 0xA802}, {0xA806, 0xA806},
|
||||
{0xA80B, 0xA80B}, {0xA823, 0xA827}, {0xA880, 0xA881},
|
||||
{0xA8B4, 0xA8C5}, {0xA8E0, 0xA8F1}, {0xA926, 0xA92D},
|
||||
{0xA947, 0xA953}, {0xA980, 0xA983}, {0xA9B3, 0xA9C0},
|
||||
{0xA9E5, 0xA9E5}, {0xAA29, 0xAA36}, {0xAA43, 0xAA43},
|
||||
{0xAA4C, 0xAA4D}, {0xAA7B, 0xAA7D}, {0xAAB0, 0xAAB0},
|
||||
{0xAAB2, 0xAAB4}, {0xAAB7, 0xAAB8}, {0xAABE, 0xAABF},
|
||||
{0xAAC1, 0xAAC1}, {0xAAEB, 0xAAEF}, {0xAAF5, 0xAAF6},
|
||||
{0xABE3, 0xABEA}, {0xABEC, 0xABED}, {0xFB1E, 0xFB1E},
|
||||
{0xFE00, 0xFE0F}, {0xFE20, 0xFE2F}, {0x101FD, 0x101FD},
|
||||
{0x102E0, 0x102E0}, {0x10376, 0x1037A}, {0x10A01, 0x10A03},
|
||||
{0x10A05, 0x10A06}, {0x10A0C, 0x10A0F}, {0x10A38, 0x10A3A},
|
||||
{0x10A3F, 0x10A3F}, {0x10AE5, 0x10AE6}, {0x11000, 0x11002},
|
||||
{0x11038, 0x11046}, {0x1107F, 0x11082}, {0x110B0, 0x110BA},
|
||||
{0x11100, 0x11102}, {0x11127, 0x11134}, {0x11173, 0x11173},
|
||||
{0x11180, 0x11182}, {0x111B3, 0x111C0}, {0x111CA, 0x111CC},
|
||||
{0x1122C, 0x11237}, {0x1123E, 0x1123E}, {0x112DF, 0x112EA},
|
||||
{0x11300, 0x11303}, {0x1133C, 0x1133C}, {0x1133E, 0x11344},
|
||||
{0x11347, 0x11348}, {0x1134B, 0x1134D}, {0x11357, 0x11357},
|
||||
{0x11362, 0x11363}, {0x11366, 0x1136C}, {0x11370, 0x11374},
|
||||
{0x11435, 0x11446}, {0x114B0, 0x114C3}, {0x115AF, 0x115B5},
|
||||
{0x115B8, 0x115C0}, {0x115DC, 0x115DD}, {0x11630, 0x11640},
|
||||
{0x116AB, 0x116B7}, {0x1171D, 0x1172B}, {0x11C2F, 0x11C36},
|
||||
{0x11C38, 0x11C3F}, {0x11C92, 0x11CA7}, {0x11CA9, 0x11CB6},
|
||||
{0x16AF0, 0x16AF4}, {0x16B30, 0x16B36}, {0x16F51, 0x16F7E},
|
||||
{0x16F8F, 0x16F92}, {0x1BC9D, 0x1BC9E}, {0x1D165, 0x1D169},
|
||||
{0x1D16D, 0x1D172}, {0x1D17B, 0x1D182}, {0x1D185, 0x1D18B},
|
||||
{0x1D1AA, 0x1D1AD}, {0x1D242, 0x1D244}, {0x1DA00, 0x1DA36},
|
||||
{0x1DA3B, 0x1DA6C}, {0x1DA75, 0x1DA75}, {0x1DA84, 0x1DA84},
|
||||
{0x1DA9B, 0x1DA9F}, {0x1DAA1, 0x1DAAF}, {0x1E000, 0x1E006},
|
||||
{0x1E008, 0x1E018}, {0x1E01B, 0x1E021}, {0x1E023, 0x1E024},
|
||||
{0x1E026, 0x1E02A}, {0x1E8D0, 0x1E8D6}, {0x1E944, 0x1E94A},
|
||||
{0xE0100, 0xE01EF},
|
||||
}
|
||||
|
||||
var doublewidth = table{
|
||||
{0x1100, 0x115F}, {0x231A, 0x231B}, {0x2329, 0x232A},
|
||||
{0x23E9, 0x23EC}, {0x23F0, 0x23F0}, {0x23F3, 0x23F3},
|
||||
{0x25FD, 0x25FE}, {0x2614, 0x2615}, {0x2648, 0x2653},
|
||||
{0x267F, 0x267F}, {0x2693, 0x2693}, {0x26A1, 0x26A1},
|
||||
{0x26AA, 0x26AB}, {0x26BD, 0x26BE}, {0x26C4, 0x26C5},
|
||||
{0x26CE, 0x26CE}, {0x26D4, 0x26D4}, {0x26EA, 0x26EA},
|
||||
{0x26F2, 0x26F3}, {0x26F5, 0x26F5}, {0x26FA, 0x26FA},
|
||||
{0x26FD, 0x26FD}, {0x2705, 0x2705}, {0x270A, 0x270B},
|
||||
{0x2728, 0x2728}, {0x274C, 0x274C}, {0x274E, 0x274E},
|
||||
{0x2753, 0x2755}, {0x2757, 0x2757}, {0x2795, 0x2797},
|
||||
{0x27B0, 0x27B0}, {0x27BF, 0x27BF}, {0x2B1B, 0x2B1C},
|
||||
{0x2B50, 0x2B50}, {0x2B55, 0x2B55}, {0x2E80, 0x2E99},
|
||||
{0x2E9B, 0x2EF3}, {0x2F00, 0x2FD5}, {0x2FF0, 0x2FFB},
|
||||
{0x3000, 0x303E}, {0x3041, 0x3096}, {0x3099, 0x30FF},
|
||||
{0x3105, 0x312D}, {0x3131, 0x318E}, {0x3190, 0x31BA},
|
||||
{0x31C0, 0x31E3}, {0x31F0, 0x321E}, {0x3220, 0x3247},
|
||||
{0x3250, 0x32FE}, {0x3300, 0x4DBF}, {0x4E00, 0xA48C},
|
||||
{0xA490, 0xA4C6}, {0xA960, 0xA97C}, {0xAC00, 0xD7A3},
|
||||
{0xF900, 0xFAFF}, {0xFE10, 0xFE19}, {0xFE30, 0xFE52},
|
||||
{0xFE54, 0xFE66}, {0xFE68, 0xFE6B}, {0xFF01, 0xFF60},
|
||||
{0xFFE0, 0xFFE6}, {0x16FE0, 0x16FE0}, {0x17000, 0x187EC},
|
||||
{0x18800, 0x18AF2}, {0x1B000, 0x1B001}, {0x1F004, 0x1F004},
|
||||
{0x1F0CF, 0x1F0CF}, {0x1F18E, 0x1F18E}, {0x1F191, 0x1F19A},
|
||||
{0x1F200, 0x1F202}, {0x1F210, 0x1F23B}, {0x1F240, 0x1F248},
|
||||
{0x1F250, 0x1F251}, {0x1F300, 0x1F320}, {0x1F32D, 0x1F335},
|
||||
{0x1F337, 0x1F37C}, {0x1F37E, 0x1F393}, {0x1F3A0, 0x1F3CA},
|
||||
{0x1F3CF, 0x1F3D3}, {0x1F3E0, 0x1F3F0}, {0x1F3F4, 0x1F3F4},
|
||||
{0x1F3F8, 0x1F43E}, {0x1F440, 0x1F440}, {0x1F442, 0x1F4FC},
|
||||
{0x1F4FF, 0x1F53D}, {0x1F54B, 0x1F54E}, {0x1F550, 0x1F567},
|
||||
{0x1F57A, 0x1F57A}, {0x1F595, 0x1F596}, {0x1F5A4, 0x1F5A4},
|
||||
{0x1F5FB, 0x1F64F}, {0x1F680, 0x1F6C5}, {0x1F6CC, 0x1F6CC},
|
||||
{0x1F6D0, 0x1F6D2}, {0x1F6EB, 0x1F6EC}, {0x1F6F4, 0x1F6F6},
|
||||
{0x1F910, 0x1F91E}, {0x1F920, 0x1F927}, {0x1F930, 0x1F930},
|
||||
{0x1F933, 0x1F93E}, {0x1F940, 0x1F94B}, {0x1F950, 0x1F95E},
|
||||
{0x1F980, 0x1F991}, {0x1F9C0, 0x1F9C0}, {0x20000, 0x2FFFD},
|
||||
{0x30000, 0x3FFFD},
|
||||
}
|
||||
|
||||
var ambiguous = table{
|
||||
{0x00A1, 0x00A1}, {0x00A4, 0x00A4}, {0x00A7, 0x00A8},
|
||||
{0x00AA, 0x00AA}, {0x00AD, 0x00AE}, {0x00B0, 0x00B4},
|
||||
{0x00B6, 0x00BA}, {0x00BC, 0x00BF}, {0x00C6, 0x00C6},
|
||||
{0x00D0, 0x00D0}, {0x00D7, 0x00D8}, {0x00DE, 0x00E1},
|
||||
{0x00E6, 0x00E6}, {0x00E8, 0x00EA}, {0x00EC, 0x00ED},
|
||||
{0x00F0, 0x00F0}, {0x00F2, 0x00F3}, {0x00F7, 0x00FA},
|
||||
{0x00FC, 0x00FC}, {0x00FE, 0x00FE}, {0x0101, 0x0101},
|
||||
{0x0111, 0x0111}, {0x0113, 0x0113}, {0x011B, 0x011B},
|
||||
{0x0126, 0x0127}, {0x012B, 0x012B}, {0x0131, 0x0133},
|
||||
{0x0138, 0x0138}, {0x013F, 0x0142}, {0x0144, 0x0144},
|
||||
{0x0148, 0x014B}, {0x014D, 0x014D}, {0x0152, 0x0153},
|
||||
{0x0166, 0x0167}, {0x016B, 0x016B}, {0x01CE, 0x01CE},
|
||||
{0x01D0, 0x01D0}, {0x01D2, 0x01D2}, {0x01D4, 0x01D4},
|
||||
{0x01D6, 0x01D6}, {0x01D8, 0x01D8}, {0x01DA, 0x01DA},
|
||||
{0x01DC, 0x01DC}, {0x0251, 0x0251}, {0x0261, 0x0261},
|
||||
{0x02C4, 0x02C4}, {0x02C7, 0x02C7}, {0x02C9, 0x02CB},
|
||||
{0x02CD, 0x02CD}, {0x02D0, 0x02D0}, {0x02D8, 0x02DB},
|
||||
{0x02DD, 0x02DD}, {0x02DF, 0x02DF}, {0x0300, 0x036F},
|
||||
{0x0391, 0x03A1}, {0x03A3, 0x03A9}, {0x03B1, 0x03C1},
|
||||
{0x03C3, 0x03C9}, {0x0401, 0x0401}, {0x0410, 0x044F},
|
||||
{0x0451, 0x0451}, {0x2010, 0x2010}, {0x2013, 0x2016},
|
||||
{0x2018, 0x2019}, {0x201C, 0x201D}, {0x2020, 0x2022},
|
||||
{0x2024, 0x2027}, {0x2030, 0x2030}, {0x2032, 0x2033},
|
||||
{0x2035, 0x2035}, {0x203B, 0x203B}, {0x203E, 0x203E},
|
||||
{0x2074, 0x2074}, {0x207F, 0x207F}, {0x2081, 0x2084},
|
||||
{0x20AC, 0x20AC}, {0x2103, 0x2103}, {0x2105, 0x2105},
|
||||
{0x2109, 0x2109}, {0x2113, 0x2113}, {0x2116, 0x2116},
|
||||
{0x2121, 0x2122}, {0x2126, 0x2126}, {0x212B, 0x212B},
|
||||
{0x2153, 0x2154}, {0x215B, 0x215E}, {0x2160, 0x216B},
|
||||
{0x2170, 0x2179}, {0x2189, 0x2189}, {0x2190, 0x2199},
|
||||
{0x21B8, 0x21B9}, {0x21D2, 0x21D2}, {0x21D4, 0x21D4},
|
||||
{0x21E7, 0x21E7}, {0x2200, 0x2200}, {0x2202, 0x2203},
|
||||
{0x2207, 0x2208}, {0x220B, 0x220B}, {0x220F, 0x220F},
|
||||
{0x2211, 0x2211}, {0x2215, 0x2215}, {0x221A, 0x221A},
|
||||
{0x221D, 0x2220}, {0x2223, 0x2223}, {0x2225, 0x2225},
|
||||
{0x2227, 0x222C}, {0x222E, 0x222E}, {0x2234, 0x2237},
|
||||
{0x223C, 0x223D}, {0x2248, 0x2248}, {0x224C, 0x224C},
|
||||
{0x2252, 0x2252}, {0x2260, 0x2261}, {0x2264, 0x2267},
|
||||
{0x226A, 0x226B}, {0x226E, 0x226F}, {0x2282, 0x2283},
|
||||
{0x2286, 0x2287}, {0x2295, 0x2295}, {0x2299, 0x2299},
|
||||
{0x22A5, 0x22A5}, {0x22BF, 0x22BF}, {0x2312, 0x2312},
|
||||
{0x2460, 0x24E9}, {0x24EB, 0x254B}, {0x2550, 0x2573},
|
||||
{0x2580, 0x258F}, {0x2592, 0x2595}, {0x25A0, 0x25A1},
|
||||
{0x25A3, 0x25A9}, {0x25B2, 0x25B3}, {0x25B6, 0x25B7},
|
||||
{0x25BC, 0x25BD}, {0x25C0, 0x25C1}, {0x25C6, 0x25C8},
|
||||
{0x25CB, 0x25CB}, {0x25CE, 0x25D1}, {0x25E2, 0x25E5},
|
||||
{0x25EF, 0x25EF}, {0x2605, 0x2606}, {0x2609, 0x2609},
|
||||
{0x260E, 0x260F}, {0x261C, 0x261C}, {0x261E, 0x261E},
|
||||
{0x2640, 0x2640}, {0x2642, 0x2642}, {0x2660, 0x2661},
|
||||
{0x2663, 0x2665}, {0x2667, 0x266A}, {0x266C, 0x266D},
|
||||
{0x266F, 0x266F}, {0x269E, 0x269F}, {0x26BF, 0x26BF},
|
||||
{0x26C6, 0x26CD}, {0x26CF, 0x26D3}, {0x26D5, 0x26E1},
|
||||
{0x26E3, 0x26E3}, {0x26E8, 0x26E9}, {0x26EB, 0x26F1},
|
||||
{0x26F4, 0x26F4}, {0x26F6, 0x26F9}, {0x26FB, 0x26FC},
|
||||
{0x26FE, 0x26FF}, {0x273D, 0x273D}, {0x2776, 0x277F},
|
||||
{0x2B56, 0x2B59}, {0x3248, 0x324F}, {0xE000, 0xF8FF},
|
||||
{0xFE00, 0xFE0F}, {0xFFFD, 0xFFFD}, {0x1F100, 0x1F10A},
|
||||
{0x1F110, 0x1F12D}, {0x1F130, 0x1F169}, {0x1F170, 0x1F18D},
|
||||
{0x1F18F, 0x1F190}, {0x1F19B, 0x1F1AC}, {0xE0100, 0xE01EF},
|
||||
{0xF0000, 0xFFFFD}, {0x100000, 0x10FFFD},
|
||||
}
|
||||
|
||||
var emoji = table{
|
||||
{0x203C, 0x203C}, {0x2049, 0x2049}, {0x2122, 0x2122},
|
||||
{0x2139, 0x2139}, {0x2194, 0x2199}, {0x21A9, 0x21AA},
|
||||
{0x231A, 0x231B}, {0x2328, 0x2328}, {0x23CF, 0x23CF},
|
||||
{0x23E9, 0x23F3}, {0x23F8, 0x23FA}, {0x24C2, 0x24C2},
|
||||
{0x25AA, 0x25AB}, {0x25B6, 0x25B6}, {0x25C0, 0x25C0},
|
||||
{0x25FB, 0x25FE}, {0x2600, 0x2604}, {0x260E, 0x260E},
|
||||
{0x2611, 0x2611}, {0x2614, 0x2615}, {0x2618, 0x2618},
|
||||
{0x261D, 0x261D}, {0x2620, 0x2620}, {0x2622, 0x2623},
|
||||
{0x2626, 0x2626}, {0x262A, 0x262A}, {0x262E, 0x262F},
|
||||
{0x2638, 0x263A}, {0x2640, 0x2640}, {0x2642, 0x2642},
|
||||
{0x2648, 0x2653}, {0x265F, 0x2660}, {0x2663, 0x2663},
|
||||
{0x2665, 0x2666}, {0x2668, 0x2668}, {0x267B, 0x267B},
|
||||
{0x267E, 0x267F}, {0x2692, 0x2697}, {0x2699, 0x2699},
|
||||
{0x269B, 0x269C}, {0x26A0, 0x26A1}, {0x26AA, 0x26AB},
|
||||
{0x26B0, 0x26B1}, {0x26BD, 0x26BE}, {0x26C4, 0x26C5},
|
||||
{0x26C8, 0x26C8}, {0x26CE, 0x26CF}, {0x26D1, 0x26D1},
|
||||
{0x26D3, 0x26D4}, {0x26E9, 0x26EA}, {0x26F0, 0x26F5},
|
||||
{0x26F7, 0x26FA}, {0x26FD, 0x26FD}, {0x2702, 0x2702},
|
||||
{0x2705, 0x2705}, {0x2708, 0x270D}, {0x270F, 0x270F},
|
||||
{0x2712, 0x2712}, {0x2714, 0x2714}, {0x2716, 0x2716},
|
||||
{0x271D, 0x271D}, {0x2721, 0x2721}, {0x2728, 0x2728},
|
||||
{0x2733, 0x2734}, {0x2744, 0x2744}, {0x2747, 0x2747},
|
||||
{0x274C, 0x274C}, {0x274E, 0x274E}, {0x2753, 0x2755},
|
||||
{0x2757, 0x2757}, {0x2763, 0x2764}, {0x2795, 0x2797},
|
||||
{0x27A1, 0x27A1}, {0x27B0, 0x27B0}, {0x27BF, 0x27BF},
|
||||
{0x2934, 0x2935}, {0x2B05, 0x2B07}, {0x2B1B, 0x2B1C},
|
||||
{0x2B50, 0x2B50}, {0x2B55, 0x2B55}, {0x3030, 0x3030},
|
||||
{0x303D, 0x303D}, {0x3297, 0x3297}, {0x3299, 0x3299},
|
||||
{0x1F004, 0x1F004}, {0x1F0CF, 0x1F0CF}, {0x1F170, 0x1F171},
|
||||
{0x1F17E, 0x1F17F}, {0x1F18E, 0x1F18E}, {0x1F191, 0x1F19A},
|
||||
{0x1F1E6, 0x1F1FF}, {0x1F201, 0x1F202}, {0x1F21A, 0x1F21A},
|
||||
{0x1F22F, 0x1F22F}, {0x1F232, 0x1F23A}, {0x1F250, 0x1F251},
|
||||
{0x1F300, 0x1F321}, {0x1F324, 0x1F393}, {0x1F396, 0x1F397},
|
||||
{0x1F399, 0x1F39B}, {0x1F39E, 0x1F3F0}, {0x1F3F3, 0x1F3F5},
|
||||
{0x1F3F7, 0x1F4FD}, {0x1F4FF, 0x1F53D}, {0x1F549, 0x1F54E},
|
||||
{0x1F550, 0x1F567}, {0x1F56F, 0x1F570}, {0x1F573, 0x1F57A},
|
||||
{0x1F587, 0x1F587}, {0x1F58A, 0x1F58D}, {0x1F590, 0x1F590},
|
||||
{0x1F595, 0x1F596}, {0x1F5A4, 0x1F5A5}, {0x1F5A8, 0x1F5A8},
|
||||
{0x1F5B1, 0x1F5B2}, {0x1F5BC, 0x1F5BC}, {0x1F5C2, 0x1F5C4},
|
||||
{0x1F5D1, 0x1F5D3}, {0x1F5DC, 0x1F5DE}, {0x1F5E1, 0x1F5E1},
|
||||
{0x1F5E3, 0x1F5E3}, {0x1F5E8, 0x1F5E8}, {0x1F5EF, 0x1F5EF},
|
||||
{0x1F5F3, 0x1F5F3}, {0x1F5FA, 0x1F64F}, {0x1F680, 0x1F6C5},
|
||||
{0x1F6CB, 0x1F6D2}, {0x1F6E0, 0x1F6E5}, {0x1F6E9, 0x1F6E9},
|
||||
{0x1F6EB, 0x1F6EC}, {0x1F6F0, 0x1F6F0}, {0x1F6F3, 0x1F6F9},
|
||||
{0x1F910, 0x1F93A}, {0x1F93C, 0x1F93E}, {0x1F940, 0x1F945},
|
||||
{0x1F947, 0x1F970}, {0x1F973, 0x1F976}, {0x1F97A, 0x1F97A},
|
||||
{0x1F97C, 0x1F9A2}, {0x1F9B0, 0x1F9B9}, {0x1F9C0, 0x1F9C2},
|
||||
{0x1F9D0, 0x1F9FF},
|
||||
}
|
||||
|
||||
var notassigned = table{
|
||||
{0x0378, 0x0379}, {0x0380, 0x0383}, {0x038B, 0x038B},
|
||||
{0x038D, 0x038D}, {0x03A2, 0x03A2}, {0x0530, 0x0530},
|
||||
{0x0557, 0x0558}, {0x0560, 0x0560}, {0x0588, 0x0588},
|
||||
{0x058B, 0x058C}, {0x0590, 0x0590}, {0x05C8, 0x05CF},
|
||||
{0x05EB, 0x05EF}, {0x05F5, 0x05FF}, {0x061D, 0x061D},
|
||||
{0x070E, 0x070E}, {0x074B, 0x074C}, {0x07B2, 0x07BF},
|
||||
{0x07FB, 0x07FF}, {0x082E, 0x082F}, {0x083F, 0x083F},
|
||||
{0x085C, 0x085D}, {0x085F, 0x089F}, {0x08B5, 0x08B5},
|
||||
{0x08BE, 0x08D3}, {0x0984, 0x0984}, {0x098D, 0x098E},
|
||||
{0x0991, 0x0992}, {0x09A9, 0x09A9}, {0x09B1, 0x09B1},
|
||||
{0x09B3, 0x09B5}, {0x09BA, 0x09BB}, {0x09C5, 0x09C6},
|
||||
{0x09C9, 0x09CA}, {0x09CF, 0x09D6}, {0x09D8, 0x09DB},
|
||||
{0x09DE, 0x09DE}, {0x09E4, 0x09E5}, {0x09FC, 0x0A00},
|
||||
{0x0A04, 0x0A04}, {0x0A0B, 0x0A0E}, {0x0A11, 0x0A12},
|
||||
{0x0A29, 0x0A29}, {0x0A31, 0x0A31}, {0x0A34, 0x0A34},
|
||||
{0x0A37, 0x0A37}, {0x0A3A, 0x0A3B}, {0x0A3D, 0x0A3D},
|
||||
{0x0A43, 0x0A46}, {0x0A49, 0x0A4A}, {0x0A4E, 0x0A50},
|
||||
{0x0A52, 0x0A58}, {0x0A5D, 0x0A5D}, {0x0A5F, 0x0A65},
|
||||
{0x0A76, 0x0A80}, {0x0A84, 0x0A84}, {0x0A8E, 0x0A8E},
|
||||
{0x0A92, 0x0A92}, {0x0AA9, 0x0AA9}, {0x0AB1, 0x0AB1},
|
||||
{0x0AB4, 0x0AB4}, {0x0ABA, 0x0ABB}, {0x0AC6, 0x0AC6},
|
||||
{0x0ACA, 0x0ACA}, {0x0ACE, 0x0ACF}, {0x0AD1, 0x0ADF},
|
||||
{0x0AE4, 0x0AE5}, {0x0AF2, 0x0AF8}, {0x0AFA, 0x0B00},
|
||||
{0x0B04, 0x0B04}, {0x0B0D, 0x0B0E}, {0x0B11, 0x0B12},
|
||||
{0x0B29, 0x0B29}, {0x0B31, 0x0B31}, {0x0B34, 0x0B34},
|
||||
{0x0B3A, 0x0B3B}, {0x0B45, 0x0B46}, {0x0B49, 0x0B4A},
|
||||
{0x0B4E, 0x0B55}, {0x0B58, 0x0B5B}, {0x0B5E, 0x0B5E},
|
||||
{0x0B64, 0x0B65}, {0x0B78, 0x0B81}, {0x0B84, 0x0B84},
|
||||
{0x0B8B, 0x0B8D}, {0x0B91, 0x0B91}, {0x0B96, 0x0B98},
|
||||
{0x0B9B, 0x0B9B}, {0x0B9D, 0x0B9D}, {0x0BA0, 0x0BA2},
|
||||
{0x0BA5, 0x0BA7}, {0x0BAB, 0x0BAD}, {0x0BBA, 0x0BBD},
|
||||
{0x0BC3, 0x0BC5}, {0x0BC9, 0x0BC9}, {0x0BCE, 0x0BCF},
|
||||
{0x0BD1, 0x0BD6}, {0x0BD8, 0x0BE5}, {0x0BFB, 0x0BFF},
|
||||
{0x0C04, 0x0C04}, {0x0C0D, 0x0C0D}, {0x0C11, 0x0C11},
|
||||
{0x0C29, 0x0C29}, {0x0C3A, 0x0C3C}, {0x0C45, 0x0C45},
|
||||
{0x0C49, 0x0C49}, {0x0C4E, 0x0C54}, {0x0C57, 0x0C57},
|
||||
{0x0C5B, 0x0C5F}, {0x0C64, 0x0C65}, {0x0C70, 0x0C77},
|
||||
{0x0C84, 0x0C84}, {0x0C8D, 0x0C8D}, {0x0C91, 0x0C91},
|
||||
{0x0CA9, 0x0CA9}, {0x0CB4, 0x0CB4}, {0x0CBA, 0x0CBB},
|
||||
{0x0CC5, 0x0CC5}, {0x0CC9, 0x0CC9}, {0x0CCE, 0x0CD4},
|
||||
{0x0CD7, 0x0CDD}, {0x0CDF, 0x0CDF}, {0x0CE4, 0x0CE5},
|
||||
{0x0CF0, 0x0CF0}, {0x0CF3, 0x0D00}, {0x0D04, 0x0D04},
|
||||
{0x0D0D, 0x0D0D}, {0x0D11, 0x0D11}, {0x0D3B, 0x0D3C},
|
||||
{0x0D45, 0x0D45}, {0x0D49, 0x0D49}, {0x0D50, 0x0D53},
|
||||
{0x0D64, 0x0D65}, {0x0D80, 0x0D81}, {0x0D84, 0x0D84},
|
||||
{0x0D97, 0x0D99}, {0x0DB2, 0x0DB2}, {0x0DBC, 0x0DBC},
|
||||
{0x0DBE, 0x0DBF}, {0x0DC7, 0x0DC9}, {0x0DCB, 0x0DCE},
|
||||
{0x0DD5, 0x0DD5}, {0x0DD7, 0x0DD7}, {0x0DE0, 0x0DE5},
|
||||
{0x0DF0, 0x0DF1}, {0x0DF5, 0x0E00}, {0x0E3B, 0x0E3E},
|
||||
{0x0E5C, 0x0E80}, {0x0E83, 0x0E83}, {0x0E85, 0x0E86},
|
||||
{0x0E89, 0x0E89}, {0x0E8B, 0x0E8C}, {0x0E8E, 0x0E93},
|
||||
{0x0E98, 0x0E98}, {0x0EA0, 0x0EA0}, {0x0EA4, 0x0EA4},
|
||||
{0x0EA6, 0x0EA6}, {0x0EA8, 0x0EA9}, {0x0EAC, 0x0EAC},
|
||||
{0x0EBA, 0x0EBA}, {0x0EBE, 0x0EBF}, {0x0EC5, 0x0EC5},
|
||||
{0x0EC7, 0x0EC7}, {0x0ECE, 0x0ECF}, {0x0EDA, 0x0EDB},
|
||||
{0x0EE0, 0x0EFF}, {0x0F48, 0x0F48}, {0x0F6D, 0x0F70},
|
||||
{0x0F98, 0x0F98}, {0x0FBD, 0x0FBD}, {0x0FCD, 0x0FCD},
|
||||
{0x0FDB, 0x0FFF}, {0x10C6, 0x10C6}, {0x10C8, 0x10CC},
|
||||
{0x10CE, 0x10CF}, {0x1249, 0x1249}, {0x124E, 0x124F},
|
||||
{0x1257, 0x1257}, {0x1259, 0x1259}, {0x125E, 0x125F},
|
||||
{0x1289, 0x1289}, {0x128E, 0x128F}, {0x12B1, 0x12B1},
|
||||
{0x12B6, 0x12B7}, {0x12BF, 0x12BF}, {0x12C1, 0x12C1},
|
||||
{0x12C6, 0x12C7}, {0x12D7, 0x12D7}, {0x1311, 0x1311},
|
||||
{0x1316, 0x1317}, {0x135B, 0x135C}, {0x137D, 0x137F},
|
||||
{0x139A, 0x139F}, {0x13F6, 0x13F7}, {0x13FE, 0x13FF},
|
||||
{0x169D, 0x169F}, {0x16F9, 0x16FF}, {0x170D, 0x170D},
|
||||
{0x1715, 0x171F}, {0x1737, 0x173F}, {0x1754, 0x175F},
|
||||
{0x176D, 0x176D}, {0x1771, 0x1771}, {0x1774, 0x177F},
|
||||
{0x17DE, 0x17DF}, {0x17EA, 0x17EF}, {0x17FA, 0x17FF},
|
||||
{0x180F, 0x180F}, {0x181A, 0x181F}, {0x1878, 0x187F},
|
||||
{0x18AB, 0x18AF}, {0x18F6, 0x18FF}, {0x191F, 0x191F},
|
||||
{0x192C, 0x192F}, {0x193C, 0x193F}, {0x1941, 0x1943},
|
||||
{0x196E, 0x196F}, {0x1975, 0x197F}, {0x19AC, 0x19AF},
|
||||
{0x19CA, 0x19CF}, {0x19DB, 0x19DD}, {0x1A1C, 0x1A1D},
|
||||
{0x1A5F, 0x1A5F}, {0x1A7D, 0x1A7E}, {0x1A8A, 0x1A8F},
|
||||
{0x1A9A, 0x1A9F}, {0x1AAE, 0x1AAF}, {0x1ABF, 0x1AFF},
|
||||
{0x1B4C, 0x1B4F}, {0x1B7D, 0x1B7F}, {0x1BF4, 0x1BFB},
|
||||
{0x1C38, 0x1C3A}, {0x1C4A, 0x1C4C}, {0x1C89, 0x1CBF},
|
||||
{0x1CC8, 0x1CCF}, {0x1CF7, 0x1CF7}, {0x1CFA, 0x1CFF},
|
||||
{0x1DF6, 0x1DFA}, {0x1F16, 0x1F17}, {0x1F1E, 0x1F1F},
|
||||
{0x1F46, 0x1F47}, {0x1F4E, 0x1F4F}, {0x1F58, 0x1F58},
|
||||
{0x1F5A, 0x1F5A}, {0x1F5C, 0x1F5C}, {0x1F5E, 0x1F5E},
|
||||
{0x1F7E, 0x1F7F}, {0x1FB5, 0x1FB5}, {0x1FC5, 0x1FC5},
|
||||
{0x1FD4, 0x1FD5}, {0x1FDC, 0x1FDC}, {0x1FF0, 0x1FF1},
|
||||
{0x1FF5, 0x1FF5}, {0x1FFF, 0x1FFF}, {0x2065, 0x2065},
|
||||
{0x2072, 0x2073}, {0x208F, 0x208F}, {0x209D, 0x209F},
|
||||
{0x20BF, 0x20CF}, {0x20F1, 0x20FF}, {0x218C, 0x218F},
|
||||
{0x23FF, 0x23FF}, {0x2427, 0x243F}, {0x244B, 0x245F},
|
||||
{0x2B74, 0x2B75}, {0x2B96, 0x2B97}, {0x2BBA, 0x2BBC},
|
||||
{0x2BC9, 0x2BC9}, {0x2BD2, 0x2BEB}, {0x2BF0, 0x2BFF},
|
||||
{0x2C2F, 0x2C2F}, {0x2C5F, 0x2C5F}, {0x2CF4, 0x2CF8},
|
||||
{0x2D26, 0x2D26}, {0x2D28, 0x2D2C}, {0x2D2E, 0x2D2F},
|
||||
{0x2D68, 0x2D6E}, {0x2D71, 0x2D7E}, {0x2D97, 0x2D9F},
|
||||
{0x2DA7, 0x2DA7}, {0x2DAF, 0x2DAF}, {0x2DB7, 0x2DB7},
|
||||
{0x2DBF, 0x2DBF}, {0x2DC7, 0x2DC7}, {0x2DCF, 0x2DCF},
|
||||
{0x2DD7, 0x2DD7}, {0x2DDF, 0x2DDF}, {0x2E45, 0x2E7F},
|
||||
{0x2E9A, 0x2E9A}, {0x2EF4, 0x2EFF}, {0x2FD6, 0x2FEF},
|
||||
{0x2FFC, 0x2FFF}, {0x3040, 0x3040}, {0x3097, 0x3098},
|
||||
{0x3100, 0x3104}, {0x312E, 0x3130}, {0x318F, 0x318F},
|
||||
{0x31BB, 0x31BF}, {0x31E4, 0x31EF}, {0x321F, 0x321F},
|
||||
{0x32FF, 0x32FF}, {0x4DB6, 0x4DBF}, {0x9FD6, 0x9FFF},
|
||||
{0xA48D, 0xA48F}, {0xA4C7, 0xA4CF}, {0xA62C, 0xA63F},
|
||||
{0xA6F8, 0xA6FF}, {0xA7AF, 0xA7AF}, {0xA7B8, 0xA7F6},
|
||||
{0xA82C, 0xA82F}, {0xA83A, 0xA83F}, {0xA878, 0xA87F},
|
||||
{0xA8C6, 0xA8CD}, {0xA8DA, 0xA8DF}, {0xA8FE, 0xA8FF},
|
||||
{0xA954, 0xA95E}, {0xA97D, 0xA97F}, {0xA9CE, 0xA9CE},
|
||||
{0xA9DA, 0xA9DD}, {0xA9FF, 0xA9FF}, {0xAA37, 0xAA3F},
|
||||
{0xAA4E, 0xAA4F}, {0xAA5A, 0xAA5B}, {0xAAC3, 0xAADA},
|
||||
{0xAAF7, 0xAB00}, {0xAB07, 0xAB08}, {0xAB0F, 0xAB10},
|
||||
{0xAB17, 0xAB1F}, {0xAB27, 0xAB27}, {0xAB2F, 0xAB2F},
|
||||
{0xAB66, 0xAB6F}, {0xABEE, 0xABEF}, {0xABFA, 0xABFF},
|
||||
{0xD7A4, 0xD7AF}, {0xD7C7, 0xD7CA}, {0xD7FC, 0xD7FF},
|
||||
{0xFA6E, 0xFA6F}, {0xFADA, 0xFAFF}, {0xFB07, 0xFB12},
|
||||
{0xFB18, 0xFB1C}, {0xFB37, 0xFB37}, {0xFB3D, 0xFB3D},
|
||||
{0xFB3F, 0xFB3F}, {0xFB42, 0xFB42}, {0xFB45, 0xFB45},
|
||||
{0xFBC2, 0xFBD2}, {0xFD40, 0xFD4F}, {0xFD90, 0xFD91},
|
||||
{0xFDC8, 0xFDEF}, {0xFDFE, 0xFDFF}, {0xFE1A, 0xFE1F},
|
||||
{0xFE53, 0xFE53}, {0xFE67, 0xFE67}, {0xFE6C, 0xFE6F},
|
||||
{0xFE75, 0xFE75}, {0xFEFD, 0xFEFE}, {0xFF00, 0xFF00},
|
||||
{0xFFBF, 0xFFC1}, {0xFFC8, 0xFFC9}, {0xFFD0, 0xFFD1},
|
||||
{0xFFD8, 0xFFD9}, {0xFFDD, 0xFFDF}, {0xFFE7, 0xFFE7},
|
||||
{0xFFEF, 0xFFF8}, {0xFFFE, 0xFFFF}, {0x1000C, 0x1000C},
|
||||
{0x10027, 0x10027}, {0x1003B, 0x1003B}, {0x1003E, 0x1003E},
|
||||
{0x1004E, 0x1004F}, {0x1005E, 0x1007F}, {0x100FB, 0x100FF},
|
||||
{0x10103, 0x10106}, {0x10134, 0x10136}, {0x1018F, 0x1018F},
|
||||
{0x1019C, 0x1019F}, {0x101A1, 0x101CF}, {0x101FE, 0x1027F},
|
||||
{0x1029D, 0x1029F}, {0x102D1, 0x102DF}, {0x102FC, 0x102FF},
|
||||
{0x10324, 0x1032F}, {0x1034B, 0x1034F}, {0x1037B, 0x1037F},
|
||||
{0x1039E, 0x1039E}, {0x103C4, 0x103C7}, {0x103D6, 0x103FF},
|
||||
{0x1049E, 0x1049F}, {0x104AA, 0x104AF}, {0x104D4, 0x104D7},
|
||||
{0x104FC, 0x104FF}, {0x10528, 0x1052F}, {0x10564, 0x1056E},
|
||||
{0x10570, 0x105FF}, {0x10737, 0x1073F}, {0x10756, 0x1075F},
|
||||
{0x10768, 0x107FF}, {0x10806, 0x10807}, {0x10809, 0x10809},
|
||||
{0x10836, 0x10836}, {0x10839, 0x1083B}, {0x1083D, 0x1083E},
|
||||
{0x10856, 0x10856}, {0x1089F, 0x108A6}, {0x108B0, 0x108DF},
|
||||
{0x108F3, 0x108F3}, {0x108F6, 0x108FA}, {0x1091C, 0x1091E},
|
||||
{0x1093A, 0x1093E}, {0x10940, 0x1097F}, {0x109B8, 0x109BB},
|
||||
{0x109D0, 0x109D1}, {0x10A04, 0x10A04}, {0x10A07, 0x10A0B},
|
||||
{0x10A14, 0x10A14}, {0x10A18, 0x10A18}, {0x10A34, 0x10A37},
|
||||
{0x10A3B, 0x10A3E}, {0x10A48, 0x10A4F}, {0x10A59, 0x10A5F},
|
||||
{0x10AA0, 0x10ABF}, {0x10AE7, 0x10AEA}, {0x10AF7, 0x10AFF},
|
||||
{0x10B36, 0x10B38}, {0x10B56, 0x10B57}, {0x10B73, 0x10B77},
|
||||
{0x10B92, 0x10B98}, {0x10B9D, 0x10BA8}, {0x10BB0, 0x10BFF},
|
||||
{0x10C49, 0x10C7F}, {0x10CB3, 0x10CBF}, {0x10CF3, 0x10CF9},
|
||||
{0x10D00, 0x10E5F}, {0x10E7F, 0x10FFF}, {0x1104E, 0x11051},
|
||||
{0x11070, 0x1107E}, {0x110C2, 0x110CF}, {0x110E9, 0x110EF},
|
||||
{0x110FA, 0x110FF}, {0x11135, 0x11135}, {0x11144, 0x1114F},
|
||||
{0x11177, 0x1117F}, {0x111CE, 0x111CF}, {0x111E0, 0x111E0},
|
||||
{0x111F5, 0x111FF}, {0x11212, 0x11212}, {0x1123F, 0x1127F},
|
||||
{0x11287, 0x11287}, {0x11289, 0x11289}, {0x1128E, 0x1128E},
|
||||
{0x1129E, 0x1129E}, {0x112AA, 0x112AF}, {0x112EB, 0x112EF},
|
||||
{0x112FA, 0x112FF}, {0x11304, 0x11304}, {0x1130D, 0x1130E},
|
||||
{0x11311, 0x11312}, {0x11329, 0x11329}, {0x11331, 0x11331},
|
||||
{0x11334, 0x11334}, {0x1133A, 0x1133B}, {0x11345, 0x11346},
|
||||
{0x11349, 0x1134A}, {0x1134E, 0x1134F}, {0x11351, 0x11356},
|
||||
{0x11358, 0x1135C}, {0x11364, 0x11365}, {0x1136D, 0x1136F},
|
||||
{0x11375, 0x113FF}, {0x1145A, 0x1145A}, {0x1145C, 0x1145C},
|
||||
{0x1145E, 0x1147F}, {0x114C8, 0x114CF}, {0x114DA, 0x1157F},
|
||||
{0x115B6, 0x115B7}, {0x115DE, 0x115FF}, {0x11645, 0x1164F},
|
||||
{0x1165A, 0x1165F}, {0x1166D, 0x1167F}, {0x116B8, 0x116BF},
|
||||
{0x116CA, 0x116FF}, {0x1171A, 0x1171C}, {0x1172C, 0x1172F},
|
||||
{0x11740, 0x1189F}, {0x118F3, 0x118FE}, {0x11900, 0x11ABF},
|
||||
{0x11AF9, 0x11BFF}, {0x11C09, 0x11C09}, {0x11C37, 0x11C37},
|
||||
{0x11C46, 0x11C4F}, {0x11C6D, 0x11C6F}, {0x11C90, 0x11C91},
|
||||
{0x11CA8, 0x11CA8}, {0x11CB7, 0x11FFF}, {0x1239A, 0x123FF},
|
||||
{0x1246F, 0x1246F}, {0x12475, 0x1247F}, {0x12544, 0x12FFF},
|
||||
{0x1342F, 0x143FF}, {0x14647, 0x167FF}, {0x16A39, 0x16A3F},
|
||||
{0x16A5F, 0x16A5F}, {0x16A6A, 0x16A6D}, {0x16A70, 0x16ACF},
|
||||
{0x16AEE, 0x16AEF}, {0x16AF6, 0x16AFF}, {0x16B46, 0x16B4F},
|
||||
{0x16B5A, 0x16B5A}, {0x16B62, 0x16B62}, {0x16B78, 0x16B7C},
|
||||
{0x16B90, 0x16EFF}, {0x16F45, 0x16F4F}, {0x16F7F, 0x16F8E},
|
||||
{0x16FA0, 0x16FDF}, {0x16FE1, 0x16FFF}, {0x187ED, 0x187FF},
|
||||
{0x18AF3, 0x1AFFF}, {0x1B002, 0x1BBFF}, {0x1BC6B, 0x1BC6F},
|
||||
{0x1BC7D, 0x1BC7F}, {0x1BC89, 0x1BC8F}, {0x1BC9A, 0x1BC9B},
|
||||
{0x1BCA4, 0x1CFFF}, {0x1D0F6, 0x1D0FF}, {0x1D127, 0x1D128},
|
||||
{0x1D1E9, 0x1D1FF}, {0x1D246, 0x1D2FF}, {0x1D357, 0x1D35F},
|
||||
{0x1D372, 0x1D3FF}, {0x1D455, 0x1D455}, {0x1D49D, 0x1D49D},
|
||||
{0x1D4A0, 0x1D4A1}, {0x1D4A3, 0x1D4A4}, {0x1D4A7, 0x1D4A8},
|
||||
{0x1D4AD, 0x1D4AD}, {0x1D4BA, 0x1D4BA}, {0x1D4BC, 0x1D4BC},
|
||||
{0x1D4C4, 0x1D4C4}, {0x1D506, 0x1D506}, {0x1D50B, 0x1D50C},
|
||||
{0x1D515, 0x1D515}, {0x1D51D, 0x1D51D}, {0x1D53A, 0x1D53A},
|
||||
{0x1D53F, 0x1D53F}, {0x1D545, 0x1D545}, {0x1D547, 0x1D549},
|
||||
{0x1D551, 0x1D551}, {0x1D6A6, 0x1D6A7}, {0x1D7CC, 0x1D7CD},
|
||||
{0x1DA8C, 0x1DA9A}, {0x1DAA0, 0x1DAA0}, {0x1DAB0, 0x1DFFF},
|
||||
{0x1E007, 0x1E007}, {0x1E019, 0x1E01A}, {0x1E022, 0x1E022},
|
||||
{0x1E025, 0x1E025}, {0x1E02B, 0x1E7FF}, {0x1E8C5, 0x1E8C6},
|
||||
{0x1E8D7, 0x1E8FF}, {0x1E94B, 0x1E94F}, {0x1E95A, 0x1E95D},
|
||||
{0x1E960, 0x1EDFF}, {0x1EE04, 0x1EE04}, {0x1EE20, 0x1EE20},
|
||||
{0x1EE23, 0x1EE23}, {0x1EE25, 0x1EE26}, {0x1EE28, 0x1EE28},
|
||||
{0x1EE33, 0x1EE33}, {0x1EE38, 0x1EE38}, {0x1EE3A, 0x1EE3A},
|
||||
{0x1EE3C, 0x1EE41}, {0x1EE43, 0x1EE46}, {0x1EE48, 0x1EE48},
|
||||
{0x1EE4A, 0x1EE4A}, {0x1EE4C, 0x1EE4C}, {0x1EE50, 0x1EE50},
|
||||
{0x1EE53, 0x1EE53}, {0x1EE55, 0x1EE56}, {0x1EE58, 0x1EE58},
|
||||
{0x1EE5A, 0x1EE5A}, {0x1EE5C, 0x1EE5C}, {0x1EE5E, 0x1EE5E},
|
||||
{0x1EE60, 0x1EE60}, {0x1EE63, 0x1EE63}, {0x1EE65, 0x1EE66},
|
||||
{0x1EE6B, 0x1EE6B}, {0x1EE73, 0x1EE73}, {0x1EE78, 0x1EE78},
|
||||
{0x1EE7D, 0x1EE7D}, {0x1EE7F, 0x1EE7F}, {0x1EE8A, 0x1EE8A},
|
||||
{0x1EE9C, 0x1EEA0}, {0x1EEA4, 0x1EEA4}, {0x1EEAA, 0x1EEAA},
|
||||
{0x1EEBC, 0x1EEEF}, {0x1EEF2, 0x1EFFF}, {0x1F02C, 0x1F02F},
|
||||
{0x1F094, 0x1F09F}, {0x1F0AF, 0x1F0B0}, {0x1F0C0, 0x1F0C0},
|
||||
{0x1F0D0, 0x1F0D0}, {0x1F0F6, 0x1F0FF}, {0x1F10D, 0x1F10F},
|
||||
{0x1F12F, 0x1F12F}, {0x1F16C, 0x1F16F}, {0x1F1AD, 0x1F1E5},
|
||||
{0x1F203, 0x1F20F}, {0x1F23C, 0x1F23F}, {0x1F249, 0x1F24F},
|
||||
{0x1F252, 0x1F2FF}, {0x1F6D3, 0x1F6DF}, {0x1F6ED, 0x1F6EF},
|
||||
{0x1F6F7, 0x1F6FF}, {0x1F774, 0x1F77F}, {0x1F7D5, 0x1F7FF},
|
||||
{0x1F80C, 0x1F80F}, {0x1F848, 0x1F84F}, {0x1F85A, 0x1F85F},
|
||||
{0x1F888, 0x1F88F}, {0x1F8AE, 0x1F90F}, {0x1F91F, 0x1F91F},
|
||||
{0x1F928, 0x1F92F}, {0x1F931, 0x1F932}, {0x1F93F, 0x1F93F},
|
||||
{0x1F94C, 0x1F94F}, {0x1F95F, 0x1F97F}, {0x1F992, 0x1F9BF},
|
||||
{0x1F9C1, 0x1FFFF}, {0x2A6D7, 0x2A6FF}, {0x2B735, 0x2B73F},
|
||||
{0x2B81E, 0x2B81F}, {0x2CEA2, 0x2F7FF}, {0x2FA1E, 0xE0000},
|
||||
{0xE0002, 0xE001F}, {0xE0080, 0xE00FF}, {0xE01F0, 0xEFFFF},
|
||||
{0xFFFFE, 0xFFFFF},
|
||||
}
|
||||
|
||||
var neutral = table{
|
||||
{0x0000, 0x001F}, {0x007F, 0x00A0}, {0x00A9, 0x00A9},
|
||||
{0x00AB, 0x00AB}, {0x00B5, 0x00B5}, {0x00BB, 0x00BB},
|
||||
{0x00C0, 0x00C5}, {0x00C7, 0x00CF}, {0x00D1, 0x00D6},
|
||||
{0x00D9, 0x00DD}, {0x00E2, 0x00E5}, {0x00E7, 0x00E7},
|
||||
{0x00EB, 0x00EB}, {0x00EE, 0x00EF}, {0x00F1, 0x00F1},
|
||||
{0x00F4, 0x00F6}, {0x00FB, 0x00FB}, {0x00FD, 0x00FD},
|
||||
{0x00FF, 0x0100}, {0x0102, 0x0110}, {0x0112, 0x0112},
|
||||
{0x0114, 0x011A}, {0x011C, 0x0125}, {0x0128, 0x012A},
|
||||
{0x012C, 0x0130}, {0x0134, 0x0137}, {0x0139, 0x013E},
|
||||
{0x0143, 0x0143}, {0x0145, 0x0147}, {0x014C, 0x014C},
|
||||
{0x014E, 0x0151}, {0x0154, 0x0165}, {0x0168, 0x016A},
|
||||
{0x016C, 0x01CD}, {0x01CF, 0x01CF}, {0x01D1, 0x01D1},
|
||||
{0x01D3, 0x01D3}, {0x01D5, 0x01D5}, {0x01D7, 0x01D7},
|
||||
{0x01D9, 0x01D9}, {0x01DB, 0x01DB}, {0x01DD, 0x0250},
|
||||
{0x0252, 0x0260}, {0x0262, 0x02C3}, {0x02C5, 0x02C6},
|
||||
{0x02C8, 0x02C8}, {0x02CC, 0x02CC}, {0x02CE, 0x02CF},
|
||||
{0x02D1, 0x02D7}, {0x02DC, 0x02DC}, {0x02DE, 0x02DE},
|
||||
{0x02E0, 0x02FF}, {0x0370, 0x0377}, {0x037A, 0x037F},
|
||||
{0x0384, 0x038A}, {0x038C, 0x038C}, {0x038E, 0x0390},
|
||||
{0x03AA, 0x03B0}, {0x03C2, 0x03C2}, {0x03CA, 0x0400},
|
||||
{0x0402, 0x040F}, {0x0450, 0x0450}, {0x0452, 0x052F},
|
||||
{0x0531, 0x0556}, {0x0559, 0x055F}, {0x0561, 0x0587},
|
||||
{0x0589, 0x058A}, {0x058D, 0x058F}, {0x0591, 0x05C7},
|
||||
{0x05D0, 0x05EA}, {0x05F0, 0x05F4}, {0x0600, 0x061C},
|
||||
{0x061E, 0x070D}, {0x070F, 0x074A}, {0x074D, 0x07B1},
|
||||
{0x07C0, 0x07FA}, {0x0800, 0x082D}, {0x0830, 0x083E},
|
||||
{0x0840, 0x085B}, {0x085E, 0x085E}, {0x08A0, 0x08B4},
|
||||
{0x08B6, 0x08BD}, {0x08D4, 0x0983}, {0x0985, 0x098C},
|
||||
{0x098F, 0x0990}, {0x0993, 0x09A8}, {0x09AA, 0x09B0},
|
||||
{0x09B2, 0x09B2}, {0x09B6, 0x09B9}, {0x09BC, 0x09C4},
|
||||
{0x09C7, 0x09C8}, {0x09CB, 0x09CE}, {0x09D7, 0x09D7},
|
||||
{0x09DC, 0x09DD}, {0x09DF, 0x09E3}, {0x09E6, 0x09FB},
|
||||
{0x0A01, 0x0A03}, {0x0A05, 0x0A0A}, {0x0A0F, 0x0A10},
|
||||
{0x0A13, 0x0A28}, {0x0A2A, 0x0A30}, {0x0A32, 0x0A33},
|
||||
{0x0A35, 0x0A36}, {0x0A38, 0x0A39}, {0x0A3C, 0x0A3C},
|
||||
{0x0A3E, 0x0A42}, {0x0A47, 0x0A48}, {0x0A4B, 0x0A4D},
|
||||
{0x0A51, 0x0A51}, {0x0A59, 0x0A5C}, {0x0A5E, 0x0A5E},
|
||||
{0x0A66, 0x0A75}, {0x0A81, 0x0A83}, {0x0A85, 0x0A8D},
|
||||
{0x0A8F, 0x0A91}, {0x0A93, 0x0AA8}, {0x0AAA, 0x0AB0},
|
||||
{0x0AB2, 0x0AB3}, {0x0AB5, 0x0AB9}, {0x0ABC, 0x0AC5},
|
||||
{0x0AC7, 0x0AC9}, {0x0ACB, 0x0ACD}, {0x0AD0, 0x0AD0},
|
||||
{0x0AE0, 0x0AE3}, {0x0AE6, 0x0AF1}, {0x0AF9, 0x0AF9},
|
||||
{0x0B01, 0x0B03}, {0x0B05, 0x0B0C}, {0x0B0F, 0x0B10},
|
||||
{0x0B13, 0x0B28}, {0x0B2A, 0x0B30}, {0x0B32, 0x0B33},
|
||||
{0x0B35, 0x0B39}, {0x0B3C, 0x0B44}, {0x0B47, 0x0B48},
|
||||
{0x0B4B, 0x0B4D}, {0x0B56, 0x0B57}, {0x0B5C, 0x0B5D},
|
||||
{0x0B5F, 0x0B63}, {0x0B66, 0x0B77}, {0x0B82, 0x0B83},
|
||||
{0x0B85, 0x0B8A}, {0x0B8E, 0x0B90}, {0x0B92, 0x0B95},
|
||||
{0x0B99, 0x0B9A}, {0x0B9C, 0x0B9C}, {0x0B9E, 0x0B9F},
|
||||
{0x0BA3, 0x0BA4}, {0x0BA8, 0x0BAA}, {0x0BAE, 0x0BB9},
|
||||
{0x0BBE, 0x0BC2}, {0x0BC6, 0x0BC8}, {0x0BCA, 0x0BCD},
|
||||
{0x0BD0, 0x0BD0}, {0x0BD7, 0x0BD7}, {0x0BE6, 0x0BFA},
|
||||
{0x0C00, 0x0C03}, {0x0C05, 0x0C0C}, {0x0C0E, 0x0C10},
|
||||
{0x0C12, 0x0C28}, {0x0C2A, 0x0C39}, {0x0C3D, 0x0C44},
|
||||
{0x0C46, 0x0C48}, {0x0C4A, 0x0C4D}, {0x0C55, 0x0C56},
|
||||
{0x0C58, 0x0C5A}, {0x0C60, 0x0C63}, {0x0C66, 0x0C6F},
|
||||
{0x0C78, 0x0C83}, {0x0C85, 0x0C8C}, {0x0C8E, 0x0C90},
|
||||
{0x0C92, 0x0CA8}, {0x0CAA, 0x0CB3}, {0x0CB5, 0x0CB9},
|
||||
{0x0CBC, 0x0CC4}, {0x0CC6, 0x0CC8}, {0x0CCA, 0x0CCD},
|
||||
{0x0CD5, 0x0CD6}, {0x0CDE, 0x0CDE}, {0x0CE0, 0x0CE3},
|
||||
{0x0CE6, 0x0CEF}, {0x0CF1, 0x0CF2}, {0x0D01, 0x0D03},
|
||||
{0x0D05, 0x0D0C}, {0x0D0E, 0x0D10}, {0x0D12, 0x0D3A},
|
||||
{0x0D3D, 0x0D44}, {0x0D46, 0x0D48}, {0x0D4A, 0x0D4F},
|
||||
{0x0D54, 0x0D63}, {0x0D66, 0x0D7F}, {0x0D82, 0x0D83},
|
||||
{0x0D85, 0x0D96}, {0x0D9A, 0x0DB1}, {0x0DB3, 0x0DBB},
|
||||
{0x0DBD, 0x0DBD}, {0x0DC0, 0x0DC6}, {0x0DCA, 0x0DCA},
|
||||
{0x0DCF, 0x0DD4}, {0x0DD6, 0x0DD6}, {0x0DD8, 0x0DDF},
|
||||
{0x0DE6, 0x0DEF}, {0x0DF2, 0x0DF4}, {0x0E01, 0x0E3A},
|
||||
{0x0E3F, 0x0E5B}, {0x0E81, 0x0E82}, {0x0E84, 0x0E84},
|
||||
{0x0E87, 0x0E88}, {0x0E8A, 0x0E8A}, {0x0E8D, 0x0E8D},
|
||||
{0x0E94, 0x0E97}, {0x0E99, 0x0E9F}, {0x0EA1, 0x0EA3},
|
||||
{0x0EA5, 0x0EA5}, {0x0EA7, 0x0EA7}, {0x0EAA, 0x0EAB},
|
||||
{0x0EAD, 0x0EB9}, {0x0EBB, 0x0EBD}, {0x0EC0, 0x0EC4},
|
||||
{0x0EC6, 0x0EC6}, {0x0EC8, 0x0ECD}, {0x0ED0, 0x0ED9},
|
||||
{0x0EDC, 0x0EDF}, {0x0F00, 0x0F47}, {0x0F49, 0x0F6C},
|
||||
{0x0F71, 0x0F97}, {0x0F99, 0x0FBC}, {0x0FBE, 0x0FCC},
|
||||
{0x0FCE, 0x0FDA}, {0x1000, 0x10C5}, {0x10C7, 0x10C7},
|
||||
{0x10CD, 0x10CD}, {0x10D0, 0x10FF}, {0x1160, 0x1248},
|
||||
{0x124A, 0x124D}, {0x1250, 0x1256}, {0x1258, 0x1258},
|
||||
{0x125A, 0x125D}, {0x1260, 0x1288}, {0x128A, 0x128D},
|
||||
{0x1290, 0x12B0}, {0x12B2, 0x12B5}, {0x12B8, 0x12BE},
|
||||
{0x12C0, 0x12C0}, {0x12C2, 0x12C5}, {0x12C8, 0x12D6},
|
||||
{0x12D8, 0x1310}, {0x1312, 0x1315}, {0x1318, 0x135A},
|
||||
{0x135D, 0x137C}, {0x1380, 0x1399}, {0x13A0, 0x13F5},
|
||||
{0x13F8, 0x13FD}, {0x1400, 0x169C}, {0x16A0, 0x16F8},
|
||||
{0x1700, 0x170C}, {0x170E, 0x1714}, {0x1720, 0x1736},
|
||||
{0x1740, 0x1753}, {0x1760, 0x176C}, {0x176E, 0x1770},
|
||||
{0x1772, 0x1773}, {0x1780, 0x17DD}, {0x17E0, 0x17E9},
|
||||
{0x17F0, 0x17F9}, {0x1800, 0x180E}, {0x1810, 0x1819},
|
||||
{0x1820, 0x1877}, {0x1880, 0x18AA}, {0x18B0, 0x18F5},
|
||||
{0x1900, 0x191E}, {0x1920, 0x192B}, {0x1930, 0x193B},
|
||||
{0x1940, 0x1940}, {0x1944, 0x196D}, {0x1970, 0x1974},
|
||||
{0x1980, 0x19AB}, {0x19B0, 0x19C9}, {0x19D0, 0x19DA},
|
||||
{0x19DE, 0x1A1B}, {0x1A1E, 0x1A5E}, {0x1A60, 0x1A7C},
|
||||
{0x1A7F, 0x1A89}, {0x1A90, 0x1A99}, {0x1AA0, 0x1AAD},
|
||||
{0x1AB0, 0x1ABE}, {0x1B00, 0x1B4B}, {0x1B50, 0x1B7C},
|
||||
{0x1B80, 0x1BF3}, {0x1BFC, 0x1C37}, {0x1C3B, 0x1C49},
|
||||
{0x1C4D, 0x1C88}, {0x1CC0, 0x1CC7}, {0x1CD0, 0x1CF6},
|
||||
{0x1CF8, 0x1CF9}, {0x1D00, 0x1DF5}, {0x1DFB, 0x1F15},
|
||||
{0x1F18, 0x1F1D}, {0x1F20, 0x1F45}, {0x1F48, 0x1F4D},
|
||||
{0x1F50, 0x1F57}, {0x1F59, 0x1F59}, {0x1F5B, 0x1F5B},
|
||||
{0x1F5D, 0x1F5D}, {0x1F5F, 0x1F7D}, {0x1F80, 0x1FB4},
|
||||
{0x1FB6, 0x1FC4}, {0x1FC6, 0x1FD3}, {0x1FD6, 0x1FDB},
|
||||
{0x1FDD, 0x1FEF}, {0x1FF2, 0x1FF4}, {0x1FF6, 0x1FFE},
|
||||
{0x2000, 0x200F}, {0x2011, 0x2012}, {0x2017, 0x2017},
|
||||
{0x201A, 0x201B}, {0x201E, 0x201F}, {0x2023, 0x2023},
|
||||
{0x2028, 0x202F}, {0x2031, 0x2031}, {0x2034, 0x2034},
|
||||
{0x2036, 0x203A}, {0x203C, 0x203D}, {0x203F, 0x2064},
|
||||
{0x2066, 0x2071}, {0x2075, 0x207E}, {0x2080, 0x2080},
|
||||
{0x2085, 0x208E}, {0x2090, 0x209C}, {0x20A0, 0x20A8},
|
||||
{0x20AA, 0x20AB}, {0x20AD, 0x20BE}, {0x20D0, 0x20F0},
|
||||
{0x2100, 0x2102}, {0x2104, 0x2104}, {0x2106, 0x2108},
|
||||
{0x210A, 0x2112}, {0x2114, 0x2115}, {0x2117, 0x2120},
|
||||
{0x2123, 0x2125}, {0x2127, 0x212A}, {0x212C, 0x2152},
|
||||
{0x2155, 0x215A}, {0x215F, 0x215F}, {0x216C, 0x216F},
|
||||
{0x217A, 0x2188}, {0x218A, 0x218B}, {0x219A, 0x21B7},
|
||||
{0x21BA, 0x21D1}, {0x21D3, 0x21D3}, {0x21D5, 0x21E6},
|
||||
{0x21E8, 0x21FF}, {0x2201, 0x2201}, {0x2204, 0x2206},
|
||||
{0x2209, 0x220A}, {0x220C, 0x220E}, {0x2210, 0x2210},
|
||||
{0x2212, 0x2214}, {0x2216, 0x2219}, {0x221B, 0x221C},
|
||||
{0x2221, 0x2222}, {0x2224, 0x2224}, {0x2226, 0x2226},
|
||||
{0x222D, 0x222D}, {0x222F, 0x2233}, {0x2238, 0x223B},
|
||||
{0x223E, 0x2247}, {0x2249, 0x224B}, {0x224D, 0x2251},
|
||||
{0x2253, 0x225F}, {0x2262, 0x2263}, {0x2268, 0x2269},
|
||||
{0x226C, 0x226D}, {0x2270, 0x2281}, {0x2284, 0x2285},
|
||||
{0x2288, 0x2294}, {0x2296, 0x2298}, {0x229A, 0x22A4},
|
||||
{0x22A6, 0x22BE}, {0x22C0, 0x2311}, {0x2313, 0x2319},
|
||||
{0x231C, 0x2328}, {0x232B, 0x23E8}, {0x23ED, 0x23EF},
|
||||
{0x23F1, 0x23F2}, {0x23F4, 0x23FE}, {0x2400, 0x2426},
|
||||
{0x2440, 0x244A}, {0x24EA, 0x24EA}, {0x254C, 0x254F},
|
||||
{0x2574, 0x257F}, {0x2590, 0x2591}, {0x2596, 0x259F},
|
||||
{0x25A2, 0x25A2}, {0x25AA, 0x25B1}, {0x25B4, 0x25B5},
|
||||
{0x25B8, 0x25BB}, {0x25BE, 0x25BF}, {0x25C2, 0x25C5},
|
||||
{0x25C9, 0x25CA}, {0x25CC, 0x25CD}, {0x25D2, 0x25E1},
|
||||
{0x25E6, 0x25EE}, {0x25F0, 0x25FC}, {0x25FF, 0x2604},
|
||||
{0x2607, 0x2608}, {0x260A, 0x260D}, {0x2610, 0x2613},
|
||||
{0x2616, 0x261B}, {0x261D, 0x261D}, {0x261F, 0x263F},
|
||||
{0x2641, 0x2641}, {0x2643, 0x2647}, {0x2654, 0x265F},
|
||||
{0x2662, 0x2662}, {0x2666, 0x2666}, {0x266B, 0x266B},
|
||||
{0x266E, 0x266E}, {0x2670, 0x267E}, {0x2680, 0x2692},
|
||||
{0x2694, 0x269D}, {0x26A0, 0x26A0}, {0x26A2, 0x26A9},
|
||||
{0x26AC, 0x26BC}, {0x26C0, 0x26C3}, {0x26E2, 0x26E2},
|
||||
{0x26E4, 0x26E7}, {0x2700, 0x2704}, {0x2706, 0x2709},
|
||||
{0x270C, 0x2727}, {0x2729, 0x273C}, {0x273E, 0x274B},
|
||||
{0x274D, 0x274D}, {0x274F, 0x2752}, {0x2756, 0x2756},
|
||||
{0x2758, 0x2775}, {0x2780, 0x2794}, {0x2798, 0x27AF},
|
||||
{0x27B1, 0x27BE}, {0x27C0, 0x27E5}, {0x27EE, 0x2984},
|
||||
{0x2987, 0x2B1A}, {0x2B1D, 0x2B4F}, {0x2B51, 0x2B54},
|
||||
{0x2B5A, 0x2B73}, {0x2B76, 0x2B95}, {0x2B98, 0x2BB9},
|
||||
{0x2BBD, 0x2BC8}, {0x2BCA, 0x2BD1}, {0x2BEC, 0x2BEF},
|
||||
{0x2C00, 0x2C2E}, {0x2C30, 0x2C5E}, {0x2C60, 0x2CF3},
|
||||
{0x2CF9, 0x2D25}, {0x2D27, 0x2D27}, {0x2D2D, 0x2D2D},
|
||||
{0x2D30, 0x2D67}, {0x2D6F, 0x2D70}, {0x2D7F, 0x2D96},
|
||||
{0x2DA0, 0x2DA6}, {0x2DA8, 0x2DAE}, {0x2DB0, 0x2DB6},
|
||||
{0x2DB8, 0x2DBE}, {0x2DC0, 0x2DC6}, {0x2DC8, 0x2DCE},
|
||||
{0x2DD0, 0x2DD6}, {0x2DD8, 0x2DDE}, {0x2DE0, 0x2E44},
|
||||
{0x303F, 0x303F}, {0x4DC0, 0x4DFF}, {0xA4D0, 0xA62B},
|
||||
{0xA640, 0xA6F7}, {0xA700, 0xA7AE}, {0xA7B0, 0xA7B7},
|
||||
{0xA7F7, 0xA82B}, {0xA830, 0xA839}, {0xA840, 0xA877},
|
||||
{0xA880, 0xA8C5}, {0xA8CE, 0xA8D9}, {0xA8E0, 0xA8FD},
|
||||
{0xA900, 0xA953}, {0xA95F, 0xA95F}, {0xA980, 0xA9CD},
|
||||
{0xA9CF, 0xA9D9}, {0xA9DE, 0xA9FE}, {0xAA00, 0xAA36},
|
||||
{0xAA40, 0xAA4D}, {0xAA50, 0xAA59}, {0xAA5C, 0xAAC2},
|
||||
{0xAADB, 0xAAF6}, {0xAB01, 0xAB06}, {0xAB09, 0xAB0E},
|
||||
{0xAB11, 0xAB16}, {0xAB20, 0xAB26}, {0xAB28, 0xAB2E},
|
||||
{0xAB30, 0xAB65}, {0xAB70, 0xABED}, {0xABF0, 0xABF9},
|
||||
{0xD7B0, 0xD7C6}, {0xD7CB, 0xD7FB}, {0xD800, 0xDFFF},
|
||||
{0xFB00, 0xFB06}, {0xFB13, 0xFB17}, {0xFB1D, 0xFB36},
|
||||
{0xFB38, 0xFB3C}, {0xFB3E, 0xFB3E}, {0xFB40, 0xFB41},
|
||||
{0xFB43, 0xFB44}, {0xFB46, 0xFBC1}, {0xFBD3, 0xFD3F},
|
||||
{0xFD50, 0xFD8F}, {0xFD92, 0xFDC7}, {0xFDF0, 0xFDFD},
|
||||
{0xFE20, 0xFE2F}, {0xFE70, 0xFE74}, {0xFE76, 0xFEFC},
|
||||
{0xFEFF, 0xFEFF}, {0xFFF9, 0xFFFC}, {0x10000, 0x1000B},
|
||||
{0x1000D, 0x10026}, {0x10028, 0x1003A}, {0x1003C, 0x1003D},
|
||||
{0x1003F, 0x1004D}, {0x10050, 0x1005D}, {0x10080, 0x100FA},
|
||||
{0x10100, 0x10102}, {0x10107, 0x10133}, {0x10137, 0x1018E},
|
||||
{0x10190, 0x1019B}, {0x101A0, 0x101A0}, {0x101D0, 0x101FD},
|
||||
{0x10280, 0x1029C}, {0x102A0, 0x102D0}, {0x102E0, 0x102FB},
|
||||
{0x10300, 0x10323}, {0x10330, 0x1034A}, {0x10350, 0x1037A},
|
||||
{0x10380, 0x1039D}, {0x1039F, 0x103C3}, {0x103C8, 0x103D5},
|
||||
{0x10400, 0x1049D}, {0x104A0, 0x104A9}, {0x104B0, 0x104D3},
|
||||
{0x104D8, 0x104FB}, {0x10500, 0x10527}, {0x10530, 0x10563},
|
||||
{0x1056F, 0x1056F}, {0x10600, 0x10736}, {0x10740, 0x10755},
|
||||
{0x10760, 0x10767}, {0x10800, 0x10805}, {0x10808, 0x10808},
|
||||
{0x1080A, 0x10835}, {0x10837, 0x10838}, {0x1083C, 0x1083C},
|
||||
{0x1083F, 0x10855}, {0x10857, 0x1089E}, {0x108A7, 0x108AF},
|
||||
{0x108E0, 0x108F2}, {0x108F4, 0x108F5}, {0x108FB, 0x1091B},
|
||||
{0x1091F, 0x10939}, {0x1093F, 0x1093F}, {0x10980, 0x109B7},
|
||||
{0x109BC, 0x109CF}, {0x109D2, 0x10A03}, {0x10A05, 0x10A06},
|
||||
{0x10A0C, 0x10A13}, {0x10A15, 0x10A17}, {0x10A19, 0x10A33},
|
||||
{0x10A38, 0x10A3A}, {0x10A3F, 0x10A47}, {0x10A50, 0x10A58},
|
||||
{0x10A60, 0x10A9F}, {0x10AC0, 0x10AE6}, {0x10AEB, 0x10AF6},
|
||||
{0x10B00, 0x10B35}, {0x10B39, 0x10B55}, {0x10B58, 0x10B72},
|
||||
{0x10B78, 0x10B91}, {0x10B99, 0x10B9C}, {0x10BA9, 0x10BAF},
|
||||
{0x10C00, 0x10C48}, {0x10C80, 0x10CB2}, {0x10CC0, 0x10CF2},
|
||||
{0x10CFA, 0x10CFF}, {0x10E60, 0x10E7E}, {0x11000, 0x1104D},
|
||||
{0x11052, 0x1106F}, {0x1107F, 0x110C1}, {0x110D0, 0x110E8},
|
||||
{0x110F0, 0x110F9}, {0x11100, 0x11134}, {0x11136, 0x11143},
|
||||
{0x11150, 0x11176}, {0x11180, 0x111CD}, {0x111D0, 0x111DF},
|
||||
{0x111E1, 0x111F4}, {0x11200, 0x11211}, {0x11213, 0x1123E},
|
||||
{0x11280, 0x11286}, {0x11288, 0x11288}, {0x1128A, 0x1128D},
|
||||
{0x1128F, 0x1129D}, {0x1129F, 0x112A9}, {0x112B0, 0x112EA},
|
||||
{0x112F0, 0x112F9}, {0x11300, 0x11303}, {0x11305, 0x1130C},
|
||||
{0x1130F, 0x11310}, {0x11313, 0x11328}, {0x1132A, 0x11330},
|
||||
{0x11332, 0x11333}, {0x11335, 0x11339}, {0x1133C, 0x11344},
|
||||
{0x11347, 0x11348}, {0x1134B, 0x1134D}, {0x11350, 0x11350},
|
||||
{0x11357, 0x11357}, {0x1135D, 0x11363}, {0x11366, 0x1136C},
|
||||
{0x11370, 0x11374}, {0x11400, 0x11459}, {0x1145B, 0x1145B},
|
||||
{0x1145D, 0x1145D}, {0x11480, 0x114C7}, {0x114D0, 0x114D9},
|
||||
{0x11580, 0x115B5}, {0x115B8, 0x115DD}, {0x11600, 0x11644},
|
||||
{0x11650, 0x11659}, {0x11660, 0x1166C}, {0x11680, 0x116B7},
|
||||
{0x116C0, 0x116C9}, {0x11700, 0x11719}, {0x1171D, 0x1172B},
|
||||
{0x11730, 0x1173F}, {0x118A0, 0x118F2}, {0x118FF, 0x118FF},
|
||||
{0x11AC0, 0x11AF8}, {0x11C00, 0x11C08}, {0x11C0A, 0x11C36},
|
||||
{0x11C38, 0x11C45}, {0x11C50, 0x11C6C}, {0x11C70, 0x11C8F},
|
||||
{0x11C92, 0x11CA7}, {0x11CA9, 0x11CB6}, {0x12000, 0x12399},
|
||||
{0x12400, 0x1246E}, {0x12470, 0x12474}, {0x12480, 0x12543},
|
||||
{0x13000, 0x1342E}, {0x14400, 0x14646}, {0x16800, 0x16A38},
|
||||
{0x16A40, 0x16A5E}, {0x16A60, 0x16A69}, {0x16A6E, 0x16A6F},
|
||||
{0x16AD0, 0x16AED}, {0x16AF0, 0x16AF5}, {0x16B00, 0x16B45},
|
||||
{0x16B50, 0x16B59}, {0x16B5B, 0x16B61}, {0x16B63, 0x16B77},
|
||||
{0x16B7D, 0x16B8F}, {0x16F00, 0x16F44}, {0x16F50, 0x16F7E},
|
||||
{0x16F8F, 0x16F9F}, {0x1BC00, 0x1BC6A}, {0x1BC70, 0x1BC7C},
|
||||
{0x1BC80, 0x1BC88}, {0x1BC90, 0x1BC99}, {0x1BC9C, 0x1BCA3},
|
||||
{0x1D000, 0x1D0F5}, {0x1D100, 0x1D126}, {0x1D129, 0x1D1E8},
|
||||
{0x1D200, 0x1D245}, {0x1D300, 0x1D356}, {0x1D360, 0x1D371},
|
||||
{0x1D400, 0x1D454}, {0x1D456, 0x1D49C}, {0x1D49E, 0x1D49F},
|
||||
{0x1D4A2, 0x1D4A2}, {0x1D4A5, 0x1D4A6}, {0x1D4A9, 0x1D4AC},
|
||||
{0x1D4AE, 0x1D4B9}, {0x1D4BB, 0x1D4BB}, {0x1D4BD, 0x1D4C3},
|
||||
{0x1D4C5, 0x1D505}, {0x1D507, 0x1D50A}, {0x1D50D, 0x1D514},
|
||||
{0x1D516, 0x1D51C}, {0x1D51E, 0x1D539}, {0x1D53B, 0x1D53E},
|
||||
{0x1D540, 0x1D544}, {0x1D546, 0x1D546}, {0x1D54A, 0x1D550},
|
||||
{0x1D552, 0x1D6A5}, {0x1D6A8, 0x1D7CB}, {0x1D7CE, 0x1DA8B},
|
||||
{0x1DA9B, 0x1DA9F}, {0x1DAA1, 0x1DAAF}, {0x1E000, 0x1E006},
|
||||
{0x1E008, 0x1E018}, {0x1E01B, 0x1E021}, {0x1E023, 0x1E024},
|
||||
{0x1E026, 0x1E02A}, {0x1E800, 0x1E8C4}, {0x1E8C7, 0x1E8D6},
|
||||
{0x1E900, 0x1E94A}, {0x1E950, 0x1E959}, {0x1E95E, 0x1E95F},
|
||||
{0x1EE00, 0x1EE03}, {0x1EE05, 0x1EE1F}, {0x1EE21, 0x1EE22},
|
||||
{0x1EE24, 0x1EE24}, {0x1EE27, 0x1EE27}, {0x1EE29, 0x1EE32},
|
||||
{0x1EE34, 0x1EE37}, {0x1EE39, 0x1EE39}, {0x1EE3B, 0x1EE3B},
|
||||
{0x1EE42, 0x1EE42}, {0x1EE47, 0x1EE47}, {0x1EE49, 0x1EE49},
|
||||
{0x1EE4B, 0x1EE4B}, {0x1EE4D, 0x1EE4F}, {0x1EE51, 0x1EE52},
|
||||
{0x1EE54, 0x1EE54}, {0x1EE57, 0x1EE57}, {0x1EE59, 0x1EE59},
|
||||
{0x1EE5B, 0x1EE5B}, {0x1EE5D, 0x1EE5D}, {0x1EE5F, 0x1EE5F},
|
||||
{0x1EE61, 0x1EE62}, {0x1EE64, 0x1EE64}, {0x1EE67, 0x1EE6A},
|
||||
{0x1EE6C, 0x1EE72}, {0x1EE74, 0x1EE77}, {0x1EE79, 0x1EE7C},
|
||||
{0x1EE7E, 0x1EE7E}, {0x1EE80, 0x1EE89}, {0x1EE8B, 0x1EE9B},
|
||||
{0x1EEA1, 0x1EEA3}, {0x1EEA5, 0x1EEA9}, {0x1EEAB, 0x1EEBB},
|
||||
{0x1EEF0, 0x1EEF1}, {0x1F000, 0x1F003}, {0x1F005, 0x1F02B},
|
||||
{0x1F030, 0x1F093}, {0x1F0A0, 0x1F0AE}, {0x1F0B1, 0x1F0BF},
|
||||
{0x1F0C1, 0x1F0CE}, {0x1F0D1, 0x1F0F5}, {0x1F10B, 0x1F10C},
|
||||
{0x1F12E, 0x1F12E}, {0x1F16A, 0x1F16B}, {0x1F1E6, 0x1F1FF},
|
||||
{0x1F321, 0x1F32C}, {0x1F336, 0x1F336}, {0x1F37D, 0x1F37D},
|
||||
{0x1F394, 0x1F39F}, {0x1F3CB, 0x1F3CE}, {0x1F3D4, 0x1F3DF},
|
||||
{0x1F3F1, 0x1F3F3}, {0x1F3F5, 0x1F3F7}, {0x1F43F, 0x1F43F},
|
||||
{0x1F441, 0x1F441}, {0x1F4FD, 0x1F4FE}, {0x1F53E, 0x1F54A},
|
||||
{0x1F54F, 0x1F54F}, {0x1F568, 0x1F579}, {0x1F57B, 0x1F594},
|
||||
{0x1F597, 0x1F5A3}, {0x1F5A5, 0x1F5FA}, {0x1F650, 0x1F67F},
|
||||
{0x1F6C6, 0x1F6CB}, {0x1F6CD, 0x1F6CF}, {0x1F6E0, 0x1F6EA},
|
||||
{0x1F6F0, 0x1F6F3}, {0x1F700, 0x1F773}, {0x1F780, 0x1F7D4},
|
||||
{0x1F800, 0x1F80B}, {0x1F810, 0x1F847}, {0x1F850, 0x1F859},
|
||||
{0x1F860, 0x1F887}, {0x1F890, 0x1F8AD}, {0xE0001, 0xE0001},
|
||||
{0xE0020, 0xE007F},
|
||||
}
|
||||
|
||||
// Condition have flag EastAsianWidth whether the current locale is CJK or not.
|
||||
type Condition struct {
|
||||
EastAsianWidth bool
|
||||
ZeroWidthJoiner bool
|
||||
}
|
||||
|
||||
// NewCondition return new instance of Condition which is current locale.
|
||||
func NewCondition() *Condition {
|
||||
return &Condition{
|
||||
EastAsianWidth: EastAsianWidth,
|
||||
ZeroWidthJoiner: ZeroWidthJoiner,
|
||||
}
|
||||
}
|
||||
|
||||
// RuneWidth returns the number of cells in r.
|
||||
// See http://www.unicode.org/reports/tr11/
|
||||
func (c *Condition) RuneWidth(r rune) int {
|
||||
switch {
|
||||
case r < 0 || r > 0x10FFFF ||
|
||||
inTables(r, nonprint, combining, notassigned):
|
||||
return 0
|
||||
case (c.EastAsianWidth && IsAmbiguousWidth(r)) ||
|
||||
inTables(r, doublewidth, emoji):
|
||||
return 2
|
||||
default:
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Condition) stringWidth(s string) (width int) {
|
||||
for _, r := range []rune(s) {
|
||||
width += c.RuneWidth(r)
|
||||
}
|
||||
return width
|
||||
}
|
||||
|
||||
func (c *Condition) stringWidthZeroJoiner(s string) (width int) {
|
||||
r1, r2 := rune(0), rune(0)
|
||||
for _, r := range []rune(s) {
|
||||
if r == 0xFE0E || r == 0xFE0F {
|
||||
continue
|
||||
}
|
||||
w := c.RuneWidth(r)
|
||||
if r2 == 0x200D && inTables(r, emoji) && inTables(r1, emoji) {
|
||||
w = 0
|
||||
}
|
||||
width += w
|
||||
r1, r2 = r2, r
|
||||
}
|
||||
return width
|
||||
}
|
||||
|
||||
// StringWidth return width as you can see
|
||||
func (c *Condition) StringWidth(s string) (width int) {
|
||||
if c.ZeroWidthJoiner {
|
||||
return c.stringWidthZeroJoiner(s)
|
||||
}
|
||||
return c.stringWidth(s)
|
||||
}
|
||||
|
||||
// Truncate return string truncated with w cells
|
||||
func (c *Condition) Truncate(s string, w int, tail string) string {
|
||||
if c.StringWidth(s) <= w {
|
||||
return s
|
||||
}
|
||||
r := []rune(s)
|
||||
tw := c.StringWidth(tail)
|
||||
w -= tw
|
||||
width := 0
|
||||
i := 0
|
||||
for ; i < len(r); i++ {
|
||||
cw := c.RuneWidth(r[i])
|
||||
if width+cw > w {
|
||||
break
|
||||
}
|
||||
width += cw
|
||||
}
|
||||
return string(r[0:i]) + tail
|
||||
}
|
||||
|
||||
// Wrap return string wrapped with w cells
|
||||
func (c *Condition) Wrap(s string, w int) string {
|
||||
width := 0
|
||||
out := ""
|
||||
for _, r := range []rune(s) {
|
||||
cw := RuneWidth(r)
|
||||
if r == '\n' {
|
||||
out += string(r)
|
||||
width = 0
|
||||
continue
|
||||
} else if width+cw > w {
|
||||
out += "\n"
|
||||
width = 0
|
||||
out += string(r)
|
||||
width += cw
|
||||
continue
|
||||
}
|
||||
out += string(r)
|
||||
width += cw
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// FillLeft return string filled in left by spaces in w cells
|
||||
func (c *Condition) FillLeft(s string, w int) string {
|
||||
width := c.StringWidth(s)
|
||||
count := w - width
|
||||
if count > 0 {
|
||||
b := make([]byte, count)
|
||||
for i := range b {
|
||||
b[i] = ' '
|
||||
}
|
||||
return string(b) + s
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// FillRight return string filled in left by spaces in w cells
|
||||
func (c *Condition) FillRight(s string, w int) string {
|
||||
width := c.StringWidth(s)
|
||||
count := w - width
|
||||
if count > 0 {
|
||||
b := make([]byte, count)
|
||||
for i := range b {
|
||||
b[i] = ' '
|
||||
}
|
||||
return s + string(b)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// RuneWidth returns the number of cells in r.
|
||||
// See http://www.unicode.org/reports/tr11/
|
||||
func RuneWidth(r rune) int {
|
||||
return DefaultCondition.RuneWidth(r)
|
||||
}
|
||||
|
||||
// IsAmbiguousWidth returns whether is ambiguous width or not.
|
||||
func IsAmbiguousWidth(r rune) bool {
|
||||
return inTables(r, private, ambiguous)
|
||||
}
|
||||
|
||||
// IsNeutralWidth returns whether is neutral width or not.
|
||||
func IsNeutralWidth(r rune) bool {
|
||||
return inTable(r, neutral)
|
||||
}
|
||||
|
||||
// StringWidth return width as you can see
|
||||
func StringWidth(s string) (width int) {
|
||||
return DefaultCondition.StringWidth(s)
|
||||
}
|
||||
|
||||
// Truncate return string truncated with w cells
|
||||
func Truncate(s string, w int, tail string) string {
|
||||
return DefaultCondition.Truncate(s, w, tail)
|
||||
}
|
||||
|
||||
// Wrap return string wrapped with w cells
|
||||
func Wrap(s string, w int) string {
|
||||
return DefaultCondition.Wrap(s, w)
|
||||
}
|
||||
|
||||
// FillLeft return string filled in left by spaces in w cells
|
||||
func FillLeft(s string, w int) string {
|
||||
return DefaultCondition.FillLeft(s, w)
|
||||
}
|
||||
|
||||
// FillRight return string filled in left by spaces in w cells
|
||||
func FillRight(s string, w int) string {
|
||||
return DefaultCondition.FillRight(s, w)
|
||||
}
|
8
vendor/github.com/mattn/go-runewidth/runewidth_appengine.go
generated
vendored
Normal file
8
vendor/github.com/mattn/go-runewidth/runewidth_appengine.go
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
// +build appengine
|
||||
|
||||
package runewidth
|
||||
|
||||
// IsEastAsian return true if the current locale is CJK
|
||||
func IsEastAsian() bool {
|
||||
return false
|
||||
}
|
9
vendor/github.com/mattn/go-runewidth/runewidth_js.go
generated
vendored
Normal file
9
vendor/github.com/mattn/go-runewidth/runewidth_js.go
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
// +build js
|
||||
// +build !appengine
|
||||
|
||||
package runewidth
|
||||
|
||||
func IsEastAsian() bool {
|
||||
// TODO: Implement this for the web. Detect east asian in a compatible way, and return true.
|
||||
return false
|
||||
}
|
79
vendor/github.com/mattn/go-runewidth/runewidth_posix.go
generated
vendored
Normal file
79
vendor/github.com/mattn/go-runewidth/runewidth_posix.go
generated
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
// +build !windows
|
||||
// +build !js
|
||||
// +build !appengine
|
||||
|
||||
package runewidth
|
||||
|
||||
import (
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var reLoc = regexp.MustCompile(`^[a-z][a-z][a-z]?(?:_[A-Z][A-Z])?\.(.+)`)
|
||||
|
||||
var mblenTable = map[string]int{
|
||||
"utf-8": 6,
|
||||
"utf8": 6,
|
||||
"jis": 8,
|
||||
"eucjp": 3,
|
||||
"euckr": 2,
|
||||
"euccn": 2,
|
||||
"sjis": 2,
|
||||
"cp932": 2,
|
||||
"cp51932": 2,
|
||||
"cp936": 2,
|
||||
"cp949": 2,
|
||||
"cp950": 2,
|
||||
"big5": 2,
|
||||
"gbk": 2,
|
||||
"gb2312": 2,
|
||||
}
|
||||
|
||||
func isEastAsian(locale string) bool {
|
||||
charset := strings.ToLower(locale)
|
||||
r := reLoc.FindStringSubmatch(locale)
|
||||
if len(r) == 2 {
|
||||
charset = strings.ToLower(r[1])
|
||||
}
|
||||
|
||||
if strings.HasSuffix(charset, "@cjk_narrow") {
|
||||
return false
|
||||
}
|
||||
|
||||
for pos, b := range []byte(charset) {
|
||||
if b == '@' {
|
||||
charset = charset[:pos]
|
||||
break
|
||||
}
|
||||
}
|
||||
max := 1
|
||||
if m, ok := mblenTable[charset]; ok {
|
||||
max = m
|
||||
}
|
||||
if max > 1 && (charset[0] != 'u' ||
|
||||
strings.HasPrefix(locale, "ja") ||
|
||||
strings.HasPrefix(locale, "ko") ||
|
||||
strings.HasPrefix(locale, "zh")) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsEastAsian return true if the current locale is CJK
|
||||
func IsEastAsian() bool {
|
||||
locale := os.Getenv("LC_CTYPE")
|
||||
if locale == "" {
|
||||
locale = os.Getenv("LANG")
|
||||
}
|
||||
|
||||
// ignore C locale
|
||||
if locale == "POSIX" || locale == "C" {
|
||||
return false
|
||||
}
|
||||
if len(locale) > 1 && locale[0] == 'C' && (locale[1] == '.' || locale[1] == '-') {
|
||||
return false
|
||||
}
|
||||
|
||||
return isEastAsian(locale)
|
||||
}
|
28
vendor/github.com/mattn/go-runewidth/runewidth_windows.go
generated
vendored
Normal file
28
vendor/github.com/mattn/go-runewidth/runewidth_windows.go
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
// +build windows
|
||||
// +build !appengine
|
||||
|
||||
package runewidth
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
var (
|
||||
kernel32 = syscall.NewLazyDLL("kernel32")
|
||||
procGetConsoleOutputCP = kernel32.NewProc("GetConsoleOutputCP")
|
||||
)
|
||||
|
||||
// IsEastAsian return true if the current locale is CJK
|
||||
func IsEastAsian() bool {
|
||||
r1, _, _ := procGetConsoleOutputCP.Call()
|
||||
if r1 == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
switch int(r1) {
|
||||
case 932, 51932, 936, 949, 950:
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
15
vendor/github.com/olekukonko/tablewriter/.gitignore
generated
vendored
Normal file
15
vendor/github.com/olekukonko/tablewriter/.gitignore
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
# Created by .ignore support plugin (hsz.mobi)
|
||||
### Go template
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
14
vendor/github.com/olekukonko/tablewriter/.travis.yml
generated
vendored
Normal file
14
vendor/github.com/olekukonko/tablewriter/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.1
|
||||
- 1.2
|
||||
- 1.3
|
||||
- 1.4
|
||||
- 1.5
|
||||
- 1.6
|
||||
- 1.7
|
||||
- 1.8
|
||||
- 1.9
|
||||
- "1.10"
|
||||
- tip
|
19
vendor/github.com/olekukonko/tablewriter/LICENSE.md
generated
vendored
Normal file
19
vendor/github.com/olekukonko/tablewriter/LICENSE.md
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
Copyright (C) 2014 by Oleku Konko
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
277
vendor/github.com/olekukonko/tablewriter/README.md
generated
vendored
Normal file
277
vendor/github.com/olekukonko/tablewriter/README.md
generated
vendored
Normal file
@ -0,0 +1,277 @@
|
||||
ASCII Table Writer
|
||||
=========
|
||||
|
||||
[](https://travis-ci.org/olekukonko/tablewriter)
|
||||
[](https://sourcegraph.com/github.com/olekukonko/tablewriter)
|
||||
[](https://godoc.org/github.com/olekukonko/tablewriter)
|
||||
|
||||
Generate ASCII table on the fly ... Installation is simple as
|
||||
|
||||
go get github.com/olekukonko/tablewriter
|
||||
|
||||
|
||||
#### Features
|
||||
- Automatic Padding
|
||||
- Support Multiple Lines
|
||||
- Supports Alignment
|
||||
- Support Custom Separators
|
||||
- Automatic Alignment of numbers & percentage
|
||||
- Write directly to http , file etc via `io.Writer`
|
||||
- Read directly from CSV file
|
||||
- Optional row line via `SetRowLine`
|
||||
- Normalise table header
|
||||
- Make CSV Headers optional
|
||||
- Enable or disable table border
|
||||
- Set custom footer support
|
||||
- Optional identical cells merging
|
||||
- Set custom caption
|
||||
- Optional reflowing of paragrpahs in multi-line cells.
|
||||
|
||||
#### Example 1 - Basic
|
||||
```go
|
||||
data := [][]string{
|
||||
[]string{"A", "The Good", "500"},
|
||||
[]string{"B", "The Very very Bad Man", "288"},
|
||||
[]string{"C", "The Ugly", "120"},
|
||||
[]string{"D", "The Gopher", "800"},
|
||||
}
|
||||
|
||||
table := tablewriter.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Name", "Sign", "Rating"})
|
||||
|
||||
for _, v := range data {
|
||||
table.Append(v)
|
||||
}
|
||||
table.Render() // Send output
|
||||
```
|
||||
|
||||
##### Output 1
|
||||
```
|
||||
+------+-----------------------+--------+
|
||||
| NAME | SIGN | RATING |
|
||||
+------+-----------------------+--------+
|
||||
| A | The Good | 500 |
|
||||
| B | The Very very Bad Man | 288 |
|
||||
| C | The Ugly | 120 |
|
||||
| D | The Gopher | 800 |
|
||||
+------+-----------------------+--------+
|
||||
```
|
||||
|
||||
#### Example 2 - Without Border / Footer / Bulk Append
|
||||
```go
|
||||
data := [][]string{
|
||||
[]string{"1/1/2014", "Domain name", "2233", "$10.98"},
|
||||
[]string{"1/1/2014", "January Hosting", "2233", "$54.95"},
|
||||
[]string{"1/4/2014", "February Hosting", "2233", "$51.00"},
|
||||
[]string{"1/4/2014", "February Extra Bandwidth", "2233", "$30.00"},
|
||||
}
|
||||
|
||||
table := tablewriter.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Date", "Description", "CV2", "Amount"})
|
||||
table.SetFooter([]string{"", "", "Total", "$146.93"}) // Add Footer
|
||||
table.SetBorder(false) // Set Border to false
|
||||
table.AppendBulk(data) // Add Bulk Data
|
||||
table.Render()
|
||||
```
|
||||
|
||||
##### Output 2
|
||||
```
|
||||
|
||||
DATE | DESCRIPTION | CV2 | AMOUNT
|
||||
+----------+--------------------------+-------+---------+
|
||||
1/1/2014 | Domain name | 2233 | $10.98
|
||||
1/1/2014 | January Hosting | 2233 | $54.95
|
||||
1/4/2014 | February Hosting | 2233 | $51.00
|
||||
1/4/2014 | February Extra Bandwidth | 2233 | $30.00
|
||||
+----------+--------------------------+-------+---------+
|
||||
TOTAL | $146 93
|
||||
+-------+---------+
|
||||
|
||||
```
|
||||
|
||||
|
||||
#### Example 3 - CSV
|
||||
```go
|
||||
table, _ := tablewriter.NewCSV(os.Stdout, "testdata/test_info.csv", true)
|
||||
table.SetAlignment(tablewriter.ALIGN_LEFT) // Set Alignment
|
||||
table.Render()
|
||||
```
|
||||
|
||||
##### Output 3
|
||||
```
|
||||
+----------+--------------+------+-----+---------+----------------+
|
||||
| FIELD | TYPE | NULL | KEY | DEFAULT | EXTRA |
|
||||
+----------+--------------+------+-----+---------+----------------+
|
||||
| user_id | smallint(5) | NO | PRI | NULL | auto_increment |
|
||||
| username | varchar(10) | NO | | NULL | |
|
||||
| password | varchar(100) | NO | | NULL | |
|
||||
+----------+--------------+------+-----+---------+----------------+
|
||||
```
|
||||
|
||||
#### Example 4 - Custom Separator
|
||||
```go
|
||||
table, _ := tablewriter.NewCSV(os.Stdout, "testdata/test.csv", true)
|
||||
table.SetRowLine(true) // Enable row line
|
||||
|
||||
// Change table lines
|
||||
table.SetCenterSeparator("*")
|
||||
table.SetColumnSeparator("╪")
|
||||
table.SetRowSeparator("-")
|
||||
|
||||
table.SetAlignment(tablewriter.ALIGN_LEFT)
|
||||
table.Render()
|
||||
```
|
||||
|
||||
##### Output 4
|
||||
```
|
||||
*------------*-----------*---------*
|
||||
╪ FIRST NAME ╪ LAST NAME ╪ SSN ╪
|
||||
*------------*-----------*---------*
|
||||
╪ John ╪ Barry ╪ 123456 ╪
|
||||
*------------*-----------*---------*
|
||||
╪ Kathy ╪ Smith ╪ 687987 ╪
|
||||
*------------*-----------*---------*
|
||||
╪ Bob ╪ McCornick ╪ 3979870 ╪
|
||||
*------------*-----------*---------*
|
||||
```
|
||||
|
||||
#### Example 5 - Markdown Format
|
||||
```go
|
||||
data := [][]string{
|
||||
[]string{"1/1/2014", "Domain name", "2233", "$10.98"},
|
||||
[]string{"1/1/2014", "January Hosting", "2233", "$54.95"},
|
||||
[]string{"1/4/2014", "February Hosting", "2233", "$51.00"},
|
||||
[]string{"1/4/2014", "February Extra Bandwidth", "2233", "$30.00"},
|
||||
}
|
||||
|
||||
table := tablewriter.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Date", "Description", "CV2", "Amount"})
|
||||
table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false})
|
||||
table.SetCenterSeparator("|")
|
||||
table.AppendBulk(data) // Add Bulk Data
|
||||
table.Render()
|
||||
```
|
||||
|
||||
##### Output 5
|
||||
```
|
||||
| DATE | DESCRIPTION | CV2 | AMOUNT |
|
||||
|----------|--------------------------|------|--------|
|
||||
| 1/1/2014 | Domain name | 2233 | $10.98 |
|
||||
| 1/1/2014 | January Hosting | 2233 | $54.95 |
|
||||
| 1/4/2014 | February Hosting | 2233 | $51.00 |
|
||||
| 1/4/2014 | February Extra Bandwidth | 2233 | $30.00 |
|
||||
```
|
||||
|
||||
#### Example 6 - Identical cells merging
|
||||
```go
|
||||
data := [][]string{
|
||||
[]string{"1/1/2014", "Domain name", "1234", "$10.98"},
|
||||
[]string{"1/1/2014", "January Hosting", "2345", "$54.95"},
|
||||
[]string{"1/4/2014", "February Hosting", "3456", "$51.00"},
|
||||
[]string{"1/4/2014", "February Extra Bandwidth", "4567", "$30.00"},
|
||||
}
|
||||
|
||||
table := tablewriter.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Date", "Description", "CV2", "Amount"})
|
||||
table.SetFooter([]string{"", "", "Total", "$146.93"})
|
||||
table.SetAutoMergeCells(true)
|
||||
table.SetRowLine(true)
|
||||
table.AppendBulk(data)
|
||||
table.Render()
|
||||
```
|
||||
|
||||
##### Output 6
|
||||
```
|
||||
+----------+--------------------------+-------+---------+
|
||||
| DATE | DESCRIPTION | CV2 | AMOUNT |
|
||||
+----------+--------------------------+-------+---------+
|
||||
| 1/1/2014 | Domain name | 1234 | $10.98 |
|
||||
+ +--------------------------+-------+---------+
|
||||
| | January Hosting | 2345 | $54.95 |
|
||||
+----------+--------------------------+-------+---------+
|
||||
| 1/4/2014 | February Hosting | 3456 | $51.00 |
|
||||
+ +--------------------------+-------+---------+
|
||||
| | February Extra Bandwidth | 4567 | $30.00 |
|
||||
+----------+--------------------------+-------+---------+
|
||||
| TOTAL | $146 93 |
|
||||
+----------+--------------------------+-------+---------+
|
||||
```
|
||||
|
||||
|
||||
#### Table with color
|
||||
```go
|
||||
data := [][]string{
|
||||
[]string{"1/1/2014", "Domain name", "2233", "$10.98"},
|
||||
[]string{"1/1/2014", "January Hosting", "2233", "$54.95"},
|
||||
[]string{"1/4/2014", "February Hosting", "2233", "$51.00"},
|
||||
[]string{"1/4/2014", "February Extra Bandwidth", "2233", "$30.00"},
|
||||
}
|
||||
|
||||
table := tablewriter.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Date", "Description", "CV2", "Amount"})
|
||||
table.SetFooter([]string{"", "", "Total", "$146.93"}) // Add Footer
|
||||
table.SetBorder(false) // Set Border to false
|
||||
|
||||
table.SetHeaderColor(tablewriter.Colors{tablewriter.Bold, tablewriter.BgGreenColor},
|
||||
tablewriter.Colors{tablewriter.FgHiRedColor, tablewriter.Bold, tablewriter.BgBlackColor},
|
||||
tablewriter.Colors{tablewriter.BgRedColor, tablewriter.FgWhiteColor},
|
||||
tablewriter.Colors{tablewriter.BgCyanColor, tablewriter.FgWhiteColor})
|
||||
|
||||
table.SetColumnColor(tablewriter.Colors{tablewriter.Bold, tablewriter.FgHiBlackColor},
|
||||
tablewriter.Colors{tablewriter.Bold, tablewriter.FgHiRedColor},
|
||||
tablewriter.Colors{tablewriter.Bold, tablewriter.FgHiBlackColor},
|
||||
tablewriter.Colors{tablewriter.Bold, tablewriter.FgBlackColor})
|
||||
|
||||
table.SetFooterColor(tablewriter.Colors{}, tablewriter.Colors{},
|
||||
tablewriter.Colors{tablewriter.Bold},
|
||||
tablewriter.Colors{tablewriter.FgHiRedColor})
|
||||
|
||||
table.AppendBulk(data)
|
||||
table.Render()
|
||||
```
|
||||
|
||||
#### Table with color Output
|
||||

|
||||
|
||||
#### Example 6 - Set table caption
|
||||
```go
|
||||
data := [][]string{
|
||||
[]string{"A", "The Good", "500"},
|
||||
[]string{"B", "The Very very Bad Man", "288"},
|
||||
[]string{"C", "The Ugly", "120"},
|
||||
[]string{"D", "The Gopher", "800"},
|
||||
}
|
||||
|
||||
table := tablewriter.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Name", "Sign", "Rating"})
|
||||
table.SetCaption(true, "Movie ratings.")
|
||||
|
||||
for _, v := range data {
|
||||
table.Append(v)
|
||||
}
|
||||
table.Render() // Send output
|
||||
```
|
||||
|
||||
Note: Caption text will wrap with total width of rendered table.
|
||||
|
||||
##### Output 6
|
||||
```
|
||||
+------+-----------------------+--------+
|
||||
| NAME | SIGN | RATING |
|
||||
+------+-----------------------+--------+
|
||||
| A | The Good | 500 |
|
||||
| B | The Very very Bad Man | 288 |
|
||||
| C | The Ugly | 120 |
|
||||
| D | The Gopher | 800 |
|
||||
+------+-----------------------+--------+
|
||||
Movie ratings.
|
||||
```
|
||||
|
||||
#### TODO
|
||||
- ~~Import Directly from CSV~~ - `done`
|
||||
- ~~Support for `SetFooter`~~ - `done`
|
||||
- ~~Support for `SetBorder`~~ - `done`
|
||||
- ~~Support table with uneven rows~~ - `done`
|
||||
- ~~Support custom alignment~~
|
||||
- General Improvement & Optimisation
|
||||
- `NewHTML` Parse table from HTML
|
52
vendor/github.com/olekukonko/tablewriter/csv.go
generated
vendored
Normal file
52
vendor/github.com/olekukonko/tablewriter/csv.go
generated
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
// Copyright 2014 Oleku Konko All rights reserved.
|
||||
// Use of this source code is governed by a MIT
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This module is a Table Writer API for the Go Programming Language.
|
||||
// The protocols were written in pure Go and works on windows and unix systems
|
||||
|
||||
package tablewriter
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Start A new table by importing from a CSV file
|
||||
// Takes io.Writer and csv File name
|
||||
func NewCSV(writer io.Writer, fileName string, hasHeader bool) (*Table, error) {
|
||||
file, err := os.Open(fileName)
|
||||
if err != nil {
|
||||
return &Table{}, err
|
||||
}
|
||||
defer file.Close()
|
||||
csvReader := csv.NewReader(file)
|
||||
t, err := NewCSVReader(writer, csvReader, hasHeader)
|
||||
return t, err
|
||||
}
|
||||
|
||||
// Start a New Table Writer with csv.Reader
|
||||
// This enables customisation such as reader.Comma = ';'
|
||||
// See http://golang.org/src/pkg/encoding/csv/reader.go?s=3213:3671#L94
|
||||
func NewCSVReader(writer io.Writer, csvReader *csv.Reader, hasHeader bool) (*Table, error) {
|
||||
t := NewWriter(writer)
|
||||
if hasHeader {
|
||||
// Read the first row
|
||||
headers, err := csvReader.Read()
|
||||
if err != nil {
|
||||
return &Table{}, err
|
||||
}
|
||||
t.SetHeader(headers)
|
||||
}
|
||||
for {
|
||||
record, err := csvReader.Read()
|
||||
if err == io.EOF {
|
||||
break
|
||||
} else if err != nil {
|
||||
return &Table{}, err
|
||||
}
|
||||
t.Append(record)
|
||||
}
|
||||
return t, nil
|
||||
}
|
839
vendor/github.com/olekukonko/tablewriter/table.go
generated
vendored
Normal file
839
vendor/github.com/olekukonko/tablewriter/table.go
generated
vendored
Normal file
@ -0,0 +1,839 @@
|
||||
// Copyright 2014 Oleku Konko All rights reserved.
|
||||
// Use of this source code is governed by a MIT
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This module is a Table Writer API for the Go Programming Language.
|
||||
// The protocols were written in pure Go and works on windows and unix systems
|
||||
|
||||
// Create & Generate text based table
|
||||
package tablewriter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
MAX_ROW_WIDTH = 30
|
||||
)
|
||||
|
||||
const (
|
||||
CENTER = "+"
|
||||
ROW = "-"
|
||||
COLUMN = "|"
|
||||
SPACE = " "
|
||||
NEWLINE = "\n"
|
||||
)
|
||||
|
||||
const (
|
||||
ALIGN_DEFAULT = iota
|
||||
ALIGN_CENTER
|
||||
ALIGN_RIGHT
|
||||
ALIGN_LEFT
|
||||
)
|
||||
|
||||
var (
|
||||
decimal = regexp.MustCompile(`^-?(?:\d{1,3}(?:,\d{3})*|\d+)(?:\.\d+)?$`)
|
||||
percent = regexp.MustCompile(`^-?\d+\.?\d*$%$`)
|
||||
)
|
||||
|
||||
type Border struct {
|
||||
Left bool
|
||||
Right bool
|
||||
Top bool
|
||||
Bottom bool
|
||||
}
|
||||
|
||||
type Table struct {
|
||||
out io.Writer
|
||||
rows [][]string
|
||||
lines [][][]string
|
||||
cs map[int]int
|
||||
rs map[int]int
|
||||
headers [][]string
|
||||
footers [][]string
|
||||
caption bool
|
||||
captionText string
|
||||
autoFmt bool
|
||||
autoWrap bool
|
||||
reflowText bool
|
||||
mW int
|
||||
pCenter string
|
||||
pRow string
|
||||
pColumn string
|
||||
tColumn int
|
||||
tRow int
|
||||
hAlign int
|
||||
fAlign int
|
||||
align int
|
||||
newLine string
|
||||
rowLine bool
|
||||
autoMergeCells bool
|
||||
hdrLine bool
|
||||
borders Border
|
||||
colSize int
|
||||
headerParams []string
|
||||
columnsParams []string
|
||||
footerParams []string
|
||||
columnsAlign []int
|
||||
}
|
||||
|
||||
// Start New Table
|
||||
// Take io.Writer Directly
|
||||
func NewWriter(writer io.Writer) *Table {
|
||||
t := &Table{
|
||||
out: writer,
|
||||
rows: [][]string{},
|
||||
lines: [][][]string{},
|
||||
cs: make(map[int]int),
|
||||
rs: make(map[int]int),
|
||||
headers: [][]string{},
|
||||
footers: [][]string{},
|
||||
caption: false,
|
||||
captionText: "Table caption.",
|
||||
autoFmt: true,
|
||||
autoWrap: true,
|
||||
reflowText: true,
|
||||
mW: MAX_ROW_WIDTH,
|
||||
pCenter: CENTER,
|
||||
pRow: ROW,
|
||||
pColumn: COLUMN,
|
||||
tColumn: -1,
|
||||
tRow: -1,
|
||||
hAlign: ALIGN_DEFAULT,
|
||||
fAlign: ALIGN_DEFAULT,
|
||||
align: ALIGN_DEFAULT,
|
||||
newLine: NEWLINE,
|
||||
rowLine: false,
|
||||
hdrLine: true,
|
||||
borders: Border{Left: true, Right: true, Bottom: true, Top: true},
|
||||
colSize: -1,
|
||||
headerParams: []string{},
|
||||
columnsParams: []string{},
|
||||
footerParams: []string{},
|
||||
columnsAlign: []int{}}
|
||||
return t
|
||||
}
|
||||
|
||||
// Render table output
|
||||
func (t *Table) Render() {
|
||||
if t.borders.Top {
|
||||
t.printLine(true)
|
||||
}
|
||||
t.printHeading()
|
||||
if t.autoMergeCells {
|
||||
t.printRowsMergeCells()
|
||||
} else {
|
||||
t.printRows()
|
||||
}
|
||||
if !t.rowLine && t.borders.Bottom {
|
||||
t.printLine(true)
|
||||
}
|
||||
t.printFooter()
|
||||
|
||||
if t.caption {
|
||||
t.printCaption()
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
headerRowIdx = -1
|
||||
footerRowIdx = -2
|
||||
)
|
||||
|
||||
// Set table header
|
||||
func (t *Table) SetHeader(keys []string) {
|
||||
t.colSize = len(keys)
|
||||
for i, v := range keys {
|
||||
lines := t.parseDimension(v, i, headerRowIdx)
|
||||
t.headers = append(t.headers, lines)
|
||||
}
|
||||
}
|
||||
|
||||
// Set table Footer
|
||||
func (t *Table) SetFooter(keys []string) {
|
||||
//t.colSize = len(keys)
|
||||
for i, v := range keys {
|
||||
lines := t.parseDimension(v, i, footerRowIdx)
|
||||
t.footers = append(t.footers, lines)
|
||||
}
|
||||
}
|
||||
|
||||
// Set table Caption
|
||||
func (t *Table) SetCaption(caption bool, captionText ...string) {
|
||||
t.caption = caption
|
||||
if len(captionText) == 1 {
|
||||
t.captionText = captionText[0]
|
||||
}
|
||||
}
|
||||
|
||||
// Turn header autoformatting on/off. Default is on (true).
|
||||
func (t *Table) SetAutoFormatHeaders(auto bool) {
|
||||
t.autoFmt = auto
|
||||
}
|
||||
|
||||
// Turn automatic multiline text adjustment on/off. Default is on (true).
|
||||
func (t *Table) SetAutoWrapText(auto bool) {
|
||||
t.autoWrap = auto
|
||||
}
|
||||
|
||||
// Turn automatic reflowing of multiline text when rewrapping. Default is on (true).
|
||||
func (t *Table) SetReflowDuringAutoWrap(auto bool) {
|
||||
t.reflowText = auto
|
||||
}
|
||||
|
||||
// Set the Default column width
|
||||
func (t *Table) SetColWidth(width int) {
|
||||
t.mW = width
|
||||
}
|
||||
|
||||
// Set the minimal width for a column
|
||||
func (t *Table) SetColMinWidth(column int, width int) {
|
||||
t.cs[column] = width
|
||||
}
|
||||
|
||||
// Set the Column Separator
|
||||
func (t *Table) SetColumnSeparator(sep string) {
|
||||
t.pColumn = sep
|
||||
}
|
||||
|
||||
// Set the Row Separator
|
||||
func (t *Table) SetRowSeparator(sep string) {
|
||||
t.pRow = sep
|
||||
}
|
||||
|
||||
// Set the center Separator
|
||||
func (t *Table) SetCenterSeparator(sep string) {
|
||||
t.pCenter = sep
|
||||
}
|
||||
|
||||
// Set Header Alignment
|
||||
func (t *Table) SetHeaderAlignment(hAlign int) {
|
||||
t.hAlign = hAlign
|
||||
}
|
||||
|
||||
// Set Footer Alignment
|
||||
func (t *Table) SetFooterAlignment(fAlign int) {
|
||||
t.fAlign = fAlign
|
||||
}
|
||||
|
||||
// Set Table Alignment
|
||||
func (t *Table) SetAlignment(align int) {
|
||||
t.align = align
|
||||
}
|
||||
|
||||
func (t *Table) SetColumnAlignment(keys []int) {
|
||||
for _, v := range keys {
|
||||
switch v {
|
||||
case ALIGN_CENTER:
|
||||
break
|
||||
case ALIGN_LEFT:
|
||||
break
|
||||
case ALIGN_RIGHT:
|
||||
break
|
||||
default:
|
||||
v = ALIGN_DEFAULT
|
||||
}
|
||||
t.columnsAlign = append(t.columnsAlign, v)
|
||||
}
|
||||
}
|
||||
|
||||
// Set New Line
|
||||
func (t *Table) SetNewLine(nl string) {
|
||||
t.newLine = nl
|
||||
}
|
||||
|
||||
// Set Header Line
|
||||
// This would enable / disable a line after the header
|
||||
func (t *Table) SetHeaderLine(line bool) {
|
||||
t.hdrLine = line
|
||||
}
|
||||
|
||||
// Set Row Line
|
||||
// This would enable / disable a line on each row of the table
|
||||
func (t *Table) SetRowLine(line bool) {
|
||||
t.rowLine = line
|
||||
}
|
||||
|
||||
// Set Auto Merge Cells
|
||||
// This would enable / disable the merge of cells with identical values
|
||||
func (t *Table) SetAutoMergeCells(auto bool) {
|
||||
t.autoMergeCells = auto
|
||||
}
|
||||
|
||||
// Set Table Border
|
||||
// This would enable / disable line around the table
|
||||
func (t *Table) SetBorder(border bool) {
|
||||
t.SetBorders(Border{border, border, border, border})
|
||||
}
|
||||
|
||||
func (t *Table) SetBorders(border Border) {
|
||||
t.borders = border
|
||||
}
|
||||
|
||||
// Append row to table
|
||||
func (t *Table) Append(row []string) {
|
||||
rowSize := len(t.headers)
|
||||
if rowSize > t.colSize {
|
||||
t.colSize = rowSize
|
||||
}
|
||||
|
||||
n := len(t.lines)
|
||||
line := [][]string{}
|
||||
for i, v := range row {
|
||||
|
||||
// Detect string width
|
||||
// Detect String height
|
||||
// Break strings into words
|
||||
out := t.parseDimension(v, i, n)
|
||||
|
||||
// Append broken words
|
||||
line = append(line, out)
|
||||
}
|
||||
t.lines = append(t.lines, line)
|
||||
}
|
||||
|
||||
// Allow Support for Bulk Append
|
||||
// Eliminates repeated for loops
|
||||
func (t *Table) AppendBulk(rows [][]string) {
|
||||
for _, row := range rows {
|
||||
t.Append(row)
|
||||
}
|
||||
}
|
||||
|
||||
// NumLines to get the number of lines
|
||||
func (t *Table) NumLines() int {
|
||||
return len(t.lines)
|
||||
}
|
||||
|
||||
// Clear rows
|
||||
func (t *Table) ClearRows() {
|
||||
t.lines = [][][]string{}
|
||||
}
|
||||
|
||||
// Clear footer
|
||||
func (t *Table) ClearFooter() {
|
||||
t.footers = [][]string{}
|
||||
}
|
||||
|
||||
// Print line based on row width
|
||||
func (t *Table) printLine(nl bool) {
|
||||
fmt.Fprint(t.out, t.pCenter)
|
||||
for i := 0; i < len(t.cs); i++ {
|
||||
v := t.cs[i]
|
||||
fmt.Fprintf(t.out, "%s%s%s%s",
|
||||
t.pRow,
|
||||
strings.Repeat(string(t.pRow), v),
|
||||
t.pRow,
|
||||
t.pCenter)
|
||||
}
|
||||
if nl {
|
||||
fmt.Fprint(t.out, t.newLine)
|
||||
}
|
||||
}
|
||||
|
||||
// Print line based on row width with our without cell separator
|
||||
func (t *Table) printLineOptionalCellSeparators(nl bool, displayCellSeparator []bool) {
|
||||
fmt.Fprint(t.out, t.pCenter)
|
||||
for i := 0; i < len(t.cs); i++ {
|
||||
v := t.cs[i]
|
||||
if i > len(displayCellSeparator) || displayCellSeparator[i] {
|
||||
// Display the cell separator
|
||||
fmt.Fprintf(t.out, "%s%s%s%s",
|
||||
t.pRow,
|
||||
strings.Repeat(string(t.pRow), v),
|
||||
t.pRow,
|
||||
t.pCenter)
|
||||
} else {
|
||||
// Don't display the cell separator for this cell
|
||||
fmt.Fprintf(t.out, "%s%s",
|
||||
strings.Repeat(" ", v+2),
|
||||
t.pCenter)
|
||||
}
|
||||
}
|
||||
if nl {
|
||||
fmt.Fprint(t.out, t.newLine)
|
||||
}
|
||||
}
|
||||
|
||||
// Return the PadRight function if align is left, PadLeft if align is right,
|
||||
// and Pad by default
|
||||
func pad(align int) func(string, string, int) string {
|
||||
padFunc := Pad
|
||||
switch align {
|
||||
case ALIGN_LEFT:
|
||||
padFunc = PadRight
|
||||
case ALIGN_RIGHT:
|
||||
padFunc = PadLeft
|
||||
}
|
||||
return padFunc
|
||||
}
|
||||
|
||||
// Print heading information
|
||||
func (t *Table) printHeading() {
|
||||
// Check if headers is available
|
||||
if len(t.headers) < 1 {
|
||||
return
|
||||
}
|
||||
|
||||
// Identify last column
|
||||
end := len(t.cs) - 1
|
||||
|
||||
// Get pad function
|
||||
padFunc := pad(t.hAlign)
|
||||
|
||||
// Checking for ANSI escape sequences for header
|
||||
is_esc_seq := false
|
||||
if len(t.headerParams) > 0 {
|
||||
is_esc_seq = true
|
||||
}
|
||||
|
||||
// Maximum height.
|
||||
max := t.rs[headerRowIdx]
|
||||
|
||||
// Print Heading
|
||||
for x := 0; x < max; x++ {
|
||||
// Check if border is set
|
||||
// Replace with space if not set
|
||||
fmt.Fprint(t.out, ConditionString(t.borders.Left, t.pColumn, SPACE))
|
||||
|
||||
for y := 0; y <= end; y++ {
|
||||
v := t.cs[y]
|
||||
h := ""
|
||||
if y < len(t.headers) && x < len(t.headers[y]) {
|
||||
h = t.headers[y][x]
|
||||
}
|
||||
if t.autoFmt {
|
||||
h = Title(h)
|
||||
}
|
||||
pad := ConditionString((y == end && !t.borders.Left), SPACE, t.pColumn)
|
||||
|
||||
if is_esc_seq {
|
||||
fmt.Fprintf(t.out, " %s %s",
|
||||
format(padFunc(h, SPACE, v),
|
||||
t.headerParams[y]), pad)
|
||||
} else {
|
||||
fmt.Fprintf(t.out, " %s %s",
|
||||
padFunc(h, SPACE, v),
|
||||
pad)
|
||||
}
|
||||
}
|
||||
// Next line
|
||||
fmt.Fprint(t.out, t.newLine)
|
||||
}
|
||||
if t.hdrLine {
|
||||
t.printLine(true)
|
||||
}
|
||||
}
|
||||
|
||||
// Print heading information
|
||||
func (t *Table) printFooter() {
|
||||
// Check if headers is available
|
||||
if len(t.footers) < 1 {
|
||||
return
|
||||
}
|
||||
|
||||
// Only print line if border is not set
|
||||
if !t.borders.Bottom {
|
||||
t.printLine(true)
|
||||
}
|
||||
|
||||
// Identify last column
|
||||
end := len(t.cs) - 1
|
||||
|
||||
// Get pad function
|
||||
padFunc := pad(t.fAlign)
|
||||
|
||||
// Checking for ANSI escape sequences for header
|
||||
is_esc_seq := false
|
||||
if len(t.footerParams) > 0 {
|
||||
is_esc_seq = true
|
||||
}
|
||||
|
||||
// Maximum height.
|
||||
max := t.rs[footerRowIdx]
|
||||
|
||||
// Print Footer
|
||||
erasePad := make([]bool, len(t.footers))
|
||||
for x := 0; x < max; x++ {
|
||||
// Check if border is set
|
||||
// Replace with space if not set
|
||||
fmt.Fprint(t.out, ConditionString(t.borders.Bottom, t.pColumn, SPACE))
|
||||
|
||||
for y := 0; y <= end; y++ {
|
||||
v := t.cs[y]
|
||||
f := ""
|
||||
if y < len(t.footers) && x < len(t.footers[y]) {
|
||||
f = t.footers[y][x]
|
||||
}
|
||||
if t.autoFmt {
|
||||
f = Title(f)
|
||||
}
|
||||
pad := ConditionString((y == end && !t.borders.Top), SPACE, t.pColumn)
|
||||
|
||||
if erasePad[y] || (x == 0 && len(f) == 0) {
|
||||
pad = SPACE
|
||||
erasePad[y] = true
|
||||
}
|
||||
|
||||
if is_esc_seq {
|
||||
fmt.Fprintf(t.out, " %s %s",
|
||||
format(padFunc(f, SPACE, v),
|
||||
t.footerParams[y]), pad)
|
||||
} else {
|
||||
fmt.Fprintf(t.out, " %s %s",
|
||||
padFunc(f, SPACE, v),
|
||||
pad)
|
||||
}
|
||||
|
||||
//fmt.Fprintf(t.out, " %s %s",
|
||||
// padFunc(f, SPACE, v),
|
||||
// pad)
|
||||
}
|
||||
// Next line
|
||||
fmt.Fprint(t.out, t.newLine)
|
||||
//t.printLine(true)
|
||||
}
|
||||
|
||||
hasPrinted := false
|
||||
|
||||
for i := 0; i <= end; i++ {
|
||||
v := t.cs[i]
|
||||
pad := t.pRow
|
||||
center := t.pCenter
|
||||
length := len(t.footers[i][0])
|
||||
|
||||
if length > 0 {
|
||||
hasPrinted = true
|
||||
}
|
||||
|
||||
// Set center to be space if length is 0
|
||||
if length == 0 && !t.borders.Right {
|
||||
center = SPACE
|
||||
}
|
||||
|
||||
// Print first junction
|
||||
if i == 0 {
|
||||
fmt.Fprint(t.out, center)
|
||||
}
|
||||
|
||||
// Pad With space of length is 0
|
||||
if length == 0 {
|
||||
pad = SPACE
|
||||
}
|
||||
// Ignore left space of it has printed before
|
||||
if hasPrinted || t.borders.Left {
|
||||
pad = t.pRow
|
||||
center = t.pCenter
|
||||
}
|
||||
|
||||
// Change Center start position
|
||||
if center == SPACE {
|
||||
if i < end && len(t.footers[i+1][0]) != 0 {
|
||||
center = t.pCenter
|
||||
}
|
||||
}
|
||||
|
||||
// Print the footer
|
||||
fmt.Fprintf(t.out, "%s%s%s%s",
|
||||
pad,
|
||||
strings.Repeat(string(pad), v),
|
||||
pad,
|
||||
center)
|
||||
|
||||
}
|
||||
|
||||
fmt.Fprint(t.out, t.newLine)
|
||||
}
|
||||
|
||||
// Print caption text
|
||||
func (t Table) printCaption() {
|
||||
width := t.getTableWidth()
|
||||
paragraph, _ := WrapString(t.captionText, width)
|
||||
for linecount := 0; linecount < len(paragraph); linecount++ {
|
||||
fmt.Fprintln(t.out, paragraph[linecount])
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the total number of characters in a row
|
||||
func (t Table) getTableWidth() int {
|
||||
var chars int
|
||||
for _, v := range t.cs {
|
||||
chars += v
|
||||
}
|
||||
|
||||
// Add chars, spaces, seperators to calculate the total width of the table.
|
||||
// ncols := t.colSize
|
||||
// spaces := ncols * 2
|
||||
// seps := ncols + 1
|
||||
|
||||
return (chars + (3 * t.colSize) + 2)
|
||||
}
|
||||
|
||||
func (t Table) printRows() {
|
||||
for i, lines := range t.lines {
|
||||
t.printRow(lines, i)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Table) fillAlignment(num int) {
|
||||
if len(t.columnsAlign) < num {
|
||||
t.columnsAlign = make([]int, num)
|
||||
for i := range t.columnsAlign {
|
||||
t.columnsAlign[i] = t.align
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Print Row Information
|
||||
// Adjust column alignment based on type
|
||||
|
||||
func (t *Table) printRow(columns [][]string, rowIdx int) {
|
||||
// Get Maximum Height
|
||||
max := t.rs[rowIdx]
|
||||
total := len(columns)
|
||||
|
||||
// TODO Fix uneven col size
|
||||
// if total < t.colSize {
|
||||
// for n := t.colSize - total; n < t.colSize ; n++ {
|
||||
// columns = append(columns, []string{SPACE})
|
||||
// t.cs[n] = t.mW
|
||||
// }
|
||||
//}
|
||||
|
||||
// Pad Each Height
|
||||
pads := []int{}
|
||||
|
||||
// Checking for ANSI escape sequences for columns
|
||||
is_esc_seq := false
|
||||
if len(t.columnsParams) > 0 {
|
||||
is_esc_seq = true
|
||||
}
|
||||
t.fillAlignment(total)
|
||||
|
||||
for i, line := range columns {
|
||||
length := len(line)
|
||||
pad := max - length
|
||||
pads = append(pads, pad)
|
||||
for n := 0; n < pad; n++ {
|
||||
columns[i] = append(columns[i], " ")
|
||||
}
|
||||
}
|
||||
//fmt.Println(max, "\n")
|
||||
for x := 0; x < max; x++ {
|
||||
for y := 0; y < total; y++ {
|
||||
|
||||
// Check if border is set
|
||||
fmt.Fprint(t.out, ConditionString((!t.borders.Left && y == 0), SPACE, t.pColumn))
|
||||
|
||||
fmt.Fprintf(t.out, SPACE)
|
||||
str := columns[y][x]
|
||||
|
||||
// Embedding escape sequence with column value
|
||||
if is_esc_seq {
|
||||
str = format(str, t.columnsParams[y])
|
||||
}
|
||||
|
||||
// This would print alignment
|
||||
// Default alignment would use multiple configuration
|
||||
switch t.columnsAlign[y] {
|
||||
case ALIGN_CENTER: //
|
||||
fmt.Fprintf(t.out, "%s", Pad(str, SPACE, t.cs[y]))
|
||||
case ALIGN_RIGHT:
|
||||
fmt.Fprintf(t.out, "%s", PadLeft(str, SPACE, t.cs[y]))
|
||||
case ALIGN_LEFT:
|
||||
fmt.Fprintf(t.out, "%s", PadRight(str, SPACE, t.cs[y]))
|
||||
default:
|
||||
if decimal.MatchString(strings.TrimSpace(str)) || percent.MatchString(strings.TrimSpace(str)) {
|
||||
fmt.Fprintf(t.out, "%s", PadLeft(str, SPACE, t.cs[y]))
|
||||
} else {
|
||||
fmt.Fprintf(t.out, "%s", PadRight(str, SPACE, t.cs[y]))
|
||||
|
||||
// TODO Custom alignment per column
|
||||
//if max == 1 || pads[y] > 0 {
|
||||
// fmt.Fprintf(t.out, "%s", Pad(str, SPACE, t.cs[y]))
|
||||
//} else {
|
||||
// fmt.Fprintf(t.out, "%s", PadRight(str, SPACE, t.cs[y]))
|
||||
//}
|
||||
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(t.out, SPACE)
|
||||
}
|
||||
// Check if border is set
|
||||
// Replace with space if not set
|
||||
fmt.Fprint(t.out, ConditionString(t.borders.Left, t.pColumn, SPACE))
|
||||
fmt.Fprint(t.out, t.newLine)
|
||||
}
|
||||
|
||||
if t.rowLine {
|
||||
t.printLine(true)
|
||||
}
|
||||
}
|
||||
|
||||
// Print the rows of the table and merge the cells that are identical
|
||||
func (t *Table) printRowsMergeCells() {
|
||||
var previousLine []string
|
||||
var displayCellBorder []bool
|
||||
var tmpWriter bytes.Buffer
|
||||
for i, lines := range t.lines {
|
||||
// We store the display of the current line in a tmp writer, as we need to know which border needs to be print above
|
||||
previousLine, displayCellBorder = t.printRowMergeCells(&tmpWriter, lines, i, previousLine)
|
||||
if i > 0 { //We don't need to print borders above first line
|
||||
if t.rowLine {
|
||||
t.printLineOptionalCellSeparators(true, displayCellBorder)
|
||||
}
|
||||
}
|
||||
tmpWriter.WriteTo(t.out)
|
||||
}
|
||||
//Print the end of the table
|
||||
if t.rowLine {
|
||||
t.printLine(true)
|
||||
}
|
||||
}
|
||||
|
||||
// Print Row Information to a writer and merge identical cells.
|
||||
// Adjust column alignment based on type
|
||||
|
||||
func (t *Table) printRowMergeCells(writer io.Writer, columns [][]string, rowIdx int, previousLine []string) ([]string, []bool) {
|
||||
// Get Maximum Height
|
||||
max := t.rs[rowIdx]
|
||||
total := len(columns)
|
||||
|
||||
// Pad Each Height
|
||||
pads := []int{}
|
||||
|
||||
for i, line := range columns {
|
||||
length := len(line)
|
||||
pad := max - length
|
||||
pads = append(pads, pad)
|
||||
for n := 0; n < pad; n++ {
|
||||
columns[i] = append(columns[i], " ")
|
||||
}
|
||||
}
|
||||
|
||||
var displayCellBorder []bool
|
||||
t.fillAlignment(total)
|
||||
for x := 0; x < max; x++ {
|
||||
for y := 0; y < total; y++ {
|
||||
|
||||
// Check if border is set
|
||||
fmt.Fprint(writer, ConditionString((!t.borders.Left && y == 0), SPACE, t.pColumn))
|
||||
|
||||
fmt.Fprintf(writer, SPACE)
|
||||
|
||||
str := columns[y][x]
|
||||
|
||||
if t.autoMergeCells {
|
||||
//Store the full line to merge mutli-lines cells
|
||||
fullLine := strings.Join(columns[y], " ")
|
||||
if len(previousLine) > y && fullLine == previousLine[y] && fullLine != "" {
|
||||
// If this cell is identical to the one above but not empty, we don't display the border and keep the cell empty.
|
||||
displayCellBorder = append(displayCellBorder, false)
|
||||
str = ""
|
||||
} else {
|
||||
// First line or different content, keep the content and print the cell border
|
||||
displayCellBorder = append(displayCellBorder, true)
|
||||
}
|
||||
}
|
||||
|
||||
// This would print alignment
|
||||
// Default alignment would use multiple configuration
|
||||
switch t.columnsAlign[y] {
|
||||
case ALIGN_CENTER: //
|
||||
fmt.Fprintf(writer, "%s", Pad(str, SPACE, t.cs[y]))
|
||||
case ALIGN_RIGHT:
|
||||
fmt.Fprintf(writer, "%s", PadLeft(str, SPACE, t.cs[y]))
|
||||
case ALIGN_LEFT:
|
||||
fmt.Fprintf(writer, "%s", PadRight(str, SPACE, t.cs[y]))
|
||||
default:
|
||||
if decimal.MatchString(strings.TrimSpace(str)) || percent.MatchString(strings.TrimSpace(str)) {
|
||||
fmt.Fprintf(writer, "%s", PadLeft(str, SPACE, t.cs[y]))
|
||||
} else {
|
||||
fmt.Fprintf(writer, "%s", PadRight(str, SPACE, t.cs[y]))
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(writer, SPACE)
|
||||
}
|
||||
// Check if border is set
|
||||
// Replace with space if not set
|
||||
fmt.Fprint(writer, ConditionString(t.borders.Left, t.pColumn, SPACE))
|
||||
fmt.Fprint(writer, t.newLine)
|
||||
}
|
||||
|
||||
//The new previous line is the current one
|
||||
previousLine = make([]string, total)
|
||||
for y := 0; y < total; y++ {
|
||||
previousLine[y] = strings.Join(columns[y], " ") //Store the full line for multi-lines cells
|
||||
}
|
||||
//Returns the newly added line and wether or not a border should be displayed above.
|
||||
return previousLine, displayCellBorder
|
||||
}
|
||||
|
||||
func (t *Table) parseDimension(str string, colKey, rowKey int) []string {
|
||||
var (
|
||||
raw []string
|
||||
maxWidth int
|
||||
)
|
||||
|
||||
raw = getLines(str)
|
||||
maxWidth = 0
|
||||
for _, line := range raw {
|
||||
if w := DisplayWidth(line); w > maxWidth {
|
||||
maxWidth = w
|
||||
}
|
||||
}
|
||||
|
||||
// If wrapping, ensure that all paragraphs in the cell fit in the
|
||||
// specified width.
|
||||
if t.autoWrap {
|
||||
// If there's a maximum allowed width for wrapping, use that.
|
||||
if maxWidth > t.mW {
|
||||
maxWidth = t.mW
|
||||
}
|
||||
|
||||
// In the process of doing so, we need to recompute maxWidth. This
|
||||
// is because perhaps a word in the cell is longer than the
|
||||
// allowed maximum width in t.mW.
|
||||
newMaxWidth := maxWidth
|
||||
newRaw := make([]string, 0, len(raw))
|
||||
|
||||
if t.reflowText {
|
||||
// Make a single paragraph of everything.
|
||||
raw = []string{strings.Join(raw, " ")}
|
||||
}
|
||||
for i, para := range raw {
|
||||
paraLines, _ := WrapString(para, maxWidth)
|
||||
for _, line := range paraLines {
|
||||
if w := DisplayWidth(line); w > newMaxWidth {
|
||||
newMaxWidth = w
|
||||
}
|
||||
}
|
||||
if i > 0 {
|
||||
newRaw = append(newRaw, " ")
|
||||
}
|
||||
newRaw = append(newRaw, paraLines...)
|
||||
}
|
||||
raw = newRaw
|
||||
maxWidth = newMaxWidth
|
||||
}
|
||||
|
||||
// Store the new known maximum width.
|
||||
v, ok := t.cs[colKey]
|
||||
if !ok || v < maxWidth || v == 0 {
|
||||
t.cs[colKey] = maxWidth
|
||||
}
|
||||
|
||||
// Remember the number of lines for the row printer.
|
||||
h := len(raw)
|
||||
v, ok = t.rs[rowKey]
|
||||
|
||||
if !ok || v < h || v == 0 {
|
||||
t.rs[rowKey] = h
|
||||
}
|
||||
//fmt.Printf("Raw %+v %d\n", raw, len(raw))
|
||||
return raw
|
||||
}
|
134
vendor/github.com/olekukonko/tablewriter/table_with_color.go
generated
vendored
Normal file
134
vendor/github.com/olekukonko/tablewriter/table_with_color.go
generated
vendored
Normal file
@ -0,0 +1,134 @@
|
||||
package tablewriter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const ESC = "\033"
|
||||
const SEP = ";"
|
||||
|
||||
const (
|
||||
BgBlackColor int = iota + 40
|
||||
BgRedColor
|
||||
BgGreenColor
|
||||
BgYellowColor
|
||||
BgBlueColor
|
||||
BgMagentaColor
|
||||
BgCyanColor
|
||||
BgWhiteColor
|
||||
)
|
||||
|
||||
const (
|
||||
FgBlackColor int = iota + 30
|
||||
FgRedColor
|
||||
FgGreenColor
|
||||
FgYellowColor
|
||||
FgBlueColor
|
||||
FgMagentaColor
|
||||
FgCyanColor
|
||||
FgWhiteColor
|
||||
)
|
||||
|
||||
const (
|
||||
BgHiBlackColor int = iota + 100
|
||||
BgHiRedColor
|
||||
BgHiGreenColor
|
||||
BgHiYellowColor
|
||||
BgHiBlueColor
|
||||
BgHiMagentaColor
|
||||
BgHiCyanColor
|
||||
BgHiWhiteColor
|
||||
)
|
||||
|
||||
const (
|
||||
FgHiBlackColor int = iota + 90
|
||||
FgHiRedColor
|
||||
FgHiGreenColor
|
||||
FgHiYellowColor
|
||||
FgHiBlueColor
|
||||
FgHiMagentaColor
|
||||
FgHiCyanColor
|
||||
FgHiWhiteColor
|
||||
)
|
||||
|
||||
const (
|
||||
Normal = 0
|
||||
Bold = 1
|
||||
UnderlineSingle = 4
|
||||
Italic
|
||||
)
|
||||
|
||||
type Colors []int
|
||||
|
||||
func startFormat(seq string) string {
|
||||
return fmt.Sprintf("%s[%sm", ESC, seq)
|
||||
}
|
||||
|
||||
func stopFormat() string {
|
||||
return fmt.Sprintf("%s[%dm", ESC, Normal)
|
||||
}
|
||||
|
||||
// Making the SGR (Select Graphic Rendition) sequence.
|
||||
func makeSequence(codes []int) string {
|
||||
codesInString := []string{}
|
||||
for _, code := range codes {
|
||||
codesInString = append(codesInString, strconv.Itoa(code))
|
||||
}
|
||||
return strings.Join(codesInString, SEP)
|
||||
}
|
||||
|
||||
// Adding ANSI escape sequences before and after string
|
||||
func format(s string, codes interface{}) string {
|
||||
var seq string
|
||||
|
||||
switch v := codes.(type) {
|
||||
|
||||
case string:
|
||||
seq = v
|
||||
case []int:
|
||||
seq = makeSequence(v)
|
||||
default:
|
||||
return s
|
||||
}
|
||||
|
||||
if len(seq) == 0 {
|
||||
return s
|
||||
}
|
||||
return startFormat(seq) + s + stopFormat()
|
||||
}
|
||||
|
||||
// Adding header colors (ANSI codes)
|
||||
func (t *Table) SetHeaderColor(colors ...Colors) {
|
||||
if t.colSize != len(colors) {
|
||||
panic("Number of header colors must be equal to number of headers.")
|
||||
}
|
||||
for i := 0; i < len(colors); i++ {
|
||||
t.headerParams = append(t.headerParams, makeSequence(colors[i]))
|
||||
}
|
||||
}
|
||||
|
||||
// Adding column colors (ANSI codes)
|
||||
func (t *Table) SetColumnColor(colors ...Colors) {
|
||||
if t.colSize != len(colors) {
|
||||
panic("Number of column colors must be equal to number of headers.")
|
||||
}
|
||||
for i := 0; i < len(colors); i++ {
|
||||
t.columnsParams = append(t.columnsParams, makeSequence(colors[i]))
|
||||
}
|
||||
}
|
||||
|
||||
// Adding column colors (ANSI codes)
|
||||
func (t *Table) SetFooterColor(colors ...Colors) {
|
||||
if len(t.footers) != len(colors) {
|
||||
panic("Number of footer colors must be equal to number of footer.")
|
||||
}
|
||||
for i := 0; i < len(colors); i++ {
|
||||
t.footerParams = append(t.footerParams, makeSequence(colors[i]))
|
||||
}
|
||||
}
|
||||
|
||||
func Color(colors ...int) []int {
|
||||
return colors
|
||||
}
|
93
vendor/github.com/olekukonko/tablewriter/util.go
generated
vendored
Normal file
93
vendor/github.com/olekukonko/tablewriter/util.go
generated
vendored
Normal file
@ -0,0 +1,93 @@
|
||||
// Copyright 2014 Oleku Konko All rights reserved.
|
||||
// Use of this source code is governed by a MIT
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This module is a Table Writer API for the Go Programming Language.
|
||||
// The protocols were written in pure Go and works on windows and unix systems
|
||||
|
||||
package tablewriter
|
||||
|
||||
import (
|
||||
"math"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/mattn/go-runewidth"
|
||||
)
|
||||
|
||||
var ansi = regexp.MustCompile("\033\\[(?:[0-9]{1,3}(?:;[0-9]{1,3})*)?[m|K]")
|
||||
|
||||
func DisplayWidth(str string) int {
|
||||
return runewidth.StringWidth(ansi.ReplaceAllLiteralString(str, ""))
|
||||
}
|
||||
|
||||
// Simple Condition for string
|
||||
// Returns value based on condition
|
||||
func ConditionString(cond bool, valid, inValid string) string {
|
||||
if cond {
|
||||
return valid
|
||||
}
|
||||
return inValid
|
||||
}
|
||||
|
||||
func isNumOrSpace(r rune) bool {
|
||||
return ('0' <= r && r <= '9') || r == ' '
|
||||
}
|
||||
|
||||
// Format Table Header
|
||||
// Replace _ , . and spaces
|
||||
func Title(name string) string {
|
||||
origLen := len(name)
|
||||
rs := []rune(name)
|
||||
for i, r := range rs {
|
||||
switch r {
|
||||
case '_':
|
||||
rs[i] = ' '
|
||||
case '.':
|
||||
// ignore floating number 0.0
|
||||
if (i != 0 && !isNumOrSpace(rs[i-1])) || (i != len(rs)-1 && !isNumOrSpace(rs[i+1])) {
|
||||
rs[i] = ' '
|
||||
}
|
||||
}
|
||||
}
|
||||
name = string(rs)
|
||||
name = strings.TrimSpace(name)
|
||||
if len(name) == 0 && origLen > 0 {
|
||||
// Keep at least one character. This is important to preserve
|
||||
// empty lines in multi-line headers/footers.
|
||||
name = " "
|
||||
}
|
||||
return strings.ToUpper(name)
|
||||
}
|
||||
|
||||
// Pad String
|
||||
// Attempts to play string in the center
|
||||
func Pad(s, pad string, width int) string {
|
||||
gap := width - DisplayWidth(s)
|
||||
if gap > 0 {
|
||||
gapLeft := int(math.Ceil(float64(gap / 2)))
|
||||
gapRight := gap - gapLeft
|
||||
return strings.Repeat(string(pad), gapLeft) + s + strings.Repeat(string(pad), gapRight)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Pad String Right position
|
||||
// This would pace string at the left side fo the screen
|
||||
func PadRight(s, pad string, width int) string {
|
||||
gap := width - DisplayWidth(s)
|
||||
if gap > 0 {
|
||||
return s + strings.Repeat(string(pad), gap)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Pad String Left position
|
||||
// This would pace string at the right side fo the screen
|
||||
func PadLeft(s, pad string, width int) string {
|
||||
gap := width - DisplayWidth(s)
|
||||
if gap > 0 {
|
||||
return strings.Repeat(string(pad), gap) + s
|
||||
}
|
||||
return s
|
||||
}
|
99
vendor/github.com/olekukonko/tablewriter/wrap.go
generated
vendored
Normal file
99
vendor/github.com/olekukonko/tablewriter/wrap.go
generated
vendored
Normal file
@ -0,0 +1,99 @@
|
||||
// Copyright 2014 Oleku Konko All rights reserved.
|
||||
// Use of this source code is governed by a MIT
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This module is a Table Writer API for the Go Programming Language.
|
||||
// The protocols were written in pure Go and works on windows and unix systems
|
||||
|
||||
package tablewriter
|
||||
|
||||
import (
|
||||
"math"
|
||||
"strings"
|
||||
|
||||
"github.com/mattn/go-runewidth"
|
||||
)
|
||||
|
||||
var (
|
||||
nl = "\n"
|
||||
sp = " "
|
||||
)
|
||||
|
||||
const defaultPenalty = 1e5
|
||||
|
||||
// Wrap wraps s into a paragraph of lines of length lim, with minimal
|
||||
// raggedness.
|
||||
func WrapString(s string, lim int) ([]string, int) {
|
||||
words := strings.Split(strings.Replace(s, nl, sp, -1), sp)
|
||||
var lines []string
|
||||
max := 0
|
||||
for _, v := range words {
|
||||
max = runewidth.StringWidth(v)
|
||||
if max > lim {
|
||||
lim = max
|
||||
}
|
||||
}
|
||||
for _, line := range WrapWords(words, 1, lim, defaultPenalty) {
|
||||
lines = append(lines, strings.Join(line, sp))
|
||||
}
|
||||
return lines, lim
|
||||
}
|
||||
|
||||
// WrapWords is the low-level line-breaking algorithm, useful if you need more
|
||||
// control over the details of the text wrapping process. For most uses,
|
||||
// WrapString will be sufficient and more convenient.
|
||||
//
|
||||
// WrapWords splits a list of words into lines with minimal "raggedness",
|
||||
// treating each rune as one unit, accounting for spc units between adjacent
|
||||
// words on each line, and attempting to limit lines to lim units. Raggedness
|
||||
// is the total error over all lines, where error is the square of the
|
||||
// difference of the length of the line and lim. Too-long lines (which only
|
||||
// happen when a single word is longer than lim units) have pen penalty units
|
||||
// added to the error.
|
||||
func WrapWords(words []string, spc, lim, pen int) [][]string {
|
||||
n := len(words)
|
||||
|
||||
length := make([][]int, n)
|
||||
for i := 0; i < n; i++ {
|
||||
length[i] = make([]int, n)
|
||||
length[i][i] = runewidth.StringWidth(words[i])
|
||||
for j := i + 1; j < n; j++ {
|
||||
length[i][j] = length[i][j-1] + spc + runewidth.StringWidth(words[j])
|
||||
}
|
||||
}
|
||||
nbrk := make([]int, n)
|
||||
cost := make([]int, n)
|
||||
for i := range cost {
|
||||
cost[i] = math.MaxInt32
|
||||
}
|
||||
for i := n - 1; i >= 0; i-- {
|
||||
if length[i][n-1] <= lim {
|
||||
cost[i] = 0
|
||||
nbrk[i] = n
|
||||
} else {
|
||||
for j := i + 1; j < n; j++ {
|
||||
d := lim - length[i][j-1]
|
||||
c := d*d + cost[j]
|
||||
if length[i][j-1] > lim {
|
||||
c += pen // too-long lines get a worse penalty
|
||||
}
|
||||
if c < cost[i] {
|
||||
cost[i] = c
|
||||
nbrk[i] = j
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var lines [][]string
|
||||
i := 0
|
||||
for i < n {
|
||||
lines = append(lines, words[i:nbrk[i]])
|
||||
i = nbrk[i]
|
||||
}
|
||||
return lines
|
||||
}
|
||||
|
||||
// getLines decomposes a multiline string into a slice of strings.
|
||||
func getLines(s string) []string {
|
||||
return strings.Split(s, nl)
|
||||
}
|
12
vendor/modules.txt
vendored
12
vendor/modules.txt
vendored
@ -49,11 +49,11 @@ github.com/go-redis/redis/internal/singleflight
|
||||
github.com/go-redis/redis/internal/util
|
||||
# github.com/go-sql-driver/mysql v1.4.1
|
||||
github.com/go-sql-driver/mysql
|
||||
# github.com/go-xorm/builder v0.0.0-20170519032130-c8871c857d25
|
||||
# github.com/go-xorm/builder v0.3.2
|
||||
github.com/go-xorm/builder
|
||||
# github.com/go-xorm/core v0.5.8
|
||||
# github.com/go-xorm/core v0.6.0
|
||||
github.com/go-xorm/core
|
||||
# github.com/go-xorm/xorm v0.0.0-20170930012613-29d4a0330a00
|
||||
# github.com/go-xorm/xorm v0.7.1
|
||||
github.com/go-xorm/xorm
|
||||
# github.com/go-xorm/xorm-redis-cache v0.0.0-20180727005610-859b313566b2
|
||||
github.com/go-xorm/xorm-redis-cache
|
||||
@ -99,12 +99,16 @@ github.com/mailru/easyjson/buffer
|
||||
github.com/mattn/go-colorable
|
||||
# github.com/mattn/go-isatty v0.0.7
|
||||
github.com/mattn/go-isatty
|
||||
# github.com/mattn/go-runewidth v0.0.4
|
||||
github.com/mattn/go-runewidth
|
||||
# github.com/mattn/go-sqlite3 v1.10.0
|
||||
github.com/mattn/go-sqlite3
|
||||
# github.com/matttproud/golang_protobuf_extensions v1.0.1
|
||||
github.com/matttproud/golang_protobuf_extensions/pbutil
|
||||
# github.com/mitchellh/mapstructure v1.1.2
|
||||
github.com/mitchellh/mapstructure
|
||||
# github.com/olekukonko/tablewriter v0.0.1
|
||||
github.com/olekukonko/tablewriter
|
||||
# github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
|
||||
github.com/op/go-logging
|
||||
# github.com/pelletier/go-toml v1.2.0
|
||||
@ -216,3 +220,5 @@ honnef.co/go/tools/ssautil
|
||||
honnef.co/go/tools/staticcheck/vrp
|
||||
honnef.co/go/tools/callgraph
|
||||
honnef.co/go/tools/callgraph/static
|
||||
# src.techknowlogick.com/xormigrate v0.0.0-20190321151057-24497c23c09c
|
||||
src.techknowlogick.com/xormigrate
|
||||
|
38
vendor/src.techknowlogick.com/xormigrate/.drone.yml
generated
vendored
Normal file
38
vendor/src.techknowlogick.com/xormigrate/.drone.yml
generated
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
kind: pipeline
|
||||
name: default
|
||||
|
||||
workspace:
|
||||
base: /go
|
||||
path: src/src.techknowlogick.com/xormigrate
|
||||
|
||||
steps:
|
||||
- name: fetch-and-test
|
||||
image: golang:1.12
|
||||
environment:
|
||||
GO111MODULE: on
|
||||
commands:
|
||||
- go get ./...
|
||||
- go test -v -tags sqlite
|
||||
- go test -v -tags mysql
|
||||
- go test -v -tags postgresql
|
||||
- go test -v -tags sqlserver
|
||||
|
||||
services:
|
||||
- name: pgsql
|
||||
image: postgres:9.5
|
||||
environment:
|
||||
POSTGRES_DB: test
|
||||
POSTGRES_PASSWORD: postgres
|
||||
|
||||
- name: mysql
|
||||
image: mysql:5.7
|
||||
environment:
|
||||
MYSQL_DATABASE: test
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: yes
|
||||
|
||||
- name: mssql
|
||||
image: microsoft/mssql-server-linux:latest
|
||||
environment:
|
||||
ACCEPT_EULA: Y
|
||||
SA_PASSWORD: MwantsaSecurePassword1
|
||||
MSSQL_PID: Standard
|
4
vendor/src.techknowlogick.com/xormigrate/.env
generated
vendored
Normal file
4
vendor/src.techknowlogick.com/xormigrate/.env
generated
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
SQLITE_CONN_STRING=file::memory:?cache=shared
|
||||
PG_CONN_STRING="user=postgres password=postgres host=pgsql dbname=test sslmode=disable"
|
||||
MYSQL_CONN_STRING="root:@(mysql)/test?multiStatements=true"
|
||||
SQLSERVER_CONN_STRING="server=mssql; database=master; user id=sa; password=MwantsaSecurePassword1; encrypt=disable"
|
19
vendor/src.techknowlogick.com/xormigrate/LICENSE
generated
vendored
Normal file
19
vendor/src.techknowlogick.com/xormigrate/LICENSE
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
Copyright (c) 2019 Matti Ranta (@techknowlogick)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
162
vendor/src.techknowlogick.com/xormigrate/README.md
generated
vendored
Normal file
162
vendor/src.techknowlogick.com/xormigrate/README.md
generated
vendored
Normal file
@ -0,0 +1,162 @@
|
||||
# Xormigrate
|
||||
[](https://cloud.drone.io/techknowlogick/xormigrate)
|
||||
[](https://goreportcard.com/report/src.techknowlogick.com/xormigrate)
|
||||
[](https://godoc.org/src.techknowlogick.com/xormigrate)
|
||||
|
||||
## Supported databases
|
||||
|
||||
It supports any of the databases Xorm supports:
|
||||
|
||||
- PostgreSQL
|
||||
- MySQL
|
||||
- SQLite
|
||||
- Microsoft SQL Server
|
||||
|
||||
## Installing
|
||||
|
||||
```bash
|
||||
go get -u src.techknowlogick.com/xormigrate
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"src.techknowlogick.com/xormigrate"
|
||||
|
||||
"github.com/go-xorm/xorm"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
func main() {
|
||||
db, err := xorm.NewEngine("sqlite3", "mydb.sqlite3")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
m := xormigrate.New(db, []*xormigrate.Migration{
|
||||
// create persons table
|
||||
{
|
||||
ID: "201608301400",
|
||||
// An optional description to print out to the Xormigrate logger
|
||||
Description: "Create the Person table",
|
||||
Migrate: func(tx *xorm.Engine) error {
|
||||
// it's a good pratice to copy the struct inside the function,
|
||||
// so side effects are prevented if the original struct changes during the time
|
||||
type Person struct {
|
||||
Name string
|
||||
}
|
||||
return tx.Sync2(&Person{})
|
||||
},
|
||||
Rollback: func(tx *xorm.Engine) error {
|
||||
return tx.DropTables(&Person{})
|
||||
},
|
||||
},
|
||||
// add age column to persons
|
||||
{
|
||||
ID: "201608301415",
|
||||
Migrate: func(tx *xorm.Engine) error {
|
||||
// when table already exists, it just adds fields as columns
|
||||
type Person struct {
|
||||
Age int
|
||||
}
|
||||
return tx.Sync2(&Person{})
|
||||
},
|
||||
Rollback: func(tx *xorm.Engine) error {
|
||||
// Note: Column dropping in sqlite is not support, and you will need to do this manually
|
||||
_, err = tx.Exec("ALTER TABLE person DROP COLUMN age")
|
||||
if err != nil {
|
||||
return fmt.Errorf("Drop column failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
// add pets table
|
||||
{
|
||||
ID: "201608301430",
|
||||
Migrate: func(tx *xorm.Engine) error {
|
||||
type Pet struct {
|
||||
Name string
|
||||
PersonID int
|
||||
}
|
||||
return tx.Sync2(&Pet{})
|
||||
},
|
||||
Rollback: func(tx *xorm.Engine) error {
|
||||
return tx.DropTables(&Pet{})
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if err = m.Migrate(); err != nil {
|
||||
log.Fatalf("Could not migrate: %v", err)
|
||||
}
|
||||
log.Printf("Migration did run successfully")
|
||||
}
|
||||
```
|
||||
|
||||
## Having a separated function for initializing the schema
|
||||
|
||||
If you have a lot of migrations, it can be a pain to run all them, as example,
|
||||
when you are deploying a new instance of the app, in a clean database.
|
||||
To prevent this, you can set a function that will run if no migration was run
|
||||
before (in a new clean database). Remember to create everything here, all tables,
|
||||
foreign keys and what more you need in your app.
|
||||
|
||||
```go
|
||||
type Person struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
type Pet struct {
|
||||
Name string
|
||||
PersonID int
|
||||
}
|
||||
|
||||
m := xormigrate.New(db, []*xormigrate.Migration{
|
||||
// your migrations here
|
||||
})
|
||||
|
||||
m.InitSchema(func(tx *xorm.Engine) error {
|
||||
err := tx.sync2(
|
||||
&Person{},
|
||||
&Pet{},
|
||||
// all other tables of your app
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
```
|
||||
|
||||
## Adding migration descriptions to your logging
|
||||
Xormigrate's logger defaults to stdout, but it can be changed to suit your needs.
|
||||
```go
|
||||
m := xormigrate.New(db, []*xormigrate.Migration{
|
||||
// your migrations here
|
||||
})
|
||||
|
||||
// Don't log anything
|
||||
m.NilLogger()
|
||||
|
||||
// This is the default logger
|
||||
// No need to initialize this unless it was changed
|
||||
// [xormigrate] message
|
||||
m.DefaultLogger()
|
||||
|
||||
// Or, create a logger with any io.Writer you want
|
||||
m.NewLogger(os.Stdout)
|
||||
```
|
||||
|
||||
## Credits
|
||||
|
||||
* Based on [Gormigrate][gormmigrate]
|
||||
* Uses [Xorm][xorm]
|
||||
|
||||
[xorm]: http://github.com/go-xorm/xorm/
|
||||
[gormmigrate]: https://github.com/go-gormigrate/gormigrate
|
9
vendor/src.techknowlogick.com/xormigrate/go.mod
generated
vendored
Normal file
9
vendor/src.techknowlogick.com/xormigrate/go.mod
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
module src.techknowlogick.com/xormigrate
|
||||
|
||||
go 1.12
|
||||
|
||||
require (
|
||||
github.com/go-xorm/xorm v0.7.1
|
||||
github.com/joho/godotenv v1.3.0
|
||||
github.com/stretchr/testify v1.3.0
|
||||
)
|
34
vendor/src.techknowlogick.com/xormigrate/go.sum
generated
vendored
Normal file
34
vendor/src.techknowlogick.com/xormigrate/go.sum
generated
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20181014144952-4e0d7dc8888f/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc=
|
||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-xorm/builder v0.3.2 h1:pSsZQRRzJNapKEAEhigw3xLmiLPeAYv5GFlpYZ8+a5I=
|
||||
github.com/go-xorm/builder v0.3.2/go.mod h1:v8mE3MFBgtL+RGFNfUnAMUqqfk/Y4W5KuwCFQIEpQLk=
|
||||
github.com/go-xorm/core v0.6.0 h1:tp6hX+ku4OD9khFZS8VGBDRY3kfVCtelPfmkgCyHxL0=
|
||||
github.com/go-xorm/core v0.6.0/go.mod h1:d8FJ9Br8OGyQl12MCclmYBuBqqxsyeedpXciV5Myih8=
|
||||
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM=
|
||||
github.com/go-xorm/xorm v0.7.1 h1:Kj7mfuqctPdX60zuxP6EoEut0f3E6K66H6hcoxiHUMc=
|
||||
github.com/go-xorm/xorm v0.7.1/go.mod h1:EHS1htMQFptzMaIHKyzqpHGw6C9Rtug75nsq6DA9unI=
|
||||
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ=
|
||||
github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
|
||||
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
|
||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/stretchr/testify.v1 v1.2.2/go.mod h1:QI5V/q6UbPmuhtm10CaFZxED9NreB8PnFYN9JcR6TxU=
|
92
vendor/src.techknowlogick.com/xormigrate/logger.go
generated
vendored
Normal file
92
vendor/src.techknowlogick.com/xormigrate/logger.go
generated
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
package xormigrate
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
type LoggerInterface interface {
|
||||
Debug(v ...interface{})
|
||||
Debugf(format string, v ...interface{})
|
||||
Info(v ...interface{})
|
||||
Infof(format string, v ...interface{})
|
||||
Warn(v ...interface{})
|
||||
Warnf(format string, v ...interface{})
|
||||
Error(v ...interface{})
|
||||
Errorf(format string, v ...interface{})
|
||||
}
|
||||
|
||||
var (
|
||||
logger LoggerInterface = defaultLogger()
|
||||
)
|
||||
|
||||
// SetLogger sets the Xormigrate logger
|
||||
func (x *Xormigrate) SetLogger(l LoggerInterface) {
|
||||
logger = l
|
||||
}
|
||||
|
||||
func defaultLogger() *XormigrateLogger {
|
||||
return &XormigrateLogger{log.New(os.Stdout, "[xormigrate] ", 0)}
|
||||
}
|
||||
|
||||
// DefaultLogger sets a Xormigrate logger with default settings
|
||||
// e.g. "[xormigrate] message"
|
||||
func (x *Xormigrate) DefaultLogger() {
|
||||
x.SetLogger(defaultLogger())
|
||||
}
|
||||
|
||||
// NilLogger sets a Xormigrate logger that discards all messages
|
||||
func (x *Xormigrate) NilLogger() {
|
||||
x.SetLogger(&XormigrateLogger{log.New(ioutil.Discard, "", 0)})
|
||||
}
|
||||
|
||||
// NewLogger sets a Xormigrate logger with a specified io.Writer
|
||||
func (x *Xormigrate) NewLogger(writer io.Writer) {
|
||||
x.SetLogger(&XormigrateLogger{log.New(writer, "", 0)})
|
||||
}
|
||||
|
||||
type XormigrateLogger struct {
|
||||
*log.Logger
|
||||
}
|
||||
|
||||
// Debug prints a Debug message
|
||||
func (l *XormigrateLogger) Debug(v ...interface{}) {
|
||||
l.Logger.Print(v...)
|
||||
}
|
||||
|
||||
// Debugf prints a formatted Debug message
|
||||
func (l *XormigrateLogger) Debugf(format string, v ...interface{}) {
|
||||
l.Logger.Printf(format, v...)
|
||||
}
|
||||
|
||||
// Info prints an Info message
|
||||
func (l *XormigrateLogger) Info(v ...interface{}) {
|
||||
l.Logger.Print(v...)
|
||||
}
|
||||
|
||||
// Infof prints a formatted Info message
|
||||
func (l *XormigrateLogger) Infof(format string, v ...interface{}) {
|
||||
l.Logger.Printf(format, v...)
|
||||
}
|
||||
|
||||
// Warn prints a Warning message
|
||||
func (l *XormigrateLogger) Warn(v ...interface{}) {
|
||||
l.Logger.Print(v...)
|
||||
}
|
||||
|
||||
// Warnf prints a formatted Warning message
|
||||
func (l *XormigrateLogger) Warnf(format string, v ...interface{}) {
|
||||
l.Logger.Printf(format, v...)
|
||||
}
|
||||
|
||||
// Error prints an Error message
|
||||
func (l *XormigrateLogger) Error(v ...interface{}) {
|
||||
l.Logger.Print(v...)
|
||||
}
|
||||
|
||||
// Errorf prints a formatted Error message
|
||||
func (l *XormigrateLogger) Errorf(format string, v ...interface{}) {
|
||||
l.Logger.Printf(format, v...)
|
||||
}
|
5
vendor/src.techknowlogick.com/xormigrate/renovate.json
generated
vendored
Normal file
5
vendor/src.techknowlogick.com/xormigrate/renovate.json
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": [
|
||||
"config:base"
|
||||
]
|
||||
}
|
322
vendor/src.techknowlogick.com/xormigrate/xormigrate.go
generated
vendored
Normal file
322
vendor/src.techknowlogick.com/xormigrate/xormigrate.go
generated
vendored
Normal file
@ -0,0 +1,322 @@
|
||||
package xormigrate // import "src.techknowlogick.com/xormigrate"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/go-xorm/xorm"
|
||||
)
|
||||
|
||||
const (
|
||||
initSchemaMigrationId = "SCHEMA_INIT"
|
||||
)
|
||||
|
||||
// MigrateFunc is the func signature for migratinx.
|
||||
type MigrateFunc func(*xorm.Engine) error
|
||||
|
||||
// RollbackFunc is the func signature for rollbackinx.
|
||||
type RollbackFunc func(*xorm.Engine) error
|
||||
|
||||
// InitSchemaFunc is the func signature for initializing the schema.
|
||||
type InitSchemaFunc func(*xorm.Engine) error
|
||||
|
||||
// Migration represents a database migration (a modification to be made on the database).
|
||||
type Migration struct {
|
||||
// ID is the migration identifier. Usually a timestamp like "201601021504".
|
||||
ID string `xorm:"id"`
|
||||
// Description is the migration description, which is optionally printed out when the migration is ran.
|
||||
Description string
|
||||
// Migrate is a function that will br executed while running this migration.
|
||||
Migrate MigrateFunc `xorm:"-"`
|
||||
// Rollback will be executed on rollback. Can be nil.
|
||||
Rollback RollbackFunc `xorm:"-"`
|
||||
}
|
||||
|
||||
// Xormigrate represents a collection of all migrations of a database schema.
|
||||
type Xormigrate struct {
|
||||
db *xorm.Engine
|
||||
migrations []*Migration
|
||||
initSchema InitSchemaFunc
|
||||
}
|
||||
|
||||
// ReservedIDError is returned when a migration is using a reserved ID
|
||||
type ReservedIDError struct {
|
||||
ID string
|
||||
}
|
||||
|
||||
func (e *ReservedIDError) Error() string {
|
||||
return fmt.Sprintf(`xormigrate: Reserved migration ID: "%s"`, e.ID)
|
||||
}
|
||||
|
||||
// DuplicatedIDError is returned when more than one migration have the same ID
|
||||
type DuplicatedIDError struct {
|
||||
ID string
|
||||
}
|
||||
|
||||
func (e *DuplicatedIDError) Error() string {
|
||||
return fmt.Sprintf(`xormigrate: Duplicated migration ID: "%s"`, e.ID)
|
||||
}
|
||||
|
||||
var (
|
||||
// ErrRollbackImpossible is returned when trying to rollback a migration
|
||||
// that has no rollback function.
|
||||
ErrRollbackImpossible = errors.New("xormigrate: It's impossible to rollback this migration")
|
||||
|
||||
// ErrNoMigrationDefined is returned when no migration is defined.
|
||||
ErrNoMigrationDefined = errors.New("xormigrate: No migration defined")
|
||||
|
||||
// ErrMissingID is returned when the ID od migration is equal to ""
|
||||
ErrMissingID = errors.New("xormigrate: Missing ID in migration")
|
||||
|
||||
// ErrNoRunMigration is returned when any run migration was found while
|
||||
// running RollbackLast
|
||||
ErrNoRunMigration = errors.New("xormigrate: Could not find last run migration")
|
||||
|
||||
// ErrMigrationIDDoesNotExist is returned when migrating or rolling back to a migration ID that
|
||||
// does not exist in the list of migrations
|
||||
ErrMigrationIDDoesNotExist = errors.New("xormigrate: Tried to migrate to an ID that doesn't exist")
|
||||
)
|
||||
|
||||
// New returns a new Xormigrate.
|
||||
func New(db *xorm.Engine, migrations []*Migration) *Xormigrate {
|
||||
return &Xormigrate{
|
||||
db: db,
|
||||
migrations: migrations,
|
||||
}
|
||||
}
|
||||
|
||||
// InitSchema sets a function that is run if no migration is found.
|
||||
// The idea is preventing to run all migrations when a new clean database
|
||||
// is being migratinx. In this function you should create all tables and
|
||||
// foreign key necessary to your application.
|
||||
func (x *Xormigrate) InitSchema(initSchema InitSchemaFunc) {
|
||||
x.initSchema = initSchema
|
||||
}
|
||||
|
||||
// Migrate executes all migrations that did not run yet.
|
||||
func (x *Xormigrate) Migrate() error {
|
||||
return x.migrate("")
|
||||
}
|
||||
|
||||
// MigrateTo executes all migrations that did not run yet up to the migration that matches `migrationID`.
|
||||
func (x *Xormigrate) MigrateTo(migrationID string) error {
|
||||
if err := x.checkIDExist(migrationID); err != nil {
|
||||
return err
|
||||
}
|
||||
return x.migrate(migrationID)
|
||||
}
|
||||
|
||||
func (x *Xormigrate) migrate(migrationID string) error {
|
||||
if !x.hasMigrations() {
|
||||
return ErrNoMigrationDefined
|
||||
}
|
||||
|
||||
if err := x.checkReservedID(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := x.checkDuplicatedID(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := x.createMigrationTableIfNotExists(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if x.initSchema != nil && x.canInitializeSchema() {
|
||||
return x.runInitSchema() // return error or nil
|
||||
}
|
||||
|
||||
for _, migration := range x.migrations {
|
||||
if err := x.runMigration(migration); err != nil {
|
||||
return err
|
||||
}
|
||||
if migrationID != "" && migration.ID == migrationID {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// There are migrations to apply if either there's a defined
|
||||
// initSchema function or if the list of migrations is not empty.
|
||||
func (x *Xormigrate) hasMigrations() bool {
|
||||
return x.initSchema != nil || len(x.migrations) > 0
|
||||
}
|
||||
|
||||
// Check whether any migration is using a reserved ID.
|
||||
// For now there's only have one reserved ID, but there may be more in the future.
|
||||
func (x *Xormigrate) checkReservedID() error {
|
||||
for _, m := range x.migrations {
|
||||
if m.ID == initSchemaMigrationId {
|
||||
return &ReservedIDError{ID: m.ID}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Xormigrate) checkDuplicatedID() error {
|
||||
lookup := make(map[string]struct{}, len(x.migrations))
|
||||
for _, m := range x.migrations {
|
||||
if _, ok := lookup[m.ID]; ok {
|
||||
return &DuplicatedIDError{ID: m.ID}
|
||||
}
|
||||
lookup[m.ID] = struct{}{}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Xormigrate) checkIDExist(migrationID string) error {
|
||||
for _, migrate := range x.migrations {
|
||||
if migrate.ID == migrationID {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return ErrMigrationIDDoesNotExist
|
||||
}
|
||||
|
||||
// RollbackLast undo the last migration
|
||||
func (x *Xormigrate) RollbackLast() error {
|
||||
if len(x.migrations) == 0 {
|
||||
return ErrNoMigrationDefined
|
||||
}
|
||||
|
||||
lastRunMigration, err := x.getLastRunMigration()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return x.RollbackMigration(lastRunMigration) // return error or nil
|
||||
}
|
||||
|
||||
// RollbackTo undoes migrations up to the given migration that matches the `migrationID`.
|
||||
// Migration with the matching `migrationID` is not rolled back.
|
||||
func (x *Xormigrate) RollbackTo(migrationID string) error {
|
||||
if len(x.migrations) == 0 {
|
||||
return ErrNoMigrationDefined
|
||||
}
|
||||
|
||||
if err := x.checkIDExist(migrationID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := len(x.migrations) - 1; i >= 0; i-- {
|
||||
migration := x.migrations[i]
|
||||
if migration.ID == migrationID {
|
||||
break
|
||||
}
|
||||
if x.migrationDidRun(migration) {
|
||||
if err := x.rollbackMigration(migration); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Xormigrate) getLastRunMigration() (*Migration, error) {
|
||||
for i := len(x.migrations) - 1; i >= 0; i-- {
|
||||
migration := x.migrations[i]
|
||||
if x.migrationDidRun(migration) {
|
||||
return migration, nil
|
||||
}
|
||||
}
|
||||
return nil, ErrNoRunMigration
|
||||
}
|
||||
|
||||
// RollbackMigration undo a migration.
|
||||
func (x *Xormigrate) RollbackMigration(m *Migration) error {
|
||||
return x.rollbackMigration(m) // return error or nil
|
||||
}
|
||||
|
||||
func (x *Xormigrate) rollbackMigration(m *Migration) error {
|
||||
if m.Rollback == nil {
|
||||
return ErrRollbackImpossible
|
||||
}
|
||||
if len(m.Description) > 0 {
|
||||
logger.Errorf("Rolling back migration: %s", m.Description)
|
||||
}
|
||||
if err := m.Rollback(x.db); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := x.db.In("id", m.ID).Delete(&Migration{}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Xormigrate) runInitSchema() error {
|
||||
logger.Info("Initializing Schema")
|
||||
if err := x.initSchema(x.db); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := x.insertMigration(initSchemaMigrationId); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, migration := range x.migrations {
|
||||
if err := x.insertMigration(migration.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Xormigrate) runMigration(migration *Migration) error {
|
||||
if len(migration.ID) == 0 {
|
||||
return ErrMissingID
|
||||
}
|
||||
|
||||
if !x.migrationDidRun(migration) {
|
||||
if len(migration.Description) > 0 {
|
||||
logger.Info(migration.Description)
|
||||
}
|
||||
if err := migration.Migrate(x.db); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := x.insertMigration(migration.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Xormigrate) createMigrationTableIfNotExists() error {
|
||||
err := x.db.Sync2(new(Migration))
|
||||
return err
|
||||
}
|
||||
|
||||
func (x *Xormigrate) migrationDidRun(m *Migration) bool {
|
||||
count, err := x.db.
|
||||
In("id", m.ID).
|
||||
Count(&Migration{})
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return count > 0
|
||||
}
|
||||
|
||||
// The schema can be initialised only if it hasn't been initialised yet
|
||||
// and no other migration has been applied already.
|
||||
func (x *Xormigrate) canInitializeSchema() bool {
|
||||
if x.migrationDidRun(&Migration{ID: initSchemaMigrationId}) {
|
||||
return false
|
||||
}
|
||||
|
||||
// If the ID doesn't exist, we also want the list of migrations to be empty
|
||||
count, err := x.db.
|
||||
Count(&Migration{})
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return count == 0
|
||||
}
|
||||
|
||||
func (x *Xormigrate) insertMigration(id string) error {
|
||||
_, err := x.db.Insert(&Migration{ID: id})
|
||||
return err
|
||||
}
|
Reference in New Issue
Block a user