use golang ci lint v1 (#2551)

Reviewed-on: https://gitea.com/xorm/xorm/pulls/2551
This commit is contained in:
Lunny Xiao
2026-02-07 23:53:33 +00:00
parent c393929a04
commit 25b614c5db
28 changed files with 216 additions and 351 deletions
+1
View File
@@ -39,3 +39,4 @@ tests/*.sql
tests/test_sqlite*
cover.out
cover.html
bin/
+27 -197
View File
@@ -1,198 +1,28 @@
version: "2"
output:
sort-order:
- file
linters:
default: none
enable:
- bidichk
- bodyclose
- depguard
- dupl
- errcheck
- forbidigo
- gocheckcompilerdirectives
- gocritic
- govet
- ineffassign
- mirror
- modernize
- nakedret
- nolintlint
- perfsprint
- revive
- staticcheck
- unconvert
- unparam
- unused
- usestdlibvars
- usetesting
- wastedassign
settings:
depguard:
rules:
main:
deny:
- pkg: github.com/unknwon/com
desc: use gitea's util and replacements
- pkg: io/ioutil
desc: use os or io instead
- pkg: golang.org/x/exp
desc: it's experimental and unreliable
- pkg: gopkg.in/ini.v1
desc: do not use the ini package, use gitea's config system instead
- pkg: github.com/pkg/errors
desc: use builtin errors package instead
- pkg: github.com/go-ap/errors
desc: use builtin errors package instead
nolintlint:
allow-unused: false
require-explanation: true
require-specific: true
gocritic:
enabled-checks:
- equalFold
disabled-checks:
- ifElseChain
- singleCaseSwitch # Every time this occurred in the code, there was no other way.
- deprecatedComment # conflicts with go-swagger comments
revive:
severity: error
rules:
- name: atomic
- name: bare-return
- name: blank-imports
- name: constant-logical-expr
- name: context-as-argument
disabled: true
- name: context-keys-type
- name: dot-imports
- name: duplicated-imports
- name: empty-lines
- name: error-naming
- name: error-return
- name: error-strings
- name: errorf
- name: exported
disabled: true
- name: identical-branches
- name: if-return
- name: increment-decrement
- name: indent-error-flow
- name: modifies-value-receiver
- name: package-comments
- name: range
- name: receiver-naming
- name: redefines-builtin-id
- name: string-of-int
- name: superfluous-else
- name: time-naming
- name: unconditional-recursion
- name: unexported-return
disabled: true
- name: unreachable-code
- name: var-declaration
- name: var-naming
disabled: true
arguments:
- [] # AllowList - do not remove as args for the rule are positional and won't work without lists first
- [] # DenyList
- - skip-package-name-checks: true # supress errors from underscore in migration packages
staticcheck:
checks:
- all
- -ST1003
- -ST1005
- -QF1001
- -QF1006
- -QF1008
testifylint:
disable:
- go-require
- require-error
usetesting:
os-temp-dir: true
perfsprint:
concat-loop: false
govet:
enable:
- nilness
- unusedwrite
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
rules:
- linters:
- dupl
- errcheck
- gocyclo
- gosec
- staticcheck
- unparam
path: _test\.go
- linters:
- dupl
- errcheck
- gocyclo
- gosec
path: models/migrations/v
- linters:
- forbidigo
path: cmd
- linters:
- dupl
text: (?i)webhook
- linters:
- dupl
path: dialects/(dameng|gbase8s|oracle)\.go
- linters:
- gocritic
text: (?i)`ID' should not be capitalized
- linters:
- deadcode
- unused
text: (?i)swagger
- linters:
- staticcheck
text: (?i)argument x is overwritten before first use
- linters:
- gocritic
text: '(?i)commentFormatting: put a space between `//` and comment text'
- linters:
- gocritic
text: '(?i)exitAfterDefer:'
paths:
- node_modules
- .venv
- public
- web_src
- third_party$
- builtin$
- examples$
issues:
max-issues-per-linter: 0
max-same-issues: 0
formatters:
enable:
- gofmt
- gofumpt
settings:
gofumpt:
extra-rules: true
exclusions:
generated: lax
paths:
- node_modules
- .venv
- public
- web_src
- third_party$
- builtin$
- examples$
run:
timeout: 10m
go: "1.20"
timeout: 5m
linters:
enable:
- govet
- errcheck
- staticcheck
- gosimple
- ineffassign
- typecheck
- gofmt
- goimports
- misspell
- unconvert
- gocritic
disable:
- depguard
- wsl
- funlen
issues:
exclude-rules:
- path: _test\.go
linters:
- errcheck
+13 -4
View File
@@ -11,7 +11,7 @@ GOFILES := $(wildcard *.go)
GOFILES += $(shell find $(GO_DIRS) -name "*.go" -type f)
INTEGRATION_PACKAGES := xorm.io/xorm/tests
PACKAGES ?= $(filter-out $(INTEGRATION_PACKAGES),$(shell $(GO) list ./...))
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.8.0
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.55.2
TEST_COCKROACH_HOST ?= cockroach:26257
TEST_COCKROACH_SCHEMA ?=
@@ -111,9 +111,18 @@ help:
@echo " - test-tidb run integration tests for tidb"
@echo " - vet examines Go source code and reports suspicious constructs"
.PHONY: lint
lint:
$(GO) run $(GOLANGCI_LINT_PACKAGE) run
GOLANGCI_LINT_VERSION ?= v1.55.2
GOLANGCI_LINT ?= $(PWD)/bin/golangci-lint
GOLANGCI_LINT_GOTOOLCHAIN ?= go1.20.14
.PHONY: lint lint-install
lint: lint-install
GOTOOLCHAIN=$(GOLANGCI_LINT_GOTOOLCHAIN) $(GOLANGCI_LINT) run
lint-install:
test -x $(GOLANGCI_LINT) || \
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | \
sh -s -- -b $(PWD)/bin $(GOLANGCI_LINT_VERSION)
.PHONY: test
test: go-check
+3 -6
View File
@@ -241,8 +241,7 @@ func Assign(dest, src any, originalLocation, convertedLocation *time.Location) e
return nil
}
case *sql.NullBool:
switch d := dest.(type) {
case *bool:
if d, ok := dest.(*bool); ok {
if s.Valid {
*d = s.Bool
}
@@ -280,16 +279,14 @@ func Assign(dest, src any, originalLocation, convertedLocation *time.Location) e
return nil
}
case *NullUint64:
switch d := dest.(type) {
case *uint64:
if d, ok := dest.(*uint64); ok {
if s.Valid {
*d = s.Uint64
}
return nil
}
case *sql.RawBytes:
switch d := dest.(type) {
case Conversion:
if d, ok := dest.(Conversion); ok {
return d.FromDB(*s)
}
}
+1 -1
View File
@@ -56,7 +56,7 @@ func AsFloat64(src any) (float64, error) {
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return float64(rv.Uint()), nil
case reflect.Float64, reflect.Float32:
return float64(rv.Float()), nil
return rv.Float(), nil
case reflect.String:
return strconv.ParseFloat(rv.String(), 64)
}
+8 -7
View File
@@ -17,7 +17,8 @@ import (
// String2Time converts a string to time with original location
// be aware for time strings (HH:mm:ss) returns zero year (LMT) for converted location
func String2Time(s string, originalLocation, convertedLocation *time.Location) (*time.Time, error) {
if len(s) == 19 {
switch {
case len(s) == 19:
if s == utils.ZeroTime0 || s == utils.ZeroTime1 {
return &time.Time{}, nil
}
@@ -27,7 +28,7 @@ func String2Time(s string, originalLocation, convertedLocation *time.Location) (
}
dt = dt.In(convertedLocation)
return &dt, nil
} else if len(s) == 20 && s[10] == 'T' && s[19] == 'Z' {
case len(s) == 20 && s[10] == 'T' && s[19] == 'Z':
if strings.HasPrefix(s, "0000-00-00T00:00:00") || strings.HasPrefix(s, "0001-01-01T00:00:00") {
return &time.Time{}, nil
}
@@ -37,7 +38,7 @@ func String2Time(s string, originalLocation, convertedLocation *time.Location) (
}
dt = dt.In(convertedLocation)
return &dt, nil
} else if len(s) == 25 && s[10] == 'T' && s[19] == '+' && s[22] == ':' {
case len(s) == 25 && s[10] == 'T' && s[19] == '+' && s[22] == ':':
if strings.HasPrefix(s, "0000-00-00T00:00:00") || strings.HasPrefix(s, "0001-01-01T00:00:00") {
return &time.Time{}, nil
}
@@ -47,7 +48,7 @@ func String2Time(s string, originalLocation, convertedLocation *time.Location) (
}
dt = dt.In(convertedLocation)
return &dt, nil
} else if len(s) >= 21 && s[10] == 'T' && s[19] == '.' {
case len(s) >= 21 && s[10] == 'T' && s[19] == '.':
if strings.HasPrefix(s, "0000-00-00T00:00:00."+strings.Repeat("0", len(s)-20)) ||
strings.HasPrefix(s, "0001-01-01T00:00:00."+strings.Repeat("0", len(s)-20)) {
return &time.Time{}, nil
@@ -58,7 +59,7 @@ func String2Time(s string, originalLocation, convertedLocation *time.Location) (
}
dt = dt.In(convertedLocation)
return &dt, nil
} else if len(s) >= 21 && s[19] == '.' {
case len(s) >= 21 && s[19] == '.':
if strings.HasPrefix(s, "0000-00-00T00:00:00."+strings.Repeat("0", len(s)-20)) ||
strings.HasPrefix(s, "0001-01-01T00:00:00."+strings.Repeat("0", len(s)-20)) {
return &time.Time{}, nil
@@ -70,7 +71,7 @@ func String2Time(s string, originalLocation, convertedLocation *time.Location) (
}
dt = dt.In(convertedLocation)
return &dt, nil
} else if len(s) == 10 && s[4] == '-' {
case len(s) == 10 && s[4] == '-':
if s == "0000-00-00" || s == "0001-01-01" {
return &time.Time{}, nil
}
@@ -80,7 +81,7 @@ func String2Time(s string, originalLocation, convertedLocation *time.Location) (
}
dt = dt.In(convertedLocation)
return &dt, nil
} else if len(s) == 8 && s[2] == ':' && s[5] == ':' {
case len(s) == 8 && s[2] == ':' && s[5] == ':':
dt, err := time.ParseInLocation("15:04:05", s, originalLocation)
if err != nil {
return nil, err
+20 -18
View File
@@ -37,38 +37,39 @@ func postgresSeqFilterConvertQuestionMark(sql, prefix string, start int) string
buf.WriteString(fmt.Sprintf("%s%v", prefix, index))
index++
} else {
if isMaybeJsonbQuestion && c == '?' {
switch {
case isMaybeJsonbQuestion && c == '?':
isMaybeJsonbQuestion = false
} else if isMaybeLineComment {
case isMaybeLineComment:
if c == '-' {
isLineComment = true
}
isMaybeLineComment = false
} else if isMaybeComment {
case isMaybeComment:
if c == '*' {
isComment = true
}
isMaybeComment = false
} else if isMaybeCommentEnd {
case isMaybeCommentEnd:
if c == '/' {
isComment = false
}
isMaybeCommentEnd = false
} else if isLineComment {
case isLineComment:
if c == '\n' {
isLineComment = false
}
} else if isComment {
case isComment:
if c == '*' {
isMaybeCommentEnd = true
}
} else if !beginSingleQuote && c == '-' {
case !beginSingleQuote && c == '-':
isMaybeLineComment = true
} else if !beginSingleQuote && c == '/' {
case !beginSingleQuote && c == '/':
isMaybeComment = true
} else if !beginSingleQuote && c == ' ' && i >= 7 && strings.TrimSpace(sql[i-7:i]) == "::jsonb" {
case !beginSingleQuote && c == ' ' && i >= 7 && strings.TrimSpace(sql[i-7:i]) == "::jsonb":
isMaybeJsonbQuestion = true
} else if c == '\'' {
case c == '\'':
beginSingleQuote = !beginSingleQuote
}
buf.WriteRune(c)
@@ -103,34 +104,35 @@ func oracleSeqFilterConvertQuestionMark(sql, prefix string, start int) string {
buf.WriteString(strconv.Itoa(index))
index++
} else {
if isMaybeLineComment {
switch {
case isMaybeLineComment:
if c == '-' {
isLineComment = true
}
isMaybeLineComment = false
} else if isMaybeComment {
case isMaybeComment:
if c == '*' {
isComment = true
}
isMaybeComment = false
} else if isMaybeCommentEnd {
case isMaybeCommentEnd:
if c == '/' {
isComment = false
}
isMaybeCommentEnd = false
} else if isLineComment {
case isLineComment:
if c == '\n' {
isLineComment = false
}
} else if isComment {
case isComment:
if c == '*' {
isMaybeCommentEnd = true
}
} else if !beginSingleQuote && c == '-' {
case !beginSingleQuote && c == '-':
isMaybeLineComment = true
} else if !beginSingleQuote && c == '/' {
case !beginSingleQuote && c == '/':
isMaybeComment = true
} else if c == '\'' {
case c == '\'':
beginSingleQuote = !beginSingleQuote
}
buf.WriteRune(c)
+4 -3
View File
@@ -622,11 +622,12 @@ func (db *gbase8s) SQLType(c *schemas.Column) string {
}
hasLen1 := c.Length > 0
hasLen2 := c.Length2 > 0
if res == "BIGINT" || res == "INT" || res == "SMALLINT" {
switch {
case res == "BIGINT" || res == "INT" || res == "SMALLINT":
// GBase 8s INT doesn't need length specification
} else if hasLen2 {
case hasLen2:
res += "(" + strconv.FormatInt(c.Length, 10) + "," + strconv.FormatInt(c.Length2, 10) + ")"
} else if hasLen1 {
case hasLen1:
res += "(" + strconv.FormatInt(c.Length, 10) + ")"
}
return res
+4 -3
View File
@@ -469,7 +469,8 @@ func (db *mysql) GetColumns(queryer core.Queryer, ctx context.Context, tableName
var len1, len2 int64
if len(cts) == 2 {
idx := strings.Index(cts[1], ")")
if colType == schemas.Enum && cts[1][0] == '\'' { // enum
switch {
case colType == schemas.Enum && cts[1][0] == '\'': // enum
options := strings.Split(cts[1][0:idx], ",")
col.EnumOptions = make(map[string]int)
for k, v := range options {
@@ -477,7 +478,7 @@ func (db *mysql) GetColumns(queryer core.Queryer, ctx context.Context, tableName
v = strings.Trim(v, "'")
col.EnumOptions[v] = k
}
} else if colType == schemas.Set && cts[1][0] == '\'' {
case colType == schemas.Set && cts[1][0] == '\'':
options := strings.Split(cts[1][0:idx], ",")
col.SetOptions = make(map[string]int)
for k, v := range options {
@@ -485,7 +486,7 @@ func (db *mysql) GetColumns(queryer core.Queryer, ctx context.Context, tableName
v = strings.Trim(v, "'")
col.SetOptions[v] = k
}
} else {
default:
lens := strings.Split(cts[1][0:idx], ",")
len1, err = strconv.ParseInt(strings.TrimSpace(lens[0]), 10, 64)
if err != nil {
+4 -3
View File
@@ -824,13 +824,14 @@ func (db *postgres) Version(ctx context.Context, queryer core.Queryer) (*schemas
// Postgres: PostgreSQL 15.3, compiled by Visual C++ build 1914, 64-bit
// KingbaseES V008R006C008B0014 on x64, compiled by Visual C++ build 1800, 64-bit
// CockroachDB CCL v19.2.4 (x86_64-unknown-linux-gnu, built
if strings.HasPrefix(version, "CockroachDB") {
switch {
case strings.HasPrefix(version, "CockroachDB"):
versions := strings.Split(strings.TrimPrefix(version, "CockroachDB CCL "), " ")
return &schemas.Version{
Number: strings.TrimPrefix(versions[0], "v"),
Edition: "CockroachDB",
}, nil
} else if strings.HasPrefix(version, "PostgreSQL") {
case strings.HasPrefix(version, "PostgreSQL"):
if strings.Contains(version, " on ") {
versions := strings.Split(strings.TrimPrefix(version, "PostgreSQL "), " on ")
return &schemas.Version{
@@ -845,7 +846,7 @@ func (db *postgres) Version(ctx context.Context, queryer core.Queryer) (*schemas
Level: versions[1],
Edition: "PostgreSQL",
}, nil
} else if strings.HasPrefix(version, "KingbaseES") {
case strings.HasPrefix(version, "KingbaseES"):
if strings.Contains(version, " on ") {
versions := strings.Split(strings.TrimPrefix(version, "KingbaseES "), " on ")
return &schemas.Version{
+6 -6
View File
@@ -16,10 +16,10 @@ func TestParsePostgres(t *testing.T) {
{"postgres://auser:password@localhost:5432/db?sslmode=disable", "db", true},
{"postgresql://auser:password@localhost:5432/db?sslmode=disable", "db", true},
{"postg://auser:password@localhost:5432/db?sslmode=disable", "db", false},
//{"postgres://auser:pass with space@localhost:5432/db?sslmode=disable", "db", true},
//{"postgres:// auser : password@localhost:5432/db?sslmode=disable", "db", true},
// {"postgres://auser:pass with space@localhost:5432/db?sslmode=disable", "db", true},
// {"postgres:// auser : password@localhost:5432/db?sslmode=disable", "db", true},
{"postgres://%20auser%20:pass%20with%20space@localhost:5432/db?sslmode=disable", "db", true},
//{"postgres://auser:パスワード@localhost:5432/データベース?sslmode=disable", "データベース", true},
// {"postgres://auser:パスワード@localhost:5432/データベース?sslmode=disable", "データベース", true},
{"dbname=db sslmode=disable", "db", true},
{"user=auser password=password dbname=db sslmode=disable", "db", true},
{"user=auser password='pass word' dbname=db sslmode=disable", "db", true},
@@ -52,10 +52,10 @@ func TestParsePgx(t *testing.T) {
{"postgres://auser:password@localhost:5432/db?sslmode=disable", "db", true},
{"postgresql://auser:password@localhost:5432/db?sslmode=disable", "db", true},
{"postg://auser:password@localhost:5432/db?sslmode=disable", "db", false},
//{"postgres://auser:pass with space@localhost:5432/db?sslmode=disable", "db", true},
//{"postgres:// auser : password@localhost:5432/db?sslmode=disable", "db", true},
// {"postgres://auser:pass with space@localhost:5432/db?sslmode=disable", "db", true},
// {"postgres:// auser : password@localhost:5432/db?sslmode=disable", "db", true},
{"postgres://%20auser%20:pass%20with%20space@localhost:5432/db?sslmode=disable", "db", true},
//{"postgres://auser:パスワード@localhost:5432/データベース?sslmode=disable", "データベース", true},
// {"postgres://auser:パスワード@localhost:5432/データベース?sslmode=disable", "データベース", true},
{"dbname=db sslmode=disable", "db", true},
{"user=auser password=password dbname=db sslmode=disable", "db", true},
{"", "db", false},
+12 -11
View File
@@ -644,7 +644,8 @@ func (engine *Engine) dumpTables(ctx context.Context, tables []*schemas.Table, w
return err
}
} else {
if table.Columns()[i].SQLType.IsBool() || stp.IsBool() || (dstDialect.URI().DBType == schemas.MSSQL && strings.EqualFold(stp.Name, schemas.Bit)) {
switch {
case table.Columns()[i].SQLType.IsBool() || stp.IsBool() || (dstDialect.URI().DBType == schemas.MSSQL && strings.EqualFold(stp.Name, schemas.Bit)):
val, err := strconv.ParseBool(s.String)
if err != nil {
return err
@@ -653,20 +654,20 @@ func (engine *Engine) dumpTables(ctx context.Context, tables []*schemas.Table, w
if _, err = io.WriteString(w, formatBool(val, dstDialect)); err != nil {
return err
}
} else if stp.IsNumeric() {
case stp.IsNumeric():
if _, err = io.WriteString(w, s.String); err != nil {
return err
}
} else if sess.engine.dialect.URI().DBType == schemas.DAMENG && stp.IsTime() && len(s.String) == 25 {
case sess.engine.dialect.URI().DBType == schemas.DAMENG && stp.IsTime() && len(s.String) == 25:
r := strings.ReplaceAll(s.String[:19], "T", " ")
if _, err = io.WriteString(w, "'"+r+"'"); err != nil {
return err
}
} else if len(s.String) == 0 {
case len(s.String) == 0:
if _, err := io.WriteString(w, "''"); err != nil {
return err
}
} else if dstDialect.URI().DBType == schemas.POSTGRES {
case dstDialect.URI().DBType == schemas.POSTGRES:
if dstTable.Columns()[i].SQLType.IsBlob() {
// Postgres has the escape format and we should use that for bytea data
if _, err := fmt.Fprintf(w, "'\\x%x'", s.String); err != nil {
@@ -708,7 +709,7 @@ func (engine *Engine) dumpTables(ctx context.Context, tables []*schemas.Table, w
}
}
}
} else if dstDialect.URI().DBType == schemas.MYSQL {
case dstDialect.URI().DBType == schemas.MYSQL:
loc := controlCharactersRe.FindStringIndex(s.String)
if loc == nil {
if _, err := io.WriteString(w, "'"+strings.ReplaceAll(s.String, "'", "''")+"'"); err != nil {
@@ -719,7 +720,7 @@ func (engine *Engine) dumpTables(ctx context.Context, tables []*schemas.Table, w
return err
}
}
} else if dstDialect.URI().DBType == schemas.SQLITE {
case dstDialect.URI().DBType == schemas.SQLITE:
if dstTable.Columns()[i].SQLType.IsBlob() {
// SQLite has its escape format
if _, err := fmt.Fprintf(w, "X'%x'", s.String); err != nil {
@@ -752,7 +753,7 @@ func (engine *Engine) dumpTables(ctx context.Context, tables []*schemas.Table, w
}
}
}
} else if dstDialect.URI().DBType == schemas.DAMENG || dstDialect.URI().DBType == schemas.ORACLE {
case dstDialect.URI().DBType == schemas.DAMENG || dstDialect.URI().DBType == schemas.ORACLE:
if dstTable.Columns()[i].SQLType.IsBlob() {
// ORACLE/DAMENG uses HEXTORAW
if _, err := fmt.Fprintf(w, "HEXTORAW('%x')", s.String); err != nil {
@@ -765,7 +766,7 @@ func (engine *Engine) dumpTables(ctx context.Context, tables []*schemas.Table, w
return err
}
}
} else if dstDialect.URI().DBType == schemas.MSSQL {
case dstDialect.URI().DBType == schemas.MSSQL:
if dstTable.Columns()[i].SQLType.IsBlob() {
// MSSQL uses CONVERT(VARBINARY(MAX), '0xDEADBEEF', 1)
if _, err := fmt.Fprintf(w, "CONVERT(VARBINARY(MAX), '0x%x', 1)", s.String); err != nil {
@@ -776,7 +777,7 @@ func (engine *Engine) dumpTables(ctx context.Context, tables []*schemas.Table, w
return err
}
}
} else if sess.engine.dialect.URI().DBType == schemas.GBASE8S {
case sess.engine.dialect.URI().DBType == schemas.GBASE8S:
stp.Name = strings.Replace(stp.Name, "SQLT_", "", 1)
if stp.IsTime() && len(s.String) == 20 { // "2025-06-10T07:55:31Z"
t, err := time.Parse(time.RFC3339, s.String)
@@ -792,7 +793,7 @@ func (engine *Engine) dumpTables(ctx context.Context, tables []*schemas.Table, w
return err
}
}
} else {
default:
if _, err = io.WriteString(w, "'"+strings.ReplaceAll(s.String, "'", "''")+"'"); err != nil {
return err
}
+8 -6
View File
@@ -143,11 +143,12 @@ func (statement *Statement) GenCountSQL(beans ...any) (string, []any, error) {
selectSQL := statement.SelectStr
if len(selectSQL) == 0 {
if statement.IsDistinct {
switch {
case statement.IsDistinct:
selectSQL = fmt.Sprintf("count(DISTINCT %s)", statement.ColumnStr())
} else if statement.ColumnStr() != "" {
case statement.ColumnStr() != "":
selectSQL = fmt.Sprintf("count(%s)", statement.ColumnStr())
} else {
default:
selectSQL = "count(*)"
}
}
@@ -317,7 +318,8 @@ func (statement *Statement) GenExistSQL(bean ...any) (string, []any, error) {
tableName = statement.quote(tableName)
buf := builder.NewWriter()
if statement.dialect.URI().DBType == schemas.MSSQL {
switch statement.dialect.URI().DBType {
case schemas.MSSQL:
if _, err := fmt.Fprintf(buf, "SELECT TOP 1 * FROM %s", tableName); err != nil {
return "", nil, err
}
@@ -327,7 +329,7 @@ func (statement *Statement) GenExistSQL(bean ...any) (string, []any, error) {
if err := statement.writeWhere(buf); err != nil {
return "", nil, err
}
} else if statement.dialect.URI().DBType == schemas.ORACLE {
case schemas.ORACLE:
if _, err := fmt.Fprintf(buf, "SELECT * FROM %s", tableName); err != nil {
return "", nil, err
}
@@ -348,7 +350,7 @@ func (statement *Statement) GenExistSQL(bean ...any) (string, []any, error) {
if _, err := fmt.Fprintf(buf, "ROWNUM=1"); err != nil {
return "", nil, err
}
} else {
default:
if _, err := fmt.Fprintf(buf, "SELECT 1 FROM %s", tableName); err != nil {
return "", nil, err
}
+4 -3
View File
@@ -713,15 +713,16 @@ func (statement *Statement) CondDeleted(col *schemas.Column) builder.Cond {
colName = statement.quote(prefix) + "." + statement.quote(col.Name)
}
var cond builder.Cond
if col.SQLType.IsNumeric() {
switch {
case col.SQLType.IsNumeric():
cond = builder.Eq{colName: 0}
} else if col.SQLType.Name == schemas.TimeStamp || col.SQLType.Name == schemas.TimeStampz {
case col.SQLType.Name == schemas.TimeStamp || col.SQLType.Name == schemas.TimeStampz:
tmZone := statement.defaultTimeZone
if col.TimeZone != nil {
tmZone = col.TimeZone
}
cond = builder.Eq{colName: time.Unix(0, 0).In(tmZone).Format("2006-01-02 15:04:05.999999999")}
} else {
default:
cond = builder.Eq{colName: utils.ZeroTime1}
}
+12 -11
View File
@@ -52,11 +52,12 @@ func (statement *Statement) ifAddColUpdate(col *schemas.Column, includeVersion,
return false
}
if statement.IncrColumns.IsColExist(col.Name) {
switch {
case statement.IncrColumns.IsColExist(col.Name):
return false
} else if statement.DecrColumns.IsColExist(col.Name) {
case statement.DecrColumns.IsColExist(col.Name):
return false
} else if statement.ExprColumns.IsColExist(col.Name) {
case statement.ExprColumns.IsColExist(col.Name):
return false
}
@@ -268,33 +269,33 @@ func (statement *Statement) BuildUpdates(tableValue reflect.Value,
}
}
if col.SQLType.IsText() {
switch {
case col.SQLType.IsText():
bytes, err := json.DefaultJSONHandler.Marshal(fieldValue.Interface())
if err != nil {
return nil, nil, err
}
val = string(bytes)
} else if col.SQLType.IsBlob() {
case col.SQLType.IsBlob():
var bytes []byte
var err error
if fieldType.Kind() == reflect.Slice &&
fieldType.Elem().Kind() == reflect.Uint8 {
switch {
case fieldType.Kind() == reflect.Slice && fieldType.Elem().Kind() == reflect.Uint8:
if fieldValue.Len() > 0 {
val = fieldValue.Bytes()
} else {
continue
}
} else if fieldType.Kind() == reflect.Array &&
fieldType.Elem().Kind() == reflect.Uint8 {
case fieldType.Kind() == reflect.Array && fieldType.Elem().Kind() == reflect.Uint8:
val = fieldValue.Slice(0, 0).Interface()
} else {
default:
bytes, err = json.DefaultJSONHandler.Marshal(fieldValue.Interface())
if err != nil {
return nil, nil, err
}
val = bytes
}
} else {
default:
continue
}
default:
+4 -3
View File
@@ -85,7 +85,8 @@ func (statement *Statement) Value2Interface(col *schemas.Column, fieldValue refl
case reflect.String:
return fieldValue.String(), nil
case reflect.Struct:
if fieldType.ConvertibleTo(schemas.TimeType) {
switch {
case fieldType.ConvertibleTo(schemas.TimeType):
t := fieldValue.Convert(schemas.TimeType).Interface().(time.Time)
tf, err := dialects.FormatColumnTime(statement.dialect, statement.defaultTimeZone, col, t)
if val, ok := tf.(string); ok {
@@ -101,13 +102,13 @@ func (statement *Statement) Value2Interface(col *schemas.Column, fieldValue refl
return &DateTimeString{Layout: layout, Str: val}, err
}
return tf, err
} else if fieldType.ConvertibleTo(nullFloatType) {
case fieldType.ConvertibleTo(nullFloatType):
t := fieldValue.Convert(nullFloatType).Interface().(sql.NullFloat64)
if !t.Valid {
return nil, nil
}
return t.Float64, nil
} else if fieldType.ConvertibleTo(bigFloatType) {
case fieldType.ConvertibleTo(bigFloatType):
t := fieldValue.Convert(bigFloatType).Interface().(big.Float)
return t.String(), nil
}
+4 -5
View File
@@ -1,7 +1,6 @@
package migrate
import (
"log"
"os"
"testing"
@@ -51,12 +50,12 @@ func TestMigration(t *testing.T) {
db, err := xorm.NewEngine("sqlite3", dbName)
if err != nil {
log.Fatal(err)
t.Fatal(err)
}
defer db.Close()
if err = db.Ping(); err != nil {
log.Fatal(err)
t.Fatal(err)
}
m := New(db, DefaultOptions, migrations)
@@ -91,11 +90,11 @@ func TestInitSchema(t *testing.T) {
db, err := xorm.NewEngine("sqlite3", dbName)
if err != nil {
log.Fatal(err)
t.Fatal(err)
}
defer db.Close()
if err = db.Ping(); err != nil {
log.Fatal(err)
t.Fatal(err)
}
m := New(db, DefaultOptions, migrations)
+8 -6
View File
@@ -31,17 +31,18 @@ func GetTableName(mapper Mapper, v reflect.Value) string {
return v.Interface().(TableName).TableName()
}
if v.Kind() == reflect.Ptr {
switch {
case v.Kind() == reflect.Ptr:
v = v.Elem()
if v.Type().Implements(tpTableName) {
return v.Interface().(TableName).TableName()
}
} else if v.CanAddr() {
case v.CanAddr():
v1 := v.Addr()
if v1.Type().Implements(tpTableName) {
return v1.Interface().(TableName).TableName()
}
} else {
default:
name, ok := tvCache.Load(v.Type())
if ok {
if name.(string) != "" {
@@ -68,17 +69,18 @@ func GetTableComment(v reflect.Value) string {
return v.Interface().(TableComment).TableComment()
}
if v.Kind() == reflect.Ptr {
switch {
case v.Kind() == reflect.Ptr:
v = v.Elem()
if v.Type().Implements(tpTableComment) {
return v.Interface().(TableComment).TableComment()
}
} else if v.CanAddr() {
case v.CanAddr():
v1 := v.Addr()
if v1.Type().Implements(tpTableComment) {
return v1.Interface().(TableComment).TableComment()
}
} else {
default:
comment, ok := tcCache.Load(v.Type())
if ok {
if comment.(string) != "" {
+8 -7
View File
@@ -303,19 +303,20 @@ func Type2SQLType(t reflect.Type) (st SQLType) {
case reflect.String:
st = SQLType{Varchar, 255, 0}
case reflect.Struct:
if t.ConvertibleTo(TimeType) {
switch {
case t.ConvertibleTo(TimeType):
st = SQLType{DateTime, 0, 0}
} else if t.ConvertibleTo(NullFloat64Type) {
case t.ConvertibleTo(NullFloat64Type):
st = SQLType{Double, 0, 0}
} else if t.ConvertibleTo(NullStringType) {
case t.ConvertibleTo(NullStringType):
st = SQLType{Varchar, 255, 0}
} else if t.ConvertibleTo(NullInt32Type) {
case t.ConvertibleTo(NullInt32Type):
st = SQLType{Integer, 0, 0}
} else if t.ConvertibleTo(NullInt64Type) {
case t.ConvertibleTo(NullInt64Type):
st = SQLType{BigInt, 0, 0}
} else if t.ConvertibleTo(NullBoolType) {
case t.ConvertibleTo(NullBoolType):
st = SQLType{Boolean, 0, 0}
} else {
default:
// TODO need to handle association struct
st = SQLType{Text, 0, 0}
}
+7 -4
View File
@@ -51,17 +51,20 @@ func (session *Session) cacheDelete(table *schemas.Table, tableName, sqlStr stri
var id int64
var pk schemas.PK = make([]any, 0)
for _, col := range pkColumns {
if v, ok := data[col.Name]; !ok {
v, ok := data[col.Name]
if !ok {
return errors.New("no id")
} else if col.SQLType.IsText() {
}
switch {
case col.SQLType.IsText():
pk = append(pk, v)
} else if col.SQLType.IsNumeric() {
case col.SQLType.IsNumeric():
id, err = strconv.ParseInt(v, 10, 64)
if err != nil {
return err
}
pk = append(pk, id)
} else {
default:
return errors.New("not supported primary key type")
}
}
+4 -3
View File
@@ -95,7 +95,8 @@ func (session *Session) find(rowsSlicePtr any, condiBean ...any) error {
tp := tpStruct
if session.statement.RefTable == nil {
if sliceElementType.Kind() == reflect.Ptr {
switch sliceElementType.Kind() {
case reflect.Ptr:
if sliceElementType.Elem().Kind() == reflect.Struct {
pv := reflect.New(sliceElementType.Elem())
if err := session.statement.SetRefValue(pv); err != nil {
@@ -104,12 +105,12 @@ func (session *Session) find(rowsSlicePtr any, condiBean ...any) error {
} else {
tp = tpNonStruct
}
} else if sliceElementType.Kind() == reflect.Struct {
case reflect.Struct:
pv := reflect.New(sliceElementType)
if err := session.statement.SetRefValue(pv); err != nil {
return err
}
} else {
default:
tp = tpNonStruct
}
}
+8 -6
View File
@@ -56,11 +56,12 @@ func (session *Session) get(beans ...any) (bool, error) {
}
beanValue := reflect.ValueOf(beans[0])
if beanValue.Kind() != reflect.Ptr {
switch {
case beanValue.Kind() != reflect.Ptr:
return false, errors.New("needs a pointer to a value")
} else if beanValue.Elem().Kind() == reflect.Ptr {
case beanValue.Elem().Kind() == reflect.Ptr:
return false, errors.New("a pointer to a pointer is not allowed")
} else if beanValue.IsNil() {
case beanValue.IsNil():
return false, ErrObjectIsNil
}
@@ -313,15 +314,16 @@ func (session *Session) cacheGet(bean any, sqlStr string, args ...any) (has bool
var pk schemas.PK = make([]any, len(table.PrimaryKeys))
for i, col := range table.PKColumns() {
if col.SQLType.IsText() {
switch {
case col.SQLType.IsText():
pk[i] = res[i]
} else if col.SQLType.IsNumeric() {
case col.SQLType.IsNumeric():
n, err := strconv.ParseInt(res[i], 10, 64)
if err != nil {
return false, err
}
pk[i] = n
} else {
default:
return false, errors.New("unsupported")
}
}
+12 -9
View File
@@ -152,7 +152,8 @@ func (session *Session) insertMultipleStruct(rowsSlicePtr any) (int64, error) {
fieldValue = reflect.ValueOf(nilValue)
}
}
if (col.IsCreated || col.IsUpdated) && session.statement.UseAutoTime {
switch {
case (col.IsCreated || col.IsUpdated) && session.statement.UseAutoTime:
val, t, err := session.engine.nowTime(col)
if err != nil {
return 0, err
@@ -164,14 +165,14 @@ func (session *Session) insertMultipleStruct(rowsSlicePtr any) (int64, error) {
col := table.GetColumn(colName)
setColumnTime(bean, col, t)
})
} else if col.IsVersion && session.statement.CheckVersion {
case col.IsVersion && session.statement.CheckVersion:
args = append(args, 1)
colName := col.Name
session.afterClosures = append(session.afterClosures, func(bean any) {
col := table.GetColumn(colName)
setColumnInt(bean, col, 1)
})
} else {
default:
arg, err := session.statement.Value2Interface(col, fieldValue)
if err != nil {
return 0, err
@@ -465,11 +466,12 @@ func (session *Session) genInsertColumns(bean any) ([]string, []any, error) {
if len(session.statement.ColumnMap) > 0 && !session.statement.ColumnMap.Contain(col.Name) {
continue
}
if session.statement.IncrColumns.IsColExist(col.Name) {
switch {
case session.statement.IncrColumns.IsColExist(col.Name):
continue
} else if session.statement.DecrColumns.IsColExist(col.Name) {
case session.statement.DecrColumns.IsColExist(col.Name):
continue
} else if session.statement.ExprColumns.IsColExist(col.Name) {
case session.statement.ExprColumns.IsColExist(col.Name):
continue
}
@@ -502,7 +504,8 @@ func (session *Session) genInsertColumns(bean any) ([]string, []any, error) {
}
}
if (col.IsCreated || col.IsUpdated) && session.statement.UseAutoTime /*&& isZero(fieldValue.Interface())*/ {
switch {
case (col.IsCreated || col.IsUpdated) && session.statement.UseAutoTime: /*&& isZero(fieldValue.Interface())*/
// if time is non-empty, then set to auto time
val, t, err := session.engine.nowTime(col)
if err != nil {
@@ -515,9 +518,9 @@ func (session *Session) genInsertColumns(bean any) ([]string, []any, error) {
col := table.GetColumn(colName)
setColumnTime(bean, col, t)
})
} else if col.IsVersion && session.statement.CheckVersion {
case col.IsVersion && session.statement.CheckVersion:
args = append(args, 1)
} else {
default:
arg, err := session.statement.Value2Interface(col, fieldValue)
if err != nil {
return colNames, args, err
+12 -9
View File
@@ -91,7 +91,8 @@ func (session *Session) Update(bean any, condiBean ...any) (int64, error) {
var err error
isMap := t.Kind() == reflect.Map
isStruct := t.Kind() == reflect.Struct
if isStruct {
switch {
case isStruct:
if err := session.statement.SetRefBean(bean); err != nil {
return 0, err
}
@@ -109,7 +110,7 @@ func (session *Session) Update(bean any, condiBean ...any) (int64, error) {
if err != nil {
return 0, err
}
} else if isMap {
case isMap:
colNames = make([]string, 0)
args = make([]any, 0)
bValue := reflect.Indirect(reflect.ValueOf(bean))
@@ -118,7 +119,7 @@ func (session *Session) Update(bean any, condiBean ...any) (int64, error) {
colNames = append(colNames, session.engine.Quote(v.String())+" = ?")
args = append(args, bValue.MapIndex(v).Interface())
}
} else {
default:
return 0, ErrParamsType
}
@@ -270,11 +271,12 @@ func (session *Session) genUpdateColumns(bean any) ([]string, []any, error) {
continue
}
if session.statement.IncrColumns.IsColExist(col.Name) {
switch {
case session.statement.IncrColumns.IsColExist(col.Name):
continue
} else if session.statement.DecrColumns.IsColExist(col.Name) {
case session.statement.DecrColumns.IsColExist(col.Name):
continue
} else if session.statement.ExprColumns.IsColExist(col.Name) {
case session.statement.ExprColumns.IsColExist(col.Name):
continue
}
@@ -286,7 +288,8 @@ func (session *Session) genUpdateColumns(bean any) ([]string, []any, error) {
}
}
if col.IsUpdated && session.statement.UseAutoTime /*&& isZero(fieldValue.Interface())*/ {
switch {
case col.IsUpdated && session.statement.UseAutoTime: /*&& isZero(fieldValue.Interface())*/
// if time is non-empty, then set to auto time
val, t, err := session.engine.nowTime(col)
if err != nil {
@@ -299,9 +302,9 @@ func (session *Session) genUpdateColumns(bean any) ([]string, []any, error) {
col := table.GetColumn(colName)
setColumnTime(bean, col, t)
})
} else if col.IsVersion && session.statement.CheckVersion {
case col.IsVersion && session.statement.CheckVersion:
args = append(args, 1)
} else {
default:
arg, err := session.statement.Value2Interface(col, fieldValue)
if err != nil {
return colNames, args, err
+8 -7
View File
@@ -157,9 +157,10 @@ func (session *Session) SyncWithOptions(opts SyncOptions, beans ...any) (*SyncRe
err = nil
expectedType := engine.dialect.SQLType(col)
curType := engine.dialect.SQLType(oriCol)
if expectedType != curType {
if expectedType == schemas.Text &&
strings.HasPrefix(curType, schemas.Varchar) {
switch {
case expectedType != curType:
switch {
case expectedType == schemas.Text && strings.HasPrefix(curType, schemas.Varchar):
// currently only support mysql & postgres
if engine.dialect.URI().DBType == schemas.MYSQL ||
engine.dialect.URI().DBType == schemas.POSTGRES {
@@ -170,7 +171,7 @@ func (session *Session) SyncWithOptions(opts SyncOptions, beans ...any) (*SyncRe
engine.logger.Warnf("Table %s column %s db type is %s, struct type is %s\n",
tbNameWithSchema, col.Name, curType, expectedType)
}
} else if strings.HasPrefix(curType, schemas.Varchar) && strings.HasPrefix(expectedType, schemas.Varchar) {
case strings.HasPrefix(curType, schemas.Varchar) && strings.HasPrefix(expectedType, schemas.Varchar):
if engine.dialect.URI().DBType == schemas.POSTGRES ||
engine.dialect.URI().DBType == schemas.MYSQL {
if oriCol.Length < col.Length {
@@ -179,7 +180,7 @@ func (session *Session) SyncWithOptions(opts SyncOptions, beans ...any) (*SyncRe
_, err = session.exec(engine.dialect.ModifyColumnSQL(tbNameWithSchema, col))
}
}
} else {
default:
if !(strings.HasPrefix(curType, expectedType) && curType[len(expectedType)] == '(') {
if !strings.EqualFold(schemas.SQLTypeName(curType), engine.dialect.Alias(schemas.SQLTypeName(expectedType))) {
engine.logger.Warnf("Table %s column %s db type is %s, struct type is %s",
@@ -187,7 +188,7 @@ func (session *Session) SyncWithOptions(opts SyncOptions, beans ...any) (*SyncRe
}
}
}
} else if expectedType == schemas.Varchar {
case expectedType == schemas.Varchar:
if engine.dialect.URI().DBType == schemas.POSTGRES ||
engine.dialect.URI().DBType == schemas.MYSQL {
if oriCol.Length < col.Length {
@@ -196,7 +197,7 @@ func (session *Session) SyncWithOptions(opts SyncOptions, beans ...any) (*SyncRe
_, err = session.exec(engine.dialect.ModifyColumnSQL(tbNameWithSchema, col))
}
}
} else if col.Comment != oriCol.Comment {
case col.Comment != oriCol.Comment:
if engine.dialect.URI().DBType == schemas.POSTGRES ||
engine.dialect.URI().DBType == schemas.GBASE8S ||
engine.dialect.URI().DBType == schemas.MYSQL {
+4 -3
View File
@@ -249,11 +249,12 @@ func (parser *Parser) parseFieldWithTags(table *schemas.Table, fieldIndex int, f
}
if col.SQLType.Name == "" {
if col.IsJSONB { // check is jsonb first because it is also json
switch {
case col.IsJSONB: // check is jsonb first because it is also json
col.SQLType = schemas.SQLType{Name: schemas.Jsonb}
} else if col.IsJSON {
case col.IsJSON:
col.SQLType = schemas.SQLType{Name: schemas.Json}
} else {
default:
var err error
col.SQLType, err = parser.getSQLTypeByType(field.Type)
if err != nil {
+9 -7
View File
@@ -580,7 +580,8 @@ func TestCollate(t *testing.T) {
UserId: 1,
Name: "Test",
})
if testEngine.Dialect().URI().DBType == schemas.MYSQL {
switch testEngine.Dialect().URI().DBType {
case schemas.MYSQL:
ver, err1 := testEngine.DBVersion()
assert.NoError(t, err1)
@@ -602,9 +603,9 @@ func TestCollate(t *testing.T) {
break
}
}
} else if testEngine.Dialect().URI().DBType == schemas.MSSQL {
case schemas.MSSQL:
assert.Error(t, err)
} else {
default:
assert.NoError(t, err)
}
@@ -614,12 +615,13 @@ func TestCollate(t *testing.T) {
}
var newCollation string
if testEngine.Dialect().URI().DBType == schemas.MYSQL {
switch testEngine.Dialect().URI().DBType {
case schemas.MYSQL:
newCollation = "utf8mb4_bin"
} else if testEngine.Dialect().URI().DBType != schemas.MSSQL {
newCollation = "Latin1_General_CS_AS"
} else {
case schemas.MSSQL:
return
default:
newCollation = "Latin1_General_CS_AS"
}
alterSQL := testEngine.Dialect().ModifyColumnSQL("test_collate_column", &schemas.Column{
+1 -3
View File
@@ -586,9 +586,7 @@ func TestDecimal(t *testing.T) {
type MyArray [20]byte
func (d *MyArray) FromDB(data []byte) error {
for i, b := range data[:20] {
(*d)[i] = b
}
copy((*d)[:], data[:20])
return nil
}