Fix label count (#8267)
* fix label count * fix vendor * fix import order * update xorm to fix bug * fix tests * fix mssql bugrelease/v1.15
parent
7cccada51e
commit
29dda47cbb
4
go.mod
4
go.mod
|
@ -48,7 +48,7 @@ require (
|
||||||
github.com/go-redis/redis v6.15.2+incompatible
|
github.com/go-redis/redis v6.15.2+incompatible
|
||||||
github.com/go-sql-driver/mysql v1.4.1
|
github.com/go-sql-driver/mysql v1.4.1
|
||||||
github.com/go-swagger/go-swagger v0.20.1
|
github.com/go-swagger/go-swagger v0.20.1
|
||||||
github.com/go-xorm/xorm v0.7.7-0.20190822154023-17592d96b35b
|
github.com/go-xorm/xorm v0.7.8-0.20190924080535-59ed80ce1a67
|
||||||
github.com/gobwas/glob v0.2.3
|
github.com/gobwas/glob v0.2.3
|
||||||
github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561
|
github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561
|
||||||
github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14
|
github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14
|
||||||
|
@ -124,6 +124,6 @@ require (
|
||||||
gopkg.in/testfixtures.v2 v2.5.0
|
gopkg.in/testfixtures.v2 v2.5.0
|
||||||
mvdan.cc/xurls/v2 v2.0.0
|
mvdan.cc/xurls/v2 v2.0.0
|
||||||
strk.kbt.io/projects/go/libravatar v0.0.0-20160628055650-5eed7bff870a
|
strk.kbt.io/projects/go/libravatar v0.0.0-20160628055650-5eed7bff870a
|
||||||
xorm.io/builder v0.3.5
|
xorm.io/builder v0.3.6
|
||||||
xorm.io/core v0.7.0
|
xorm.io/core v0.7.0
|
||||||
)
|
)
|
||||||
|
|
8
go.sum
8
go.sum
|
@ -250,10 +250,11 @@ github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013/go.m
|
||||||
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y=
|
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/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM=
|
||||||
github.com/go-xorm/xorm v0.7.6/go.mod h1:nqz2TAsuOHWH2yk4FYWtacCGgdbrcdZ5mF1XadqEHls=
|
github.com/go-xorm/xorm v0.7.6/go.mod h1:nqz2TAsuOHWH2yk4FYWtacCGgdbrcdZ5mF1XadqEHls=
|
||||||
github.com/go-xorm/xorm v0.7.7-0.20190822154023-17592d96b35b h1:Y0hWUheXDHpIs7BWtJcykO4d1VOsVDKg1PsP5YJwxxM=
|
github.com/go-xorm/xorm v0.7.8-0.20190924080535-59ed80ce1a67 h1:mB5RWONyATkQ48+iQZ1lCZNPG3tABilyaEOxDm1QWyU=
|
||||||
github.com/go-xorm/xorm v0.7.7-0.20190822154023-17592d96b35b/go.mod h1:nqz2TAsuOHWH2yk4FYWtacCGgdbrcdZ5mF1XadqEHls=
|
github.com/go-xorm/xorm v0.7.8-0.20190924080535-59ed80ce1a67/go.mod h1:RSsmsVARCy4sayuKWFPaVNQMPYGLNRIK71YIVvgImL0=
|
||||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||||
|
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||||
github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561 h1:deE7ritpK04PgtpyVOS2TYcQEld9qLCD5b5EbVNOuLA=
|
github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561 h1:deE7ritpK04PgtpyVOS2TYcQEld9qLCD5b5EbVNOuLA=
|
||||||
github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561/go.mod h1:YgYOrVn3Nj9Tq0EvjmFbphRytDj7JNRoWSStJZWDJTQ=
|
github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561/go.mod h1:YgYOrVn3Nj9Tq0EvjmFbphRytDj7JNRoWSStJZWDJTQ=
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
|
@ -340,6 +341,7 @@ github.com/jackc/pgx v3.3.0+incompatible h1:Wa90/+qsITBAPkAZjiByeIGHFcj3Ztu+Vzrr
|
||||||
github.com/jackc/pgx v3.3.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
|
github.com/jackc/pgx v3.3.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
|
||||||
github.com/jackc/pgx v3.5.0+incompatible h1:BRJ4G3UPtvml5R1ey0biqqGuYUGayMYekm3woO75orY=
|
github.com/jackc/pgx v3.5.0+incompatible h1:BRJ4G3UPtvml5R1ey0biqqGuYUGayMYekm3woO75orY=
|
||||||
github.com/jackc/pgx v3.5.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
|
github.com/jackc/pgx v3.5.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
|
||||||
|
github.com/jackc/pgx v3.6.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
|
||||||
github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da/go.mod h1:ks+b9deReOc7jgqp+e7LuFiCBH6Rm5hL32cLcEAArb4=
|
github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da/go.mod h1:ks+b9deReOc7jgqp+e7LuFiCBH6Rm5hL32cLcEAArb4=
|
||||||
github.com/jaytaylor/html2text v0.0.0-20160923191438-8fb95d837f7d h1:ig/iUfDDg06RVW8OMby+GrmW6K2nPO3AFHlEIdvJSd4=
|
github.com/jaytaylor/html2text v0.0.0-20160923191438-8fb95d837f7d h1:ig/iUfDDg06RVW8OMby+GrmW6K2nPO3AFHlEIdvJSd4=
|
||||||
github.com/jaytaylor/html2text v0.0.0-20160923191438-8fb95d837f7d/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk=
|
github.com/jaytaylor/html2text v0.0.0-20160923191438-8fb95d837f7d/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk=
|
||||||
|
@ -818,5 +820,7 @@ strk.kbt.io/projects/go/libravatar v0.0.0-20160628055650-5eed7bff870a h1:8q33Shx
|
||||||
strk.kbt.io/projects/go/libravatar v0.0.0-20160628055650-5eed7bff870a/go.mod h1:FJGmPh3vz9jSos1L/F91iAgnC/aejc0wIIrF2ZwJxdY=
|
strk.kbt.io/projects/go/libravatar v0.0.0-20160628055650-5eed7bff870a/go.mod h1:FJGmPh3vz9jSos1L/F91iAgnC/aejc0wIIrF2ZwJxdY=
|
||||||
xorm.io/builder v0.3.5 h1:EilU39fvWDxjb1cDaELpYhsF+zziRBhew8xk4pngO+A=
|
xorm.io/builder v0.3.5 h1:EilU39fvWDxjb1cDaELpYhsF+zziRBhew8xk4pngO+A=
|
||||||
xorm.io/builder v0.3.5/go.mod h1:ZFbByS/KxZI1FKRjL05PyJ4YrK2bcxlUaAxdum5aTR8=
|
xorm.io/builder v0.3.5/go.mod h1:ZFbByS/KxZI1FKRjL05PyJ4YrK2bcxlUaAxdum5aTR8=
|
||||||
|
xorm.io/builder v0.3.6 h1:ha28mQ2M+TFx96Hxo+iq6tQgnkC9IZkM6D8w9sKHHF8=
|
||||||
|
xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU=
|
||||||
xorm.io/core v0.7.0 h1:hKxuOKWZNeiFQsSuGet/KV8HZ788hclvAl+7azx3tkM=
|
xorm.io/core v0.7.0 h1:hKxuOKWZNeiFQsSuGet/KV8HZ788hclvAl+7azx3tkM=
|
||||||
xorm.io/core v0.7.0/go.mod h1:TuOJjIVa7e3w/rN8tDcAvuLBMtwzdHPbyOzE6Gk1EUI=
|
xorm.io/core v0.7.0/go.mod h1:TuOJjIVa7e3w/rN8tDcAvuLBMtwzdHPbyOzE6Gk1EUI=
|
||||||
|
|
|
@ -760,11 +760,6 @@ func (issue *Issue) changeStatus(e *xorm.Session, doer *User, isClosed bool) (er
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for idx := range issue.Labels {
|
for idx := range issue.Labels {
|
||||||
if issue.IsClosed {
|
|
||||||
issue.Labels[idx].NumClosedIssues++
|
|
||||||
} else {
|
|
||||||
issue.Labels[idx].NumClosedIssues--
|
|
||||||
}
|
|
||||||
if err = updateLabel(e, issue.Labels[idx]); err != nil {
|
if err = updateLabel(e, issue.Labels[idx]); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
|
|
||||||
"github.com/go-xorm/xorm"
|
"github.com/go-xorm/xorm"
|
||||||
|
"xorm.io/builder"
|
||||||
)
|
)
|
||||||
|
|
||||||
var labelColorPattern = regexp.MustCompile("#([a-fA-F0-9]{6})")
|
var labelColorPattern = regexp.MustCompile("#([a-fA-F0-9]{6})")
|
||||||
|
@ -294,7 +295,20 @@ func GetLabelsByIssueID(issueID int64) ([]*Label, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateLabel(e Engine, l *Label) error {
|
func updateLabel(e Engine, l *Label) error {
|
||||||
_, err := e.ID(l.ID).AllCols().Update(l)
|
_, err := e.ID(l.ID).
|
||||||
|
SetExpr("num_issues",
|
||||||
|
builder.Select("count(*)").From("issue_label").
|
||||||
|
Where(builder.Eq{"label_id": l.ID}),
|
||||||
|
).
|
||||||
|
SetExpr("num_closed_issues",
|
||||||
|
builder.Select("count(*)").From("issue_label").
|
||||||
|
InnerJoin("issue", "issue_label.issue_id = issue.id").
|
||||||
|
Where(builder.Eq{
|
||||||
|
"issue_label.label_id": l.ID,
|
||||||
|
"issue.is_closed": true,
|
||||||
|
}),
|
||||||
|
).
|
||||||
|
AllCols().Update(l)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -375,10 +389,6 @@ func newIssueLabel(e *xorm.Session, issue *Issue, label *Label, doer *User) (err
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
label.NumIssues++
|
|
||||||
if issue.IsClosed {
|
|
||||||
label.NumClosedIssues++
|
|
||||||
}
|
|
||||||
return updateLabel(e, label)
|
return updateLabel(e, label)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -448,10 +458,6 @@ func deleteIssueLabel(e *xorm.Session, issue *Issue, label *Label, doer *User) (
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
label.NumIssues--
|
|
||||||
if issue.IsClosed {
|
|
||||||
label.NumClosedIssues--
|
|
||||||
}
|
|
||||||
return updateLabel(e, label)
|
return updateLabel(e, label)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -205,6 +205,7 @@ func TestNewIssueLabel(t *testing.T) {
|
||||||
LabelID: label.ID,
|
LabelID: label.ID,
|
||||||
Content: "1",
|
Content: "1",
|
||||||
})
|
})
|
||||||
|
label = AssertExistsAndLoadBean(t, &Label{ID: 2}).(*Label)
|
||||||
assert.EqualValues(t, prevNumIssues+1, label.NumIssues)
|
assert.EqualValues(t, prevNumIssues+1, label.NumIssues)
|
||||||
|
|
||||||
// re-add existing IssueLabel
|
// re-add existing IssueLabel
|
||||||
|
|
|
@ -103,7 +103,18 @@ steps:
|
||||||
commands:
|
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 -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"
|
- "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
|
||||||
|
|
||||||
|
- name: test-mssql
|
||||||
|
pull: default
|
||||||
|
image: golang:1.10
|
||||||
|
commands:
|
||||||
|
- "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -coverprofile=coverage6-1.txt -covermode=atomic"
|
||||||
|
- "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -cache=true -coverprofile=coverage6-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 coverage6-1.txt coverage6-2.txt > coverage.txt
|
||||||
when:
|
when:
|
||||||
event:
|
event:
|
||||||
- push
|
- push
|
||||||
|
@ -134,6 +145,19 @@ services:
|
||||||
- tag
|
- tag
|
||||||
- pull_request
|
- pull_request
|
||||||
|
|
||||||
|
- name: mssql
|
||||||
|
pull: default
|
||||||
|
image: microsoft/mssql-server-linux:latest
|
||||||
|
environment:
|
||||||
|
ACCEPT_EULA: Y
|
||||||
|
SA_PASSWORD: yourStrong(!)Password
|
||||||
|
MSSQL_PID: Developer
|
||||||
|
when:
|
||||||
|
event:
|
||||||
|
- push
|
||||||
|
- tag
|
||||||
|
- pull_request
|
||||||
|
|
||||||
---
|
---
|
||||||
kind: pipeline
|
kind: pipeline
|
||||||
name: matrix-2
|
name: matrix-2
|
||||||
|
@ -167,11 +191,13 @@ steps:
|
||||||
- name: build
|
- name: build
|
||||||
pull: default
|
pull: default
|
||||||
image: golang:1.11
|
image: golang:1.11
|
||||||
|
environment:
|
||||||
|
GO111MODULE: "off"
|
||||||
commands:
|
commands:
|
||||||
- go get -t -d -v ./...
|
- go get -t -d -v ./...
|
||||||
- go get -u xorm.io/core
|
- go get -u xorm.io/core
|
||||||
- go get -u xorm.io/builder
|
- go get -u xorm.io/builder
|
||||||
- GO111MODULE=off go build -v
|
- go build -v
|
||||||
when:
|
when:
|
||||||
event:
|
event:
|
||||||
- push
|
- push
|
||||||
|
@ -181,9 +207,10 @@ steps:
|
||||||
pull: default
|
pull: default
|
||||||
image: golang:1.11
|
image: golang:1.11
|
||||||
environment:
|
environment:
|
||||||
|
GO111MODULE: "on"
|
||||||
GOPROXY: "https://goproxy.cn"
|
GOPROXY: "https://goproxy.cn"
|
||||||
commands:
|
commands:
|
||||||
- GO111MODULE=on go build -v
|
- go build -v
|
||||||
when:
|
when:
|
||||||
event:
|
event:
|
||||||
- push
|
- push
|
||||||
|
@ -192,8 +219,10 @@ steps:
|
||||||
- name: test-sqlite
|
- name: test-sqlite
|
||||||
pull: default
|
pull: default
|
||||||
image: golang:1.11
|
image: golang:1.11
|
||||||
|
environment:
|
||||||
|
GO111MODULE: "on"
|
||||||
|
GOPROXY: "https://goproxy.cn"
|
||||||
commands:
|
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\" -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=\"sqlite3\" -conn_str=\"./test.db\" -cache=true -coverprofile=coverage1-2.txt -covermode=atomic"
|
||||||
when:
|
when:
|
||||||
|
@ -204,6 +233,9 @@ steps:
|
||||||
- name: test-mysql
|
- name: test-mysql
|
||||||
pull: default
|
pull: default
|
||||||
image: golang:1.11
|
image: golang:1.11
|
||||||
|
environment:
|
||||||
|
GO111MODULE: "on"
|
||||||
|
GOPROXY: "https://goproxy.cn"
|
||||||
commands:
|
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\" -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"
|
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test\" -cache=true -coverprofile=coverage2-2.txt -covermode=atomic"
|
||||||
|
@ -215,6 +247,9 @@ steps:
|
||||||
- name: test-mysql-utf8mb4
|
- name: test-mysql-utf8mb4
|
||||||
pull: default
|
pull: default
|
||||||
image: golang:1.11
|
image: golang:1.11
|
||||||
|
environment:
|
||||||
|
GO111MODULE: "on"
|
||||||
|
GOPROXY: "https://goproxy.cn"
|
||||||
commands:
|
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\" -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"
|
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test?charset=utf8mb4\" -cache=true -coverprofile=coverage2.1-2.txt -covermode=atomic"
|
||||||
|
@ -226,6 +261,9 @@ steps:
|
||||||
- name: test-mymysql
|
- name: test-mymysql
|
||||||
pull: default
|
pull: default
|
||||||
image: golang:1.11
|
image: golang:1.11
|
||||||
|
environment:
|
||||||
|
GO111MODULE: "on"
|
||||||
|
GOPROXY: "https://goproxy.cn"
|
||||||
commands:
|
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/\" -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"
|
- "go test -v -race -db=\"mymysql\" -conn_str=\"tcp:mysql:3306*xorm_test/root/\" -cache=true -coverprofile=coverage3-2.txt -covermode=atomic"
|
||||||
|
@ -237,6 +275,9 @@ steps:
|
||||||
- name: test-postgres
|
- name: test-postgres
|
||||||
pull: default
|
pull: default
|
||||||
image: golang:1.11
|
image: golang:1.11
|
||||||
|
environment:
|
||||||
|
GO111MODULE: "on"
|
||||||
|
GOPROXY: "https://goproxy.cn"
|
||||||
commands:
|
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\" -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"
|
- "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -cache=true -coverprofile=coverage4-2.txt -covermode=atomic"
|
||||||
|
@ -248,10 +289,28 @@ steps:
|
||||||
- name: test-postgres-schema
|
- name: test-postgres-schema
|
||||||
pull: default
|
pull: default
|
||||||
image: golang:1.11
|
image: golang:1.11
|
||||||
|
environment:
|
||||||
|
GO111MODULE: "on"
|
||||||
|
GOPROXY: "https://goproxy.cn"
|
||||||
commands:
|
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 -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"
|
- "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
|
||||||
|
|
||||||
|
- name: test-mssql
|
||||||
|
pull: default
|
||||||
|
image: golang:1.11
|
||||||
|
environment:
|
||||||
|
GO111MODULE: "on"
|
||||||
|
GOPROXY: "https://goproxy.cn"
|
||||||
|
commands:
|
||||||
|
- "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -coverprofile=coverage6-1.txt -covermode=atomic"
|
||||||
|
- "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -cache=true -coverprofile=coverage6-2.txt -covermode=atomic"
|
||||||
|
- go get github.com/wadey/gocovmerge
|
||||||
|
- 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 coverage6-1.txt coverage6-2.txt > coverage.txt
|
||||||
when:
|
when:
|
||||||
event:
|
event:
|
||||||
- push
|
- push
|
||||||
|
@ -282,6 +341,19 @@ services:
|
||||||
- tag
|
- tag
|
||||||
- pull_request
|
- pull_request
|
||||||
|
|
||||||
|
- name: mssql
|
||||||
|
pull: default
|
||||||
|
image: microsoft/mssql-server-linux:latest
|
||||||
|
environment:
|
||||||
|
ACCEPT_EULA: Y
|
||||||
|
SA_PASSWORD: yourStrong(!)Password
|
||||||
|
MSSQL_PID: Developer
|
||||||
|
when:
|
||||||
|
event:
|
||||||
|
- push
|
||||||
|
- tag
|
||||||
|
- pull_request
|
||||||
|
|
||||||
---
|
---
|
||||||
kind: pipeline
|
kind: pipeline
|
||||||
name: matrix-3
|
name: matrix-3
|
||||||
|
@ -315,11 +387,13 @@ steps:
|
||||||
- name: build
|
- name: build
|
||||||
pull: default
|
pull: default
|
||||||
image: golang:1.12
|
image: golang:1.12
|
||||||
|
environment:
|
||||||
|
GO111MODULE: "off"
|
||||||
commands:
|
commands:
|
||||||
- go get -t -d -v ./...
|
- go get -t -d -v ./...
|
||||||
- go get -u xorm.io/core
|
- go get -u xorm.io/core
|
||||||
- go get -u xorm.io/builder
|
- go get -u xorm.io/builder
|
||||||
- GO111MODULE=off go build -v
|
- go build -v
|
||||||
when:
|
when:
|
||||||
event:
|
event:
|
||||||
- push
|
- push
|
||||||
|
@ -329,9 +403,10 @@ steps:
|
||||||
pull: default
|
pull: default
|
||||||
image: golang:1.12
|
image: golang:1.12
|
||||||
environment:
|
environment:
|
||||||
GOPROXY: "https://goproxy.cn"
|
GO111MODULE: "on"
|
||||||
|
GOPROXY: "https://goproxy.cn"
|
||||||
commands:
|
commands:
|
||||||
- GO111MODULE=on go build -v
|
- go build -v
|
||||||
when:
|
when:
|
||||||
event:
|
event:
|
||||||
- push
|
- push
|
||||||
|
@ -340,8 +415,10 @@ steps:
|
||||||
- name: test-sqlite
|
- name: test-sqlite
|
||||||
pull: default
|
pull: default
|
||||||
image: golang:1.12
|
image: golang:1.12
|
||||||
|
environment:
|
||||||
|
GO111MODULE: "on"
|
||||||
|
GOPROXY: "https://goproxy.cn"
|
||||||
commands:
|
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\" -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=\"sqlite3\" -conn_str=\"./test.db\" -cache=true -coverprofile=coverage1-2.txt -covermode=atomic"
|
||||||
when:
|
when:
|
||||||
|
@ -352,6 +429,9 @@ steps:
|
||||||
- name: test-mysql
|
- name: test-mysql
|
||||||
pull: default
|
pull: default
|
||||||
image: golang:1.12
|
image: golang:1.12
|
||||||
|
environment:
|
||||||
|
GO111MODULE: "on"
|
||||||
|
GOPROXY: "https://goproxy.cn"
|
||||||
commands:
|
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\" -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"
|
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test\" -cache=true -coverprofile=coverage2-2.txt -covermode=atomic"
|
||||||
|
@ -363,6 +443,9 @@ steps:
|
||||||
- name: test-mysql-utf8mb4
|
- name: test-mysql-utf8mb4
|
||||||
pull: default
|
pull: default
|
||||||
image: golang:1.12
|
image: golang:1.12
|
||||||
|
environment:
|
||||||
|
GO111MODULE: "on"
|
||||||
|
GOPROXY: "https://goproxy.cn"
|
||||||
commands:
|
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\" -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"
|
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test?charset=utf8mb4\" -cache=true -coverprofile=coverage2.1-2.txt -covermode=atomic"
|
||||||
|
@ -374,6 +457,9 @@ steps:
|
||||||
- name: test-mymysql
|
- name: test-mymysql
|
||||||
pull: default
|
pull: default
|
||||||
image: golang:1.12
|
image: golang:1.12
|
||||||
|
environment:
|
||||||
|
GO111MODULE: "on"
|
||||||
|
GOPROXY: "https://goproxy.cn"
|
||||||
commands:
|
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/\" -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"
|
- "go test -v -race -db=\"mymysql\" -conn_str=\"tcp:mysql:3306*xorm_test/root/\" -cache=true -coverprofile=coverage3-2.txt -covermode=atomic"
|
||||||
|
@ -385,6 +471,9 @@ steps:
|
||||||
- name: test-postgres
|
- name: test-postgres
|
||||||
pull: default
|
pull: default
|
||||||
image: golang:1.12
|
image: golang:1.12
|
||||||
|
environment:
|
||||||
|
GO111MODULE: "on"
|
||||||
|
GOPROXY: "https://goproxy.cn"
|
||||||
commands:
|
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\" -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"
|
- "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -cache=true -coverprofile=coverage4-2.txt -covermode=atomic"
|
||||||
|
@ -396,10 +485,28 @@ steps:
|
||||||
- name: test-postgres-schema
|
- name: test-postgres-schema
|
||||||
pull: default
|
pull: default
|
||||||
image: golang:1.12
|
image: golang:1.12
|
||||||
|
environment:
|
||||||
|
GO111MODULE: "on"
|
||||||
|
GOPROXY: "https://goproxy.cn"
|
||||||
commands:
|
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 -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"
|
- "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
|
||||||
|
|
||||||
|
- name: test-mssql
|
||||||
|
pull: default
|
||||||
|
image: golang:1.12
|
||||||
|
environment:
|
||||||
|
GO111MODULE: "on"
|
||||||
|
GOPROXY: "https://goproxy.cn"
|
||||||
|
commands:
|
||||||
|
- "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -coverprofile=coverage6-1.txt -covermode=atomic"
|
||||||
|
- "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -cache=true -coverprofile=coverage6-2.txt -covermode=atomic"
|
||||||
|
- go get -u github.com/wadey/gocovmerge
|
||||||
|
- 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 coverage6-1.txt coverage6-2.txt > coverage.txt
|
||||||
when:
|
when:
|
||||||
event:
|
event:
|
||||||
- push
|
- push
|
||||||
|
@ -424,6 +531,19 @@ services:
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_DB: xorm_test
|
POSTGRES_DB: xorm_test
|
||||||
POSTGRES_USER: postgres
|
POSTGRES_USER: postgres
|
||||||
|
when:
|
||||||
|
event:
|
||||||
|
- push
|
||||||
|
- tag
|
||||||
|
- pull_request
|
||||||
|
|
||||||
|
- name: mssql
|
||||||
|
pull: default
|
||||||
|
image: microsoft/mssql-server-linux:latest
|
||||||
|
environment:
|
||||||
|
ACCEPT_EULA: Y
|
||||||
|
SA_PASSWORD: yourStrong(!)Password
|
||||||
|
MSSQL_PID: Developer
|
||||||
when:
|
when:
|
||||||
event:
|
event:
|
||||||
- push
|
- push
|
||||||
|
|
|
@ -952,7 +952,7 @@ func (db *postgres) IsColumnExist(tableName, colName string) (bool, error) {
|
||||||
|
|
||||||
func (db *postgres) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
|
func (db *postgres) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
|
||||||
args := []interface{}{tableName}
|
args := []interface{}{tableName}
|
||||||
s := `SELECT column_name, column_default, is_nullable, data_type, character_maximum_length, numeric_precision, numeric_precision_radix ,
|
s := `SELECT column_name, column_default, is_nullable, data_type, character_maximum_length,
|
||||||
CASE WHEN p.contype = 'p' THEN true ELSE false END AS primarykey,
|
CASE WHEN p.contype = 'p' THEN true ELSE false END AS primarykey,
|
||||||
CASE WHEN p.contype = 'u' THEN true ELSE false END AS uniquekey
|
CASE WHEN p.contype = 'u' THEN true ELSE false END AS uniquekey
|
||||||
FROM pg_attribute f
|
FROM pg_attribute f
|
||||||
|
@ -987,14 +987,14 @@ WHERE c.relkind = 'r'::char AND c.relname = $1%s AND f.attnum > 0 ORDER BY f.att
|
||||||
col.Indexes = make(map[string]int)
|
col.Indexes = make(map[string]int)
|
||||||
|
|
||||||
var colName, isNullable, dataType string
|
var colName, isNullable, dataType string
|
||||||
var maxLenStr, colDefault, numPrecision, numRadix *string
|
var maxLenStr, colDefault *string
|
||||||
var isPK, isUnique bool
|
var isPK, isUnique bool
|
||||||
err = rows.Scan(&colName, &colDefault, &isNullable, &dataType, &maxLenStr, &numPrecision, &numRadix, &isPK, &isUnique)
|
err = rows.Scan(&colName, &colDefault, &isNullable, &dataType, &maxLenStr, &isPK, &isUnique)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// fmt.Println(args, colName, isNullable, dataType, maxLenStr, colDefault, numPrecision, numRadix, isPK, isUnique)
|
// fmt.Println(args, colName, isNullable, dataType, maxLenStr, colDefault, isPK, isUnique)
|
||||||
var maxLen int
|
var maxLen int
|
||||||
if maxLenStr != nil {
|
if maxLenStr != nil {
|
||||||
maxLen, err = strconv.Atoi(*maxLenStr)
|
maxLen, err = strconv.Atoi(*maxLenStr)
|
||||||
|
|
|
@ -190,14 +190,14 @@ func (engine *Engine) Quote(value string) string {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := builder.StringBuilder{}
|
buf := strings.Builder{}
|
||||||
engine.QuoteTo(&buf, value)
|
engine.QuoteTo(&buf, value)
|
||||||
|
|
||||||
return buf.String()
|
return buf.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// QuoteTo quotes string and writes into the buffer
|
// QuoteTo quotes string and writes into the buffer
|
||||||
func (engine *Engine) QuoteTo(buf *builder.StringBuilder, value string) {
|
func (engine *Engine) QuoteTo(buf *strings.Builder, value string) {
|
||||||
if buf == nil {
|
if buf == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -729,7 +729,7 @@ func (engine *Engine) Decr(column string, arg ...interface{}) *Session {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetExpr provides a update string like "column = {expression}"
|
// SetExpr provides a update string like "column = {expression}"
|
||||||
func (engine *Engine) SetExpr(column string, expression string) *Session {
|
func (engine *Engine) SetExpr(column string, expression interface{}) *Session {
|
||||||
session := engine.NewSession()
|
session := engine.NewSession()
|
||||||
session.isAutoClose = true
|
session.isAutoClose = true
|
||||||
return session.SetExpr(column, expression)
|
return session.SetExpr(column, expression)
|
||||||
|
|
|
@ -1,19 +1,20 @@
|
||||||
module github.com/go-xorm/xorm
|
module github.com/go-xorm/xorm
|
||||||
|
|
||||||
|
go 1.11
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/cockroachdb/apd v1.1.0 // indirect
|
github.com/cockroachdb/apd v1.1.0 // indirect
|
||||||
github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4
|
github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4
|
||||||
github.com/go-sql-driver/mysql v1.4.1
|
github.com/go-sql-driver/mysql v1.4.1
|
||||||
|
github.com/gofrs/uuid v3.2.0+incompatible // indirect
|
||||||
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 // indirect
|
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 // indirect
|
||||||
github.com/jackc/pgx v3.3.0+incompatible
|
github.com/jackc/pgx v3.6.0+incompatible
|
||||||
github.com/kr/pretty v0.1.0 // indirect
|
|
||||||
github.com/lib/pq v1.0.0
|
github.com/lib/pq v1.0.0
|
||||||
github.com/mattn/go-sqlite3 v1.10.0
|
github.com/mattn/go-sqlite3 v1.10.0
|
||||||
github.com/pkg/errors v0.8.1 // indirect
|
github.com/pkg/errors v0.8.1 // indirect
|
||||||
github.com/satori/go.uuid v1.2.0 // indirect
|
|
||||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 // indirect
|
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 // indirect
|
||||||
github.com/stretchr/testify v1.3.0
|
github.com/stretchr/testify v1.3.0
|
||||||
github.com/ziutek/mymysql v1.5.4
|
github.com/ziutek/mymysql v1.5.4
|
||||||
xorm.io/builder v0.3.5
|
xorm.io/builder v0.3.6
|
||||||
xorm.io/core v0.7.0
|
xorm.io/core v0.7.0
|
||||||
)
|
)
|
||||||
|
|
|
@ -28,6 +28,8 @@ github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y=
|
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/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM=
|
||||||
|
github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE=
|
||||||
|
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
|
@ -48,18 +50,13 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc=
|
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/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ=
|
||||||
github.com/jackc/pgx v3.3.0+incompatible h1:Wa90/+qsITBAPkAZjiByeIGHFcj3Ztu+VzrrIpHjL90=
|
github.com/jackc/pgx v3.6.0+incompatible h1:bJeo4JdVbDAW8KB2m8XkFeo8CPipREoG37BwEoKGz+Q=
|
||||||
github.com/jackc/pgx v3.3.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
|
github.com/jackc/pgx v3.6.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
|
||||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
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 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
|
||||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o=
|
github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o=
|
||||||
|
@ -84,8 +81,6 @@ github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8
|
||||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||||
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 h1:pntxY8Ary0t43dCZ5dqY4YTJCObLY1kIXl0uzMv+7DE=
|
||||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
|
@ -133,6 +128,7 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||||
golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
@ -162,7 +158,7 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
xorm.io/builder v0.3.5 h1:EilU39fvWDxjb1cDaELpYhsF+zziRBhew8xk4pngO+A=
|
xorm.io/builder v0.3.6 h1:ha28mQ2M+TFx96Hxo+iq6tQgnkC9IZkM6D8w9sKHHF8=
|
||||||
xorm.io/builder v0.3.5/go.mod h1:ZFbByS/KxZI1FKRjL05PyJ4YrK2bcxlUaAxdum5aTR8=
|
xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU=
|
||||||
xorm.io/core v0.7.0 h1:hKxuOKWZNeiFQsSuGet/KV8HZ788hclvAl+7azx3tkM=
|
xorm.io/core v0.7.0 h1:hKxuOKWZNeiFQsSuGet/KV8HZ788hclvAl+7azx3tkM=
|
||||||
xorm.io/core v0.7.0/go.mod h1:TuOJjIVa7e3w/rN8tDcAvuLBMtwzdHPbyOzE6Gk1EUI=
|
xorm.io/core v0.7.0/go.mod h1:TuOJjIVa7e3w/rN8tDcAvuLBMtwzdHPbyOzE6Gk1EUI=
|
||||||
|
|
|
@ -54,7 +54,7 @@ type Interface interface {
|
||||||
QueryInterface(sqlOrArgs ...interface{}) ([]map[string]interface{}, error)
|
QueryInterface(sqlOrArgs ...interface{}) ([]map[string]interface{}, error)
|
||||||
QueryString(sqlOrArgs ...interface{}) ([]map[string]string, error)
|
QueryString(sqlOrArgs ...interface{}) ([]map[string]string, error)
|
||||||
Rows(bean interface{}) (*Rows, error)
|
Rows(bean interface{}) (*Rows, error)
|
||||||
SetExpr(string, string) *Session
|
SetExpr(string, interface{}) *Session
|
||||||
SQL(interface{}, ...interface{}) *Session
|
SQL(interface{}, ...interface{}) *Session
|
||||||
Sum(bean interface{}, colName string) (float64, error)
|
Sum(bean interface{}, colName string) (float64, error)
|
||||||
SumInt(bean interface{}, colName string) (int64, error)
|
SumInt(bean interface{}, colName string) (int64, error)
|
||||||
|
|
|
@ -12,49 +12,6 @@ import (
|
||||||
"xorm.io/core"
|
"xorm.io/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) {
|
func setColumnInt(bean interface{}, col *core.Column, t int64) {
|
||||||
v, err := col.ValueOf(bean)
|
v, err := col.ValueOf(bean)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -132,7 +89,7 @@ func (session *Session) Decr(column string, arg ...interface{}) *Session {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetExpr provides a query string like "column = {expression}"
|
// SetExpr provides a query string like "column = {expression}"
|
||||||
func (session *Session) SetExpr(column string, expression string) *Session {
|
func (session *Session) SetExpr(column string, expression interface{}) *Session {
|
||||||
session.statement.SetExpr(column, expression)
|
session.statement.SetExpr(column, expression)
|
||||||
return session
|
return session
|
||||||
}
|
}
|
||||||
|
|
|
@ -340,74 +340,96 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
// insert expr columns, override if exists
|
|
||||||
exprColumns := session.statement.getExpr()
|
|
||||||
exprColVals := make([]string, 0, len(exprColumns))
|
|
||||||
for _, v := range exprColumns {
|
|
||||||
// remove the expr columns
|
|
||||||
for i, colName := range colNames {
|
|
||||||
if colName == strings.Trim(v.colName, "`") {
|
|
||||||
colNames = append(colNames[:i], colNames[i+1:]...)
|
|
||||||
args = append(args[:i], args[i+1:]...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// append expr column to the end
|
exprs := session.statement.exprColumns
|
||||||
colNames = append(colNames, v.colName)
|
colPlaces := strings.Repeat("?, ", len(colNames))
|
||||||
exprColVals = append(exprColVals, v.expr)
|
if exprs.Len() <= 0 && len(colPlaces) > 0 {
|
||||||
|
colPlaces = colPlaces[0 : len(colPlaces)-2]
|
||||||
}
|
}
|
||||||
|
|
||||||
colPlaces := strings.Repeat("?, ", len(colNames)-len(exprColumns))
|
|
||||||
if len(exprColVals) > 0 {
|
|
||||||
colPlaces = colPlaces + strings.Join(exprColVals, ", ")
|
|
||||||
} else {
|
|
||||||
if len(colPlaces) > 0 {
|
|
||||||
colPlaces = colPlaces[0 : len(colPlaces)-2]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var sqlStr string
|
|
||||||
var tableName = session.statement.TableName()
|
var tableName = session.statement.TableName()
|
||||||
var output string
|
var output string
|
||||||
if session.engine.dialect.DBType() == core.MSSQL && len(table.AutoIncrement) > 0 {
|
if session.engine.dialect.DBType() == core.MSSQL && len(table.AutoIncrement) > 0 {
|
||||||
output = fmt.Sprintf(" OUTPUT Inserted.%s", table.AutoIncrement)
|
output = fmt.Sprintf(" OUTPUT Inserted.%s", table.AutoIncrement)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(colPlaces) > 0 {
|
var buf = builder.NewWriter()
|
||||||
|
if _, err := buf.WriteString(fmt.Sprintf("INSERT INTO %s", session.engine.Quote(tableName))); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(colPlaces) <= 0 {
|
||||||
|
if session.engine.dialect.DBType() == core.MYSQL {
|
||||||
|
if _, err := buf.WriteString(" VALUES ()"); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if _, err := buf.WriteString(fmt.Sprintf("%s DEFAULT VALUES", output)); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if _, err := buf.WriteString(" ("); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := writeStrings(buf, append(colNames, exprs.colNames...), "`", "`"); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
if session.statement.cond.IsValid() {
|
if session.statement.cond.IsValid() {
|
||||||
condSQL, condArgs, err := builder.ToSQL(session.statement.cond)
|
if _, err := buf.WriteString(fmt.Sprintf(")%s SELECT ", output)); err != nil {
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlStr = fmt.Sprintf("INSERT INTO %s (%v)%s SELECT %v FROM %v WHERE %v",
|
if err := session.statement.writeArgs(buf, args); err != nil {
|
||||||
session.engine.Quote(tableName),
|
return 0, err
|
||||||
quoteColumns(colNames, session.engine.Quote, ","),
|
}
|
||||||
output,
|
|
||||||
colPlaces,
|
if len(exprs.args) > 0 {
|
||||||
session.engine.Quote(tableName),
|
if _, err := buf.WriteString(","); err != nil {
|
||||||
condSQL,
|
return 0, err
|
||||||
)
|
}
|
||||||
args = append(args, condArgs...)
|
}
|
||||||
|
if err := exprs.writeArgs(buf); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := buf.WriteString(fmt.Sprintf(" FROM %v WHERE ", session.engine.Quote(tableName))); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := session.statement.cond.WriteTo(buf); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
sqlStr = fmt.Sprintf("INSERT INTO %s (%v)%s VALUES (%v)",
|
buf.Append(args...)
|
||||||
session.engine.Quote(tableName),
|
|
||||||
quoteColumns(colNames, session.engine.Quote, ","),
|
if _, err := buf.WriteString(fmt.Sprintf(")%s VALUES (%v",
|
||||||
output,
|
output,
|
||||||
colPlaces)
|
colPlaces)); err != nil {
|
||||||
}
|
return 0, err
|
||||||
} else {
|
}
|
||||||
if session.engine.dialect.DBType() == core.MYSQL {
|
|
||||||
sqlStr = fmt.Sprintf("INSERT INTO %s VALUES ()", session.engine.Quote(tableName))
|
if err := exprs.writeArgs(buf); err != nil {
|
||||||
} else {
|
return 0, err
|
||||||
sqlStr = fmt.Sprintf("INSERT INTO %s%s DEFAULT VALUES", session.engine.Quote(tableName), output)
|
}
|
||||||
|
|
||||||
|
if _, err := buf.WriteString(")"); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(table.AutoIncrement) > 0 && session.engine.dialect.DBType() == core.POSTGRES {
|
if len(table.AutoIncrement) > 0 && session.engine.dialect.DBType() == core.POSTGRES {
|
||||||
sqlStr = sqlStr + " RETURNING " + session.engine.Quote(table.AutoIncrement)
|
if _, err := buf.WriteString(" RETURNING " + session.engine.Quote(table.AutoIncrement)); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sqlStr := buf.String()
|
||||||
|
args = buf.Args()
|
||||||
|
|
||||||
handleAfterInsertProcessorFunc := func(bean interface{}) {
|
handleAfterInsertProcessorFunc := func(bean interface{}) {
|
||||||
if session.isAutoCommit {
|
if session.isAutoCommit {
|
||||||
for _, closure := range session.afterClosures {
|
for _, closure := range session.afterClosures {
|
||||||
|
@ -611,9 +633,11 @@ func (session *Session) genInsertColumns(bean interface{}) ([]string, []interfac
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := session.statement.incrColumns[col.Name]; ok {
|
if session.statement.incrColumns.isColExist(col.Name) {
|
||||||
continue
|
continue
|
||||||
} else if _, ok := session.statement.decrColumns[col.Name]; ok {
|
} else if session.statement.decrColumns.isColExist(col.Name) {
|
||||||
|
continue
|
||||||
|
} else if session.statement.exprColumns.isColExist(col.Name) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -688,46 +712,66 @@ func (session *Session) insertMapInterface(m map[string]interface{}) (int64, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var columns = make([]string, 0, len(m))
|
var columns = make([]string, 0, len(m))
|
||||||
|
exprs := session.statement.exprColumns
|
||||||
for k := range m {
|
for k := range m {
|
||||||
columns = append(columns, k)
|
if !exprs.isColExist(k) {
|
||||||
|
columns = append(columns, k)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
sort.Strings(columns)
|
sort.Strings(columns)
|
||||||
|
|
||||||
qm := strings.Repeat("?,", len(columns))
|
|
||||||
|
|
||||||
var args = make([]interface{}, 0, len(m))
|
var args = make([]interface{}, 0, len(m))
|
||||||
for _, colName := range columns {
|
for _, colName := range columns {
|
||||||
args = append(args, m[colName])
|
args = append(args, m[colName])
|
||||||
}
|
}
|
||||||
|
|
||||||
// insert expr columns, override if exists
|
w := builder.NewWriter()
|
||||||
exprColumns := session.statement.getExpr()
|
|
||||||
for _, col := range exprColumns {
|
|
||||||
columns = append(columns, strings.Trim(col.colName, "`"))
|
|
||||||
qm = qm + col.expr + ","
|
|
||||||
}
|
|
||||||
|
|
||||||
qm = qm[:len(qm)-1]
|
|
||||||
|
|
||||||
var sql string
|
|
||||||
|
|
||||||
if session.statement.cond.IsValid() {
|
if session.statement.cond.IsValid() {
|
||||||
condSQL, condArgs, err := builder.ToSQL(session.statement.cond)
|
if _, err := w.WriteString(fmt.Sprintf("INSERT INTO %s (", session.engine.Quote(tableName))); err != nil {
|
||||||
if err != nil {
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := writeStrings(w, append(columns, exprs.colNames...), "`", "`"); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := w.WriteString(") SELECT "); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := session.statement.writeArgs(w, args); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(exprs.args) > 0 {
|
||||||
|
if _, err := w.WriteString(","); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if err := exprs.writeArgs(w); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := w.WriteString(fmt.Sprintf(" FROM %s WHERE ", session.engine.Quote(tableName))); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := session.statement.cond.WriteTo(w); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
sql = fmt.Sprintf("INSERT INTO %s (`%s`) SELECT %s FROM %s WHERE %s",
|
|
||||||
session.engine.Quote(tableName),
|
|
||||||
strings.Join(columns, "`,`"),
|
|
||||||
qm,
|
|
||||||
session.engine.Quote(tableName),
|
|
||||||
condSQL,
|
|
||||||
)
|
|
||||||
args = append(args, condArgs...)
|
|
||||||
} else {
|
} else {
|
||||||
sql = fmt.Sprintf("INSERT INTO %s (`%s`) VALUES (%s)", session.engine.Quote(tableName), strings.Join(columns, "`,`"), qm)
|
qm := strings.Repeat("?,", len(columns))
|
||||||
|
qm = qm[:len(qm)-1]
|
||||||
|
|
||||||
|
if _, err := w.WriteString(fmt.Sprintf("INSERT INTO %s (`%s`) VALUES (%s)", session.engine.Quote(tableName), strings.Join(columns, "`,`"), qm)); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
w.Append(args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sql := w.String()
|
||||||
|
args = w.Args()
|
||||||
|
|
||||||
if err := session.cacheInsert(tableName); err != nil {
|
if err := session.cacheInsert(tableName); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
@ -754,8 +798,11 @@ func (session *Session) insertMapString(m map[string]string) (int64, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var columns = make([]string, 0, len(m))
|
var columns = make([]string, 0, len(m))
|
||||||
|
exprs := session.statement.exprColumns
|
||||||
for k := range m {
|
for k := range m {
|
||||||
columns = append(columns, k)
|
if !exprs.isColExist(k) {
|
||||||
|
columns = append(columns, k)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
sort.Strings(columns)
|
sort.Strings(columns)
|
||||||
|
|
||||||
|
@ -764,37 +811,53 @@ func (session *Session) insertMapString(m map[string]string) (int64, error) {
|
||||||
args = append(args, m[colName])
|
args = append(args, m[colName])
|
||||||
}
|
}
|
||||||
|
|
||||||
qm := strings.Repeat("?,", len(columns))
|
w := builder.NewWriter()
|
||||||
|
|
||||||
// insert expr columns, override if exists
|
|
||||||
exprColumns := session.statement.getExpr()
|
|
||||||
for _, col := range exprColumns {
|
|
||||||
columns = append(columns, strings.Trim(col.colName, "`"))
|
|
||||||
qm = qm + col.expr + ","
|
|
||||||
}
|
|
||||||
|
|
||||||
qm = qm[:len(qm)-1]
|
|
||||||
|
|
||||||
var sql string
|
|
||||||
|
|
||||||
if session.statement.cond.IsValid() {
|
if session.statement.cond.IsValid() {
|
||||||
qm = "(" + qm[:len(qm)-1] + ")"
|
if _, err := w.WriteString(fmt.Sprintf("INSERT INTO %s (", session.engine.Quote(tableName))); err != nil {
|
||||||
condSQL, condArgs, err := builder.ToSQL(session.statement.cond)
|
return 0, err
|
||||||
if err != nil {
|
}
|
||||||
|
|
||||||
|
if err := writeStrings(w, append(columns, exprs.colNames...), "`", "`"); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := w.WriteString(") SELECT "); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := session.statement.writeArgs(w, args); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(exprs.args) > 0 {
|
||||||
|
if _, err := w.WriteString(","); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if err := exprs.writeArgs(w); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := w.WriteString(fmt.Sprintf(" FROM %s WHERE ", session.engine.Quote(tableName))); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := session.statement.cond.WriteTo(w); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
sql = fmt.Sprintf("INSERT INTO %s (`%s`) SELECT %s FROM %s WHERE %s",
|
|
||||||
session.engine.Quote(tableName),
|
|
||||||
strings.Join(columns, "`,`"),
|
|
||||||
qm,
|
|
||||||
session.engine.Quote(tableName),
|
|
||||||
condSQL,
|
|
||||||
)
|
|
||||||
args = append(args, condArgs...)
|
|
||||||
} else {
|
} else {
|
||||||
sql = fmt.Sprintf("INSERT INTO %s (`%s`) VALUES (%s)", session.engine.Quote(tableName), strings.Join(columns, "`,`"), qm)
|
qm := strings.Repeat("?,", len(columns))
|
||||||
|
qm = qm[:len(qm)-1]
|
||||||
|
|
||||||
|
if _, err := w.WriteString(fmt.Sprintf("INSERT INTO %s (`%s`) VALUES (%s)", session.engine.Quote(tableName), strings.Join(columns, "`,`"), qm)); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
w.Append(args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sql := w.String()
|
||||||
|
args = w.Args()
|
||||||
|
|
||||||
if err := session.cacheInsert(tableName); err != nil {
|
if err := session.cacheInsert(tableName); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -223,21 +223,31 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
|
||||||
}
|
}
|
||||||
|
|
||||||
// for update action to like "column = column + ?"
|
// for update action to like "column = column + ?"
|
||||||
incColumns := session.statement.getInc()
|
incColumns := session.statement.incrColumns
|
||||||
for _, v := range incColumns {
|
for i, colName := range incColumns.colNames {
|
||||||
colNames = append(colNames, session.engine.Quote(v.colName)+" = "+session.engine.Quote(v.colName)+" + ?")
|
colNames = append(colNames, session.engine.Quote(colName)+" = "+session.engine.Quote(colName)+" + ?")
|
||||||
args = append(args, v.arg)
|
args = append(args, incColumns.args[i])
|
||||||
}
|
}
|
||||||
// for update action to like "column = column - ?"
|
// for update action to like "column = column - ?"
|
||||||
decColumns := session.statement.getDec()
|
decColumns := session.statement.decrColumns
|
||||||
for _, v := range decColumns {
|
for i, colName := range decColumns.colNames {
|
||||||
colNames = append(colNames, session.engine.Quote(v.colName)+" = "+session.engine.Quote(v.colName)+" - ?")
|
colNames = append(colNames, session.engine.Quote(colName)+" = "+session.engine.Quote(colName)+" - ?")
|
||||||
args = append(args, v.arg)
|
args = append(args, decColumns.args[i])
|
||||||
}
|
}
|
||||||
// for update action to like "column = expression"
|
// for update action to like "column = expression"
|
||||||
exprColumns := session.statement.getExpr()
|
exprColumns := session.statement.exprColumns
|
||||||
for _, v := range exprColumns {
|
for i, colName := range exprColumns.colNames {
|
||||||
colNames = append(colNames, session.engine.Quote(v.colName)+" = "+v.expr)
|
switch tp := exprColumns.args[i].(type) {
|
||||||
|
case string:
|
||||||
|
colNames = append(colNames, session.engine.Quote(colName)+" = "+tp)
|
||||||
|
case *builder.Builder:
|
||||||
|
subQuery, subArgs, err := builder.ToSQL(tp)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
colNames = append(colNames, session.engine.Quote(colName)+" = ("+subQuery+")")
|
||||||
|
args = append(args, subArgs...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = session.statement.processIDParam(); err != nil {
|
if err = session.statement.processIDParam(); err != nil {
|
||||||
|
@ -468,14 +478,17 @@ func (session *Session) genUpdateColumns(bean interface{}) ([]string, []interfac
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(session.statement.columnMap) > 0 {
|
// if only update specify columns
|
||||||
if !session.statement.columnMap.contain(col.Name) {
|
if len(session.statement.columnMap) > 0 && !session.statement.columnMap.contain(col.Name) {
|
||||||
continue
|
continue
|
||||||
} else if _, ok := session.statement.incrColumns[col.Name]; ok {
|
}
|
||||||
continue
|
|
||||||
} else if _, ok := session.statement.decrColumns[col.Name]; ok {
|
if session.statement.incrColumns.isColExist(col.Name) {
|
||||||
continue
|
continue
|
||||||
}
|
} else if session.statement.decrColumns.isColExist(col.Name) {
|
||||||
|
continue
|
||||||
|
} else if session.statement.exprColumns.isColExist(col.Name) {
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// !evalphobia! set fieldValue as nil when column is nullable and zero-value
|
// !evalphobia! set fieldValue as nil when column is nullable and zero-value
|
||||||
|
|
|
@ -52,9 +52,9 @@ type Statement struct {
|
||||||
omitColumnMap columnMap
|
omitColumnMap columnMap
|
||||||
mustColumnMap map[string]bool
|
mustColumnMap map[string]bool
|
||||||
nullableMap map[string]bool
|
nullableMap map[string]bool
|
||||||
incrColumns map[string]incrParam
|
incrColumns exprParams
|
||||||
decrColumns map[string]decrParam
|
decrColumns exprParams
|
||||||
exprColumns map[string]exprParam
|
exprColumns exprParams
|
||||||
cond builder.Cond
|
cond builder.Cond
|
||||||
bufferSize int
|
bufferSize int
|
||||||
context ContextCache
|
context ContextCache
|
||||||
|
@ -94,9 +94,9 @@ func (statement *Statement) Init() {
|
||||||
statement.nullableMap = make(map[string]bool)
|
statement.nullableMap = make(map[string]bool)
|
||||||
statement.checkVersion = true
|
statement.checkVersion = true
|
||||||
statement.unscoped = false
|
statement.unscoped = false
|
||||||
statement.incrColumns = make(map[string]incrParam)
|
statement.incrColumns = exprParams{}
|
||||||
statement.decrColumns = make(map[string]decrParam)
|
statement.decrColumns = exprParams{}
|
||||||
statement.exprColumns = make(map[string]exprParam)
|
statement.exprColumns = exprParams{}
|
||||||
statement.cond = builder.NewCond()
|
statement.cond = builder.NewCond()
|
||||||
statement.bufferSize = 0
|
statement.bufferSize = 0
|
||||||
statement.context = nil
|
statement.context = nil
|
||||||
|
@ -534,48 +534,30 @@ func (statement *Statement) ID(id interface{}) *Statement {
|
||||||
|
|
||||||
// Incr Generate "Update ... Set column = column + arg" statement
|
// Incr Generate "Update ... Set column = column + arg" statement
|
||||||
func (statement *Statement) Incr(column string, arg ...interface{}) *Statement {
|
func (statement *Statement) Incr(column string, arg ...interface{}) *Statement {
|
||||||
k := strings.ToLower(column)
|
|
||||||
if len(arg) > 0 {
|
if len(arg) > 0 {
|
||||||
statement.incrColumns[k] = incrParam{column, arg[0]}
|
statement.incrColumns.addParam(column, arg[0])
|
||||||
} else {
|
} else {
|
||||||
statement.incrColumns[k] = incrParam{column, 1}
|
statement.incrColumns.addParam(column, 1)
|
||||||
}
|
}
|
||||||
return statement
|
return statement
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decr Generate "Update ... Set column = column - arg" statement
|
// Decr Generate "Update ... Set column = column - arg" statement
|
||||||
func (statement *Statement) Decr(column string, arg ...interface{}) *Statement {
|
func (statement *Statement) Decr(column string, arg ...interface{}) *Statement {
|
||||||
k := strings.ToLower(column)
|
|
||||||
if len(arg) > 0 {
|
if len(arg) > 0 {
|
||||||
statement.decrColumns[k] = decrParam{column, arg[0]}
|
statement.decrColumns.addParam(column, arg[0])
|
||||||
} else {
|
} else {
|
||||||
statement.decrColumns[k] = decrParam{column, 1}
|
statement.decrColumns.addParam(column, 1)
|
||||||
}
|
}
|
||||||
return statement
|
return statement
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetExpr Generate "Update ... Set column = {expression}" statement
|
// SetExpr Generate "Update ... Set column = {expression}" statement
|
||||||
func (statement *Statement) SetExpr(column string, expression string) *Statement {
|
func (statement *Statement) SetExpr(column string, expression interface{}) *Statement {
|
||||||
k := strings.ToLower(column)
|
statement.exprColumns.addParam(column, expression)
|
||||||
statement.exprColumns[k] = exprParam{column, expression}
|
|
||||||
return statement
|
return statement
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate "Update ... Set column = column + arg" statement
|
|
||||||
func (statement *Statement) getInc() map[string]incrParam {
|
|
||||||
return statement.incrColumns
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate "Update ... Set column = column - arg" statement
|
|
||||||
func (statement *Statement) getDec() map[string]decrParam {
|
|
||||||
return statement.decrColumns
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate "Update ... Set column = {expression}" statement
|
|
||||||
func (statement *Statement) getExpr() map[string]exprParam {
|
|
||||||
return statement.exprColumns
|
|
||||||
}
|
|
||||||
|
|
||||||
func (statement *Statement) col2NewColsWithQuote(columns ...string) []string {
|
func (statement *Statement) col2NewColsWithQuote(columns ...string) []string {
|
||||||
newColumns := make([]string, 0)
|
newColumns := make([]string, 0)
|
||||||
quotes := append(strings.Split(statement.Engine.Quote(""), ""), "`")
|
quotes := append(strings.Split(statement.Engine.Quote(""), ""), "`")
|
||||||
|
@ -695,7 +677,7 @@ func (statement *Statement) OrderBy(order string) *Statement {
|
||||||
|
|
||||||
// Desc generate `ORDER BY xx DESC`
|
// Desc generate `ORDER BY xx DESC`
|
||||||
func (statement *Statement) Desc(colNames ...string) *Statement {
|
func (statement *Statement) Desc(colNames ...string) *Statement {
|
||||||
var buf builder.StringBuilder
|
var buf strings.Builder
|
||||||
if len(statement.OrderStr) > 0 {
|
if len(statement.OrderStr) > 0 {
|
||||||
fmt.Fprint(&buf, statement.OrderStr, ", ")
|
fmt.Fprint(&buf, statement.OrderStr, ", ")
|
||||||
}
|
}
|
||||||
|
@ -707,7 +689,7 @@ func (statement *Statement) Desc(colNames ...string) *Statement {
|
||||||
|
|
||||||
// Asc provide asc order by query condition, the input parameters are columns.
|
// Asc provide asc order by query condition, the input parameters are columns.
|
||||||
func (statement *Statement) Asc(colNames ...string) *Statement {
|
func (statement *Statement) Asc(colNames ...string) *Statement {
|
||||||
var buf builder.StringBuilder
|
var buf strings.Builder
|
||||||
if len(statement.OrderStr) > 0 {
|
if len(statement.OrderStr) > 0 {
|
||||||
fmt.Fprint(&buf, statement.OrderStr, ", ")
|
fmt.Fprint(&buf, statement.OrderStr, ", ")
|
||||||
}
|
}
|
||||||
|
@ -736,7 +718,7 @@ func (statement *Statement) Table(tableNameOrBean interface{}) *Statement {
|
||||||
|
|
||||||
// Join The joinOP should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN
|
// 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 {
|
func (statement *Statement) Join(joinOP string, tablename interface{}, condition string, args ...interface{}) *Statement {
|
||||||
var buf builder.StringBuilder
|
var buf strings.Builder
|
||||||
if len(statement.JoinStr) > 0 {
|
if len(statement.JoinStr) > 0 {
|
||||||
fmt.Fprintf(&buf, "%v %v JOIN ", statement.JoinStr, joinOP)
|
fmt.Fprintf(&buf, "%v %v JOIN ", statement.JoinStr, joinOP)
|
||||||
} else {
|
} else {
|
||||||
|
@ -801,7 +783,7 @@ func (statement *Statement) genColumnStr() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
var buf builder.StringBuilder
|
var buf strings.Builder
|
||||||
columns := statement.RefTable.Columns()
|
columns := statement.RefTable.Columns()
|
||||||
|
|
||||||
for _, col := range columns {
|
for _, col := range columns {
|
||||||
|
@ -1118,7 +1100,7 @@ func (statement *Statement) genSelectSQL(columnStr, condSQL string, needLimit, n
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var buf builder.StringBuilder
|
var buf strings.Builder
|
||||||
fmt.Fprintf(&buf, "SELECT %v%v%v%v%v", distinct, top, columnStr, fromStr, whereStr)
|
fmt.Fprintf(&buf, "SELECT %v%v%v%v%v", distinct, top, columnStr, fromStr, whereStr)
|
||||||
if len(mssqlCondi) > 0 {
|
if len(mssqlCondi) > 0 {
|
||||||
if len(whereStr) > 0 {
|
if len(whereStr) > 0 {
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
// Copyright 2019 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"
|
||||||
|
|
||||||
|
"xorm.io/builder"
|
||||||
|
"xorm.io/core"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (statement *Statement) writeArg(w *builder.BytesWriter, arg interface{}) error {
|
||||||
|
switch argv := arg.(type) {
|
||||||
|
case string:
|
||||||
|
if _, err := w.WriteString("'" + argv + "'"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case bool:
|
||||||
|
if statement.Engine.dialect.DBType() == core.MSSQL {
|
||||||
|
if argv {
|
||||||
|
if _, err := w.WriteString("1"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if _, err := w.WriteString("0"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if argv {
|
||||||
|
if _, err := w.WriteString("true"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if _, err := w.WriteString("false"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case *builder.Builder:
|
||||||
|
if _, err := w.WriteString("("); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := argv.WriteTo(w); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := w.WriteString(")"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if _, err := w.WriteString(fmt.Sprintf("%v", argv)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (statement *Statement) writeArgs(w *builder.BytesWriter, args []interface{}) error {
|
||||||
|
for i, arg := range args {
|
||||||
|
if err := statement.writeArg(w, arg); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if i+1 != len(args) {
|
||||||
|
if _, err := w.WriteString(","); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeStrings(w *builder.BytesWriter, cols []string, leftQuote, rightQuote string) error {
|
||||||
|
for i, colName := range cols {
|
||||||
|
if len(leftQuote) > 0 && colName[0] != '`' {
|
||||||
|
if _, err := w.WriteString(leftQuote); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if _, err := w.WriteString(colName); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(rightQuote) > 0 && colName[len(colName)-1] != '`' {
|
||||||
|
if _, err := w.WriteString(rightQuote); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if i+1 != len(cols) {
|
||||||
|
if _, err := w.WriteString(","); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
// Copyright 2019 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 "strings"
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
|
@ -0,0 +1,112 @@
|
||||||
|
// Copyright 2019 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"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"xorm.io/builder"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ErrUnsupportedExprType struct {
|
||||||
|
tp string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrUnsupportedExprType) Error() string {
|
||||||
|
return fmt.Sprintf("Unsupported expression type: %v", err.tp)
|
||||||
|
}
|
||||||
|
|
||||||
|
type exprParam struct {
|
||||||
|
colName string
|
||||||
|
arg interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type exprParams struct {
|
||||||
|
colNames []string
|
||||||
|
args []interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (exprs *exprParams) Len() int {
|
||||||
|
return len(exprs.colNames)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (exprs *exprParams) addParam(colName string, arg interface{}) {
|
||||||
|
exprs.colNames = append(exprs.colNames, colName)
|
||||||
|
exprs.args = append(exprs.args, arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (exprs *exprParams) isColExist(colName string) bool {
|
||||||
|
for _, name := range exprs.colNames {
|
||||||
|
if strings.EqualFold(trimQuote(name), trimQuote(colName)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (exprs *exprParams) getByName(colName string) (exprParam, bool) {
|
||||||
|
for i, name := range exprs.colNames {
|
||||||
|
if strings.EqualFold(name, colName) {
|
||||||
|
return exprParam{name, exprs.args[i]}, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return exprParam{}, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (exprs *exprParams) writeArgs(w *builder.BytesWriter) error {
|
||||||
|
for _, expr := range exprs.args {
|
||||||
|
switch arg := expr.(type) {
|
||||||
|
case *builder.Builder:
|
||||||
|
if _, err := w.WriteString("("); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := arg.WriteTo(w); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := w.WriteString(")"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if _, err := w.WriteString(fmt.Sprintf("%v", arg)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (exprs *exprParams) writeNameArgs(w *builder.BytesWriter) error {
|
||||||
|
for i, colName := range exprs.colNames {
|
||||||
|
if _, err := w.WriteString(colName); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := w.WriteString("="); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch arg := exprs.args[i].(type) {
|
||||||
|
case *builder.Builder:
|
||||||
|
if _, err := w.WriteString("("); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := arg.WriteTo(w); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := w.WriteString("("); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
w.Append(exprs.args[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
if i+1 != len(exprs.colNames) {
|
||||||
|
if _, err := w.WriteString(","); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
// Copyright 2019 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
|
||||||
|
|
||||||
|
func trimQuote(s string) string {
|
||||||
|
if len(s) == 0 {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
if s[0] == '`' {
|
||||||
|
s = s[1:]
|
||||||
|
}
|
||||||
|
if len(s) > 0 && s[len(s)-1] == '`' {
|
||||||
|
return s[:len(s)-1]
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
|
@ -1 +1 @@
|
||||||
go test -db=mssql -conn_str="server=localhost;user id=sa;password=yourStrong(!)Password;database=xorm_test"
|
go test -db=mssql -conn_str="server=localhost;user id=sa;password=MwantsaSecurePassword1;database=xorm_test"
|
|
@ -198,7 +198,7 @@ github.com/go-swagger/go-swagger/cmd/swagger/commands/initcmd
|
||||||
github.com/go-swagger/go-swagger/codescan
|
github.com/go-swagger/go-swagger/codescan
|
||||||
github.com/go-swagger/go-swagger/generator
|
github.com/go-swagger/go-swagger/generator
|
||||||
github.com/go-swagger/go-swagger/scan
|
github.com/go-swagger/go-swagger/scan
|
||||||
# github.com/go-xorm/xorm v0.7.7-0.20190822154023-17592d96b35b
|
# github.com/go-xorm/xorm v0.7.8-0.20190924080535-59ed80ce1a67
|
||||||
github.com/go-xorm/xorm
|
github.com/go-xorm/xorm
|
||||||
# github.com/gobwas/glob v0.2.3
|
# github.com/gobwas/glob v0.2.3
|
||||||
github.com/gobwas/glob
|
github.com/gobwas/glob
|
||||||
|
@ -612,7 +612,7 @@ gopkg.in/yaml.v2
|
||||||
mvdan.cc/xurls/v2
|
mvdan.cc/xurls/v2
|
||||||
# strk.kbt.io/projects/go/libravatar v0.0.0-20160628055650-5eed7bff870a
|
# strk.kbt.io/projects/go/libravatar v0.0.0-20160628055650-5eed7bff870a
|
||||||
strk.kbt.io/projects/go/libravatar
|
strk.kbt.io/projects/go/libravatar
|
||||||
# xorm.io/builder v0.3.5
|
# xorm.io/builder v0.3.6
|
||||||
xorm.io/builder
|
xorm.io/builder
|
||||||
# xorm.io/core v0.7.0
|
# xorm.io/core v0.7.0
|
||||||
xorm.io/core
|
xorm.io/core
|
||||||
|
|
|
@ -1,37 +1,90 @@
|
||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
name: go1.10
|
||||||
|
|
||||||
workspace:
|
workspace:
|
||||||
base: /go
|
base: /go
|
||||||
path: src/github.com/go-xorm/builder
|
path: src/xorm.io/builder
|
||||||
|
|
||||||
clone:
|
steps:
|
||||||
git:
|
- name: test
|
||||||
image: plugins/git:next
|
pull: default
|
||||||
depth: 50
|
image: golang:1.10
|
||||||
tags: true
|
commands:
|
||||||
|
- go get -u golang.org/x/lint/golint
|
||||||
|
- go get -u github.com/stretchr/testify/assert
|
||||||
|
- go get -u github.com/go-xorm/sqlfiddle
|
||||||
|
- golint ./...
|
||||||
|
- go vet
|
||||||
|
- go test -v -race -coverprofile=coverage.txt -covermode=atomic
|
||||||
|
when:
|
||||||
|
event:
|
||||||
|
- push
|
||||||
|
- tag
|
||||||
|
- pull_request
|
||||||
|
|
||||||
matrix:
|
---
|
||||||
GO_VERSION:
|
kind: pipeline
|
||||||
- 1.8
|
name: go1.11
|
||||||
- 1.9
|
|
||||||
- 1.10
|
|
||||||
- 1.11
|
|
||||||
|
|
||||||
pipeline:
|
steps:
|
||||||
test:
|
- name: test
|
||||||
image: golang:${GO_VERSION}
|
pull: default
|
||||||
commands:
|
image: golang:1.11
|
||||||
- go get -u github.com/golang/lint/golint
|
commands:
|
||||||
- go get -u github.com/stretchr/testify/assert
|
- go get -u golang.org/x/lint/golint
|
||||||
- go get -u github.com/go-xorm/sqlfiddle
|
- golint ./...
|
||||||
- golint ./...
|
- go vet
|
||||||
- go test -v -race -coverprofile=coverage.txt -covermode=atomic
|
- go test -v -race -coverprofile=coverage.txt -covermode=atomic
|
||||||
when:
|
environment:
|
||||||
event: [ push, tag, pull_request ]
|
GOPROXY: https://goproxy.cn
|
||||||
|
GO111MODULE: "on"
|
||||||
|
when:
|
||||||
|
event:
|
||||||
|
- push
|
||||||
|
- tag
|
||||||
|
- pull_request
|
||||||
|
|
||||||
codecov:
|
---
|
||||||
image: robertstettner/drone-codecov
|
kind: pipeline
|
||||||
group: build
|
name: go1.12
|
||||||
secrets: [ codecov_token ]
|
|
||||||
files:
|
steps:
|
||||||
- coverage.txt
|
- name: test
|
||||||
when:
|
pull: default
|
||||||
event: [ push, pull_request ]
|
image: golang:1.12
|
||||||
|
commands:
|
||||||
|
- go get -u golang.org/x/lint/golint
|
||||||
|
- golint ./...
|
||||||
|
- go vet
|
||||||
|
- go test -v -race -coverprofile=coverage.txt -covermode=atomic
|
||||||
|
environment:
|
||||||
|
GOPROXY: https://goproxy.cn
|
||||||
|
GO111MODULE: "on"
|
||||||
|
when:
|
||||||
|
event:
|
||||||
|
- push
|
||||||
|
- tag
|
||||||
|
- pull_request
|
||||||
|
|
||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
name: go1.13
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: test
|
||||||
|
pull: default
|
||||||
|
image: golang:1.13
|
||||||
|
commands:
|
||||||
|
- go get -u golang.org/x/lint/golint
|
||||||
|
- golint ./...
|
||||||
|
- go vet
|
||||||
|
- go test -v -race -coverprofile=coverage.txt -covermode=atomic
|
||||||
|
environment:
|
||||||
|
GOPROXY: https://goproxy.cn
|
||||||
|
GO111MODULE: "on"
|
||||||
|
when:
|
||||||
|
event:
|
||||||
|
- push
|
||||||
|
- tag
|
||||||
|
- pull_request
|
|
@ -1,13 +1,13 @@
|
||||||
# SQL builder
|
# SQL builder
|
||||||
|
|
||||||
[![GitCI.cn](https://gitci.cn/api/badges/go-xorm/builder/status.svg)](https://gitci.cn/go-xorm/builder) [![codecov](https://codecov.io/gh/go-xorm/builder/branch/master/graph/badge.svg)](https://codecov.io/gh/go-xorm/builder)
|
[![Build Status](https://drone.gitea.com/api/badges/xorm/builder/status.svg)](https://drone.gitea.com/xorm/builder) [![](http://gocover.io/_badge/xorm.io/builder)](http://gocover.io/xorm.io/builder)
|
||||||
[![](https://goreportcard.com/badge/github.com/go-xorm/builder)](https://goreportcard.com/report/github.com/go-xorm/builder)
|
[![](https://goreportcard.com/badge/xorm.io/builder)](https://goreportcard.com/report/xorm.io/builder)
|
||||||
|
|
||||||
Package builder is a lightweight and fast SQL builder for Go and XORM.
|
Package builder is a lightweight and fast SQL builder for Go and XORM.
|
||||||
|
|
||||||
Make sure you have installed Go 1.8+ and then:
|
Make sure you have installed Go 1.8+ and then:
|
||||||
|
|
||||||
go get github.com/go-xorm/builder
|
go get xorm.io/builder
|
||||||
|
|
||||||
# Insert
|
# Insert
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ sql, args, err := Select("*").From("a").Where(Eq{"status": "1"}).
|
||||||
* `Eq` is a redefine of a map, you can give one or more conditions to `Eq`
|
* `Eq` is a redefine of a map, you can give one or more conditions to `Eq`
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
import . "github.com/go-xorm/builder"
|
import . "xorm.io/builder"
|
||||||
|
|
||||||
sql, args, _ := ToSQL(Eq{"a":1})
|
sql, args, _ := ToSQL(Eq{"a":1})
|
||||||
// a=? [1]
|
// a=? [1]
|
||||||
|
@ -90,7 +90,7 @@ sql, args, _ := ToSQL(Eq{"b": 1, "c":[]int{2, 3}})
|
||||||
* `Neq` is the same to `Eq`
|
* `Neq` is the same to `Eq`
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
import . "github.com/go-xorm/builder"
|
import . "xorm.io/builder"
|
||||||
|
|
||||||
sql, args, _ := ToSQL(Neq{"a":1})
|
sql, args, _ := ToSQL(Neq{"a":1})
|
||||||
// a<>? [1]
|
// a<>? [1]
|
||||||
|
@ -109,7 +109,7 @@ sql, args, _ := ToSQL(Neq{"b": 1, "c":[]int{2, 3}})
|
||||||
* `Gt`, `Gte`, `Lt`, `Lte`
|
* `Gt`, `Gte`, `Lt`, `Lte`
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
import . "github.com/go-xorm/builder"
|
import . "xorm.io/builder"
|
||||||
|
|
||||||
sql, args, _ := ToSQL(Gt{"a", 1}.And(Gte{"b", 2}))
|
sql, args, _ := ToSQL(Gt{"a", 1}.And(Gte{"b", 2}))
|
||||||
// a>? AND b>=? [1, 2]
|
// a>? AND b>=? [1, 2]
|
||||||
|
@ -120,7 +120,7 @@ sql, args, _ := ToSQL(Lt{"a", 1}.Or(Lte{"b", 2}))
|
||||||
* `Like`
|
* `Like`
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
import . "github.com/go-xorm/builder"
|
import . "xorm.io/builder"
|
||||||
|
|
||||||
sql, args, _ := ToSQL(Like{"a", "c"})
|
sql, args, _ := ToSQL(Like{"a", "c"})
|
||||||
// a LIKE ? [%c%]
|
// a LIKE ? [%c%]
|
||||||
|
@ -129,7 +129,7 @@ sql, args, _ := ToSQL(Like{"a", "c"})
|
||||||
* `Expr` you can customerize your sql with `Expr`
|
* `Expr` you can customerize your sql with `Expr`
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
import . "github.com/go-xorm/builder"
|
import . "xorm.io/builder"
|
||||||
|
|
||||||
sql, args, _ := ToSQL(Expr("a = ? ", 1))
|
sql, args, _ := ToSQL(Expr("a = ? ", 1))
|
||||||
// a = ? [1]
|
// a = ? [1]
|
||||||
|
@ -140,7 +140,7 @@ sql, args, _ := ToSQL(Eq{"a": Expr("select id from table where c = ?", 1)})
|
||||||
* `In` and `NotIn`
|
* `In` and `NotIn`
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
import . "github.com/go-xorm/builder"
|
import . "xorm.io/builder"
|
||||||
|
|
||||||
sql, args, _ := ToSQL(In("a", 1, 2, 3))
|
sql, args, _ := ToSQL(In("a", 1, 2, 3))
|
||||||
// a IN (?,?,?) [1,2,3]
|
// a IN (?,?,?) [1,2,3]
|
||||||
|
@ -153,7 +153,7 @@ sql, args, _ := ToSQL(In("a", Expr("select id from b where c = ?", 1))))
|
||||||
* `IsNull` and `NotNull`
|
* `IsNull` and `NotNull`
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
import . "github.com/go-xorm/builder"
|
import . "xorm.io/builder"
|
||||||
|
|
||||||
sql, args, _ := ToSQL(IsNull{"a"})
|
sql, args, _ := ToSQL(IsNull{"a"})
|
||||||
// a IS NULL []
|
// a IS NULL []
|
||||||
|
@ -164,7 +164,7 @@ sql, args, _ := ToSQL(NotNull{"b"})
|
||||||
* `And(conds ...Cond)`, And can connect one or more condtions via And
|
* `And(conds ...Cond)`, And can connect one or more condtions via And
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
import . "github.com/go-xorm/builder"
|
import . "xorm.io/builder"
|
||||||
|
|
||||||
sql, args, _ := ToSQL(And(Eq{"a":1}, Like{"b", "c"}, Neq{"d", 2}))
|
sql, args, _ := ToSQL(And(Eq{"a":1}, Like{"b", "c"}, Neq{"d", 2}))
|
||||||
// a=? AND b LIKE ? AND d<>? [1, %c%, 2]
|
// a=? AND b LIKE ? AND d<>? [1, %c%, 2]
|
||||||
|
@ -173,7 +173,7 @@ sql, args, _ := ToSQL(And(Eq{"a":1}, Like{"b", "c"}, Neq{"d", 2}))
|
||||||
* `Or(conds ...Cond)`, Or can connect one or more conditions via Or
|
* `Or(conds ...Cond)`, Or can connect one or more conditions via Or
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
import . "github.com/go-xorm/builder"
|
import . "xorm.io/builder"
|
||||||
|
|
||||||
sql, args, _ := ToSQL(Or(Eq{"a":1}, Like{"b", "c"}, Neq{"d", 2}))
|
sql, args, _ := ToSQL(Or(Eq{"a":1}, Like{"b", "c"}, Neq{"d", 2}))
|
||||||
// a=? OR b LIKE ? OR d<>? [1, %c%, 2]
|
// a=? OR b LIKE ? OR d<>? [1, %c%, 2]
|
||||||
|
@ -184,7 +184,7 @@ sql, args, _ := ToSQL(Or(Eq{"a":1}, And(Like{"b", "c"}, Neq{"d", 2})))
|
||||||
* `Between`
|
* `Between`
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
import . "github.com/go-xorm/builder"
|
import . "xorm.io/builder"
|
||||||
|
|
||||||
sql, args, _ := ToSQL(Between{"a", 1, 2})
|
sql, args, _ := ToSQL(Between{"a", 1, 2})
|
||||||
// a BETWEEN 1 AND 2
|
// a BETWEEN 1 AND 2
|
||||||
|
|
|
@ -7,7 +7,6 @@ package builder
|
||||||
import (
|
import (
|
||||||
sql2 "database/sql"
|
sql2 "database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type optype byte
|
type optype byte
|
||||||
|
@ -21,6 +20,7 @@ const (
|
||||||
unionType // union
|
unionType // union
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// all databasees
|
||||||
const (
|
const (
|
||||||
POSTGRES = "postgres"
|
POSTGRES = "postgres"
|
||||||
SQLITE = "sqlite3"
|
SQLITE = "sqlite3"
|
||||||
|
@ -31,7 +31,7 @@ const (
|
||||||
|
|
||||||
type join struct {
|
type join struct {
|
||||||
joinType string
|
joinType string
|
||||||
joinTable string
|
joinTable interface{}
|
||||||
joinCond Cond
|
joinCond Cond
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ type Builder struct {
|
||||||
limitation *limit
|
limitation *limit
|
||||||
insertCols []string
|
insertCols []string
|
||||||
insertVals []interface{}
|
insertVals []interface{}
|
||||||
updates []Eq
|
updates []UpdateCond
|
||||||
orderBy string
|
orderBy string
|
||||||
groupBy string
|
groupBy string
|
||||||
having string
|
having string
|
||||||
|
@ -143,18 +143,6 @@ func (b *Builder) Into(tableName string) *Builder {
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
// Join sets join table and conditions
|
|
||||||
func (b *Builder) Join(joinType, joinTable string, joinCond interface{}) *Builder {
|
|
||||||
switch joinCond.(type) {
|
|
||||||
case Cond:
|
|
||||||
b.joins = append(b.joins, join{joinType, joinTable, joinCond.(Cond)})
|
|
||||||
case string:
|
|
||||||
b.joins = append(b.joins, join{joinType, joinTable, Expr(joinCond.(string))})
|
|
||||||
}
|
|
||||||
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
// Union sets union conditions
|
// Union sets union conditions
|
||||||
func (b *Builder) Union(unionTp string, unionCond *Builder) *Builder {
|
func (b *Builder) Union(unionTp string, unionCond *Builder) *Builder {
|
||||||
var builder *Builder
|
var builder *Builder
|
||||||
|
@ -199,31 +187,6 @@ func (b *Builder) Limit(limitN int, offset ...int) *Builder {
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
// InnerJoin sets inner join
|
|
||||||
func (b *Builder) InnerJoin(joinTable string, joinCond interface{}) *Builder {
|
|
||||||
return b.Join("INNER", joinTable, joinCond)
|
|
||||||
}
|
|
||||||
|
|
||||||
// LeftJoin sets left join SQL
|
|
||||||
func (b *Builder) LeftJoin(joinTable string, joinCond interface{}) *Builder {
|
|
||||||
return b.Join("LEFT", joinTable, joinCond)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RightJoin sets right join SQL
|
|
||||||
func (b *Builder) RightJoin(joinTable string, joinCond interface{}) *Builder {
|
|
||||||
return b.Join("RIGHT", joinTable, joinCond)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CrossJoin sets cross join SQL
|
|
||||||
func (b *Builder) CrossJoin(joinTable string, joinCond interface{}) *Builder {
|
|
||||||
return b.Join("CROSS", joinTable, joinCond)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FullJoin sets full join SQL
|
|
||||||
func (b *Builder) FullJoin(joinTable string, joinCond interface{}) *Builder {
|
|
||||||
return b.Join("FULL", joinTable, joinCond)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Select sets select SQL
|
// Select sets select SQL
|
||||||
func (b *Builder) Select(cols ...string) *Builder {
|
func (b *Builder) Select(cols ...string) *Builder {
|
||||||
b.selects = cols
|
b.selects = cols
|
||||||
|
@ -245,68 +208,12 @@ func (b *Builder) Or(cond Cond) *Builder {
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
type insertColsSorter struct {
|
|
||||||
cols []string
|
|
||||||
vals []interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s insertColsSorter) Len() int {
|
|
||||||
return len(s.cols)
|
|
||||||
}
|
|
||||||
func (s insertColsSorter) Swap(i, j int) {
|
|
||||||
s.cols[i], s.cols[j] = s.cols[j], s.cols[i]
|
|
||||||
s.vals[i], s.vals[j] = s.vals[j], s.vals[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s insertColsSorter) Less(i, j int) bool {
|
|
||||||
return s.cols[i] < s.cols[j]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert sets insert SQL
|
|
||||||
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.Sort(insertColsSorter{
|
|
||||||
cols: b.insertCols,
|
|
||||||
vals: b.insertVals,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
b.optype = insertType
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update sets update SQL
|
// Update sets update SQL
|
||||||
func (b *Builder) Update(updates ...Eq) *Builder {
|
func (b *Builder) Update(updates ...Cond) *Builder {
|
||||||
b.updates = make([]Eq, 0, len(updates))
|
b.updates = make([]UpdateCond, 0, len(updates))
|
||||||
for _, update := range updates {
|
for _, update := range updates {
|
||||||
if update.IsValid() {
|
if u, ok := update.(UpdateCond); ok && u.IsValid() {
|
||||||
b.updates = append(b.updates, update)
|
b.updates = append(b.updates, u)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
b.optype = updateType
|
b.optype = updateType
|
||||||
|
@ -354,7 +261,7 @@ func (b *Builder) ToSQL() (string, []interface{}, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var sql = w.writer.String()
|
var sql = w.String()
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
switch b.dialect {
|
switch b.dialect {
|
||||||
|
@ -383,12 +290,12 @@ func (b *Builder) ToSQL() (string, []interface{}, error) {
|
||||||
return sql, w.args, nil
|
return sql, w.args, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToBoundSQL
|
// ToBoundSQL generated a bound SQL string
|
||||||
func (b *Builder) ToBoundSQL() (string, error) {
|
func (b *Builder) ToBoundSQL() (string, error) {
|
||||||
w := NewWriter()
|
w := NewWriter()
|
||||||
if err := b.WriteTo(w); err != nil {
|
if err := b.WriteTo(w); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
return ConvertToBoundSQL(w.writer.String(), w.args)
|
return ConvertToBoundSQL(w.String(), w.args)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ package builder
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Insert creates an insert Builder
|
// Insert creates an insert Builder
|
||||||
|
@ -87,3 +88,60 @@ func (b *Builder) insertWriteTo(w Writer) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type insertColsSorter struct {
|
||||||
|
cols []string
|
||||||
|
vals []interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s insertColsSorter) Len() int {
|
||||||
|
return len(s.cols)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s insertColsSorter) Swap(i, j int) {
|
||||||
|
s.cols[i], s.cols[j] = s.cols[j], s.cols[i]
|
||||||
|
s.vals[i], s.vals[j] = s.vals[j], s.vals[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s insertColsSorter) Less(i, j int) bool {
|
||||||
|
return s.cols[i] < s.cols[j]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert sets insert SQL
|
||||||
|
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.Sort(insertColsSorter{
|
||||||
|
cols: b.insertCols,
|
||||||
|
vals: b.insertVals,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
b.optype = insertType
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
// Copyright 2019 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
|
||||||
|
|
||||||
|
// InnerJoin sets inner join
|
||||||
|
func (b *Builder) InnerJoin(joinTable, joinCond interface{}) *Builder {
|
||||||
|
return b.Join("INNER", joinTable, joinCond)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LeftJoin sets left join SQL
|
||||||
|
func (b *Builder) LeftJoin(joinTable, joinCond interface{}) *Builder {
|
||||||
|
return b.Join("LEFT", joinTable, joinCond)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RightJoin sets right join SQL
|
||||||
|
func (b *Builder) RightJoin(joinTable, joinCond interface{}) *Builder {
|
||||||
|
return b.Join("RIGHT", joinTable, joinCond)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CrossJoin sets cross join SQL
|
||||||
|
func (b *Builder) CrossJoin(joinTable, joinCond interface{}) *Builder {
|
||||||
|
return b.Join("CROSS", joinTable, joinCond)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FullJoin sets full join SQL
|
||||||
|
func (b *Builder) FullJoin(joinTable, joinCond interface{}) *Builder {
|
||||||
|
return b.Join("FULL", joinTable, joinCond)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Join sets join table and conditions
|
||||||
|
func (b *Builder) Join(joinType string, joinTable, joinCond interface{}) *Builder {
|
||||||
|
switch joinCond.(type) {
|
||||||
|
case Cond:
|
||||||
|
b.joins = append(b.joins, join{joinType, joinTable, joinCond.(Cond)})
|
||||||
|
case string:
|
||||||
|
b.joins = append(b.joins, join{joinType, joinTable, Expr(joinCond.(string))})
|
||||||
|
}
|
||||||
|
|
||||||
|
return b
|
||||||
|
}
|
|
@ -80,8 +80,21 @@ func (b *Builder) selectWriteTo(w Writer) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, v := range b.joins {
|
for _, v := range b.joins {
|
||||||
if _, err := fmt.Fprintf(w, " %s JOIN %s ON ", v.joinType, v.joinTable); err != nil {
|
b, ok := v.joinTable.(*Builder)
|
||||||
return err
|
if ok {
|
||||||
|
if _, err := fmt.Fprintf(w, " %s JOIN (", v.joinType); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := b.WriteTo(w); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := fmt.Fprintf(w, ") ON "); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
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 {
|
if err := v.joinCond.WriteTo(w); err != nil {
|
||||||
|
|
|
@ -8,8 +8,14 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// UpdateCond defines an interface that cond could be used with update
|
||||||
|
type UpdateCond interface {
|
||||||
|
IsValid() bool
|
||||||
|
OpWriteTo(op string, w Writer) error
|
||||||
|
}
|
||||||
|
|
||||||
// Update creates an update Builder
|
// Update creates an update Builder
|
||||||
func Update(updates ...Eq) *Builder {
|
func Update(updates ...Cond) *Builder {
|
||||||
builder := &Builder{cond: NewCond()}
|
builder := &Builder{cond: NewCond()}
|
||||||
return builder.Update(updates...)
|
return builder.Update(updates...)
|
||||||
}
|
}
|
||||||
|
@ -27,7 +33,8 @@ func (b *Builder) updateWriteTo(w Writer) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, s := range b.updates {
|
for i, s := range b.updates {
|
||||||
if err := s.opWriteTo(",", w); err != nil {
|
|
||||||
|
if err := s.OpWriteTo(",", w); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,42 +4,6 @@
|
||||||
|
|
||||||
package builder
|
package builder
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Writer defines the interface
|
|
||||||
type Writer interface {
|
|
||||||
io.Writer
|
|
||||||
Append(...interface{})
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ Writer = NewWriter()
|
|
||||||
|
|
||||||
// BytesWriter implments Writer and save SQL in bytes.Buffer
|
|
||||||
type BytesWriter struct {
|
|
||||||
writer *StringBuilder
|
|
||||||
args []interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewWriter creates a new string writer
|
|
||||||
func NewWriter() *BytesWriter {
|
|
||||||
w := &BytesWriter{
|
|
||||||
writer: &StringBuilder{},
|
|
||||||
}
|
|
||||||
return w
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write writes data to Writer
|
|
||||||
func (s *BytesWriter) Write(buf []byte) (int, error) {
|
|
||||||
return s.writer.Write(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Append appends args to Writer
|
|
||||||
func (s *BytesWriter) Append(args ...interface{}) {
|
|
||||||
s.args = append(s.args, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cond defines an interface
|
// Cond defines an interface
|
||||||
type Cond interface {
|
type Cond interface {
|
||||||
WriteTo(Writer) error
|
WriteTo(Writer) error
|
||||||
|
|
|
@ -20,7 +20,8 @@ type Eq map[string]interface{}
|
||||||
|
|
||||||
var _ Cond = Eq{}
|
var _ Cond = Eq{}
|
||||||
|
|
||||||
func (eq Eq) opWriteTo(op string, w Writer) error {
|
// OpWriteTo writes conditions with special operator
|
||||||
|
func (eq Eq) OpWriteTo(op string, w Writer) error {
|
||||||
var i = 0
|
var i = 0
|
||||||
for _, k := range eq.sortedKeys() {
|
for _, k := range eq.sortedKeys() {
|
||||||
v := eq[k]
|
v := eq[k]
|
||||||
|
@ -81,7 +82,7 @@ func (eq Eq) opWriteTo(op string, w Writer) error {
|
||||||
|
|
||||||
// WriteTo writes SQL to Writer
|
// WriteTo writes SQL to Writer
|
||||||
func (eq Eq) WriteTo(w Writer) error {
|
func (eq Eq) WriteTo(w Writer) error {
|
||||||
return eq.opWriteTo(" AND ", w)
|
return eq.OpWriteTo(" AND ", w)
|
||||||
}
|
}
|
||||||
|
|
||||||
// And implements And with other conditions
|
// And implements And with other conditions
|
||||||
|
@ -101,7 +102,7 @@ func (eq Eq) IsValid() bool {
|
||||||
|
|
||||||
// sortedKeys returns all keys of this Eq sorted with sort.Strings.
|
// sortedKeys returns all keys of this Eq sorted with sort.Strings.
|
||||||
// It is used internally for consistent ordering when generating
|
// It is used internally for consistent ordering when generating
|
||||||
// SQL, see https://github.com/go-xorm/builder/issues/10
|
// SQL, see https://gitea.com/xorm/builder/issues/10
|
||||||
func (eq Eq) sortedKeys() []string {
|
func (eq Eq) sortedKeys() []string {
|
||||||
keys := make([]string, 0, len(eq))
|
keys := make([]string, 0, len(eq))
|
||||||
for key := range eq {
|
for key := range eq {
|
||||||
|
|
|
@ -18,6 +18,10 @@ func Expr(sql string, args ...interface{}) Cond {
|
||||||
return expr{sql, args}
|
return expr{sql, args}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (expr expr) OpWriteTo(op string, w Writer) error {
|
||||||
|
return expr.WriteTo(w)
|
||||||
|
}
|
||||||
|
|
||||||
func (expr expr) WriteTo(w Writer) error {
|
func (expr expr) WriteTo(w Writer) error {
|
||||||
if _, err := fmt.Fprint(w, expr.sql); err != nil {
|
if _, err := fmt.Fprint(w, expr.sql); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -83,7 +83,7 @@ func (neq Neq) IsValid() bool {
|
||||||
|
|
||||||
// sortedKeys returns all keys of this Neq sorted with sort.Strings.
|
// sortedKeys returns all keys of this Neq sorted with sort.Strings.
|
||||||
// It is used internally for consistent ordering when generating
|
// It is used internally for consistent ordering when generating
|
||||||
// SQL, see https://github.com/go-xorm/builder/issues/10
|
// SQL, see https://gitea.com/xorm/builder/issues/10
|
||||||
func (neq Neq) sortedKeys() []string {
|
func (neq Neq) sortedKeys() []string {
|
||||||
keys := make([]string, 0, len(neq))
|
keys := make([]string, 0, len(neq))
|
||||||
for key := range neq {
|
for key := range neq {
|
||||||
|
|
|
@ -8,13 +8,13 @@ Package builder is a simple and powerful sql builder for Go.
|
||||||
|
|
||||||
Make sure you have installed Go 1.1+ and then:
|
Make sure you have installed Go 1.1+ and then:
|
||||||
|
|
||||||
go get github.com/go-xorm/builder
|
go get xorm.io/builder
|
||||||
|
|
||||||
WARNNING: Currently, only query conditions are supported. Below is the supported conditions.
|
WARNNING: Currently, only query conditions are supported. Below is the supported conditions.
|
||||||
|
|
||||||
1. Eq is a redefine of a map, you can give one or more conditions to Eq
|
1. Eq is a redefine of a map, you can give one or more conditions to Eq
|
||||||
|
|
||||||
import . "github.com/go-xorm/builder"
|
import . "xorm.io/builder"
|
||||||
|
|
||||||
sql, args, _ := ToSQL(Eq{"a":1})
|
sql, args, _ := ToSQL(Eq{"a":1})
|
||||||
// a=? [1]
|
// a=? [1]
|
||||||
|
@ -31,7 +31,7 @@ WARNNING: Currently, only query conditions are supported. Below is the supported
|
||||||
|
|
||||||
2. Neq is the same to Eq
|
2. Neq is the same to Eq
|
||||||
|
|
||||||
import . "github.com/go-xorm/builder"
|
import . "xorm.io/builder"
|
||||||
|
|
||||||
sql, args, _ := ToSQL(Neq{"a":1})
|
sql, args, _ := ToSQL(Neq{"a":1})
|
||||||
// a<>? [1]
|
// a<>? [1]
|
||||||
|
@ -48,7 +48,7 @@ WARNNING: Currently, only query conditions are supported. Below is the supported
|
||||||
|
|
||||||
3. Gt, Gte, Lt, Lte
|
3. Gt, Gte, Lt, Lte
|
||||||
|
|
||||||
import . "github.com/go-xorm/builder"
|
import . "xorm.io/builder"
|
||||||
|
|
||||||
sql, args, _ := ToSQL(Gt{"a", 1}.And(Gte{"b", 2}))
|
sql, args, _ := ToSQL(Gt{"a", 1}.And(Gte{"b", 2}))
|
||||||
// a>? AND b>=? [1, 2]
|
// a>? AND b>=? [1, 2]
|
||||||
|
@ -57,14 +57,14 @@ WARNNING: Currently, only query conditions are supported. Below is the supported
|
||||||
|
|
||||||
4. Like
|
4. Like
|
||||||
|
|
||||||
import . "github.com/go-xorm/builder"
|
import . "xorm.io/builder"
|
||||||
|
|
||||||
sql, args, _ := ToSQL(Like{"a", "c"})
|
sql, args, _ := ToSQL(Like{"a", "c"})
|
||||||
// a LIKE ? [%c%]
|
// a LIKE ? [%c%]
|
||||||
|
|
||||||
5. Expr you can customerize your sql with Expr
|
5. Expr you can customerize your sql with Expr
|
||||||
|
|
||||||
import . "github.com/go-xorm/builder"
|
import . "xorm.io/builder"
|
||||||
|
|
||||||
sql, args, _ := ToSQL(Expr("a = ? ", 1))
|
sql, args, _ := ToSQL(Expr("a = ? ", 1))
|
||||||
// a = ? [1]
|
// a = ? [1]
|
||||||
|
@ -73,7 +73,7 @@ WARNNING: Currently, only query conditions are supported. Below is the supported
|
||||||
|
|
||||||
6. In and NotIn
|
6. In and NotIn
|
||||||
|
|
||||||
import . "github.com/go-xorm/builder"
|
import . "xorm.io/builder"
|
||||||
|
|
||||||
sql, args, _ := ToSQL(In("a", 1, 2, 3))
|
sql, args, _ := ToSQL(In("a", 1, 2, 3))
|
||||||
// a IN (?,?,?) [1,2,3]
|
// a IN (?,?,?) [1,2,3]
|
||||||
|
@ -84,7 +84,7 @@ WARNNING: Currently, only query conditions are supported. Below is the supported
|
||||||
|
|
||||||
7. IsNull and NotNull
|
7. IsNull and NotNull
|
||||||
|
|
||||||
import . "github.com/go-xorm/builder"
|
import . "xorm.io/builder"
|
||||||
|
|
||||||
sql, args, _ := ToSQL(IsNull{"a"})
|
sql, args, _ := ToSQL(IsNull{"a"})
|
||||||
// a IS NULL []
|
// a IS NULL []
|
||||||
|
@ -93,14 +93,14 @@ WARNNING: Currently, only query conditions are supported. Below is the supported
|
||||||
|
|
||||||
8. And(conds ...Cond), And can connect one or more condtions via AND
|
8. And(conds ...Cond), And can connect one or more condtions via AND
|
||||||
|
|
||||||
import . "github.com/go-xorm/builder"
|
import . "xorm.io/builder"
|
||||||
|
|
||||||
sql, args, _ := ToSQL(And(Eq{"a":1}, Like{"b", "c"}, Neq{"d", 2}))
|
sql, args, _ := ToSQL(And(Eq{"a":1}, Like{"b", "c"}, Neq{"d", 2}))
|
||||||
// a=? AND b LIKE ? AND d<>? [1, %c%, 2]
|
// a=? AND b LIKE ? AND d<>? [1, %c%, 2]
|
||||||
|
|
||||||
9. Or(conds ...Cond), Or can connect one or more conditions via Or
|
9. Or(conds ...Cond), Or can connect one or more conditions via Or
|
||||||
|
|
||||||
import . "github.com/go-xorm/builder"
|
import . "xorm.io/builder"
|
||||||
|
|
||||||
sql, args, _ := ToSQL(Or(Eq{"a":1}, Like{"b", "c"}, Neq{"d", 2}))
|
sql, args, _ := ToSQL(Or(Eq{"a":1}, Like{"b", "c"}, Neq{"d", 2}))
|
||||||
// a=? OR b LIKE ? OR d<>? [1, %c%, 2]
|
// a=? OR b LIKE ? OR d<>? [1, %c%, 2]
|
||||||
|
@ -109,7 +109,7 @@ WARNNING: Currently, only query conditions are supported. Below is the supported
|
||||||
|
|
||||||
10. Between
|
10. Between
|
||||||
|
|
||||||
import . "github.com/go-xorm/builder"
|
import . "xorm.io/builder"
|
||||||
|
|
||||||
sql, args, _ := ToSQL(Between("a", 1, 2))
|
sql, args, _ := ToSQL(Between("a", 1, 2))
|
||||||
// a BETWEEN 1 AND 2
|
// a BETWEEN 1 AND 2
|
||||||
|
|
|
@ -17,9 +17,9 @@ var (
|
||||||
ErrNeedMoreArguments = errors.New("Need more sql arguments")
|
ErrNeedMoreArguments = errors.New("Need more sql arguments")
|
||||||
// ErrNoTableName no table name
|
// ErrNoTableName no table name
|
||||||
ErrNoTableName = errors.New("No table indicated")
|
ErrNoTableName = errors.New("No table indicated")
|
||||||
// ErrNoColumnToInsert no column to update
|
// ErrNoColumnToUpdate no column to update
|
||||||
ErrNoColumnToUpdate = errors.New("No column(s) to update")
|
ErrNoColumnToUpdate = errors.New("No column(s) to update")
|
||||||
// ErrNoColumnToInsert no column to update
|
// ErrNoColumnToInsert no column to insert
|
||||||
ErrNoColumnToInsert = errors.New("No column(s) to insert")
|
ErrNoColumnToInsert = errors.New("No column(s) to insert")
|
||||||
// ErrNotSupportDialectType not supported dialect type error
|
// ErrNotSupportDialectType not supported dialect type error
|
||||||
ErrNotSupportDialectType = errors.New("Not supported dialect type")
|
ErrNotSupportDialectType = errors.New("Not supported dialect type")
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
module xorm.io/builder
|
module xorm.io/builder
|
||||||
|
|
||||||
|
go 1.11
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a
|
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a
|
||||||
github.com/stretchr/testify v1.3.0
|
github.com/stretchr/testify v1.3.0
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
sql2 "database/sql"
|
sql2 "database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -20,7 +21,7 @@ func condToSQL(cond Cond) (string, []interface{}, error) {
|
||||||
if err := cond.WriteTo(w); err != nil {
|
if err := cond.WriteTo(w); err != nil {
|
||||||
return "", nil, err
|
return "", nil, err
|
||||||
}
|
}
|
||||||
return w.writer.String(), w.args, nil
|
return w.String(), w.args, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func condToBoundSQL(cond Cond) (string, error) {
|
func condToBoundSQL(cond Cond) (string, error) {
|
||||||
|
@ -32,7 +33,7 @@ func condToBoundSQL(cond Cond) (string, error) {
|
||||||
if err := cond.WriteTo(w); err != nil {
|
if err := cond.WriteTo(w); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return ConvertToBoundSQL(w.writer.String(), w.args)
|
return ConvertToBoundSQL(w.String(), w.args)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToSQL convert a builder or conditions to SQL and args
|
// ToSQL convert a builder or conditions to SQL and args
|
||||||
|
@ -92,7 +93,7 @@ func noSQLQuoteNeeded(a interface{}) bool {
|
||||||
|
|
||||||
// ConvertToBoundSQL will convert SQL and args to a bound SQL
|
// ConvertToBoundSQL will convert SQL and args to a bound SQL
|
||||||
func ConvertToBoundSQL(sql string, args []interface{}) (string, error) {
|
func ConvertToBoundSQL(sql string, args []interface{}) (string, error) {
|
||||||
buf := StringBuilder{}
|
buf := strings.Builder{}
|
||||||
var i, j, start int
|
var i, j, start int
|
||||||
for ; i < len(sql); i++ {
|
for ; i < len(sql); i++ {
|
||||||
if sql[i] == '?' {
|
if sql[i] == '?' {
|
||||||
|
@ -114,7 +115,10 @@ func ConvertToBoundSQL(sql string, args []interface{}) (string, error) {
|
||||||
if noSQLQuoteNeeded(arg) {
|
if noSQLQuoteNeeded(arg) {
|
||||||
_, err = fmt.Fprint(&buf, arg)
|
_, err = fmt.Fprint(&buf, arg)
|
||||||
} else {
|
} else {
|
||||||
_, err = fmt.Fprintf(&buf, "'%v'", arg)
|
// replace ' -> '' (standard replacement) to avoid critical SQL injection,
|
||||||
|
// NOTICE: may allow some injection like % (or _) in LIKE query
|
||||||
|
_, err = fmt.Fprintf(&buf, "'%v'", strings.Replace(fmt.Sprintf("%v", arg), "'",
|
||||||
|
"''", -1))
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -131,7 +135,7 @@ func ConvertToBoundSQL(sql string, args []interface{}) (string, error) {
|
||||||
|
|
||||||
// ConvertPlaceholder replaces ? to $1, $2 ... or :1, :2 ... according prefix
|
// ConvertPlaceholder replaces ? to $1, $2 ... or :1, :2 ... according prefix
|
||||||
func ConvertPlaceholder(sql, prefix string) (string, error) {
|
func ConvertPlaceholder(sql, prefix string) (string, error) {
|
||||||
buf := StringBuilder{}
|
buf := strings.Builder{}
|
||||||
var i, j, start int
|
var i, j, start int
|
||||||
for ; i < len(sql); i++ {
|
for ; i < len(sql); i++ {
|
||||||
if sql[i] == '?' {
|
if sql[i] == '?' {
|
||||||
|
|
|
@ -1,119 +0,0 @@
|
||||||
// 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
|
|
||||||
}
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
// Copyright 2019 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 (
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Writer defines the interface
|
||||||
|
type Writer interface {
|
||||||
|
io.Writer
|
||||||
|
Append(...interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ Writer = NewWriter()
|
||||||
|
|
||||||
|
// BytesWriter implments Writer and save SQL in bytes.Buffer
|
||||||
|
type BytesWriter struct {
|
||||||
|
*strings.Builder
|
||||||
|
args []interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWriter creates a new string writer
|
||||||
|
func NewWriter() *BytesWriter {
|
||||||
|
w := &BytesWriter{
|
||||||
|
Builder: &strings.Builder{},
|
||||||
|
}
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append appends args to Writer
|
||||||
|
func (w *BytesWriter) Append(args ...interface{}) {
|
||||||
|
w.args = append(w.args, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Args returns args
|
||||||
|
func (w *BytesWriter) Args() []interface{} {
|
||||||
|
return w.args
|
||||||
|
}
|
Loading…
Reference in New Issue