Merge branch 'master' into master
This commit is contained in:
commit
b8bdb512f0
767
.drone.yml
767
.drone.yml
|
@ -2,57 +2,288 @@
|
|||
kind: pipeline
|
||||
name: testing
|
||||
steps:
|
||||
- name: restore-cache
|
||||
image: meltwater/drone-cache
|
||||
pull: always
|
||||
settings:
|
||||
backend: "filesystem"
|
||||
restore: true
|
||||
cache_key: '{{ .Repo.Name }}_{{ checksum "go.mod" }}_{{ checksum "go.sum" }}_{{ arch }}_{{ os }}'
|
||||
archive_format: "gzip"
|
||||
filesystem_cache_root: "/go"
|
||||
mount:
|
||||
- pkg.mod
|
||||
- pkg.build
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /go
|
||||
|
||||
- name: test-vet
|
||||
image: golang:1.11 # The lowest golang requirement
|
||||
image: golang:1.15
|
||||
environment:
|
||||
GO111MODULE: "on"
|
||||
GOPROXY: "https://goproxy.cn"
|
||||
GOPROXY: "https://goproxy.io"
|
||||
CGO_ENABLED: 1
|
||||
GOMODCACHE: '/drone/src/pkg.mod'
|
||||
GOCACHE: '/drone/src/pkg.build'
|
||||
commands:
|
||||
- make vet
|
||||
- make test
|
||||
- make fmt-check
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /go
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- pull_request
|
||||
|
||||
- name: test-sqlite
|
||||
image: golang:1.12
|
||||
- name: rebuild-cache
|
||||
image: meltwater/drone-cache
|
||||
pull: true
|
||||
settings:
|
||||
backend: "filesystem"
|
||||
rebuild: true
|
||||
cache_key: '{{ .Repo.Name }}_{{ checksum "go.mod" }}_{{ checksum "go.sum" }}_{{ arch }}_{{ os }}'
|
||||
archive_format: "gzip"
|
||||
filesystem_cache_root: "/go"
|
||||
mount:
|
||||
- pkg.mod
|
||||
- pkg.build
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /go
|
||||
|
||||
volumes:
|
||||
- name: cache
|
||||
temp: {}
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
name: test-sqlite
|
||||
depends_on:
|
||||
- testing
|
||||
steps:
|
||||
- name: restore-cache
|
||||
image: meltwater/drone-cache:dev
|
||||
pull: always
|
||||
settings:
|
||||
backend: "filesystem"
|
||||
restore: true
|
||||
cache_key: '{{ .Repo.Name }}_{{ checksum "go.mod" }}_{{ checksum "go.sum" }}_{{ arch }}_{{ os }}'
|
||||
archive_format: "gzip"
|
||||
filesystem_cache_root: "/go"
|
||||
mount:
|
||||
- pkg.mod
|
||||
- pkg.build
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /go
|
||||
|
||||
- name: test-sqlite3
|
||||
image: golang:1.15
|
||||
environment:
|
||||
GO111MODULE: "on"
|
||||
GOPROXY: "https://goproxy.cn"
|
||||
GOPROXY: "https://goproxy.io"
|
||||
CGO_ENABLED: 1
|
||||
GOMODCACHE: '/drone/src/pkg.mod'
|
||||
GOCACHE: '/drone/src/pkg.build'
|
||||
commands:
|
||||
- make test-sqlite3
|
||||
- TEST_CACHE_ENABLE=true make test-sqlite3
|
||||
- TEST_QUOTE_POLICY=reserved make test-sqlite3
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /go
|
||||
|
||||
- name: test-sqlite
|
||||
image: golang:1.15
|
||||
environment:
|
||||
GO111MODULE: "on"
|
||||
GOPROXY: "https://goproxy.io"
|
||||
CGO_ENABLED: 1
|
||||
GOMODCACHE: '/drone/src/pkg.mod'
|
||||
GOCACHE: '/drone/src/pkg.build'
|
||||
commands:
|
||||
- make test-sqlite
|
||||
- TEST_CACHE_ENABLE=true make test-sqlite
|
||||
- TEST_QUOTE_POLICY=reserved make test-sqlite
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- pull_request
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /go
|
||||
|
||||
- name: rebuild-cache
|
||||
image: meltwater/drone-cache:dev
|
||||
pull: true
|
||||
settings:
|
||||
backend: "filesystem"
|
||||
rebuild: true
|
||||
cache_key: '{{ .Repo.Name }}_{{ checksum "go.mod" }}_{{ checksum "go.sum" }}_{{ arch }}_{{ os }}'
|
||||
archive_format: "gzip"
|
||||
filesystem_cache_root: "/go"
|
||||
mount:
|
||||
- pkg.mod
|
||||
- pkg.build
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /go
|
||||
|
||||
volumes:
|
||||
- name: cache
|
||||
temp: {}
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
name: test-mysql
|
||||
depends_on:
|
||||
- testing
|
||||
steps:
|
||||
- name: restore-cache
|
||||
image: meltwater/drone-cache
|
||||
pull: always
|
||||
settings:
|
||||
backend: "filesystem"
|
||||
restore: true
|
||||
cache_key: '{{ .Repo.Name }}_{{ checksum "go.mod" }}_{{ checksum "go.sum" }}_{{ arch }}_{{ os }}'
|
||||
archive_format: "gzip"
|
||||
filesystem_cache_root: "/go"
|
||||
mount:
|
||||
- pkg.mod
|
||||
- pkg.build
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /go
|
||||
|
||||
- name: test-mysql
|
||||
image: golang:1.12
|
||||
image: golang:1.15
|
||||
environment:
|
||||
GO111MODULE: "on"
|
||||
GOPROXY: "https://goproxy.cn"
|
||||
GOPROXY: "https://goproxy.io"
|
||||
CGO_ENABLED: 1
|
||||
GOMODCACHE: '/drone/src/pkg.mod'
|
||||
GOCACHE: '/drone/src/pkg.build'
|
||||
TEST_MYSQL_HOST: mysql
|
||||
TEST_MYSQL_CHARSET: utf8
|
||||
TEST_MYSQL_DBNAME: xorm_test
|
||||
TEST_MYSQL_USERNAME: root
|
||||
TEST_MYSQL_PASSWORD:
|
||||
commands:
|
||||
- make test
|
||||
- make test-mysql
|
||||
- TEST_CACHE_ENABLE=true make test-mysql
|
||||
- TEST_QUOTE_POLICY=reserved make test-mysql
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /go
|
||||
|
||||
- name: test-mysql-utf8mb4
|
||||
image: golang:1.15
|
||||
depends_on:
|
||||
- test-mysql
|
||||
environment:
|
||||
GO111MODULE: "on"
|
||||
GOPROXY: "https://goproxy.io"
|
||||
CGO_ENABLED: 1
|
||||
GOMODCACHE: '/drone/src/pkg.mod'
|
||||
GOCACHE: '/drone/src/pkg.build'
|
||||
TEST_MYSQL_HOST: mysql
|
||||
TEST_MYSQL_CHARSET: utf8mb4
|
||||
TEST_MYSQL_DBNAME: xorm_test
|
||||
TEST_MYSQL_USERNAME: root
|
||||
TEST_MYSQL_PASSWORD:
|
||||
commands:
|
||||
- make test-mysql
|
||||
- TEST_CACHE_ENABLE=true make test-mysql
|
||||
- TEST_QUOTE_POLICY=reserved make test-mysql
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- pull_request
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /go
|
||||
|
||||
- name: test-mysql8
|
||||
image: golang:1.12
|
||||
- name: test-mymysql
|
||||
pull: default
|
||||
image: golang:1.15
|
||||
depends_on:
|
||||
- test-mysql-utf8mb4
|
||||
environment:
|
||||
GO111MODULE: "on"
|
||||
GOPROXY: "https://goproxy.cn"
|
||||
GOPROXY: "https://goproxy.io"
|
||||
CGO_ENABLED: 1
|
||||
GOMODCACHE: '/drone/src/pkg.mod'
|
||||
GOCACHE: '/drone/src/pkg.build'
|
||||
TEST_MYSQL_HOST: mysql:3306
|
||||
TEST_MYSQL_DBNAME: xorm_test
|
||||
TEST_MYSQL_USERNAME: root
|
||||
TEST_MYSQL_PASSWORD:
|
||||
commands:
|
||||
- make test-mymysql
|
||||
- TEST_CACHE_ENABLE=true make test-mymysql
|
||||
- TEST_QUOTE_POLICY=reserved make test-mymysql
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /go
|
||||
|
||||
- name: rebuild-cache
|
||||
image: meltwater/drone-cache
|
||||
depends_on:
|
||||
- test-mysql
|
||||
- test-mysql-utf8mb4
|
||||
- test-mymysql
|
||||
pull: true
|
||||
settings:
|
||||
backend: "filesystem"
|
||||
rebuild: true
|
||||
cache_key: '{{ .Repo.Name }}_{{ checksum "go.mod" }}_{{ checksum "go.sum" }}_{{ arch }}_{{ os }}'
|
||||
archive_format: "gzip"
|
||||
filesystem_cache_root: "/go"
|
||||
mount:
|
||||
- pkg.mod
|
||||
- pkg.build
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /go
|
||||
|
||||
volumes:
|
||||
- name: cache
|
||||
temp: {}
|
||||
|
||||
services:
|
||||
- name: mysql
|
||||
pull: default
|
||||
image: mysql:5.7
|
||||
environment:
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: yes
|
||||
MYSQL_DATABASE: xorm_test
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
name: test-mysql8
|
||||
depends_on:
|
||||
- test-mysql
|
||||
- test-sqlite
|
||||
steps:
|
||||
- name: restore-cache
|
||||
image: meltwater/drone-cache
|
||||
pull: always
|
||||
settings:
|
||||
backend: "filesystem"
|
||||
restore: true
|
||||
cache_key: '{{ .Repo.Name }}_{{ checksum "go.mod" }}_{{ checksum "go.sum" }}_{{ arch }}_{{ os }}'
|
||||
archive_format: "gzip"
|
||||
filesystem_cache_root: "/go"
|
||||
mount:
|
||||
- pkg.mod
|
||||
- pkg.build
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /go
|
||||
|
||||
- name: test-mysql8
|
||||
image: golang:1.15
|
||||
environment:
|
||||
GO111MODULE: "on"
|
||||
GOPROXY: "https://goproxy.io"
|
||||
CGO_ENABLED: 1
|
||||
GOMODCACHE: '/drone/src/pkg.mod'
|
||||
GOCACHE: '/drone/src/pkg.build'
|
||||
TEST_MYSQL_HOST: mysql8
|
||||
TEST_MYSQL_CHARSET: utf8mb4
|
||||
TEST_MYSQL_DBNAME: xorm_test
|
||||
|
@ -62,19 +293,71 @@ steps:
|
|||
- make test-mysql
|
||||
- TEST_CACHE_ENABLE=true make test-mysql
|
||||
- TEST_QUOTE_POLICY=reserved make test-mysql
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- pull_request
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /go
|
||||
|
||||
- name: test-mysql-utf8mb4
|
||||
image: golang:1.12
|
||||
- name: rebuild-cache
|
||||
image: meltwater/drone-cache:dev
|
||||
pull: true
|
||||
depends_on:
|
||||
- test-mysql
|
||||
- test-mysql8
|
||||
settings:
|
||||
backend: "filesystem"
|
||||
rebuild: true
|
||||
cache_key: '{{ .Repo.Name }}_{{ checksum "go.mod" }}_{{ checksum "go.sum" }}_{{ arch }}_{{ os }}'
|
||||
archive_format: "gzip"
|
||||
filesystem_cache_root: "/go"
|
||||
mount:
|
||||
- pkg.mod
|
||||
- pkg.build
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /go
|
||||
|
||||
volumes:
|
||||
- name: cache
|
||||
temp: {}
|
||||
|
||||
services:
|
||||
- name: mysql8
|
||||
pull: default
|
||||
image: mysql:8.0
|
||||
environment:
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: yes
|
||||
MYSQL_DATABASE: xorm_test
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
name: test-mariadb
|
||||
depends_on:
|
||||
- test-mysql8
|
||||
steps:
|
||||
- name: restore-cache
|
||||
image: meltwater/drone-cache
|
||||
pull: always
|
||||
settings:
|
||||
backend: "filesystem"
|
||||
restore: true
|
||||
cache_key: '{{ .Repo.Name }}_{{ checksum "go.mod" }}_{{ checksum "go.sum" }}_{{ arch }}_{{ os }}'
|
||||
archive_format: "gzip"
|
||||
filesystem_cache_root: "/go"
|
||||
mount:
|
||||
- pkg.mod
|
||||
- pkg.build
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /go
|
||||
|
||||
- name: test-mariadb
|
||||
image: golang:1.15
|
||||
environment:
|
||||
GO111MODULE: "on"
|
||||
GOPROXY: "https://goproxy.cn"
|
||||
TEST_MYSQL_HOST: mysql
|
||||
GOPROXY: "https://goproxy.io"
|
||||
CGO_ENABLED: 1
|
||||
GOMODCACHE: '/drone/src/pkg.mod'
|
||||
GOCACHE: '/drone/src/pkg.build'
|
||||
TEST_MYSQL_HOST: mariadb
|
||||
TEST_MYSQL_CHARSET: utf8mb4
|
||||
TEST_MYSQL_DBNAME: xorm_test
|
||||
TEST_MYSQL_USERNAME: root
|
||||
|
@ -83,38 +366,71 @@ steps:
|
|||
- make test-mysql
|
||||
- TEST_CACHE_ENABLE=true make test-mysql
|
||||
- TEST_QUOTE_POLICY=reserved make test-mysql
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- pull_request
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /go
|
||||
|
||||
- name: test-mymysql
|
||||
pull: default
|
||||
image: golang:1.12
|
||||
- name: rebuild-cache
|
||||
image: meltwater/drone-cache:dev
|
||||
depends_on:
|
||||
- test-mysql-utf8mb4
|
||||
- test-mariadb
|
||||
pull: true
|
||||
settings:
|
||||
backend: "filesystem"
|
||||
rebuild: true
|
||||
cache_key: '{{ .Repo.Name }}_{{ checksum "go.mod" }}_{{ checksum "go.sum" }}_{{ arch }}_{{ os }}'
|
||||
archive_format: "gzip"
|
||||
filesystem_cache_root: "/go"
|
||||
mount:
|
||||
- pkg.mod
|
||||
- pkg.build
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /go
|
||||
|
||||
volumes:
|
||||
- name: cache
|
||||
temp: {}
|
||||
|
||||
services:
|
||||
- name: mariadb
|
||||
pull: default
|
||||
image: mariadb:10.4
|
||||
environment:
|
||||
GO111MODULE: "on"
|
||||
GOPROXY: "https://goproxy.cn"
|
||||
TEST_MYSQL_HOST: mysql:3306
|
||||
TEST_MYSQL_DBNAME: xorm_test
|
||||
TEST_MYSQL_USERNAME: root
|
||||
TEST_MYSQL_PASSWORD:
|
||||
commands:
|
||||
- make test-mymysql
|
||||
- TEST_CACHE_ENABLE=true make test-mymysql
|
||||
- TEST_QUOTE_POLICY=reserved make test-mymysql
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- pull_request
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: yes
|
||||
MYSQL_DATABASE: xorm_test
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
name: test-postgres
|
||||
depends_on:
|
||||
- test-mariadb
|
||||
steps:
|
||||
- name: restore-cache
|
||||
image: meltwater/drone-cache
|
||||
pull: always
|
||||
settings:
|
||||
backend: "filesystem"
|
||||
restore: true
|
||||
cache_key: '{{ .Repo.Name }}_{{ checksum "go.mod" }}_{{ checksum "go.sum" }}_{{ arch }}_{{ os }}'
|
||||
archive_format: "gzip"
|
||||
filesystem_cache_root: "/go"
|
||||
mount:
|
||||
- pkg.mod
|
||||
- pkg.build
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /go
|
||||
|
||||
- name: test-postgres
|
||||
pull: default
|
||||
image: golang:1.12
|
||||
image: golang:1.15
|
||||
environment:
|
||||
GO111MODULE: "on"
|
||||
GOPROXY: "https://goproxy.cn"
|
||||
GOPROXY: "https://goproxy.io"
|
||||
CGO_ENABLED: 1
|
||||
GOMODCACHE: '/drone/src/pkg.mod'
|
||||
GOCACHE: '/drone/src/pkg.build'
|
||||
TEST_PGSQL_HOST: pgsql
|
||||
TEST_PGSQL_DBNAME: xorm_test
|
||||
TEST_PGSQL_USERNAME: postgres
|
||||
|
@ -123,19 +439,21 @@ steps:
|
|||
- make test-postgres
|
||||
- TEST_CACHE_ENABLE=true make test-postgres
|
||||
- TEST_QUOTE_POLICY=reserved make test-postgres
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- pull_request
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /go
|
||||
|
||||
- name: test-postgres-schema
|
||||
pull: default
|
||||
image: golang:1.12
|
||||
image: golang:1.15
|
||||
depends_on:
|
||||
- test-postgres
|
||||
environment:
|
||||
GO111MODULE: "on"
|
||||
GOPROXY: "https://goproxy.cn"
|
||||
GOPROXY: "https://goproxy.io"
|
||||
CGO_ENABLED: 1
|
||||
GOMODCACHE: '/drone/src/pkg.mod'
|
||||
GOCACHE: '/drone/src/pkg.build'
|
||||
TEST_PGSQL_HOST: pgsql
|
||||
TEST_PGSQL_SCHEMA: xorm
|
||||
TEST_PGSQL_DBNAME: xorm_test
|
||||
|
@ -145,17 +463,72 @@ steps:
|
|||
- make test-postgres
|
||||
- TEST_CACHE_ENABLE=true make test-postgres
|
||||
- TEST_QUOTE_POLICY=reserved make test-postgres
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- pull_request
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /go
|
||||
|
||||
- name: rebuild-cache
|
||||
image: meltwater/drone-cache:dev
|
||||
pull: true
|
||||
depends_on:
|
||||
- test-postgres-schema
|
||||
settings:
|
||||
backend: "filesystem"
|
||||
rebuild: true
|
||||
cache_key: '{{ .Repo.Name }}_{{ checksum "go.mod" }}_{{ checksum "go.sum" }}_{{ arch }}_{{ os }}'
|
||||
archive_format: "gzip"
|
||||
filesystem_cache_root: "/go"
|
||||
mount:
|
||||
- pkg.mod
|
||||
- pkg.build
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /go
|
||||
|
||||
volumes:
|
||||
- name: cache
|
||||
temp: {}
|
||||
|
||||
services:
|
||||
- name: pgsql
|
||||
pull: default
|
||||
image: postgres:9.5
|
||||
environment:
|
||||
POSTGRES_DB: xorm_test
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
name: test-mssql
|
||||
depends_on:
|
||||
- test-postgres
|
||||
steps:
|
||||
- name: restore-cache
|
||||
image: meltwater/drone-cache
|
||||
pull: always
|
||||
settings:
|
||||
backend: "filesystem"
|
||||
restore: true
|
||||
cache_key: '{{ .Repo.Name }}_{{ checksum "go.mod" }}_{{ checksum "go.sum" }}_{{ arch }}_{{ os }}'
|
||||
archive_format: "gzip"
|
||||
filesystem_cache_root: "/go"
|
||||
mount:
|
||||
- pkg.mod
|
||||
- pkg.build
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /go
|
||||
|
||||
- name: test-mssql
|
||||
pull: default
|
||||
image: golang:1.12
|
||||
image: golang:1.15
|
||||
environment:
|
||||
GO111MODULE: "on"
|
||||
GOPROXY: "https://goproxy.cn"
|
||||
GOPROXY: "https://goproxy.io"
|
||||
CGO_ENABLED: 1
|
||||
GOMODCACHE: '/drone/src/pkg.mod'
|
||||
GOCACHE: '/drone/src/pkg.build'
|
||||
TEST_MSSQL_HOST: mssql
|
||||
TEST_MSSQL_DBNAME: xorm_test
|
||||
TEST_MSSQL_USERNAME: sa
|
||||
|
@ -164,17 +537,71 @@ steps:
|
|||
- make test-mssql
|
||||
- TEST_CACHE_ENABLE=true make test-mssql
|
||||
- TEST_QUOTE_POLICY=reserved make test-mssql
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- pull_request
|
||||
- TEST_MSSQL_DEFAULT_VARCHAR=NVARCHAR TEST_MSSQL_DEFAULT_CHAR=NCHAR make test-mssql
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /go
|
||||
|
||||
- name: rebuild-cache
|
||||
image: meltwater/drone-cache:dev
|
||||
pull: true
|
||||
settings:
|
||||
backend: "filesystem"
|
||||
rebuild: true
|
||||
cache_key: '{{ .Repo.Name }}_{{ checksum "go.mod" }}_{{ checksum "go.sum" }}_{{ arch }}_{{ os }}'
|
||||
archive_format: "gzip"
|
||||
filesystem_cache_root: "/go"
|
||||
mount:
|
||||
- pkg.mod
|
||||
- pkg.build
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /go
|
||||
|
||||
volumes:
|
||||
- name: cache
|
||||
temp: {}
|
||||
|
||||
services:
|
||||
- name: mssql
|
||||
pull: default
|
||||
image: microsoft/mssql-server-linux:latest
|
||||
environment:
|
||||
ACCEPT_EULA: Y
|
||||
SA_PASSWORD: yourStrong(!)Password
|
||||
MSSQL_PID: Developer
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
name: test-tidb
|
||||
depends_on:
|
||||
- test-mssql
|
||||
steps:
|
||||
- name: restore-cache
|
||||
image: meltwater/drone-cache
|
||||
pull: always
|
||||
settings:
|
||||
backend: "filesystem"
|
||||
restore: true
|
||||
cache_key: '{{ .Repo.Name }}_{{ checksum "go.mod" }}_{{ checksum "go.sum" }}_{{ arch }}_{{ os }}'
|
||||
archive_format: "gzip"
|
||||
filesystem_cache_root: "/go"
|
||||
mount:
|
||||
- pkg.mod
|
||||
- pkg.build
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /go
|
||||
|
||||
- name: test-tidb
|
||||
pull: default
|
||||
image: golang:1.12
|
||||
image: golang:1.15
|
||||
environment:
|
||||
GO111MODULE: "on"
|
||||
GOPROXY: "https://goproxy.cn"
|
||||
GOPROXY: "https://goproxy.io"
|
||||
CGO_ENABLED: 1
|
||||
GOMODCACHE: '/drone/src/pkg.mod'
|
||||
GOCACHE: '/drone/src/pkg.build'
|
||||
TEST_TIDB_HOST: "tidb:4000"
|
||||
TEST_TIDB_DBNAME: xorm_test
|
||||
TEST_TIDB_USERNAME: root
|
||||
|
@ -183,17 +610,66 @@ steps:
|
|||
- make test-tidb
|
||||
- TEST_CACHE_ENABLE=true make test-tidb
|
||||
- TEST_QUOTE_POLICY=reserved make test-tidb
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- pull_request
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /go
|
||||
|
||||
- name: rebuild-cache
|
||||
image: meltwater/drone-cache:dev
|
||||
pull: true
|
||||
settings:
|
||||
backend: "filesystem"
|
||||
rebuild: true
|
||||
cache_key: '{{ .Repo.Name }}_{{ checksum "go.mod" }}_{{ checksum "go.sum" }}_{{ arch }}_{{ os }}'
|
||||
archive_format: "gzip"
|
||||
filesystem_cache_root: "/go"
|
||||
mount:
|
||||
- pkg.mod
|
||||
- pkg.build
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /go
|
||||
|
||||
volumes:
|
||||
- name: cache
|
||||
temp: {}
|
||||
|
||||
services:
|
||||
- name: tidb
|
||||
pull: default
|
||||
image: pingcap/tidb:v3.0.3
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
name: test-cockroach
|
||||
depends_on:
|
||||
- test-tidb
|
||||
steps:
|
||||
- name: restore-cache
|
||||
image: meltwater/drone-cache
|
||||
pull: always
|
||||
settings:
|
||||
backend: "filesystem"
|
||||
restore: true
|
||||
cache_key: '{{ .Repo.Name }}_{{ checksum "go.mod" }}_{{ checksum "go.sum" }}_{{ arch }}_{{ os }}'
|
||||
archive_format: "gzip"
|
||||
filesystem_cache_root: "/go"
|
||||
mount:
|
||||
- pkg.mod
|
||||
- pkg.build
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /go
|
||||
|
||||
- name: test-cockroach
|
||||
pull: default
|
||||
image: golang:1.13
|
||||
image: golang:1.15
|
||||
environment:
|
||||
GO111MODULE: "on"
|
||||
GOPROXY: "https://goproxy.cn"
|
||||
GOPROXY: "https://goproxy.io"
|
||||
CGO_ENABLED: 1
|
||||
GOMODCACHE: '/drone/src/pkg.mod'
|
||||
GOCACHE: '/drone/src/pkg.build'
|
||||
TEST_COCKROACH_HOST: "cockroach:26257"
|
||||
TEST_COCKROACH_DBNAME: xorm_test
|
||||
TEST_COCKROACH_USERNAME: root
|
||||
|
@ -202,103 +678,62 @@ steps:
|
|||
- sleep 10
|
||||
- make test-cockroach
|
||||
- TEST_CACHE_ENABLE=true make test-cockroach
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- pull_request
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /go
|
||||
|
||||
- name: merge_coverage
|
||||
pull: default
|
||||
image: golang:1.12
|
||||
environment:
|
||||
GO111MODULE: "on"
|
||||
GOPROXY: "https://goproxy.cn"
|
||||
depends_on:
|
||||
- test-vet
|
||||
- test-sqlite
|
||||
- test-mysql
|
||||
- test-mysql8
|
||||
- test-mymysql
|
||||
- test-postgres
|
||||
- test-postgres-schema
|
||||
- test-mssql
|
||||
- test-tidb
|
||||
- test-cockroach
|
||||
commands:
|
||||
- make coverage
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- pull_request
|
||||
- name: rebuild-cache
|
||||
image: meltwater/drone-cache:dev
|
||||
pull: true
|
||||
settings:
|
||||
backend: "filesystem"
|
||||
rebuild: true
|
||||
cache_key: '{{ .Repo.Name }}_{{ checksum "go.mod" }}_{{ checksum "go.sum" }}_{{ arch }}_{{ os }}'
|
||||
archive_format: "gzip"
|
||||
filesystem_cache_root: "/go"
|
||||
mount:
|
||||
- pkg.mod
|
||||
- pkg.build
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /go
|
||||
|
||||
volumes:
|
||||
- name: cache
|
||||
temp: {}
|
||||
|
||||
services:
|
||||
|
||||
- name: mysql
|
||||
pull: default
|
||||
image: mysql:5.7
|
||||
environment:
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: yes
|
||||
MYSQL_DATABASE: xorm_test
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- tag
|
||||
- pull_request
|
||||
|
||||
- name: mysql8
|
||||
pull: default
|
||||
image: mysql:8.0
|
||||
environment:
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: yes
|
||||
MYSQL_DATABASE: xorm_test
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- tag
|
||||
- pull_request
|
||||
|
||||
- name: pgsql
|
||||
pull: default
|
||||
image: postgres:9.5
|
||||
environment:
|
||||
POSTGRES_DB: xorm_test
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: 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:
|
||||
event:
|
||||
- push
|
||||
- tag
|
||||
- pull_request
|
||||
|
||||
- name: tidb
|
||||
pull: default
|
||||
image: pingcap/tidb:v3.0.3
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- tag
|
||||
- pull_request
|
||||
|
||||
- name: cockroach
|
||||
pull: default
|
||||
image: cockroachdb/cockroach:v19.2.4
|
||||
commands:
|
||||
- /cockroach/cockroach start --insecure
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
name: merge_coverage
|
||||
depends_on:
|
||||
- testing
|
||||
- test-sqlite
|
||||
- test-mysql
|
||||
- test-mysql8
|
||||
- test-mariadb
|
||||
- test-postgres
|
||||
- test-mssql
|
||||
- test-tidb
|
||||
- test-cockroach
|
||||
steps:
|
||||
- name: merge_coverage
|
||||
pull: default
|
||||
image: golang:1.15
|
||||
environment:
|
||||
GO111MODULE: "on"
|
||||
GOPROXY: "https://goproxy.io"
|
||||
commands:
|
||||
- make coverage
|
||||
when:
|
||||
branch:
|
||||
- master
|
||||
event:
|
||||
- push
|
||||
- tag
|
||||
- pull_request
|
||||
- push
|
||||
- pull_request
|
||||
|
|
|
@ -36,3 +36,4 @@ test.db.sql
|
|||
*coverage.out
|
||||
test.db
|
||||
integrations/*.sql
|
||||
integrations/test_sqlite*
|
62
CHANGELOG.md
62
CHANGELOG.md
|
@ -3,6 +3,68 @@
|
|||
This changelog goes through all the changes that have been made in each release
|
||||
without substantial changes to our git log.
|
||||
|
||||
## [1.0.7](https://gitea.com/xorm/xorm/pulls?q=&type=all&state=closed&milestone=1336) - 2021-01-21
|
||||
|
||||
* BUGFIXES
|
||||
* Fix bug for mssql (#1854)
|
||||
* MISC
|
||||
* fix_bugs_for_mssql (#1852)
|
||||
|
||||
## [1.0.6](https://gitea.com/xorm/xorm/pulls?q=&type=all&state=closed&milestone=1308) - 2021-01-05
|
||||
|
||||
* BUGFIXES
|
||||
* Fix bug when modify column on mssql (#1849)
|
||||
* Fix find and count bug with cols (#1826)
|
||||
* Fix update bug (#1823)
|
||||
* Fix json tag with other type (#1822)
|
||||
* ENHANCEMENTS
|
||||
* prevent panic when struct with unexport field (#1839)
|
||||
* Automatically convert datetime to int64 (#1715)
|
||||
* MISC
|
||||
* Fix index (#1841)
|
||||
* Performance improvement for columnsbyName (#1788)
|
||||
|
||||
## [1.0.5](https://gitea.com/xorm/xorm/pulls?q=&type=all&state=closed&milestone=1299) - 2020-09-08
|
||||
|
||||
* BUGFIXES
|
||||
* Fix bug of ToDB when update on a nil pointer (#1786)
|
||||
* Fix warnings with schema Sync2 with default varchar as NVARCHAR (#1783)
|
||||
* Do not ever quote asterisk symbol. Fixes #1780 (#1781)
|
||||
* Fix bug on get columns for postgres (#1779)
|
||||
|
||||
## [1.0.4](https://gitea.com/xorm/xorm/pulls?q=&type=all&state=closed&milestone=1286) - 2020-09-02
|
||||
|
||||
* FEATURES
|
||||
* Add params for mssql to allow redefine varchar as nvarchar or char as nchar (#1741)
|
||||
* BUGFIXES
|
||||
* Fix mysql dialect error from invalid db identifier in orderby clause (#1743) (#1751)
|
||||
* ENHANCEMENTS
|
||||
* Support get dataSourceName on ContextHook for monitor which DB executed SQL (#1740)
|
||||
* MISC
|
||||
* Correct default detection in MariaDB >= 10.2.7 (#1778)
|
||||
|
||||
## [1.0.3](https://gitea.com/xorm/xorm/pulls?q=&type=all&state=closed&milestone=1281) - 2020-07-10
|
||||
|
||||
* BUGFIXES
|
||||
* Fix dump of sqlite (#1639)
|
||||
* ENHANCEMENTS
|
||||
* Fix index name parsing in SQLite dialect (#1737)
|
||||
* add hooks for Commit and Rollback (#1733)
|
||||
|
||||
## [1.0.2](https://gitea.com/xorm/xorm/pulls?q=&type=all&state=closed&milestone=1261) - 2020-06-16
|
||||
|
||||
* FEATURES
|
||||
* Add Hook (#1644)
|
||||
* BUGFIXES
|
||||
* Fix bug when ID used but no reference table given (#1709)
|
||||
* Fix find and count bug (#1651)
|
||||
* ENHANCEMENTS
|
||||
* chore: improve snakeCasedName performance (#1688)
|
||||
* Fix find with another struct (#1666)
|
||||
* fix GetColumns missing ordinal position (#1660)
|
||||
* MISC
|
||||
* chore: improve titleCasedName performance (#1691)
|
||||
|
||||
## [1.0.1](https://gitea.com/xorm/xorm/pulls?q=&type=all&state=closed&milestone=1253) - 2020-03-25
|
||||
|
||||
* BUGFIXES
|
||||
|
|
36
Makefile
36
Makefile
|
@ -6,7 +6,9 @@ GOFMT ?= gofmt -s
|
|||
TAGS ?=
|
||||
SED_INPLACE := sed -i
|
||||
|
||||
GOFILES := $(shell find . -name "*.go" -type f)
|
||||
GO_DIRS := caches contexts integrations convert core dialects internal log migrate names schemas tags
|
||||
GOFILES := $(wildcard *.go)
|
||||
GOFILES += $(shell find $(GO_DIRS) -name "*.go" -type f)
|
||||
INTEGRATION_PACKAGES := xorm.io/xorm/integrations
|
||||
PACKAGES ?= $(filter-out $(INTEGRATION_PACKAGES),$(shell $(GO) list ./...))
|
||||
|
||||
|
@ -20,6 +22,9 @@ TEST_MSSQL_HOST ?= mssql:1433
|
|||
TEST_MSSQL_DBNAME ?= gitea
|
||||
TEST_MSSQL_USERNAME ?= sa
|
||||
TEST_MSSQL_PASSWORD ?= MwantsaSecurePassword1
|
||||
TEST_MSSQL_DEFAULT_VARCHAR ?= varchar
|
||||
TEST_MSSQL_DEFAULT_CHAR ?= char
|
||||
TEST_MSSQL_DO_NVARCHAR_OVERRIDE_TEST ?= true
|
||||
|
||||
TEST_MYSQL_HOST ?= mysql:3306
|
||||
TEST_MYSQL_CHARSET ?= utf8
|
||||
|
@ -96,7 +101,8 @@ help:
|
|||
@echo " - test-mysql run integration tests for mysql"
|
||||
@echo " - test-mssql run integration tests for mssql"
|
||||
@echo " - test-postgres run integration tests for postgres"
|
||||
@echo " - test-sqlite run integration tests for sqlite"
|
||||
@echo " - test-sqlite3 run integration tests for sqlite"
|
||||
@echo " - test-sqlite run integration tests for pure go sqlite"
|
||||
@echo " - test-tidb run integration tests for tidb"
|
||||
@echo " - vet examines Go source code and reports suspicious constructs"
|
||||
|
||||
|
@ -144,12 +150,16 @@ test-cockroach\#%: go-check
|
|||
test-mssql: go-check
|
||||
$(GO) test $(INTEGRATION_PACKAGES) -v -race -db=mssql -cache=$(TEST_CACHE_ENABLE) -quote=$(TEST_QUOTE_POLICY) \
|
||||
-conn_str="server=$(TEST_MSSQL_HOST);user id=$(TEST_MSSQL_USERNAME);password=$(TEST_MSSQL_PASSWORD);database=$(TEST_MSSQL_DBNAME)" \
|
||||
-default_varchar=$(TEST_MSSQL_DEFAULT_VARCHAR) -default_char=$(TEST_MSSQL_DEFAULT_CHAR) \
|
||||
-do_nvarchar_override_test=$(TEST_MSSQL_DO_NVARCHAR_OVERRIDE_TEST) \
|
||||
-coverprofile=mssql.$(TEST_QUOTE_POLICY).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
||||
|
||||
.PNONY: test-mssql\#%
|
||||
test-mssql\#%: go-check
|
||||
$(GO) test $(INTEGRATION_PACKAGES) -v -race -run $* -db=mssql -cache=$(TEST_CACHE_ENABLE) -quote=$(TEST_QUOTE_POLICY) \
|
||||
-conn_str="server=$(TEST_MSSQL_HOST);user id=$(TEST_MSSQL_USERNAME);password=$(TEST_MSSQL_PASSWORD);database=$(TEST_MSSQL_DBNAME)" \
|
||||
-default_varchar=$(TEST_MSSQL_DEFAULT_VARCHAR) -default_char=$(TEST_MSSQL_DEFAULT_CHAR) \
|
||||
-do_nvarchar_override_test=$(TEST_MSSQL_DO_NVARCHAR_OVERRIDE_TEST) \
|
||||
-coverprofile=mssql.$(TEST_QUOTE_POLICY).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
||||
|
||||
.PNONY: test-mymysql
|
||||
|
@ -188,21 +198,37 @@ test-postgres\#%: go-check
|
|||
-conn_str="postgres://$(TEST_PGSQL_USERNAME):$(TEST_PGSQL_PASSWORD)@$(TEST_PGSQL_HOST)/$(TEST_PGSQL_DBNAME)?sslmode=disable" \
|
||||
-quote=$(TEST_QUOTE_POLICY) -coverprofile=postgres.$(TEST_QUOTE_POLICY).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
||||
|
||||
.PHONY: test-sqlite3
|
||||
test-sqlite3: go-check
|
||||
$(GO) test $(INTEGRATION_PACKAGES) -v -race -cache=$(TEST_CACHE_ENABLE) -db=sqlite3 -conn_str="./test.db?cache=shared&mode=rwc" \
|
||||
-quote=$(TEST_QUOTE_POLICY) -coverprofile=sqlite3.$(TEST_QUOTE_POLICY).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
||||
|
||||
.PHONY: test-sqlite3-schema
|
||||
test-sqlite3-schema: go-check
|
||||
$(GO) test $(INTEGRATION_PACKAGES) -v -race -schema=xorm -cache=$(TEST_CACHE_ENABLE) -db=sqlite3 -conn_str="./test.db?cache=shared&mode=rwc" \
|
||||
-quote=$(TEST_QUOTE_POLICY) -coverprofile=sqlite3.$(TEST_QUOTE_POLICY).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
||||
|
||||
.PHONY: test-sqlite3\#%
|
||||
test-sqlite3\#%: go-check
|
||||
$(GO) test $(INTEGRATION_PACKAGES) -v -race -run $* -cache=$(TEST_CACHE_ENABLE) -db=sqlite3 -conn_str="./test.db?cache=shared&mode=rwc" \
|
||||
-quote=$(TEST_QUOTE_POLICY) -coverprofile=sqlite3.$(TEST_QUOTE_POLICY).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
||||
|
||||
.PHONY: test-sqlite
|
||||
test-sqlite: go-check
|
||||
$(GO) test $(INTEGRATION_PACKAGES) -v -race -cache=$(TEST_CACHE_ENABLE) -db=sqlite3 -conn_str="./test.db?cache=shared&mode=rwc" \
|
||||
$(GO) test $(INTEGRATION_PACKAGES) -v -race -cache=$(TEST_CACHE_ENABLE) -db=sqlite -conn_str="./test.db?cache=shared&mode=rwc" \
|
||||
-quote=$(TEST_QUOTE_POLICY) -coverprofile=sqlite.$(TEST_QUOTE_POLICY).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
||||
|
||||
.PHONY: test-sqlite-schema
|
||||
test-sqlite-schema: go-check
|
||||
$(GO) test $(INTEGRATION_PACKAGES) -v -race -schema=xorm -cache=$(TEST_CACHE_ENABLE) -db=sqlite3 -conn_str="./test.db?cache=shared&mode=rwc" \
|
||||
$(GO) test $(INTEGRATION_PACKAGES) -v -race -schema=xorm -cache=$(TEST_CACHE_ENABLE) -db=sqlite -conn_str="./test.db?cache=shared&mode=rwc" \
|
||||
-quote=$(TEST_QUOTE_POLICY) -coverprofile=sqlite.$(TEST_QUOTE_POLICY).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
||||
|
||||
.PHONY: test-sqlite\#%
|
||||
test-sqlite\#%: go-check
|
||||
$(GO) test $(INTEGRATION_PACKAGES) -v -race -run $* -cache=$(TEST_CACHE_ENABLE) -db=sqlite3 -conn_str="./test.db?cache=shared&mode=rwc" \
|
||||
$(GO) test $(INTEGRATION_PACKAGES) -v -race -run $* -cache=$(TEST_CACHE_ENABLE) -db=sqlite -conn_str="./test.db?cache=shared&mode=rwc" \
|
||||
-quote=$(TEST_QUOTE_POLICY) -coverprofile=sqlite.$(TEST_QUOTE_POLICY).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
||||
|
||||
|
||||
.PNONY: test-tidb
|
||||
test-tidb: go-check
|
||||
$(GO) test $(INTEGRATION_PACKAGES) -v -race -db=mysql -cache=$(TEST_CACHE_ENABLE) -ignore_select_update=true \
|
||||
|
|
|
@ -4,9 +4,7 @@
|
|||
|
||||
Xorm is a simple and powerful ORM for Go.
|
||||
|
||||
[](https://drone.gitea.com/xorm/xorm) [](https://gocover.io/xorm.io/xorm)
|
||||
[](https://goreportcard.com/report/xorm.io/xorm)
|
||||
[](https://discord.gg/HuR2CF3)
|
||||
[](https://drone.gitea.com/xorm/xorm) [](https://gocover.io/xorm.io/xorm) [](https://goreportcard.com/report/xorm.io/xorm) [](https://discord.gg/HuR2CF3)
|
||||
|
||||
## Notice
|
||||
|
||||
|
@ -315,7 +313,7 @@ err := engine.Where(builder.NotIn("a", 1, 2).And(builder.In("b", "c", "d", "e"))
|
|||
// SELECT id, name ... FROM user WHERE a NOT IN (?, ?) AND b IN (?, ?, ?)
|
||||
```
|
||||
|
||||
* Multiple operations in one go routine, no transation here but resue session memory
|
||||
* Multiple operations in one go routine, no transaction here but resue session memory
|
||||
|
||||
```Go
|
||||
session := engine.NewSession()
|
||||
|
@ -338,7 +336,7 @@ if _, err := session.Exec("delete from userinfo where username = ?", user2.Usern
|
|||
return nil
|
||||
```
|
||||
|
||||
* Transation should be on one go routine. There is transaction and resue session memory
|
||||
* Transaction should be on one go routine. There is transaction and resue session memory
|
||||
|
||||
```Go
|
||||
session := engine.NewSession()
|
||||
|
|
|
@ -4,9 +4,7 @@
|
|||
|
||||
xorm 是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作非常简便。
|
||||
|
||||
[](https://drone.gitea.com/xorm/xorm) [](https://gocover.io/xorm.io/xorm)
|
||||
[](https://goreportcard.com/report/xorm.io/xorm)
|
||||
[](https://discord.gg/HuR2CF3)
|
||||
[](https://drone.gitea.com/xorm/xorm) [](https://gocover.io/xorm.io/xorm) [](https://goreportcard.com/report/xorm.io/xorm) [](https://discord.gg/HuR2CF3)
|
||||
|
||||
## Notice
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ type LevelDBStore struct {
|
|||
|
||||
var _ CacheStore = &LevelDBStore{}
|
||||
|
||||
// NewLevelDBStore creates a leveldb store
|
||||
func NewLevelDBStore(dbfile string) (*LevelDBStore, error) {
|
||||
db := &LevelDBStore{}
|
||||
h, err := leveldb.OpenFile(dbfile, nil)
|
||||
|
@ -29,6 +30,7 @@ func NewLevelDBStore(dbfile string) (*LevelDBStore, error) {
|
|||
return db, nil
|
||||
}
|
||||
|
||||
// Put implements CacheStore
|
||||
func (s *LevelDBStore) Put(key string, value interface{}) error {
|
||||
val, err := Encode(value)
|
||||
if err != nil {
|
||||
|
@ -50,6 +52,7 @@ func (s *LevelDBStore) Put(key string, value interface{}) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// Get implements CacheStore
|
||||
func (s *LevelDBStore) Get(key string) (interface{}, error) {
|
||||
data, err := s.store.Get([]byte(key), nil)
|
||||
if err != nil {
|
||||
|
@ -75,6 +78,7 @@ func (s *LevelDBStore) Get(key string) (interface{}, error) {
|
|||
return s.v, err
|
||||
}
|
||||
|
||||
// Del implements CacheStore
|
||||
func (s *LevelDBStore) Del(key string) error {
|
||||
err := s.store.Delete([]byte(key), nil)
|
||||
if err != nil {
|
||||
|
@ -89,6 +93,7 @@ func (s *LevelDBStore) Del(key string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// Close implements CacheStore
|
||||
func (s *LevelDBStore) Close() {
|
||||
s.store.Close()
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ package caches
|
|||
|
||||
import "sync"
|
||||
|
||||
// Manager represents a cache manager
|
||||
type Manager struct {
|
||||
cacher Cacher
|
||||
disableGlobalCache bool
|
||||
|
@ -14,6 +15,7 @@ type Manager struct {
|
|||
cacherLock sync.RWMutex
|
||||
}
|
||||
|
||||
// NewManager creates a cache manager
|
||||
func NewManager() *Manager {
|
||||
return &Manager{
|
||||
cachers: make(map[string]Cacher),
|
||||
|
@ -27,12 +29,14 @@ func (mgr *Manager) SetDisableGlobalCache(disable bool) {
|
|||
}
|
||||
}
|
||||
|
||||
// SetCacher set cacher of table
|
||||
func (mgr *Manager) SetCacher(tableName string, cacher Cacher) {
|
||||
mgr.cacherLock.Lock()
|
||||
mgr.cachers[tableName] = cacher
|
||||
mgr.cacherLock.Unlock()
|
||||
}
|
||||
|
||||
// GetCacher returns a cache of a table
|
||||
func (mgr *Manager) GetCacher(tableName string) Cacher {
|
||||
var cacher Cacher
|
||||
var ok bool
|
||||
|
|
|
@ -31,6 +31,7 @@ func NewContextHook(ctx context.Context, sql string, args []interface{}) *Contex
|
|||
}
|
||||
}
|
||||
|
||||
// End finish the hook invokation
|
||||
func (c *ContextHook) End(ctx context.Context, result sql.Result, err error) {
|
||||
c.Ctx = ctx
|
||||
c.Result = result
|
||||
|
@ -38,19 +39,23 @@ func (c *ContextHook) End(ctx context.Context, result sql.Result, err error) {
|
|||
c.ExecuteTime = time.Now().Sub(c.start)
|
||||
}
|
||||
|
||||
// Hook represents a hook behaviour
|
||||
type Hook interface {
|
||||
BeforeProcess(c *ContextHook) (context.Context, error)
|
||||
AfterProcess(c *ContextHook) error
|
||||
}
|
||||
|
||||
// Hooks implements Hook interface but contains multiple Hook
|
||||
type Hooks struct {
|
||||
hooks []Hook
|
||||
}
|
||||
|
||||
// AddHook adds a Hook
|
||||
func (h *Hooks) AddHook(hooks ...Hook) {
|
||||
h.hooks = append(h.hooks, hooks...)
|
||||
}
|
||||
|
||||
// BeforeProcess invoked before execute the process
|
||||
func (h *Hooks) BeforeProcess(c *ContextHook) (context.Context, error) {
|
||||
ctx := c.Ctx
|
||||
for _, h := range h.hooks {
|
||||
|
@ -63,6 +68,7 @@ func (h *Hooks) BeforeProcess(c *ContextHook) (context.Context, error) {
|
|||
return ctx, nil
|
||||
}
|
||||
|
||||
// AfterProcess invoked after exetue the process
|
||||
func (h *Hooks) AfterProcess(c *ContextHook) error {
|
||||
firstErr := c.Err
|
||||
for _, h := range h.hooks {
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
_ "modernc.org/sqlite"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -27,7 +28,7 @@ func TestMain(m *testing.M) {
|
|||
flag.Parse()
|
||||
|
||||
switch *dbtype {
|
||||
case "sqlite3":
|
||||
case "sqlite3", "sqlite":
|
||||
createTableSql = "CREATE TABLE IF NOT EXISTS `user` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NULL, " +
|
||||
"`title` TEXT NULL, `age` FLOAT NULL, `alias` TEXT NULL, `nick_name` TEXT NULL, `created` datetime);"
|
||||
case "mysql":
|
||||
|
@ -45,8 +46,11 @@ func TestMain(m *testing.M) {
|
|||
func testOpen() (*DB, error) {
|
||||
switch *dbtype {
|
||||
case "sqlite3":
|
||||
os.Remove("./test.db")
|
||||
os.Remove("./test_sqlite3.db")
|
||||
return Open("sqlite3", "./test.db")
|
||||
case "sqlite":
|
||||
os.Remove("./test_sqlite.db")
|
||||
return Open("sqlite", "./test.db")
|
||||
case "mysql":
|
||||
return Open("mysql", *dbConn)
|
||||
default:
|
||||
|
|
33
core/tx.go
33
core/tx.go
|
@ -18,7 +18,8 @@ var (
|
|||
// Tx represents a transaction
|
||||
type Tx struct {
|
||||
*sql.Tx
|
||||
db *DB
|
||||
db *DB
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
func (db *DB) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) {
|
||||
|
@ -32,13 +33,41 @@ func (db *DB) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) {
|
|||
if err := db.afterProcess(hookCtx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Tx{tx, db}, nil
|
||||
return &Tx{tx, db, ctx}, nil
|
||||
}
|
||||
|
||||
func (db *DB) Begin() (*Tx, error) {
|
||||
return db.BeginTx(context.Background(), nil)
|
||||
}
|
||||
|
||||
func (tx *Tx) Commit() error {
|
||||
hookCtx := contexts.NewContextHook(tx.ctx, "COMMIT", nil)
|
||||
ctx, err := tx.db.beforeProcess(hookCtx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = tx.Tx.Commit()
|
||||
hookCtx.End(ctx, nil, err)
|
||||
if err := tx.db.afterProcess(hookCtx); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tx *Tx) Rollback() error {
|
||||
hookCtx := contexts.NewContextHook(tx.ctx, "ROLLBACK", nil)
|
||||
ctx, err := tx.db.beforeProcess(hookCtx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = tx.Tx.Rollback()
|
||||
hookCtx.End(ctx, nil, err)
|
||||
if err := tx.db.afterProcess(hookCtx); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tx *Tx) PrepareContext(ctx context.Context, query string) (*Stmt, error) {
|
||||
names := make(map[string]int)
|
||||
var i int
|
||||
|
|
|
@ -79,32 +79,34 @@ type Base struct {
|
|||
quoter schemas.Quoter
|
||||
}
|
||||
|
||||
func (b *Base) Quoter() schemas.Quoter {
|
||||
return b.quoter
|
||||
// Quoter returns the current database Quoter
|
||||
func (db *Base) Quoter() schemas.Quoter {
|
||||
return db.quoter
|
||||
}
|
||||
|
||||
func (b *Base) Init(dialect Dialect, uri *URI) error {
|
||||
b.dialect, b.uri = dialect, uri
|
||||
// Init initialize the dialect
|
||||
func (db *Base) Init(dialect Dialect, uri *URI) error {
|
||||
db.dialect, db.uri = dialect, uri
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Base) URI() *URI {
|
||||
return b.uri
|
||||
// URI returns the uri of database
|
||||
func (db *Base) URI() *URI {
|
||||
return db.uri
|
||||
}
|
||||
|
||||
func (b *Base) DBType() schemas.DBType {
|
||||
return b.uri.DBType
|
||||
}
|
||||
|
||||
func (b *Base) FormatBytes(bs []byte) string {
|
||||
// FormatBytes formats bytes
|
||||
func (db *Base) FormatBytes(bs []byte) string {
|
||||
return fmt.Sprintf("0x%x", bs)
|
||||
}
|
||||
|
||||
// DropTableSQL returns drop table SQL
|
||||
func (db *Base) DropTableSQL(tableName string) (string, bool) {
|
||||
quote := db.dialect.Quoter().Quote
|
||||
return fmt.Sprintf("DROP TABLE IF EXISTS %s", quote(tableName)), true
|
||||
}
|
||||
|
||||
// HasRecords returns true if the SQL has records returned
|
||||
func (db *Base) HasRecords(queryer core.Queryer, ctx context.Context, query string, args ...interface{}) (bool, error) {
|
||||
rows, err := queryer.QueryContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
|
@ -118,6 +120,7 @@ func (db *Base) HasRecords(queryer core.Queryer, ctx context.Context, query stri
|
|||
return false, nil
|
||||
}
|
||||
|
||||
// IsColumnExist returns true if the column of the table exist
|
||||
func (db *Base) IsColumnExist(queryer core.Queryer, ctx context.Context, tableName, colName string) (bool, error) {
|
||||
quote := db.dialect.Quoter().Quote
|
||||
query := fmt.Sprintf(
|
||||
|
@ -132,11 +135,13 @@ func (db *Base) IsColumnExist(queryer core.Queryer, ctx context.Context, tableNa
|
|||
return db.HasRecords(queryer, ctx, query, db.uri.DBName, tableName, colName)
|
||||
}
|
||||
|
||||
// AddColumnSQL returns a SQL to add a column
|
||||
func (db *Base) AddColumnSQL(tableName string, col *schemas.Column) string {
|
||||
s, _ := ColumnString(db.dialect, col, true)
|
||||
return fmt.Sprintf("ALTER TABLE %v ADD %v", db.dialect.Quoter().Quote(tableName), s)
|
||||
}
|
||||
|
||||
// CreateIndexSQL returns a SQL to create index
|
||||
func (db *Base) CreateIndexSQL(tableName string, index *schemas.Index) string {
|
||||
quoter := db.dialect.Quoter()
|
||||
var unique string
|
||||
|
@ -150,6 +155,7 @@ func (db *Base) CreateIndexSQL(tableName string, index *schemas.Index) string {
|
|||
quoter.Join(index.Cols, ","))
|
||||
}
|
||||
|
||||
// DropIndexSQL returns a SQL to drop index
|
||||
func (db *Base) DropIndexSQL(tableName string, index *schemas.Index) string {
|
||||
quote := db.dialect.Quoter().Quote
|
||||
var name string
|
||||
|
@ -161,16 +167,19 @@ func (db *Base) DropIndexSQL(tableName string, index *schemas.Index) string {
|
|||
return fmt.Sprintf("DROP INDEX %v ON %s", quote(name), quote(tableName))
|
||||
}
|
||||
|
||||
// ModifyColumnSQL returns a SQL to modify SQL
|
||||
func (db *Base) ModifyColumnSQL(tableName string, col *schemas.Column) string {
|
||||
s, _ := ColumnString(db.dialect, col, false)
|
||||
return fmt.Sprintf("alter table %s MODIFY COLUMN %s", tableName, s)
|
||||
return fmt.Sprintf("ALTER TABLE %s MODIFY COLUMN %s", tableName, s)
|
||||
}
|
||||
|
||||
func (b *Base) ForUpdateSQL(query string) string {
|
||||
// ForUpdateSQL returns for updateSQL
|
||||
func (db *Base) ForUpdateSQL(query string) string {
|
||||
return query + " FOR UPDATE"
|
||||
}
|
||||
|
||||
func (b *Base) SetParams(params map[string]string) {
|
||||
// SetParams set params
|
||||
func (db *Base) SetParams(params map[string]string) {
|
||||
}
|
||||
|
||||
var (
|
||||
|
@ -206,6 +215,7 @@ func regDrvsNDialects() bool {
|
|||
"postgres": {"postgres", func() Driver { return &pqDriver{} }, func() Dialect { return &postgres{} }},
|
||||
"pgx": {"postgres", func() Driver { return &pqDriverPgx{} }, func() Dialect { return &postgres{} }},
|
||||
"sqlite3": {"sqlite3", func() Driver { return &sqlite3Driver{} }, func() Dialect { return &sqlite3{} }},
|
||||
"sqlite": {"sqlite3", func() Driver { return &sqlite3Driver{} }, func() Dialect { return &sqlite3{} }},
|
||||
"oci8": {"oracle", func() Driver { return &oci8Driver{} }, func() Dialect { return &oracle{} }},
|
||||
"goracle": {"oracle", func() Driver { return &goracleDriver{} }, func() Dialect { return &oracle{} }},
|
||||
}
|
||||
|
|
|
@ -214,13 +214,45 @@ var (
|
|||
|
||||
type mssql struct {
|
||||
Base
|
||||
defaultVarchar string
|
||||
defaultChar string
|
||||
}
|
||||
|
||||
func (db *mssql) Init(uri *URI) error {
|
||||
db.quoter = mssqlQuoter
|
||||
db.defaultChar = "CHAR"
|
||||
db.defaultVarchar = "VARCHAR"
|
||||
return db.Base.Init(db, uri)
|
||||
}
|
||||
|
||||
func (db *mssql) SetParams(params map[string]string) {
|
||||
defaultVarchar, ok := params["DEFAULT_VARCHAR"]
|
||||
if ok {
|
||||
var t = strings.ToUpper(defaultVarchar)
|
||||
switch t {
|
||||
case "NVARCHAR", "VARCHAR":
|
||||
db.defaultVarchar = t
|
||||
default:
|
||||
db.defaultVarchar = "VARCHAR"
|
||||
}
|
||||
} else {
|
||||
db.defaultVarchar = "VARCHAR"
|
||||
}
|
||||
|
||||
defaultChar, ok := params["DEFAULT_CHAR"]
|
||||
if ok {
|
||||
var t = strings.ToUpper(defaultChar)
|
||||
switch t {
|
||||
case "NCHAR", "CHAR":
|
||||
db.defaultChar = t
|
||||
default:
|
||||
db.defaultChar = "CHAR"
|
||||
}
|
||||
} else {
|
||||
db.defaultChar = "CHAR"
|
||||
}
|
||||
}
|
||||
|
||||
func (db *mssql) SQLType(c *schemas.Column) string {
|
||||
var res string
|
||||
switch t := c.SQLType.Name; t {
|
||||
|
@ -231,6 +263,7 @@ func (db *mssql) SQLType(c *schemas.Column) string {
|
|||
} else if strings.EqualFold(c.Default, "false") {
|
||||
c.Default = "0"
|
||||
}
|
||||
return res
|
||||
case schemas.Serial:
|
||||
c.IsAutoIncrement = true
|
||||
c.IsPrimaryKey = true
|
||||
|
@ -251,10 +284,10 @@ func (db *mssql) SQLType(c *schemas.Column) string {
|
|||
case schemas.TimeStampz:
|
||||
res = "DATETIMEOFFSET"
|
||||
c.Length = 7
|
||||
case schemas.MediumInt:
|
||||
case schemas.MediumInt, schemas.UnsignedInt:
|
||||
res = schemas.Int
|
||||
case schemas.Text, schemas.MediumText, schemas.TinyText, schemas.LongText, schemas.Json:
|
||||
res = schemas.Varchar + "(MAX)"
|
||||
res = db.defaultVarchar + "(MAX)"
|
||||
case schemas.Double:
|
||||
res = schemas.Real
|
||||
case schemas.Uuid:
|
||||
|
@ -263,15 +296,35 @@ func (db *mssql) SQLType(c *schemas.Column) string {
|
|||
case schemas.TinyInt:
|
||||
res = schemas.TinyInt
|
||||
c.Length = 0
|
||||
case schemas.BigInt:
|
||||
case schemas.BigInt, schemas.UnsignedBigInt:
|
||||
res = schemas.BigInt
|
||||
c.Length = 0
|
||||
case schemas.NVarchar:
|
||||
res = t
|
||||
if c.Length == -1 {
|
||||
res += "(MAX)"
|
||||
}
|
||||
case schemas.Varchar:
|
||||
res = db.defaultVarchar
|
||||
if c.Length == -1 {
|
||||
res += "(MAX)"
|
||||
}
|
||||
case schemas.Char:
|
||||
res = db.defaultChar
|
||||
if c.Length == -1 {
|
||||
res += "(MAX)"
|
||||
}
|
||||
case schemas.NChar:
|
||||
res = t
|
||||
if c.Length == -1 {
|
||||
res += "(MAX)"
|
||||
}
|
||||
default:
|
||||
res = t
|
||||
}
|
||||
|
||||
if res == schemas.Int {
|
||||
return schemas.Int
|
||||
if res == schemas.Int || res == schemas.Bit || res == schemas.DateTime {
|
||||
return res
|
||||
}
|
||||
|
||||
hasLen1 := (c.Length > 0)
|
||||
|
@ -317,6 +370,11 @@ func (db *mssql) DropTableSQL(tableName string) (string, bool) {
|
|||
"DROP TABLE \"%s\"", tableName, tableName), true
|
||||
}
|
||||
|
||||
func (db *mssql) ModifyColumnSQL(tableName string, col *schemas.Column) string {
|
||||
s, _ := ColumnString(db.dialect, col, false)
|
||||
return fmt.Sprintf("ALTER TABLE %s ALTER COLUMN %s", tableName, s)
|
||||
}
|
||||
|
||||
func (db *mssql) IndexCheckSQL(tableName, idxName string) (string, []interface{}) {
|
||||
args := []interface{}{idxName}
|
||||
sql := "select name from sysindexes where id=object_id('" + tableName + "') and name=?"
|
||||
|
@ -389,8 +447,18 @@ func (db *mssql) GetColumns(queryer core.Queryer, ctx context.Context, tableName
|
|||
col.SQLType = schemas.SQLType{Name: schemas.TimeStampz, DefaultLength: 0, DefaultLength2: 0}
|
||||
case "NVARCHAR":
|
||||
col.SQLType = schemas.SQLType{Name: schemas.NVarchar, DefaultLength: 0, DefaultLength2: 0}
|
||||
if col.Length > 0 {
|
||||
col.Length /= 2
|
||||
col.Length2 /= 2
|
||||
}
|
||||
case "IMAGE":
|
||||
col.SQLType = schemas.SQLType{Name: schemas.VarBinary, DefaultLength: 0, DefaultLength2: 0}
|
||||
case "NCHAR":
|
||||
if col.Length > 0 {
|
||||
col.Length /= 2
|
||||
col.Length2 /= 2
|
||||
}
|
||||
fallthrough
|
||||
default:
|
||||
if _, ok := schemas.SqlTypes[ct]; ok {
|
||||
col.SQLType = schemas.SQLType{Name: ct, DefaultLength: 0, DefaultLength2: 0}
|
||||
|
@ -472,7 +540,7 @@ WHERE IXS.TYPE_DESC='NONCLUSTERED' and OBJECT_NAME(IXS.OBJECT_ID) =?
|
|||
|
||||
colName = strings.Trim(colName, "` ")
|
||||
var isRegular bool
|
||||
if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
|
||||
if (strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName)) && len(indexName) > (5+len(tableName)) {
|
||||
indexName = indexName[5+len(tableName):]
|
||||
isRegular = true
|
||||
}
|
||||
|
|
|
@ -254,6 +254,10 @@ func (db *mysql) SQLType(c *schemas.Column) string {
|
|||
c.Length = 40
|
||||
case schemas.Json:
|
||||
res = schemas.Text
|
||||
case schemas.UnsignedInt:
|
||||
res = schemas.Int
|
||||
case schemas.UnsignedBigInt:
|
||||
res = schemas.BigInt
|
||||
default:
|
||||
res = t
|
||||
}
|
||||
|
@ -271,6 +275,11 @@ func (db *mysql) SQLType(c *schemas.Column) string {
|
|||
} else if hasLen1 {
|
||||
res += "(" + strconv.Itoa(c.Length) + ")"
|
||||
}
|
||||
|
||||
if c.SQLType.Name == schemas.UnsignedBigInt || c.SQLType.Name == schemas.UnsignedInt {
|
||||
res += " UNSIGNED"
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
|
@ -307,8 +316,17 @@ func (db *mysql) AddColumnSQL(tableName string, col *schemas.Column) string {
|
|||
|
||||
func (db *mysql) GetColumns(queryer core.Queryer, ctx context.Context, tableName string) ([]string, map[string]*schemas.Column, error) {
|
||||
args := []interface{}{db.uri.DBName, tableName}
|
||||
alreadyQuoted := "(INSTR(VERSION(), 'maria') > 0 && " +
|
||||
"(SUBSTRING_INDEX(VERSION(), '.', 1) > 10 || " +
|
||||
"(SUBSTRING_INDEX(VERSION(), '.', 1) = 10 && " +
|
||||
"(SUBSTRING_INDEX(SUBSTRING(VERSION(), 4), '.', 1) > 2 || " +
|
||||
"(SUBSTRING_INDEX(SUBSTRING(VERSION(), 4), '.', 1) = 2 && " +
|
||||
"SUBSTRING_INDEX(SUBSTRING(VERSION(), 6), '-', 1) >= 7)))))"
|
||||
s := "SELECT `COLUMN_NAME`, `IS_NULLABLE`, `COLUMN_DEFAULT`, `COLUMN_TYPE`," +
|
||||
" `COLUMN_KEY`, `EXTRA`,`COLUMN_COMMENT` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?"
|
||||
" `COLUMN_KEY`, `EXTRA`, `COLUMN_COMMENT`, " +
|
||||
alreadyQuoted + " AS NEEDS_QUOTE " +
|
||||
"FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?" +
|
||||
" ORDER BY `COLUMNS`.ORDINAL_POSITION"
|
||||
|
||||
rows, err := queryer.QueryContext(ctx, s, args...)
|
||||
if err != nil {
|
||||
|
@ -322,27 +340,35 @@ func (db *mysql) GetColumns(queryer core.Queryer, ctx context.Context, tableName
|
|||
col := new(schemas.Column)
|
||||
col.Indexes = make(map[string]int)
|
||||
|
||||
var columnName, isNullable, colType, colKey, extra, comment string
|
||||
var columnName, nullableStr, colType, colKey, extra, comment string
|
||||
var alreadyQuoted, isUnsigned bool
|
||||
var colDefault *string
|
||||
err = rows.Scan(&columnName, &isNullable, &colDefault, &colType, &colKey, &extra, &comment)
|
||||
err = rows.Scan(&columnName, &nullableStr, &colDefault, &colType, &colKey, &extra, &comment, &alreadyQuoted)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
col.Name = strings.Trim(columnName, "` ")
|
||||
col.Comment = comment
|
||||
if "YES" == isNullable {
|
||||
if nullableStr == "YES" {
|
||||
col.Nullable = true
|
||||
}
|
||||
|
||||
if colDefault != nil {
|
||||
if colDefault != nil && (!alreadyQuoted || *colDefault != "NULL") {
|
||||
col.Default = *colDefault
|
||||
col.DefaultIsEmpty = false
|
||||
} else {
|
||||
col.DefaultIsEmpty = true
|
||||
}
|
||||
|
||||
fields := strings.Fields(colType)
|
||||
if len(fields) == 2 && fields[1] == "unsigned" {
|
||||
isUnsigned = true
|
||||
}
|
||||
colType = fields[0]
|
||||
cts := strings.Split(colType, "(")
|
||||
colName := cts[0]
|
||||
// Remove the /* mariadb-5.3 */ suffix from coltypes
|
||||
colName = strings.TrimSuffix(colName, "/* mariadb-5.3 */")
|
||||
colType = strings.ToUpper(colName)
|
||||
var len1, len2 int
|
||||
if len(cts) == 2 {
|
||||
|
@ -377,11 +403,8 @@ func (db *mysql) GetColumns(queryer core.Queryer, ctx context.Context, tableName
|
|||
}
|
||||
}
|
||||
}
|
||||
if colType == "FLOAT UNSIGNED" {
|
||||
colType = "FLOAT"
|
||||
}
|
||||
if colType == "DOUBLE UNSIGNED" {
|
||||
colType = "DOUBLE"
|
||||
if isUnsigned {
|
||||
colType = "UNSIGNED " + colType
|
||||
}
|
||||
col.Length = len1
|
||||
col.Length2 = len2
|
||||
|
@ -403,9 +426,9 @@ func (db *mysql) GetColumns(queryer core.Queryer, ctx context.Context, tableName
|
|||
}
|
||||
|
||||
if !col.DefaultIsEmpty {
|
||||
if col.SQLType.IsText() {
|
||||
if !alreadyQuoted && col.SQLType.IsText() {
|
||||
col.Default = "'" + col.Default + "'"
|
||||
} else if col.SQLType.IsTime() && col.Default != "CURRENT_TIMESTAMP" {
|
||||
} else if col.SQLType.IsTime() && !alreadyQuoted && col.Default != "CURRENT_TIMESTAMP" {
|
||||
col.Default = "'" + col.Default + "'"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -500,8 +500,8 @@ var (
|
|||
}
|
||||
|
||||
oracleQuoter = schemas.Quoter{
|
||||
Prefix: '[',
|
||||
Suffix: ']',
|
||||
Prefix: '"',
|
||||
Suffix: '"',
|
||||
IsReserved: schemas.AlwaysReserve,
|
||||
}
|
||||
)
|
||||
|
|
|
@ -833,12 +833,12 @@ func (db *postgres) SQLType(c *schemas.Column) string {
|
|||
case schemas.Bit:
|
||||
res = schemas.Boolean
|
||||
return res
|
||||
case schemas.MediumInt, schemas.Int, schemas.Integer:
|
||||
case schemas.MediumInt, schemas.Int, schemas.Integer, schemas.UnsignedInt:
|
||||
if c.IsAutoIncrement {
|
||||
return schemas.Serial
|
||||
}
|
||||
return schemas.Integer
|
||||
case schemas.BigInt:
|
||||
case schemas.BigInt, schemas.UnsignedBigInt:
|
||||
if c.IsAutoIncrement {
|
||||
return schemas.BigSerial
|
||||
}
|
||||
|
@ -857,6 +857,8 @@ func (db *postgres) SQLType(c *schemas.Column) string {
|
|||
res = schemas.Real
|
||||
case schemas.TinyText, schemas.MediumText, schemas.LongText:
|
||||
res = schemas.Text
|
||||
case schemas.NChar:
|
||||
res = schemas.Char
|
||||
case schemas.NVarchar:
|
||||
res = schemas.Varchar
|
||||
case schemas.Uuid:
|
||||
|
@ -1015,7 +1017,7 @@ WHERE n.nspname= s.table_schema AND c.relkind = 'r'::char AND c.relname = $1%s A
|
|||
|
||||
schema := db.getSchema()
|
||||
if schema != "" {
|
||||
s = fmt.Sprintf(s, "AND s.table_schema = $2")
|
||||
s = fmt.Sprintf(s, " AND s.table_schema = $2")
|
||||
args = append(args, schema)
|
||||
} else {
|
||||
s = fmt.Sprintf(s, "")
|
||||
|
@ -1050,6 +1052,10 @@ WHERE n.nspname= s.table_schema AND c.relkind = 'r'::char AND c.relname = $1%s A
|
|||
}
|
||||
}
|
||||
|
||||
if colDefault != nil && *colDefault == "unique_rowid()" { // ignore the system column added by cockroach
|
||||
continue
|
||||
}
|
||||
|
||||
col.Name = strings.Trim(colName, `" `)
|
||||
|
||||
if colDefault != nil {
|
||||
|
@ -1086,8 +1092,10 @@ WHERE n.nspname= s.table_schema AND c.relkind = 'r'::char AND c.relname = $1%s A
|
|||
col.Nullable = (isNullable == "YES")
|
||||
|
||||
switch strings.ToLower(dataType) {
|
||||
case "character varying", "character", "string":
|
||||
case "character varying", "string":
|
||||
col.SQLType = schemas.SQLType{Name: schemas.Varchar, DefaultLength: 0, DefaultLength2: 0}
|
||||
case "character":
|
||||
col.SQLType = schemas.SQLType{Name: schemas.Char, DefaultLength: 0, DefaultLength2: 0}
|
||||
case "timestamp without time zone":
|
||||
col.SQLType = schemas.SQLType{Name: schemas.DateTime, DefaultLength: 0, DefaultLength2: 0}
|
||||
case "timestamp with time zone":
|
||||
|
|
|
@ -193,7 +193,8 @@ func (db *sqlite3) SQLType(c *schemas.Column) string {
|
|||
case schemas.Char, schemas.Varchar, schemas.NVarchar, schemas.TinyText,
|
||||
schemas.Text, schemas.MediumText, schemas.LongText, schemas.Json:
|
||||
return schemas.Text
|
||||
case schemas.Bit, schemas.TinyInt, schemas.SmallInt, schemas.MediumInt, schemas.Int, schemas.Integer, schemas.BigInt:
|
||||
case schemas.Bit, schemas.TinyInt, schemas.SmallInt, schemas.MediumInt, schemas.Int, schemas.Integer, schemas.BigInt,
|
||||
schemas.UnsignedBigInt, schemas.UnsignedInt:
|
||||
return schemas.Integer
|
||||
case schemas.Float, schemas.Double, schemas.Real:
|
||||
return schemas.Real
|
||||
|
@ -483,7 +484,7 @@ func (db *sqlite3) GetIndexes(queryer core.Queryer, ctx context.Context, tableNa
|
|||
continue
|
||||
}
|
||||
|
||||
indexName := strings.Trim(sql[nNStart+6:nNEnd], "` []")
|
||||
indexName := strings.Trim(strings.TrimSpace(sql[nNStart+6:nNEnd]), "`[]'\"")
|
||||
var isRegular bool
|
||||
if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
|
||||
index.Name = indexName[5+len(tableName):]
|
||||
|
|
|
@ -19,7 +19,11 @@ func FormatTime(dialect Dialect, sqlTypeName string, t time.Time) (v interface{}
|
|||
case schemas.Date:
|
||||
v = t.Format("2006-01-02")
|
||||
case schemas.DateTime, schemas.TimeStamp, schemas.Varchar: // !DarthPestilane! format time when sqlTypeName is schemas.Varchar.
|
||||
v = t.Format("2006-01-02 15:04:05")
|
||||
if dialect.URI().DBType == schemas.ORACLE {
|
||||
v = t
|
||||
} else {
|
||||
v = t.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
case schemas.TimeStampz:
|
||||
if dialect.URI().DBType == schemas.MSSQL {
|
||||
v = t.Format("2006-01-02T15:04:05.9999999Z07:00")
|
||||
|
|
253
engine.go
253
engine.go
|
@ -61,6 +61,10 @@ func NewEngine(driverName string, dataSourceName string) (*Engine, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return newEngine(driverName, dataSourceName, dialect, db)
|
||||
}
|
||||
|
||||
func newEngine(driverName, dataSourceName string, dialect dialects.Dialect, db *core.DB) (*Engine, error) {
|
||||
cacherMgr := caches.NewManager()
|
||||
mapper := names.NewCacheMapper(new(names.SnakeMapper))
|
||||
tagParser := tags.NewParser("xorm", dialect, mapper, mapper, cacherMgr)
|
||||
|
@ -88,7 +92,7 @@ func NewEngine(driverName string, dataSourceName string) (*Engine, error) {
|
|||
engine.SetLogger(log.NewLoggerAdapter(logger))
|
||||
|
||||
runtime.SetFinalizer(engine, func(engine *Engine) {
|
||||
engine.Close()
|
||||
_ = engine.Close()
|
||||
})
|
||||
|
||||
return engine, nil
|
||||
|
@ -101,6 +105,23 @@ func NewEngineWithParams(driverName string, dataSourceName string, params map[st
|
|||
return engine, err
|
||||
}
|
||||
|
||||
// NewEngineWithDB new a db manager with db. The params will be passed to db.
|
||||
func NewEngineWithDB(driverName string, dataSourceName string, db *core.DB) (*Engine, error) {
|
||||
dialect, err := dialects.OpenDialect(driverName, dataSourceName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newEngine(driverName, dataSourceName, dialect, db)
|
||||
}
|
||||
|
||||
// NewEngineWithDialectAndDB new a db manager according to the parameter.
|
||||
// If you do not want to use your own dialect or db, please use NewEngine.
|
||||
// For creating dialect, you can call dialects.OpenDialect. And, for creating db,
|
||||
// you can call core.Open or core.FromDB.
|
||||
func NewEngineWithDialectAndDB(driverName, dataSourceName string, dialect dialects.Dialect, db *core.DB) (*Engine, error) {
|
||||
return newEngine(driverName, dataSourceName, dialect, db)
|
||||
}
|
||||
|
||||
// EnableSessionID if enable session id
|
||||
func (engine *Engine) EnableSessionID(enable bool) {
|
||||
engine.logSessionID = enable
|
||||
|
@ -143,10 +164,12 @@ func (engine *Engine) Logger() log.ContextLogger {
|
|||
func (engine *Engine) SetLogger(logger interface{}) {
|
||||
var realLogger log.ContextLogger
|
||||
switch t := logger.(type) {
|
||||
case log.Logger:
|
||||
realLogger = log.NewLoggerAdapter(t)
|
||||
case log.ContextLogger:
|
||||
realLogger = t
|
||||
case log.Logger:
|
||||
realLogger = log.NewLoggerAdapter(t)
|
||||
default:
|
||||
panic("logger should implement either log.ContextLogger or log.Logger")
|
||||
}
|
||||
engine.logger = realLogger
|
||||
engine.DB().Logger = realLogger
|
||||
|
@ -188,6 +211,11 @@ func (engine *Engine) SetColumnMapper(mapper names.Mapper) {
|
|||
engine.tagParser.SetColumnMapper(mapper)
|
||||
}
|
||||
|
||||
// SetTagIdentifier set the tag identifier
|
||||
func (engine *Engine) SetTagIdentifier(tagIdentifier string) {
|
||||
engine.tagParser.SetIdentifier(tagIdentifier)
|
||||
}
|
||||
|
||||
// Quote Use QuoteStr quote the string sql
|
||||
func (engine *Engine) Quote(value string) string {
|
||||
value = strings.TrimSpace(value)
|
||||
|
@ -347,13 +375,16 @@ func (engine *Engine) loadTableInfo(table *schemas.Table) error {
|
|||
var seq int
|
||||
for _, index := range indexes {
|
||||
for _, name := range index.Cols {
|
||||
parts := strings.Split(name, " ")
|
||||
parts := strings.Split(strings.TrimSpace(name), " ")
|
||||
if len(parts) > 1 {
|
||||
if parts[1] == "DESC" {
|
||||
seq = 1
|
||||
} else if parts[1] == "ASC" {
|
||||
seq = 0
|
||||
}
|
||||
}
|
||||
if col := table.GetColumn(parts[0]); col != nil {
|
||||
var colName = strings.Trim(parts[0], `"`)
|
||||
if col := table.GetColumn(colName); col != nil {
|
||||
col.Indexes[index.Name] = index.Type
|
||||
} else {
|
||||
return fmt.Errorf("Unknown col %s seq %d, in index %v of table %v, columns %v", name, seq, index.Name, table.Name, table.ColumnsSeq())
|
||||
|
@ -412,6 +443,82 @@ func (engine *Engine) DumpTables(tables []*schemas.Table, w io.Writer, tp ...sch
|
|||
return engine.dumpTables(tables, w, tp...)
|
||||
}
|
||||
|
||||
func formatColumnValue(dstDialect dialects.Dialect, d interface{}, col *schemas.Column) string {
|
||||
if d == nil {
|
||||
return "NULL"
|
||||
}
|
||||
|
||||
if dq, ok := d.(bool); ok && (dstDialect.URI().DBType == schemas.SQLITE ||
|
||||
dstDialect.URI().DBType == schemas.MSSQL) {
|
||||
if dq {
|
||||
return "1"
|
||||
}
|
||||
return "0"
|
||||
}
|
||||
|
||||
if col.SQLType.IsText() {
|
||||
var v = fmt.Sprintf("%s", d)
|
||||
return "'" + strings.Replace(v, "'", "''", -1) + "'"
|
||||
} else if col.SQLType.IsTime() {
|
||||
var v = fmt.Sprintf("%s", d)
|
||||
if strings.HasSuffix(v, " +0000 UTC") {
|
||||
return fmt.Sprintf("'%s'", v[0:len(v)-len(" +0000 UTC")])
|
||||
} else if strings.HasSuffix(v, " +0000 +0000") {
|
||||
return fmt.Sprintf("'%s'", v[0:len(v)-len(" +0000 +0000")])
|
||||
}
|
||||
return "'" + strings.Replace(v, "'", "''", -1) + "'"
|
||||
} else if col.SQLType.IsBlob() {
|
||||
if reflect.TypeOf(d).Kind() == reflect.Slice {
|
||||
return fmt.Sprintf("%s", dstDialect.FormatBytes(d.([]byte)))
|
||||
} else if reflect.TypeOf(d).Kind() == reflect.String {
|
||||
return fmt.Sprintf("'%s'", d.(string))
|
||||
}
|
||||
} else if col.SQLType.IsNumeric() {
|
||||
switch reflect.TypeOf(d).Kind() {
|
||||
case reflect.Slice:
|
||||
if col.SQLType.Name == schemas.Bool {
|
||||
return fmt.Sprintf("%v", strconv.FormatBool(d.([]byte)[0] != byte('0')))
|
||||
}
|
||||
return fmt.Sprintf("%s", string(d.([]byte)))
|
||||
case reflect.Int16, reflect.Int8, reflect.Int32, reflect.Int64, reflect.Int:
|
||||
if col.SQLType.Name == schemas.Bool {
|
||||
v := reflect.ValueOf(d).Int() > 0
|
||||
if dstDialect.URI().DBType == schemas.SQLITE {
|
||||
if v {
|
||||
return "1"
|
||||
}
|
||||
return "0"
|
||||
}
|
||||
return fmt.Sprintf("%v", strconv.FormatBool(v))
|
||||
}
|
||||
return fmt.Sprintf("%v", d)
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
if col.SQLType.Name == schemas.Bool {
|
||||
v := reflect.ValueOf(d).Uint() > 0
|
||||
if dstDialect.URI().DBType == schemas.SQLITE {
|
||||
if v {
|
||||
return "1"
|
||||
}
|
||||
return "0"
|
||||
}
|
||||
return fmt.Sprintf("%v", strconv.FormatBool(v))
|
||||
}
|
||||
return fmt.Sprintf("%v", d)
|
||||
default:
|
||||
return fmt.Sprintf("%v", d)
|
||||
}
|
||||
}
|
||||
|
||||
s := fmt.Sprintf("%v", d)
|
||||
if strings.Contains(s, ":") || strings.Contains(s, "-") {
|
||||
if strings.HasSuffix(s, " +0000 UTC") {
|
||||
return fmt.Sprintf("'%s'", s[0:len(s)-len(" +0000 UTC")])
|
||||
}
|
||||
return fmt.Sprintf("'%s'", s)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// dumpTables dump database all table structs and data to w with specify db type
|
||||
func (engine *Engine) dumpTables(tables []*schemas.Table, w io.Writer, tp ...schemas.DBType) error {
|
||||
var dstDialect dialects.Dialect
|
||||
|
@ -424,7 +531,10 @@ func (engine *Engine) dumpTables(tables []*schemas.Table, w io.Writer, tp ...sch
|
|||
}
|
||||
|
||||
uri := engine.dialect.URI()
|
||||
destURI := *uri
|
||||
destURI := dialects.URI{
|
||||
DBType: tp[0],
|
||||
DBName: uri.DBName,
|
||||
}
|
||||
dstDialect.Init(&destURI)
|
||||
}
|
||||
|
||||
|
@ -495,59 +605,9 @@ func (engine *Engine) dumpTables(tables []*schemas.Table, w io.Writer, tp ...sch
|
|||
if col == nil {
|
||||
return errors.New("unknow column error")
|
||||
}
|
||||
|
||||
if d == nil {
|
||||
temp += ", NULL"
|
||||
} else if col.SQLType.IsText() || col.SQLType.IsTime() {
|
||||
var v = fmt.Sprintf("%s", d)
|
||||
if strings.HasSuffix(v, " +0000 UTC") {
|
||||
temp += fmt.Sprintf(", '%s'", v[0:len(v)-len(" +0000 UTC")])
|
||||
} else {
|
||||
temp += ", '" + strings.Replace(v, "'", "''", -1) + "'"
|
||||
}
|
||||
} else if col.SQLType.IsBlob() {
|
||||
if reflect.TypeOf(d).Kind() == reflect.Slice {
|
||||
temp += fmt.Sprintf(", %s", dstDialect.FormatBytes(d.([]byte)))
|
||||
} else if reflect.TypeOf(d).Kind() == reflect.String {
|
||||
temp += fmt.Sprintf(", '%s'", d.(string))
|
||||
}
|
||||
} else if col.SQLType.IsNumeric() {
|
||||
switch reflect.TypeOf(d).Kind() {
|
||||
case reflect.Slice:
|
||||
if col.SQLType.Name == schemas.Bool {
|
||||
temp += fmt.Sprintf(", %v", strconv.FormatBool(d.([]byte)[0] != byte('0')))
|
||||
} else {
|
||||
temp += fmt.Sprintf(", %s", string(d.([]byte)))
|
||||
}
|
||||
case reflect.Int16, reflect.Int8, reflect.Int32, reflect.Int64, reflect.Int:
|
||||
if col.SQLType.Name == schemas.Bool {
|
||||
temp += fmt.Sprintf(", %v", strconv.FormatBool(reflect.ValueOf(d).Int() > 0))
|
||||
} else {
|
||||
temp += fmt.Sprintf(", %v", d)
|
||||
}
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
if col.SQLType.Name == schemas.Bool {
|
||||
temp += fmt.Sprintf(", %v", strconv.FormatBool(reflect.ValueOf(d).Uint() > 0))
|
||||
} else {
|
||||
temp += fmt.Sprintf(", %v", d)
|
||||
}
|
||||
default:
|
||||
temp += fmt.Sprintf(", %v", d)
|
||||
}
|
||||
} else {
|
||||
s := fmt.Sprintf("%v", d)
|
||||
if strings.Contains(s, ":") || strings.Contains(s, "-") {
|
||||
if strings.HasSuffix(s, " +0000 UTC") {
|
||||
temp += fmt.Sprintf(", '%s'", s[0:len(s)-len(" +0000 UTC")])
|
||||
} else {
|
||||
temp += fmt.Sprintf(", '%s'", s)
|
||||
}
|
||||
} else {
|
||||
temp += fmt.Sprintf(", %s", s)
|
||||
}
|
||||
}
|
||||
temp += "," + formatColumnValue(dstDialect, d, col)
|
||||
}
|
||||
_, err = io.WriteString(w, temp[2:]+");\n")
|
||||
_, err = io.WriteString(w, temp[1:]+");\n")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -816,81 +876,11 @@ func (engine *Engine) IsTableExist(beanOrTableName interface{}) (bool, error) {
|
|||
return session.IsTableExist(beanOrTableName)
|
||||
}
|
||||
|
||||
// IDOf get id from one struct
|
||||
func (engine *Engine) IDOf(bean interface{}) (schemas.PK, error) {
|
||||
return engine.IDOfV(reflect.ValueOf(bean))
|
||||
}
|
||||
|
||||
// TableName returns table name with schema prefix if has
|
||||
func (engine *Engine) TableName(bean interface{}, includeSchema ...bool) string {
|
||||
return dialects.FullTableName(engine.dialect, engine.GetTableMapper(), bean, includeSchema...)
|
||||
}
|
||||
|
||||
// IDOfV get id from one value of struct
|
||||
func (engine *Engine) IDOfV(rv reflect.Value) (schemas.PK, error) {
|
||||
return engine.idOfV(rv)
|
||||
}
|
||||
|
||||
func (engine *Engine) idOfV(rv reflect.Value) (schemas.PK, error) {
|
||||
v := reflect.Indirect(rv)
|
||||
table, err := engine.tagParser.ParseWithCache(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pk := make([]interface{}, len(table.PrimaryKeys))
|
||||
for i, col := range table.PKColumns() {
|
||||
var err error
|
||||
|
||||
fieldName := col.FieldName
|
||||
for {
|
||||
parts := strings.SplitN(fieldName, ".", 2)
|
||||
if len(parts) == 1 {
|
||||
break
|
||||
}
|
||||
|
||||
v = v.FieldByName(parts[0])
|
||||
if v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
}
|
||||
if v.Kind() != reflect.Struct {
|
||||
return nil, ErrUnSupportedType
|
||||
}
|
||||
fieldName = parts[1]
|
||||
}
|
||||
|
||||
pkField := v.FieldByName(fieldName)
|
||||
switch pkField.Kind() {
|
||||
case reflect.String:
|
||||
pk[i], err = engine.idTypeAssertion(col, pkField.String())
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
pk[i], err = engine.idTypeAssertion(col, strconv.FormatInt(pkField.Int(), 10))
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
// id of uint will be converted to int64
|
||||
pk[i], err = engine.idTypeAssertion(col, strconv.FormatUint(pkField.Uint(), 10))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return schemas.PK(pk), nil
|
||||
}
|
||||
|
||||
func (engine *Engine) idTypeAssertion(col *schemas.Column, sid string) (interface{}, error) {
|
||||
if col.SQLType.IsNumeric() {
|
||||
n, err := strconv.ParseInt(sid, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return n, nil
|
||||
} else if col.SQLType.IsText() {
|
||||
return sid, nil
|
||||
} else {
|
||||
return nil, errors.New("not supported")
|
||||
}
|
||||
}
|
||||
|
||||
// CreateIndexes create indexes
|
||||
func (engine *Engine) CreateIndexes(bean interface{}) error {
|
||||
session := engine.NewSession()
|
||||
|
@ -1288,6 +1278,7 @@ func (engine *Engine) SetSchema(schema string) {
|
|||
engine.dialect.URI().SetSchema(schema)
|
||||
}
|
||||
|
||||
// AddHook adds a context Hook
|
||||
func (engine *Engine) AddHook(hook contexts.Hook) {
|
||||
engine.db.AddHook(hook)
|
||||
}
|
||||
|
@ -1303,7 +1294,7 @@ func (engine *Engine) tbNameWithSchema(v string) string {
|
|||
return dialects.TableNameWithSchema(engine.dialect, v)
|
||||
}
|
||||
|
||||
// ContextHook creates a session with the context
|
||||
// Context creates a session with the context
|
||||
func (engine *Engine) Context(ctx context.Context) *Session {
|
||||
session := engine.NewSession()
|
||||
session.isAutoClose = true
|
||||
|
@ -1333,11 +1324,11 @@ func (engine *Engine) Transaction(f func(*Session) (interface{}, error)) (interf
|
|||
|
||||
result, err := f(session)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return result, err
|
||||
}
|
||||
|
||||
if err := session.Commit(); err != nil {
|
||||
return nil, err
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
|
|
|
@ -79,7 +79,7 @@ func (eg *EngineGroup) Close() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ContextHook returned a group session
|
||||
// Context returned a group session
|
||||
func (eg *EngineGroup) Context(ctx context.Context) *Session {
|
||||
sess := eg.NewSession()
|
||||
sess.isAutoClose = true
|
||||
|
@ -144,6 +144,7 @@ func (eg *EngineGroup) SetLogger(logger interface{}) {
|
|||
}
|
||||
}
|
||||
|
||||
// AddHook adds Hook
|
||||
func (eg *EngineGroup) AddHook(hook contexts.Hook) {
|
||||
eg.Engine.AddHook(hook)
|
||||
for i := 0; i < len(eg.slaves); i++ {
|
||||
|
@ -167,6 +168,14 @@ func (eg *EngineGroup) SetMapper(mapper names.Mapper) {
|
|||
}
|
||||
}
|
||||
|
||||
// SetTagIdentifier set the tag identifier
|
||||
func (eg *EngineGroup) SetTagIdentifier(tagIdentifier string) {
|
||||
eg.Engine.SetTagIdentifier(tagIdentifier)
|
||||
for i := 0; i < len(eg.slaves); i++ {
|
||||
eg.slaves[i].SetTagIdentifier(tagIdentifier)
|
||||
}
|
||||
}
|
||||
|
||||
// SetMaxIdleConns set the max idle connections on pool, default is 2
|
||||
func (eg *EngineGroup) SetMaxIdleConns(conns int) {
|
||||
eg.Engine.DB().SetMaxIdleConns(conns)
|
||||
|
|
15
go.mod
15
go.mod
|
@ -1,16 +1,15 @@
|
|||
module xorm.io/xorm
|
||||
|
||||
go 1.11
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4
|
||||
github.com/go-sql-driver/mysql v1.4.1
|
||||
github.com/kr/pretty v0.1.0 // indirect
|
||||
github.com/lib/pq v1.0.0
|
||||
github.com/mattn/go-sqlite3 v1.10.0
|
||||
github.com/denisenkom/go-mssqldb v0.9.0
|
||||
github.com/go-sql-driver/mysql v1.5.0
|
||||
github.com/lib/pq v1.7.0
|
||||
github.com/mattn/go-sqlite3 v1.14.6
|
||||
github.com/stretchr/testify v1.4.0
|
||||
github.com/syndtr/goleveldb v1.0.0
|
||||
github.com/ziutek/mymysql v1.5.4
|
||||
google.golang.org/appengine v1.6.0 // indirect
|
||||
xorm.io/builder v0.3.7
|
||||
modernc.org/sqlite v1.10.1-0.20210314190707-798bbeb9bb84
|
||||
xorm.io/builder v0.3.8
|
||||
)
|
||||
|
|
201
go.sum
201
go.sum
|
@ -1,152 +1,89 @@
|
|||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.37.4 h1:glPeL3BQJsbF6aIIYfZizMwc5LTYz250bDMjttbBGAU=
|
||||
cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw=
|
||||
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s=
|
||||
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4 h1:YcpmyvADGYw5LqMnHqSkyIELsHCGF6PkrmM31V8rF7o=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM=
|
||||
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||
github.com/denisenkom/go-mssqldb v0.9.0 h1:RSohk2RsiZqLZ0zCjtfn3S4Gp4exhpBWHyQ7D0yGjAk=
|
||||
github.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
|
||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
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/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/google/go-cmp v0.5.3 h1:x95R7cp+rSeeqAMI2knLtQ0DKlaBhv2NrtrOvafPHRo=
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
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/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/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/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/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||
github.com/lib/pq v1.7.0 h1:h93mCPfUSkaul3Ka/VG8uZdmW1uMHDGxzu0NWHuJmHY=
|
||||
github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg=
|
||||
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
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/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
|
||||
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
|
||||
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
||||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c h1:Vj5n4GlwjmQteupaxJ9+0FNOmBrHfq7vN4btdGoDZgI=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 h1:bjcUS9ztw9kFmmIxJInhon/0Is3p+EHBKNgquIzo1OI=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 h1:z99zHgr7hKfrUcX/KsoJk5FJfjTceCKIp96+biqP4To=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
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-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.0 h1:Tfd7cKwKbFRsI8RMAD3oqqw7JPFRrvFlOsfbgVkjOOw=
|
||||
google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78 h1:M8tBwCtWD/cZV9DZpFYRUgaymAYAr+aIUTWzDaM3uPs=
|
||||
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
|
@ -154,8 +91,32 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD
|
|||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
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-20190102054323-c2f93a96b099/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.7 h1:2pETdKRK+2QG4mLX4oODHEhn5Z8j1m8sXa7jfu+/SZI=
|
||||
xorm.io/builder v0.3.7/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
|
||||
modernc.org/cc/v3 v3.31.5-0.20210308123301-7a3e9dab9009 h1:u0oCo5b9wyLr++HF3AN9JicGhkUxJhMz51+8TIZH9N0=
|
||||
modernc.org/cc/v3 v3.31.5-0.20210308123301-7a3e9dab9009/go.mod h1:0R6jl1aZlIl2avnYfbfHBS1QB6/f+16mihBObaBC878=
|
||||
modernc.org/ccgo/v3 v3.9.0 h1:JbcEIqjw4Agf+0g3Tc85YvfYqkkFOv6xBwS4zkfqSoA=
|
||||
modernc.org/ccgo/v3 v3.9.0/go.mod h1:nQbgkn8mwzPdp4mm6BT6+p85ugQ7FrGgIcYaE7nSrpY=
|
||||
modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
|
||||
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
|
||||
modernc.org/libc v1.7.13-0.20210308123627-12f642a52bb8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w=
|
||||
modernc.org/libc v1.8.0 h1:Pp4uv9g0csgBMpGPABKtkieF6O5MGhfGo6ZiOdlYfR8=
|
||||
modernc.org/libc v1.8.0/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w=
|
||||
modernc.org/mathutil v1.1.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
||||
modernc.org/mathutil v1.2.2 h1:+yFk8hBprV+4c0U9GjFtL+dV3N8hOJ8JCituQcMShFY=
|
||||
modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
||||
modernc.org/memory v1.0.4 h1:utMBrFcpnQDdNsmM6asmyH/FM9TqLPS7XF7otpJmrwM=
|
||||
modernc.org/memory v1.0.4/go.mod h1:nV2OApxradM3/OVbs2/0OsP6nPfakXpi50C7dcoHXlc=
|
||||
modernc.org/opt v0.1.1 h1:/0RX92k9vwVeDXj+Xn23DKp2VJubL7k8qNffND6qn3A=
|
||||
modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
||||
modernc.org/sqlite v1.10.1-0.20210314190707-798bbeb9bb84 h1:rgEUzE849tFlHSoeCrKyS9cZAljC+DY7MdMHKq6R6sY=
|
||||
modernc.org/sqlite v1.10.1-0.20210314190707-798bbeb9bb84/go.mod h1:PGzq6qlhyYjL6uVbSgS6WoF7ZopTW/sI7+7p+mb4ZVU=
|
||||
modernc.org/strutil v1.1.0 h1:+1/yCzZxY2pZwwrsbH+4T7BQMoLQ9QiBshRC9eicYsc=
|
||||
modernc.org/strutil v1.1.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=
|
||||
modernc.org/tcl v1.5.0 h1:euZSUNfE0Fd4W8VqXI1Ly1v7fqDJoBuAV88Ea+SnaSs=
|
||||
modernc.org/tcl v1.5.0/go.mod h1:gb57hj4pO8fRrK54zveIfFXBaMHK3SKJNWcmRw1cRzc=
|
||||
modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk=
|
||||
modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||
modernc.org/z v1.0.1-0.20210308123920-1f282aa71362/go.mod h1:8/SRk5C/HgiQWCgXdfpb+1RvhORdkz5sw72d3jjtyqA=
|
||||
modernc.org/z v1.0.1 h1:WyIDpEpAIx4Hel6q/Pcgj/VhaQV5XPJ2I6ryIYbjnpc=
|
||||
modernc.org/z v1.0.1/go.mod h1:8/SRk5C/HgiQWCgXdfpb+1RvhORdkz5sw72d3jjtyqA=
|
||||
xorm.io/builder v0.3.8 h1:P/wPgRqa9kX5uE0aA1/ukJ23u9KH0aSRpHLwDKXigSE=
|
||||
xorm.io/builder v0.3.8/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
_ "github.com/mattn/go-sqlite3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
_ "github.com/ziutek/mymysql/godrv"
|
||||
_ "modernc.org/sqlite"
|
||||
)
|
||||
|
||||
func TestPing(t *testing.T) {
|
||||
|
@ -93,19 +94,23 @@ func TestDump(t *testing.T) {
|
|||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type TestDumpStruct struct {
|
||||
Id int64
|
||||
Name string
|
||||
Id int64
|
||||
Name string
|
||||
IsMan bool
|
||||
Created time.Time `xorm:"created"`
|
||||
}
|
||||
|
||||
assertSync(t, new(TestDumpStruct))
|
||||
|
||||
testEngine.Insert([]TestDumpStruct{
|
||||
{Name: "1"},
|
||||
cnt, err := testEngine.Insert([]TestDumpStruct{
|
||||
{Name: "1", IsMan: true},
|
||||
{Name: "2\n"},
|
||||
{Name: "3;"},
|
||||
{Name: "4\n;\n''"},
|
||||
{Name: "5'\n"},
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 5, cnt)
|
||||
|
||||
fp := fmt.Sprintf("%v.sql", testEngine.Dialect().URI().DBType)
|
||||
os.Remove(fp)
|
||||
|
@ -116,7 +121,7 @@ func TestDump(t *testing.T) {
|
|||
sess := testEngine.NewSession()
|
||||
defer sess.Close()
|
||||
assert.NoError(t, sess.Begin())
|
||||
_, err := sess.ImportFile(fp)
|
||||
_, err = sess.ImportFile(fp)
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, sess.Commit())
|
||||
|
||||
|
@ -128,6 +133,49 @@ func TestDump(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestDumpTables(t *testing.T) {
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type TestDumpTableStruct struct {
|
||||
Id int64
|
||||
Name string
|
||||
IsMan bool
|
||||
Created time.Time `xorm:"created"`
|
||||
}
|
||||
|
||||
assertSync(t, new(TestDumpTableStruct))
|
||||
|
||||
testEngine.Insert([]TestDumpTableStruct{
|
||||
{Name: "1", IsMan: true},
|
||||
{Name: "2\n"},
|
||||
{Name: "3;"},
|
||||
{Name: "4\n;\n''"},
|
||||
{Name: "5'\n"},
|
||||
})
|
||||
|
||||
fp := fmt.Sprintf("%v-table.sql", testEngine.Dialect().URI().DBType)
|
||||
os.Remove(fp)
|
||||
tb, err := testEngine.TableInfo(new(TestDumpTableStruct))
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, testEngine.(*xorm.Engine).DumpTablesToFile([]*schemas.Table{tb}, fp))
|
||||
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
sess := testEngine.NewSession()
|
||||
defer sess.Close()
|
||||
assert.NoError(t, sess.Begin())
|
||||
_, err = sess.ImportFile(fp)
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, sess.Commit())
|
||||
|
||||
for _, tp := range []schemas.DBType{schemas.SQLITE, schemas.MYSQL, schemas.POSTGRES, schemas.MSSQL} {
|
||||
name := fmt.Sprintf("dump_%v-table.sql", tp)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert.NoError(t, testEngine.(*xorm.Engine).DumpTablesToFile([]*schemas.Table{tb}, name, tp))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetSchema(t *testing.T) {
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
|
@ -139,3 +187,16 @@ func TestSetSchema(t *testing.T) {
|
|||
assert.EqualValues(t, oldSchema, testEngine.Dialect().URI().Schema)
|
||||
}
|
||||
}
|
||||
|
||||
func TestImport(t *testing.T) {
|
||||
if testEngine.Dialect().URI().DBType != schemas.MYSQL {
|
||||
t.Skip()
|
||||
return
|
||||
}
|
||||
sess := testEngine.NewSession()
|
||||
defer sess.Close()
|
||||
assert.NoError(t, sess.Begin())
|
||||
_, err := sess.ImportFile("./testdata/import1.sql")
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, sess.Commit())
|
||||
}
|
||||
|
|
|
@ -502,13 +502,58 @@ func TestFindAndCountOneFunc(t *testing.T) {
|
|||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
results = make([]FindAndCountStruct, 0, 1)
|
||||
cnt, err = testEngine.Where("msg = ?", true).Limit(1).FindAndCount(&results)
|
||||
cnt, err = testEngine.Where("1=1").Limit(1).FindAndCount(&results)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(results))
|
||||
assert.EqualValues(t, 2, cnt)
|
||||
assert.EqualValues(t, FindAndCountStruct{
|
||||
Id: 1,
|
||||
Content: "111",
|
||||
Msg: false,
|
||||
}, results[0])
|
||||
|
||||
results = make([]FindAndCountStruct, 0, 1)
|
||||
cnt, err = testEngine.Where("1=1").Limit(1).FindAndCount(&results)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(results))
|
||||
assert.EqualValues(t, 2, cnt)
|
||||
assert.EqualValues(t, FindAndCountStruct{
|
||||
Id: 1,
|
||||
Content: "111",
|
||||
Msg: false,
|
||||
}, results[0])
|
||||
|
||||
results = make([]FindAndCountStruct, 0, 1)
|
||||
cnt, err = testEngine.Where("1=1").Limit(1, 1).FindAndCount(&results)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(results))
|
||||
assert.EqualValues(t, 2, cnt)
|
||||
assert.EqualValues(t, FindAndCountStruct{
|
||||
Id: 2,
|
||||
Content: "222",
|
||||
Msg: true,
|
||||
}, results[0])
|
||||
|
||||
results = make([]FindAndCountStruct, 0, 1)
|
||||
cnt, err = testEngine.Where("1=1").Limit(1, 1).FindAndCount(&results)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(results))
|
||||
assert.EqualValues(t, 2, cnt)
|
||||
assert.EqualValues(t, FindAndCountStruct{
|
||||
Id: 2,
|
||||
Content: "222",
|
||||
Msg: true,
|
||||
}, results[0])
|
||||
|
||||
results = make([]FindAndCountStruct, 0, 1)
|
||||
cnt, err = testEngine.Where("msg = ?", true).Select("id, content, msg").
|
||||
Limit(1).FindAndCount(&results)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(results))
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
results = make([]FindAndCountStruct, 0, 1)
|
||||
cnt, err = testEngine.Where("msg = ?", true).Select("id, content, msg").
|
||||
cnt, err = testEngine.Where("msg = ?", true).Cols("id", "content", "msg").
|
||||
Limit(1).FindAndCount(&results)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(results))
|
||||
|
@ -708,6 +753,13 @@ func TestFindExtends(t *testing.T) {
|
|||
err = testEngine.Find(&results)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 2, len(results))
|
||||
|
||||
results = make([]FindExtendsA, 0, 2)
|
||||
err = testEngine.Find(&results, &FindExtendsB{
|
||||
ID: 1,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(results))
|
||||
}
|
||||
|
||||
func TestFindExtends3(t *testing.T) {
|
||||
|
|
|
@ -6,11 +6,13 @@ package integrations
|
|||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm"
|
||||
"xorm.io/xorm/contexts"
|
||||
"xorm.io/xorm/schemas"
|
||||
|
||||
|
@ -394,6 +396,60 @@ func TestJSONString(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(jss))
|
||||
assert.True(t, `["1","2"]` == jss[0].Content || `["1", "2"]` == jss[0].Content)
|
||||
|
||||
type JsonAnonymousStruct struct {
|
||||
Id int64
|
||||
JsonString `xorm:"'json_string' JSON LONGTEXT"`
|
||||
}
|
||||
|
||||
assertSync(t, new(JsonAnonymousStruct))
|
||||
|
||||
_, err = testEngine.Insert(&JsonAnonymousStruct{
|
||||
JsonString: JsonString{
|
||||
Content: "1",
|
||||
},
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
var jas JsonAnonymousStruct
|
||||
has, err = testEngine.Get(&jas)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
assert.EqualValues(t, 1, jas.Id)
|
||||
assert.EqualValues(t, "1", jas.Content)
|
||||
|
||||
var jass []JsonAnonymousStruct
|
||||
err = testEngine.Find(&jass)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(jass))
|
||||
assert.EqualValues(t, "1", jass[0].Content)
|
||||
|
||||
type JsonStruct struct {
|
||||
Id int64
|
||||
JSON JsonString `xorm:"'json_string' JSON LONGTEXT"`
|
||||
}
|
||||
|
||||
assertSync(t, new(JsonStruct))
|
||||
|
||||
_, err = testEngine.Insert(&JsonStruct{
|
||||
JSON: JsonString{
|
||||
Content: "2",
|
||||
},
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
var jst JsonStruct
|
||||
has, err = testEngine.Get(&jst)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
assert.EqualValues(t, 1, jst.Id)
|
||||
assert.EqualValues(t, "2", jst.JSON.Content)
|
||||
|
||||
var jsts []JsonStruct
|
||||
err = testEngine.Find(&jsts)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(jsts))
|
||||
assert.EqualValues(t, "2", jsts[0].JSON.Content)
|
||||
}
|
||||
|
||||
func TestGetActionMapping(t *testing.T) {
|
||||
|
@ -696,3 +752,17 @@ func TestGetViaMapCond(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
assert.False(t, has)
|
||||
}
|
||||
|
||||
func TestGetNil(t *testing.T) {
|
||||
type GetNil struct {
|
||||
Id int64
|
||||
}
|
||||
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(GetNil))
|
||||
|
||||
var gn *GetNil
|
||||
has, err := testEngine.Get(gn)
|
||||
assert.True(t, errors.Is(err, xorm.ErrObjectIsNil))
|
||||
assert.False(t, has)
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"xorm.io/xorm/schemas"
|
||||
)
|
||||
|
||||
func TestStoreEngine(t *testing.T) {
|
||||
|
@ -102,6 +103,9 @@ func TestSyncTable(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(tables))
|
||||
assert.EqualValues(t, "sync_table1", tables[0].Name)
|
||||
tableInfo, err := testEngine.TableInfo(new(SyncTable1))
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, testEngine.Dialect().SQLType(tables[0].GetColumn("name")), testEngine.Dialect().SQLType(tableInfo.GetColumn("name")))
|
||||
|
||||
assert.NoError(t, testEngine.Sync2(new(SyncTable2)))
|
||||
|
||||
|
@ -109,6 +113,9 @@ func TestSyncTable(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(tables))
|
||||
assert.EqualValues(t, "sync_table1", tables[0].Name)
|
||||
tableInfo, err = testEngine.TableInfo(new(SyncTable2))
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, testEngine.Dialect().SQLType(tables[0].GetColumn("name")), testEngine.Dialect().SQLType(tableInfo.GetColumn("name")))
|
||||
|
||||
assert.NoError(t, testEngine.Sync2(new(SyncTable3)))
|
||||
|
||||
|
@ -116,6 +123,9 @@ func TestSyncTable(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(tables))
|
||||
assert.EqualValues(t, "sync_table1", tables[0].Name)
|
||||
tableInfo, err = testEngine.TableInfo(new(SyncTable3))
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, testEngine.Dialect().SQLType(tables[0].GetColumn("name")), testEngine.Dialect().SQLType(tableInfo.GetColumn("name")))
|
||||
}
|
||||
|
||||
func TestSyncTable2(t *testing.T) {
|
||||
|
@ -143,6 +153,63 @@ func TestSyncTable2(t *testing.T) {
|
|||
assert.EqualValues(t, colMapper.Obj2Table("NewCol"), tables[0].Columns()[3].Name)
|
||||
}
|
||||
|
||||
func TestSyncTable3(t *testing.T) {
|
||||
type SyncTable5 struct {
|
||||
Id int64
|
||||
Name string
|
||||
Text string `xorm:"TEXT"`
|
||||
Char byte `xorm:"CHAR(1)"`
|
||||
TenChar [10]byte `xorm:"CHAR(10)"`
|
||||
TenVarChar string `xorm:"VARCHAR(10)"`
|
||||
}
|
||||
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
assert.NoError(t, testEngine.Sync2(new(SyncTable5)))
|
||||
|
||||
tables, err := testEngine.DBMetas()
|
||||
assert.NoError(t, err)
|
||||
tableInfo, err := testEngine.TableInfo(new(SyncTable5))
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, testEngine.Dialect().SQLType(tableInfo.GetColumn("name")), testEngine.Dialect().SQLType(tables[0].GetColumn("name")))
|
||||
assert.EqualValues(t, testEngine.Dialect().SQLType(tableInfo.GetColumn("text")), testEngine.Dialect().SQLType(tables[0].GetColumn("text")))
|
||||
assert.EqualValues(t, testEngine.Dialect().SQLType(tableInfo.GetColumn("char")), testEngine.Dialect().SQLType(tables[0].GetColumn("char")))
|
||||
assert.EqualValues(t, testEngine.Dialect().SQLType(tableInfo.GetColumn("ten_char")), testEngine.Dialect().SQLType(tables[0].GetColumn("ten_char")))
|
||||
assert.EqualValues(t, testEngine.Dialect().SQLType(tableInfo.GetColumn("ten_var_char")), testEngine.Dialect().SQLType(tables[0].GetColumn("ten_var_char")))
|
||||
|
||||
if *doNVarcharTest {
|
||||
var oldDefaultVarchar string
|
||||
var oldDefaultChar string
|
||||
oldDefaultVarchar, *defaultVarchar = *defaultVarchar, "nvarchar"
|
||||
oldDefaultChar, *defaultChar = *defaultChar, "nchar"
|
||||
testEngine.Dialect().SetParams(map[string]string{
|
||||
"DEFAULT_VARCHAR": *defaultVarchar,
|
||||
"DEFAULT_CHAR": *defaultChar,
|
||||
})
|
||||
defer func() {
|
||||
*defaultVarchar = oldDefaultVarchar
|
||||
*defaultChar = oldDefaultChar
|
||||
testEngine.Dialect().SetParams(map[string]string{
|
||||
"DEFAULT_VARCHAR": *defaultVarchar,
|
||||
"DEFAULT_CHAR": *defaultChar,
|
||||
})
|
||||
}()
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
assert.NoError(t, testEngine.Sync2(new(SyncTable5)))
|
||||
|
||||
tables, err := testEngine.DBMetas()
|
||||
assert.NoError(t, err)
|
||||
tableInfo, err := testEngine.TableInfo(new(SyncTable5))
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, testEngine.Dialect().SQLType(tableInfo.GetColumn("name")), testEngine.Dialect().SQLType(tables[0].GetColumn("name")))
|
||||
assert.EqualValues(t, testEngine.Dialect().SQLType(tableInfo.GetColumn("text")), testEngine.Dialect().SQLType(tables[0].GetColumn("text")))
|
||||
assert.EqualValues(t, testEngine.Dialect().SQLType(tableInfo.GetColumn("char")), testEngine.Dialect().SQLType(tables[0].GetColumn("char")))
|
||||
assert.EqualValues(t, testEngine.Dialect().SQLType(tableInfo.GetColumn("ten_char")), testEngine.Dialect().SQLType(tables[0].GetColumn("ten_char")))
|
||||
assert.EqualValues(t, testEngine.Dialect().SQLType(tableInfo.GetColumn("ten_var_char")), testEngine.Dialect().SQLType(tables[0].GetColumn("ten_var_char")))
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsTableExist(t *testing.T) {
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
|
@ -330,3 +397,30 @@ func TestSync2_Default(t *testing.T) {
|
|||
assertSync(t, new(TestSync2Default))
|
||||
assert.NoError(t, testEngine.Sync2(new(TestSync2Default)))
|
||||
}
|
||||
|
||||
func TestModifyColum(t *testing.T) {
|
||||
// Since SQLITE don't support modify column SQL, currrently just ignore
|
||||
if testEngine.Dialect().URI().DBType == schemas.SQLITE {
|
||||
return
|
||||
}
|
||||
type TestModifyColumn struct {
|
||||
Id int64
|
||||
UserId int64 `xorm:"default(1)"`
|
||||
IsMember bool `xorm:"default(true)"`
|
||||
Name string `xorm:"char(10)"`
|
||||
}
|
||||
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(TestModifyColumn))
|
||||
|
||||
alterSQL := testEngine.Dialect().ModifyColumnSQL("test_modify_column", &schemas.Column{
|
||||
Name: "name",
|
||||
SQLType: schemas.SQLType{
|
||||
Name: "VARCHAR",
|
||||
},
|
||||
Length: 16,
|
||||
Nullable: false,
|
||||
})
|
||||
_, err := testEngine.Exec(alterSQL)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
|
|
@ -54,3 +54,11 @@ func TestMustLogSQL(t *testing.T) {
|
|||
_, err := testEngine.Table("userinfo").MustLogSQL(true).Get(new(Userinfo))
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestEnableSessionId(t *testing.T) {
|
||||
assert.NoError(t, PrepareEngine())
|
||||
testEngine.EnableSessionID(true)
|
||||
assertSync(t, new(Userinfo))
|
||||
_, err := testEngine.Table("userinfo").MustLogSQL(true).Get(new(Userinfo))
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
|
|
@ -12,8 +12,10 @@ import (
|
|||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"xorm.io/xorm"
|
||||
"xorm.io/xorm/internal/statements"
|
||||
"xorm.io/xorm/internal/utils"
|
||||
"xorm.io/xorm/names"
|
||||
"xorm.io/xorm/schemas"
|
||||
)
|
||||
|
||||
func TestUpdateMap(t *testing.T) {
|
||||
|
@ -39,6 +41,27 @@ func TestUpdateMap(t *testing.T) {
|
|||
})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
cnt, err = testEngine.Table("update_table").ID(tb.Id).Update(map[string]interface{}{
|
||||
"name": "test2",
|
||||
"age": 36,
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.True(t, statements.IsIDConditionWithNoTableErr(err))
|
||||
assert.EqualValues(t, 0, cnt)
|
||||
|
||||
cnt, err = testEngine.Table("update_table").Update(map[string]interface{}{
|
||||
"name": "test2",
|
||||
"age": 36,
|
||||
}, &UpdateTable{
|
||||
Id: tb.Id,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
if testEngine.Dialect().URI().DBType == schemas.MYSQL {
|
||||
assert.EqualValues(t, 0, cnt)
|
||||
} else {
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateLimit(t *testing.T) {
|
||||
|
@ -179,6 +202,9 @@ func TestForUpdate(t *testing.T) {
|
|||
|
||||
// lock is NOT used
|
||||
wg.Add(1)
|
||||
|
||||
wg2 := &sync.WaitGroup{}
|
||||
wg2.Add(1)
|
||||
go func() {
|
||||
f3 := new(ForUpdate)
|
||||
session3.Where("id = ?", 1)
|
||||
|
@ -192,10 +218,10 @@ func TestForUpdate(t *testing.T) {
|
|||
t.Errorf("read lock failed")
|
||||
}
|
||||
wg.Done()
|
||||
wg2.Done()
|
||||
}()
|
||||
|
||||
// wait for go rountines
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
wg2.Wait()
|
||||
|
||||
f := new(ForUpdate)
|
||||
f.Name = "updated by session1"
|
||||
|
@ -988,7 +1014,7 @@ func TestUpdateMapContent(t *testing.T) {
|
|||
assert.EqualValues(t, false, c2.IsMan)
|
||||
assert.EqualValues(t, 2, c2.Gender)
|
||||
|
||||
cnt, err = testEngine.Table(testEngine.TableName(new(UpdateMapContent))).ID(c.Id).Update(map[string]interface{}{
|
||||
cnt, err = testEngine.Table(new(UpdateMapContent)).ID(c.Id).Update(map[string]interface{}{
|
||||
"age": 15,
|
||||
"is_man": true,
|
||||
"gender": 1,
|
||||
|
@ -1341,3 +1367,50 @@ func TestUpdateMultiplePK(t *testing.T) {
|
|||
_, err = testEngine.ID(&MySlice{test.Id, test.Name}).Update(test)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
type TestFieldType1 struct {
|
||||
cb []byte
|
||||
}
|
||||
|
||||
func (a *TestFieldType1) FromDB(src []byte) error {
|
||||
a.cb = src
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a TestFieldType1) ToDB() ([]byte, error) {
|
||||
return a.cb, nil
|
||||
}
|
||||
|
||||
type TestTable1 struct {
|
||||
Id int64
|
||||
Field1 *TestFieldType1 `xorm:"text"`
|
||||
UpdateTime time.Time
|
||||
}
|
||||
|
||||
func TestNilFromDB(t *testing.T) {
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(TestTable1))
|
||||
|
||||
cnt, err := testEngine.Insert(&TestTable1{
|
||||
Field1: &TestFieldType1{
|
||||
cb: []byte("string"),
|
||||
},
|
||||
UpdateTime: time.Now(),
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
cnt, err = testEngine.Update(TestTable1{
|
||||
UpdateTime: time.Now().Add(time.Second),
|
||||
}, TestTable1{
|
||||
Id: 1,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
cnt, err = testEngine.Insert(&TestTable1{
|
||||
UpdateTime: time.Now(),
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,279 @@
|
|||
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
|
||||
SET time_zone = "+00:00";
|
||||
|
||||
-- 基本用户信息表
|
||||
CREATE TABLE IF NOT EXISTS `user` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `uid` (`id`),
|
||||
`user_name` varchar(128) CHARACTER SET utf8mb4 NOT NULL,
|
||||
KEY `user_name` (`user_name`),
|
||||
`email` varchar(32) NOT NULL,
|
||||
KEY `email` (`email`),
|
||||
`pass` varchar(256) NOT NULL,
|
||||
`passwd` varchar(16) NOT NULL,
|
||||
`uuid` TEXT NULL DEFAULT NULL COMMENT 'uuid',
|
||||
`t` int(11) NOT NULL DEFAULT '0',
|
||||
`u` bigint(20) NOT NULL,
|
||||
`d` bigint(20) NOT NULL,
|
||||
`plan` varchar(2) CHARACTER SET utf8mb4 NOT NULL DEFAULT 'A',
|
||||
`node_group` INT NOT NULL DEFAULT '0',
|
||||
`auto_reset_day` INT NOT NULL DEFAULT '0',
|
||||
`auto_reset_bandwidth` DECIMAL(12,2) NOT NULL DEFAULT '0.00',
|
||||
`transfer_enable` BIGINT(20) NOT NULL,
|
||||
`port` int(11) NOT NULL,
|
||||
`protocol_param` VARCHAR(128) NULL DEFAULT NULL,
|
||||
`obfs_param` VARCHAR(128) NULL DEFAULT NULL,
|
||||
`switch` tinyint(4) NOT NULL DEFAULT '1',
|
||||
`enable` tinyint(4) NOT NULL DEFAULT '1',
|
||||
`type` tinyint(4) NOT NULL DEFAULT '1',
|
||||
`last_get_gift_time` int(11) NOT NULL DEFAULT '0',
|
||||
`last_check_in_time` int(11) NOT NULL DEFAULT '0',
|
||||
`last_rest_pass_time` int(11) NOT NULL DEFAULT '0',
|
||||
`reg_date` datetime NOT NULL,
|
||||
`invite_num` int(8) NOT NULL,
|
||||
`money` decimal(12,2) NOT NULL,
|
||||
`ref_by` int(11) NOT NULL DEFAULT '0',
|
||||
`expire_time` int(11) NOT NULL DEFAULT '0',
|
||||
`is_email_verify` tinyint(4) NOT NULL DEFAULT '0',
|
||||
`reg_ip` varchar(128) NOT NULL DEFAULT '127.0.0.1',
|
||||
`node_speedlimit` DECIMAL(12,2) NOT NULL DEFAULT '0.00',
|
||||
`node_connector` int(11) NOT NULL DEFAULT '0',
|
||||
`forbidden_ip` LONGTEXT NULL DEFAULT '',
|
||||
`forbidden_port` LONGTEXT NULL DEFAULT '',
|
||||
`disconnect_ip` LONGTEXT NULL DEFAULT '',
|
||||
`is_hide` INT NOT NULL DEFAULT '0',
|
||||
`last_detect_ban_time` datetime DEFAULT '1989-06-04 00:05:00',
|
||||
`all_detect_number` int(11) NOT NULL DEFAULT '0',
|
||||
`is_multi_user` INT NOT NULL DEFAULT '0',
|
||||
`telegram_id` BIGINT NULL,
|
||||
`is_admin` int(2) NOT NULL DEFAULT '0',
|
||||
`im_type` int(11) DEFAULT '1',
|
||||
`im_value` text,
|
||||
`last_day_t` bigint(20) NOT NULL DEFAULT '0',
|
||||
`mail_notified` int(11) NOT NULL DEFAULT '0',
|
||||
`class` int(11) NOT NULL DEFAULT '0',
|
||||
`class_expire` datetime NOT NULL DEFAULT '1989-06-04 00:05:00',
|
||||
`expire_in` datetime NOT NULL DEFAULT '2099-06-04 00:05:00',
|
||||
`theme` text NOT NULL,
|
||||
`ga_token` text NOT NULL,
|
||||
`ga_enable` int(11) NOT NULL DEFAULT '0',
|
||||
`pac` LONGTEXT,
|
||||
`remark` text
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- 用户流量信息表
|
||||
-- TODO: 重写流量信息提取逻辑
|
||||
CREATE TABLE IF NOT EXISTS `user_traffic_log` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
PRIMARY KEY (`id`),
|
||||
`user_id` int(11) NOT NULL,
|
||||
`u` BIGINT(20) NOT NULL,
|
||||
`d` BIGINT(20) NOT NULL,
|
||||
`node_id` int(11) NOT NULL,
|
||||
`rate` float NOT NULL,
|
||||
`traffic` varchar(32) NOT NULL,
|
||||
`log_time` int(11) NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- 用户订阅 TOKEN 信息表
|
||||
CREATE TABLE IF NOT EXISTS `user_token` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
PRIMARY KEY (`id`),
|
||||
`token` varchar(256) NOT NULL,
|
||||
`user_id` int(11) NOT NULL,
|
||||
`create_time` int(11) NOT NULL,
|
||||
`expire_time` int(11) NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- 充值码使用信息表
|
||||
CREATE TABLE IF NOT EXISTS `charge_code` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||
PRIMARY KEY (`id`),
|
||||
`code` text NOT NULL,
|
||||
`type` int(11) NOT NULL,
|
||||
`number` DECIMAL(11,2) NOT NULL,
|
||||
`isused` int(11) NOT NULL DEFAULT '0',
|
||||
`userid` bigint(20) NOT NULL,
|
||||
`usedatetime` datetime NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- 邀请码使用信息表
|
||||
CREATE TABLE IF NOT EXISTS `invite_code` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
PRIMARY KEY (`id`),
|
||||
`code` varchar(128) NOT NULL,
|
||||
KEY `user_id` (`user_id`),
|
||||
`user_id` int(11) NOT NULL,
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NOT NULL DEFAULT '2016-06-01 00:00:00'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- 公告信息表
|
||||
CREATE TABLE IF NOT EXISTS `announcement` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
PRIMARY KEY (`id`),
|
||||
`date` datetime NOT NULL,
|
||||
`content` LONGTEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`markdown` LONGTEXT NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- 节点信息表
|
||||
CREATE TABLE IF NOT EXISTS `node` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
PRIMARY KEY (`id`),
|
||||
`name` varchar(128) NOT NULL,
|
||||
`type` int(3) NOT NULL,
|
||||
`online_user` int(11) NOT NULL,
|
||||
`mu_only` INT NULL DEFAULT '0',
|
||||
`online` BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
`server` varchar(128) NOT NULL,
|
||||
`method` varchar(64) NOT NULL,
|
||||
`info` varchar(128) NOT NULL,
|
||||
`status` varchar(128) NOT NULL,
|
||||
`node_group` INT NOT NULL DEFAULT '0',
|
||||
`sort` int(3) NOT NULL,
|
||||
`custom_method` tinyint(1) NOT NULL DEFAULT '0',
|
||||
`traffic_rate` float NOT NULL DEFAULT '1',
|
||||
`node_class` int(11) NOT NULL DEFAULT '0',
|
||||
`node_speedlimit` DECIMAL(12,2) NOT NULL DEFAULT '0.00',
|
||||
`node_connector` int(11) NOT NULL DEFAULT '0',
|
||||
`node_bandwidth` bigint(20) NOT NULL DEFAULT '0',
|
||||
`node_bandwidth_limit` bigint(20) NOT NULL DEFAULT '0',
|
||||
`bandwidthlimit_resetday` int(11) NOT NULL DEFAULT '0',
|
||||
`node_heartbeat` bigint(20) NOT NULL DEFAULT '0',
|
||||
`node_ip` text
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
-- TODO: 修改 VPN 节点的结算说明
|
||||
|
||||
-- 商店数据表
|
||||
CREATE TABLE `shop` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`name` TEXT NOT NULL,
|
||||
`price` DECIMAL(12,2) NOT NULL,
|
||||
`content` TEXT NOT NULL,
|
||||
`auto_renew` INT NOT NULL,
|
||||
`status` INT NOT NULL DEFAULT '1',
|
||||
`auto_reset_bandwidth` INT NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE = InnoDB CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- 优惠券数据表
|
||||
CREATE TABLE `coupon` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`code` TEXT NOT NULL,
|
||||
`onetime` INT NOT NULL,
|
||||
`expire` BIGINT NOT NULL,
|
||||
`shop` TEXT NOT NULL,
|
||||
`credit` INT NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE = InnoDB CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- 购买记录数据表
|
||||
CREATE TABLE `bought` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`userid` BIGINT NOT NULL,
|
||||
`shopid` BIGINT NOT NULL,
|
||||
`coupon` TEXT NOT NULL,
|
||||
`datetime` BIGINT NOT NULL,
|
||||
`renew` BIGINT(11) NOT NULL,
|
||||
`price` DECIMAL(12,2) NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE = InnoDB CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- 工单数据表
|
||||
CREATE TABLE `ticket` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`title` LONGTEXT NOT NULL,
|
||||
`status` INT NOT NULL DEFAULT '1',
|
||||
`content` LONGTEXT NOT NULL,
|
||||
`rootid` BIGINT NOT NULL,`userid` BIGINT NOT NULL,
|
||||
`datetime` BIGINT NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE = InnoDB CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- 返利记录数据表
|
||||
CREATE TABLE `payback` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`total` DECIMAL(12,2) NOT NULL,
|
||||
`userid` BIGINT NOT NULL,
|
||||
`ref_by` BIGINT NOT NULL,
|
||||
`ref_get` DECIMAL(12,2) NOT NULL,
|
||||
`datetime` BIGINT NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE = InnoDB CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- 审计规则数据表
|
||||
CREATE TABLE `detect_list` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`name` LONGTEXT NOT NULL,
|
||||
`type` INT NOT NULL,
|
||||
`text` LONGTEXT NOT NULL,
|
||||
`regex` LONGTEXT NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE = InnoDB CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- 审计记录数据表
|
||||
CREATE TABLE `detect_log` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`user_id` BIGINT NOT NULL,
|
||||
`node_id` INT NOT NULL,
|
||||
`list_id` BIGINT NOT NULL,
|
||||
`datetime` BIGINT NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE = InnoDB CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- 中转规则数据表
|
||||
CREATE TABLE IF NOT EXISTS `relay` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||
PRIMARY KEY (`id`),
|
||||
`user_id` bigint(20) NOT NULL,
|
||||
`source_node_id` bigint(20) NOT NULL,
|
||||
`dist_node_id` bigint(20) NOT NULL,
|
||||
`dist_ip` text NOT NULL,
|
||||
`port` int(11) NOT NULL,
|
||||
`priority` int(11) NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- 用户订阅日志
|
||||
CREATE TABLE IF NOT EXISTS `user_subscribe_log` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`user_name` varchar(128) NOT NULL COMMENT '用户名',
|
||||
`user_id` int(11) NOT NULL COMMENT '用户 ID',
|
||||
`email` varchar(32) NOT NULL COMMENT '用户邮箱',
|
||||
`subscribe_type` varchar(20) NOT NULL COMMENT '获取的订阅类型',
|
||||
`request_ip` varchar(128) NOT NULL COMMENT '请求 IP',
|
||||
`request_time` datetime NOT NULL COMMENT '请求时间',
|
||||
`request_user_agent` text COMMENT '请求 UA 信息',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户订阅日志';
|
||||
|
||||
-- 审计封禁日志
|
||||
CREATE TABLE IF NOT EXISTS `detect_ban_log` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`user_name` varchar(128) NOT NULL COMMENT '用户名',
|
||||
`user_id` int(11) NOT NULL COMMENT '用户 ID',
|
||||
`email` varchar(32) NOT NULL COMMENT '用户邮箱',
|
||||
`detect_number` int(11) NOT NULL COMMENT '本次违规次数',
|
||||
`ban_time` int(11) NOT NULL COMMENT '本次封禁时长',
|
||||
`start_time` bigint(20) NOT NULL COMMENT '统计开始时间',
|
||||
`end_time` bigint(20) NOT NULL COMMENT '统计结束时间',
|
||||
`all_detect_number` int(11) NOT NULL COMMENT '累计违规次数',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='审计封禁日志';
|
||||
|
||||
-- 管理员操作记录
|
||||
CREATE TABLE IF NOT EXISTS `gconfig` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`key` varchar(128) NOT NULL COMMENT '配置键名',
|
||||
`type` varchar(32) NOT NULL COMMENT '值类型',
|
||||
`value` text NOT NULL COMMENT '配置值',
|
||||
`oldvalue` text NOT NULL COMMENT '之前的配置值',
|
||||
`name` varchar(128) NOT NULL COMMENT '配置名称',
|
||||
`comment` text NOT NULL COMMENT '配置描述',
|
||||
`operator_id` int(11) NOT NULL COMMENT '操作员 ID',
|
||||
`operator_name` varchar(128) NOT NULL COMMENT '操作员名称',
|
||||
`operator_email` varchar(32) NOT NULL COMMENT '操作员邮箱',
|
||||
`last_update` bigint(20) NOT NULL COMMENT '修改时间',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='网站配置';
|
|
@ -8,6 +8,7 @@ import (
|
|||
"database/sql"
|
||||
"flag"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
@ -35,7 +36,10 @@ var (
|
|||
schema = flag.String("schema", "", "specify the schema")
|
||||
ignoreSelectUpdate = flag.Bool("ignore_select_update", false, "ignore select update if implementation difference, only for tidb")
|
||||
ingoreUpdateLimit = flag.Bool("ignore_update_limit", false, "ignore update limit if implementation difference, only for cockroach")
|
||||
doNVarcharTest = flag.Bool("do_nvarchar_override_test", false, "do nvarchar override test in sync table, only for mssql")
|
||||
quotePolicyStr = flag.String("quote", "always", "quote could be always, none, reversed")
|
||||
defaultVarchar = flag.String("default_varchar", "varchar", "default varchar type, mssql only, could be varchar or nvarchar, default is varchar")
|
||||
defaultChar = flag.String("default_char", "char", "default char type, mssql only, could be char or nchar, default is char")
|
||||
tableMapper names.Mapper
|
||||
colMapper names.Mapper
|
||||
)
|
||||
|
@ -94,6 +98,13 @@ func createEngine(dbType, connStr string) error {
|
|||
return fmt.Errorf("db.Exec: %v", err)
|
||||
}
|
||||
db.Close()
|
||||
case schemas.SQLITE, "sqlite":
|
||||
u, err := url.Parse(connStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
connStr = u.Path
|
||||
*ignoreSelectUpdate = true
|
||||
default:
|
||||
*ignoreSelectUpdate = true
|
||||
}
|
||||
|
@ -137,6 +148,11 @@ func createEngine(dbType, connStr string) error {
|
|||
} else {
|
||||
testEngine.SetQuotePolicy(dialects.QuotePolicyAlways)
|
||||
}
|
||||
|
||||
testEngine.Dialect().SetParams(map[string]string{
|
||||
"DEFAULT_VARCHAR": *defaultVarchar,
|
||||
"DEFAULT_CHAR": *defaultChar,
|
||||
})
|
||||
}
|
||||
|
||||
tableMapper = testEngine.GetTableMapper()
|
||||
|
@ -156,17 +172,25 @@ func createEngine(dbType, connStr string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// PrepareEngine prepare tests ORM engine
|
||||
func PrepareEngine() error {
|
||||
return createEngine(dbType, connString)
|
||||
}
|
||||
|
||||
// MainTest the tests entrance
|
||||
func MainTest(m *testing.M) {
|
||||
flag.Parse()
|
||||
|
||||
dbType = *db
|
||||
if *db == "sqlite3" {
|
||||
if ptrConnStr == nil {
|
||||
connString = "./test.db?cache=shared&mode=rwc"
|
||||
connString = "./test_sqlite3.db?cache=shared&mode=rwc"
|
||||
} else {
|
||||
connString = *ptrConnStr
|
||||
}
|
||||
} else if *db == "sqlite" {
|
||||
if ptrConnStr == nil {
|
||||
connString = "./test_sqlite.db?cache=shared&mode=rwc"
|
||||
} else {
|
||||
connString = *ptrConnStr
|
||||
}
|
||||
|
|
|
@ -375,3 +375,30 @@ func TestCustomType2(t *testing.T) {
|
|||
|
||||
fmt.Println(users)
|
||||
}
|
||||
|
||||
func TestUnsigned(t *testing.T) {
|
||||
type MyUnsignedStruct struct {
|
||||
Id uint64
|
||||
}
|
||||
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(MyUnsignedStruct))
|
||||
|
||||
tables, err := testEngine.DBMetas()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(tables))
|
||||
assert.EqualValues(t, 1, len(tables[0].Columns()))
|
||||
|
||||
switch testEngine.Dialect().URI().DBType {
|
||||
case schemas.SQLITE:
|
||||
assert.EqualValues(t, "INTEGER", tables[0].Columns()[0].SQLType.Name)
|
||||
case schemas.MYSQL:
|
||||
assert.EqualValues(t, "UNSIGNED BIGINT", tables[0].Columns()[0].SQLType.Name)
|
||||
case schemas.POSTGRES:
|
||||
assert.EqualValues(t, "BIGINT", tables[0].Columns()[0].SQLType.Name)
|
||||
case schemas.MSSQL:
|
||||
assert.EqualValues(t, "BIGINT", tables[0].Columns()[0].SQLType.Name)
|
||||
default:
|
||||
assert.False(t, true, "Unsigned is not implemented")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -101,6 +101,7 @@ type EngineInterface interface {
|
|||
SetCacher(string, caches.Cacher)
|
||||
SetConnMaxLifetime(time.Duration)
|
||||
SetColumnMapper(names.Mapper)
|
||||
SetTagIdentifier(string)
|
||||
SetDefaultCacher(caches.Cacher)
|
||||
SetLogger(logger interface{})
|
||||
SetLogLevel(log.LogLevel)
|
||||
|
@ -120,6 +121,7 @@ type EngineInterface interface {
|
|||
TableInfo(bean interface{}) (*schemas.Table, error)
|
||||
TableName(interface{}, ...bool) string
|
||||
UnMapType(reflect.Type)
|
||||
EnableSessionID(bool)
|
||||
}
|
||||
|
||||
var (
|
||||
|
|
|
@ -6,15 +6,15 @@ package json
|
|||
|
||||
import "encoding/json"
|
||||
|
||||
// JSONInterface represents an interface to handle json data
|
||||
type JSONInterface interface {
|
||||
// Interface represents an interface to handle json data
|
||||
type Interface interface {
|
||||
Marshal(v interface{}) ([]byte, error)
|
||||
Unmarshal(data []byte, v interface{}) error
|
||||
}
|
||||
|
||||
var (
|
||||
// DefaultJSONHandler default json handler
|
||||
DefaultJSONHandler JSONInterface = StdJSON{}
|
||||
DefaultJSONHandler Interface = StdJSON{}
|
||||
)
|
||||
|
||||
// StdJSON implements JSONInterface via encoding/json
|
||||
|
|
|
@ -20,6 +20,21 @@ var (
|
|||
uintType = reflect.TypeOf(uint64(0))
|
||||
)
|
||||
|
||||
// ErrIDConditionWithNoTable represents an error there is no reference table with an ID condition
|
||||
type ErrIDConditionWithNoTable struct {
|
||||
ID schemas.PK
|
||||
}
|
||||
|
||||
func (err ErrIDConditionWithNoTable) Error() string {
|
||||
return fmt.Sprintf("ID condition %#v need reference table", err.ID)
|
||||
}
|
||||
|
||||
// IsIDConditionWithNoTableErr return true if the err is ErrIDConditionWithNoTable
|
||||
func IsIDConditionWithNoTableErr(err error) bool {
|
||||
_, ok := err.(ErrIDConditionWithNoTable)
|
||||
return ok
|
||||
}
|
||||
|
||||
// ID generate "where id = ? " statement or for composite key "where key1 = ? and key2 = ?"
|
||||
func (statement *Statement) ID(id interface{}) *Statement {
|
||||
switch t := id.(type) {
|
||||
|
@ -58,13 +73,17 @@ func (statement *Statement) ID(id interface{}) *Statement {
|
|||
return statement
|
||||
}
|
||||
|
||||
// ProcessIDParam handles the process of id condition
|
||||
func (statement *Statement) ProcessIDParam() error {
|
||||
if statement.idParam == nil || statement.RefTable == nil {
|
||||
if statement.idParam == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if statement.RefTable == nil {
|
||||
return ErrIDConditionWithNoTable{statement.idParam}
|
||||
}
|
||||
|
||||
if len(statement.RefTable.PrimaryKeys) != len(statement.idParam) {
|
||||
fmt.Println("=====", statement.RefTable.PrimaryKeys, statement.idParam)
|
||||
return fmt.Errorf("ID condition is error, expect %d primarykeys, there are %d",
|
||||
len(statement.RefTable.PrimaryKeys),
|
||||
len(statement.idParam),
|
||||
|
|
|
@ -704,7 +704,7 @@ func (statement *Statement) buildConds2(table *schemas.Table, bean interface{},
|
|||
col.SQLType.IsBlob() || col.SQLType.Name == schemas.TimeStampz) {
|
||||
continue
|
||||
}
|
||||
if col.SQLType.IsJson() {
|
||||
if col.IsJSON {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -813,7 +813,7 @@ func (statement *Statement) buildConds2(table *schemas.Table, bean interface{},
|
|||
continue
|
||||
}
|
||||
} else {
|
||||
if col.SQLType.IsJson() {
|
||||
if col.IsJSON {
|
||||
if col.SQLType.IsText() {
|
||||
bytes, err := json.DefaultJSONHandler.Marshal(fieldValue.Interface())
|
||||
if err != nil {
|
||||
|
|
|
@ -130,7 +130,7 @@ func (statement *Statement) BuildUpdates(tableValue reflect.Value,
|
|||
}
|
||||
}
|
||||
|
||||
if structConvert, ok := fieldValue.Interface().(convert.Conversion); ok {
|
||||
if structConvert, ok := fieldValue.Interface().(convert.Conversion); ok && !fieldValue.IsNil() {
|
||||
data, err := structConvert.ToDB()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
@ -204,7 +204,7 @@ func (statement *Statement) BuildUpdates(tableValue reflect.Value,
|
|||
continue
|
||||
}
|
||||
} else {
|
||||
if !col.SQLType.IsJson() {
|
||||
if !col.IsJSON {
|
||||
table, err := statement.tagParser.ParseWithCache(fieldValue)
|
||||
if err != nil {
|
||||
val = fieldValue.Interface()
|
||||
|
|
|
@ -36,18 +36,21 @@ func (statement *Statement) Value2Interface(col *schemas.Column, fieldValue refl
|
|||
}
|
||||
}
|
||||
|
||||
if fieldConvert, ok := fieldValue.Interface().(convert.Conversion); ok {
|
||||
data, err := fieldConvert.ToDB()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
isNil := fieldValue.Kind() == reflect.Ptr && fieldValue.IsNil()
|
||||
if !isNil {
|
||||
if fieldConvert, ok := fieldValue.Interface().(convert.Conversion); ok {
|
||||
data, err := fieldConvert.ToDB()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if col.SQLType.IsBlob() {
|
||||
return data, nil
|
||||
}
|
||||
if nil == data {
|
||||
return nil, nil
|
||||
}
|
||||
return string(data), nil
|
||||
}
|
||||
if col.SQLType.IsBlob() {
|
||||
return data, nil
|
||||
}
|
||||
if nil == data {
|
||||
return nil, nil
|
||||
}
|
||||
return string(data), nil
|
||||
}
|
||||
|
||||
fieldType := fieldValue.Type()
|
||||
|
@ -83,7 +86,7 @@ func (statement *Statement) Value2Interface(col *schemas.Column, fieldValue refl
|
|||
return t.Float64, nil
|
||||
}
|
||||
|
||||
if !col.SQLType.IsJson() {
|
||||
if !col.IsJSON {
|
||||
// !<winxxp>! 增加支持driver.Valuer接口的结构,如sql.NullString
|
||||
if v, ok := fieldValue.Interface().(driver.Valuer); ok {
|
||||
return v.Value()
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"fmt"
|
||||
)
|
||||
|
||||
// IndexName returns index name
|
||||
func IndexName(tableName, idxName string) string {
|
||||
return fmt.Sprintf("IDX_%v_%v", tableName, idxName)
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"reflect"
|
||||
)
|
||||
|
||||
// ReflectValue returns value of a bean
|
||||
func ReflectValue(bean interface{}) reflect.Value {
|
||||
return reflect.Indirect(reflect.ValueOf(bean))
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
// IsSubQuery returns true if it contains a sub query
|
||||
func IsSubQuery(tbName string) bool {
|
||||
const selStr = "select"
|
||||
if len(tbName) <= len(selStr)+1 {
|
||||
|
|
|
@ -8,10 +8,12 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
// IndexNoCase index a string in a string with no care of capitalize
|
||||
func IndexNoCase(s, sep string) int {
|
||||
return strings.Index(strings.ToLower(s), strings.ToLower(sep))
|
||||
}
|
||||
|
||||
// SplitNoCase split a string by a seperator with no care of capitalize
|
||||
func SplitNoCase(s, sep string) []string {
|
||||
idx := IndexNoCase(s, sep)
|
||||
if idx < 0 {
|
||||
|
@ -20,6 +22,7 @@ func SplitNoCase(s, sep string) []string {
|
|||
return strings.Split(s, s[idx:idx+len(sep)])
|
||||
}
|
||||
|
||||
// SplitNNoCase split n by a seperator with no care of capitalize
|
||||
func SplitNNoCase(s, sep string, n int) []string {
|
||||
idx := IndexNoCase(s, sep)
|
||||
if idx < 0 {
|
||||
|
@ -27,4 +30,3 @@ func SplitNNoCase(s, sep string, n int) []string {
|
|||
}
|
||||
return strings.SplitN(s, s[idx:idx+len(sep)], n)
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
// Zeroable represents an interface which could know if it's a zero value
|
||||
type Zeroable interface {
|
||||
IsZero() bool
|
||||
}
|
||||
|
@ -21,39 +22,39 @@ func IsZero(k interface{}) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
switch k.(type) {
|
||||
switch t := k.(type) {
|
||||
case int:
|
||||
return k.(int) == 0
|
||||
return t == 0
|
||||
case int8:
|
||||
return k.(int8) == 0
|
||||
return t == 0
|
||||
case int16:
|
||||
return k.(int16) == 0
|
||||
return t == 0
|
||||
case int32:
|
||||
return k.(int32) == 0
|
||||
return t == 0
|
||||
case int64:
|
||||
return k.(int64) == 0
|
||||
return t == 0
|
||||
case uint:
|
||||
return k.(uint) == 0
|
||||
return t == 0
|
||||
case uint8:
|
||||
return k.(uint8) == 0
|
||||
return t == 0
|
||||
case uint16:
|
||||
return k.(uint16) == 0
|
||||
return t == 0
|
||||
case uint32:
|
||||
return k.(uint32) == 0
|
||||
return t == 0
|
||||
case uint64:
|
||||
return k.(uint64) == 0
|
||||
return t == 0
|
||||
case float32:
|
||||
return k.(float32) == 0
|
||||
return t == 0
|
||||
case float64:
|
||||
return k.(float64) == 0
|
||||
return t == 0
|
||||
case bool:
|
||||
return k.(bool) == false
|
||||
return !t
|
||||
case string:
|
||||
return k.(string) == ""
|
||||
return t == ""
|
||||
case *time.Time:
|
||||
return k.(*time.Time) == nilTime || IsTimeZero(*k.(*time.Time))
|
||||
return t == nilTime || IsTimeZero(*t)
|
||||
case time.Time:
|
||||
return IsTimeZero(k.(time.Time))
|
||||
return IsTimeZero(t)
|
||||
case Zeroable:
|
||||
return k.(Zeroable) == nil || k.(Zeroable).IsZero()
|
||||
case reflect.Value: // for go version less than 1.13 because reflect.Value has no method IsZero
|
||||
|
@ -65,6 +66,7 @@ func IsZero(k interface{}) bool {
|
|||
|
||||
var zeroType = reflect.TypeOf((*Zeroable)(nil)).Elem()
|
||||
|
||||
// IsValueZero returns true if the reflect Value is a zero
|
||||
func IsValueZero(v reflect.Value) bool {
|
||||
switch v.Kind() {
|
||||
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Slice:
|
||||
|
@ -88,6 +90,7 @@ func IsValueZero(v reflect.Value) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// IsStructZero returns true if the Value is a struct and all fields is zero
|
||||
func IsStructZero(v reflect.Value) bool {
|
||||
if !v.IsValid() || v.NumField() == 0 {
|
||||
return true
|
||||
|
@ -120,6 +123,7 @@ func IsStructZero(v reflect.Value) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// IsArrayZero returns true is a slice of array is zero
|
||||
func IsArrayZero(v reflect.Value) bool {
|
||||
if !v.IsValid() || v.Len() == 0 {
|
||||
return true
|
||||
|
@ -134,11 +138,13 @@ func IsArrayZero(v reflect.Value) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// represents all zero times
|
||||
const (
|
||||
ZeroTime0 = "0000-00-00 00:00:00"
|
||||
ZeroTime1 = "0001-01-01 00:00:00"
|
||||
)
|
||||
|
||||
// IsTimeZero return true if a time is zero
|
||||
func IsTimeZero(t time.Time) bool {
|
||||
return t.IsZero() || t.Format("2006-01-02 15:04:05") == ZeroTime0 ||
|
||||
t.Format("2006-01-02 15:04:05") == ZeroTime1
|
||||
|
|
|
@ -42,6 +42,7 @@ var (
|
|||
// enumerate all the context keys
|
||||
var (
|
||||
SessionIDKey = "__xorm_session_id"
|
||||
SessionKey = "__xorm_session_key"
|
||||
SessionShowSQLKey = "__xorm_show_sql"
|
||||
)
|
||||
|
||||
|
|
|
@ -110,10 +110,7 @@ func (m *Migrate) RollbackLast() error {
|
|||
return err
|
||||
}
|
||||
|
||||
if err := m.RollbackMigration(lastRunnedMigration); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return m.RollbackMigration(lastRunnedMigration)
|
||||
}
|
||||
|
||||
func (m *Migrate) getLastRunnedMigration() (*Migration, error) {
|
||||
|
|
|
@ -106,10 +106,7 @@ func TestInitSchema(t *testing.T) {
|
|||
if err := tx.Sync2(&Person{}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Sync2(&Pet{}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return tx.Sync2(&Pet{})
|
||||
})
|
||||
|
||||
err = m.Migrate()
|
||||
|
|
|
@ -7,6 +7,7 @@ package names
|
|||
import (
|
||||
"strings"
|
||||
"sync"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Mapper represents a name convertation between struct's fields name and table's column name
|
||||
|
@ -77,19 +78,24 @@ func (m SameMapper) Table2Obj(t string) string {
|
|||
type SnakeMapper struct {
|
||||
}
|
||||
|
||||
func b2s(b []byte) string {
|
||||
return *(*string)(unsafe.Pointer(&b))
|
||||
}
|
||||
|
||||
func snakeCasedName(name string) string {
|
||||
newstr := make([]rune, 0)
|
||||
for idx, chr := range name {
|
||||
if isUpper := 'A' <= chr && chr <= 'Z'; isUpper {
|
||||
if idx > 0 {
|
||||
newstr := make([]byte, 0, len(name)+1)
|
||||
for i := 0; i < len(name); i++ {
|
||||
c := name[i]
|
||||
if isUpper := 'A' <= c && c <= 'Z'; isUpper {
|
||||
if i > 0 {
|
||||
newstr = append(newstr, '_')
|
||||
}
|
||||
chr -= ('A' - 'a')
|
||||
c += 'a' - 'A'
|
||||
}
|
||||
newstr = append(newstr, chr)
|
||||
newstr = append(newstr, c)
|
||||
}
|
||||
|
||||
return string(newstr)
|
||||
return b2s(newstr)
|
||||
}
|
||||
|
||||
func (mapper SnakeMapper) Obj2Table(name string) string {
|
||||
|
@ -97,27 +103,28 @@ func (mapper SnakeMapper) Obj2Table(name string) string {
|
|||
}
|
||||
|
||||
func titleCasedName(name string) string {
|
||||
newstr := make([]rune, 0)
|
||||
newstr := make([]byte, 0, len(name))
|
||||
upNextChar := true
|
||||
|
||||
name = strings.ToLower(name)
|
||||
|
||||
for _, chr := range name {
|
||||
for i := 0; i < len(name); i++ {
|
||||
c := name[i]
|
||||
switch {
|
||||
case upNextChar:
|
||||
upNextChar = false
|
||||
if 'a' <= chr && chr <= 'z' {
|
||||
chr -= ('a' - 'A')
|
||||
if 'a' <= c && c <= 'z' {
|
||||
c -= 'a' - 'A'
|
||||
}
|
||||
case chr == '_':
|
||||
case c == '_':
|
||||
upNextChar = true
|
||||
continue
|
||||
}
|
||||
|
||||
newstr = append(newstr, chr)
|
||||
newstr = append(newstr, c)
|
||||
}
|
||||
|
||||
return string(newstr)
|
||||
return b2s(newstr)
|
||||
}
|
||||
|
||||
func (mapper SnakeMapper) Table2Obj(name string) string {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
package names
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
@ -47,3 +48,23 @@ func TestGonicMapperToObj(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSnakeCasedName(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
s := strings.Repeat("FooBar", 32)
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = snakeCasedName(s)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTitleCasedName(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
s := strings.Repeat("foo_bar", 32)
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = titleCasedName(s)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,10 @@
|
|||
package schemas
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
@ -49,6 +51,7 @@ type Column struct {
|
|||
func NewColumn(name, fieldName string, sqlType SQLType, len1, len2 int, nullable bool) *Column {
|
||||
return &Column{
|
||||
Name: name,
|
||||
IsJSON: sqlType.IsJson(),
|
||||
TableName: "",
|
||||
FieldName: fieldName,
|
||||
SQLType: sqlType,
|
||||
|
@ -115,3 +118,17 @@ func (col *Column) ValueOfV(dataStruct *reflect.Value) (*reflect.Value, error) {
|
|||
|
||||
return &fieldValue, nil
|
||||
}
|
||||
|
||||
// ConvertID converts id content to suitable type according column type
|
||||
func (col *Column) ConvertID(sid string) (interface{}, error) {
|
||||
if col.SQLType.IsNumeric() {
|
||||
n, err := strconv.ParseInt(sid, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return n, nil
|
||||
} else if col.SQLType.IsText() {
|
||||
return sid, nil
|
||||
}
|
||||
return nil, errors.New("not supported")
|
||||
}
|
||||
|
|
|
@ -82,9 +82,7 @@ func (q Quoter) JoinWrite(b *strings.Builder, a []string, sep string) error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
if s != "*" {
|
||||
q.QuoteTo(b, strings.TrimSpace(s))
|
||||
}
|
||||
q.QuoteTo(b, strings.TrimSpace(s))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -143,7 +141,7 @@ func (q Quoter) quoteWordTo(buf *strings.Builder, word string) error {
|
|||
}
|
||||
|
||||
isReserved := q.IsReserved(realWord)
|
||||
if isReserved {
|
||||
if isReserved && realWord != "*" {
|
||||
if err := buf.WriteByte(q.Prefix); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -151,7 +149,7 @@ func (q Quoter) quoteWordTo(buf *strings.Builder, word string) error {
|
|||
if _, err := buf.WriteString(realWord); err != nil {
|
||||
return err
|
||||
}
|
||||
if isReserved {
|
||||
if isReserved && realWord != "*" {
|
||||
return buf.WriteByte(q.Suffix)
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ func TestAlwaysQuoteTo(t *testing.T) {
|
|||
{"[mytable]", "`mytable`"},
|
||||
{"[mytable]", `[mytable]`},
|
||||
{`["mytable"]`, `"mytable"`},
|
||||
{`[mytable].*`, `[mytable].*`},
|
||||
{"[myschema].[mytable]", "myschema.mytable"},
|
||||
{"[myschema].[mytable]", "`myschema`.mytable"},
|
||||
{"[myschema].[mytable]", "myschema.`mytable`"},
|
||||
|
@ -65,6 +66,7 @@ func TestReversedQuoteTo(t *testing.T) {
|
|||
{"[mytable]", "mytable"},
|
||||
{"[mytable]", "`mytable`"},
|
||||
{"[mytable]", `[mytable]`},
|
||||
{"[mytable].*", `[mytable].*`},
|
||||
{`"mytable"`, `"mytable"`},
|
||||
{"myschema.[mytable]", "myschema.mytable"},
|
||||
{"myschema.[mytable]", "`myschema`.mytable"},
|
||||
|
@ -98,6 +100,7 @@ func TestNoQuoteTo(t *testing.T) {
|
|||
{"mytable", "mytable"},
|
||||
{"mytable", "`mytable`"},
|
||||
{"mytable", `[mytable]`},
|
||||
{"mytable.*", `[mytable].*`},
|
||||
{`"mytable"`, `"mytable"`},
|
||||
{"myschema.mytable", "myschema.mytable"},
|
||||
{"myschema.mytable", "`myschema`.mytable"},
|
||||
|
@ -127,6 +130,8 @@ func TestJoin(t *testing.T) {
|
|||
|
||||
assert.EqualValues(t, "[a],[b]", quoter.Join([]string{"a", " b"}, ","))
|
||||
|
||||
assert.EqualValues(t, "[a].*,[b].[c]", quoter.Join([]string{"a.*", " b.c"}, ","))
|
||||
|
||||
assert.EqualValues(t, "[f1], [f2], [f3]", quoter.Join(cols, ", "))
|
||||
|
||||
quoter.IsReserved = AlwaysNoReserve
|
||||
|
@ -134,11 +139,11 @@ func TestJoin(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestStrings(t *testing.T) {
|
||||
cols := []string{"f1", "f2", "t3.f3"}
|
||||
cols := []string{"f1", "f2", "t3.f3", "t4.*"}
|
||||
quoter := Quoter{'[', ']', AlwaysReserve}
|
||||
|
||||
quotedCols := quoter.Strings(cols)
|
||||
assert.EqualValues(t, []string{"[f1]", "[f2]", "[t3].[f3]"}, quotedCols)
|
||||
assert.EqualValues(t, []string{"[f1]", "[f2]", "[t3].[f3]", "[t4].*"}, quotedCols)
|
||||
}
|
||||
|
||||
func TestTrim(t *testing.T) {
|
||||
|
|
|
@ -5,7 +5,9 @@
|
|||
package schemas
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
@ -28,6 +30,7 @@ type Table struct {
|
|||
Comment string
|
||||
}
|
||||
|
||||
// NewEmptyTable creates an empty table
|
||||
func NewEmptyTable() *Table {
|
||||
return NewTable("", nil)
|
||||
}
|
||||
|
@ -44,23 +47,21 @@ func NewTable(name string, t reflect.Type) *Table {
|
|||
}
|
||||
}
|
||||
|
||||
// Columns returns table's columns
|
||||
func (table *Table) Columns() []*Column {
|
||||
return table.columns
|
||||
}
|
||||
|
||||
// ColumnsSeq returns table's column names according sequence
|
||||
func (table *Table) ColumnsSeq() []string {
|
||||
return table.columnsSeq
|
||||
}
|
||||
|
||||
func (table *Table) columnsByName(name string) []*Column {
|
||||
for k, cols := range table.columnsMap {
|
||||
if strings.EqualFold(k, name) {
|
||||
return cols
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return table.columnsMap[strings.ToLower(name)]
|
||||
}
|
||||
|
||||
// GetColumn returns column according column name, if column not found, return nil
|
||||
func (table *Table) GetColumn(name string) *Column {
|
||||
cols := table.columnsByName(name)
|
||||
if cols != nil {
|
||||
|
@ -70,6 +71,7 @@ func (table *Table) GetColumn(name string) *Column {
|
|||
return nil
|
||||
}
|
||||
|
||||
// GetColumnIdx returns column according name and idx
|
||||
func (table *Table) GetColumnIdx(name string, idx int) *Column {
|
||||
cols := table.columnsByName(name)
|
||||
if cols != nil && idx < len(cols) {
|
||||
|
@ -144,3 +146,45 @@ func (table *Table) AddColumn(col *Column) {
|
|||
func (table *Table) AddIndex(index *Index) {
|
||||
table.Indexes[index.Name] = index
|
||||
}
|
||||
|
||||
// IDOfV get id from one value of struct
|
||||
func (table *Table) IDOfV(rv reflect.Value) (PK, error) {
|
||||
v := reflect.Indirect(rv)
|
||||
pk := make([]interface{}, len(table.PrimaryKeys))
|
||||
for i, col := range table.PKColumns() {
|
||||
var err error
|
||||
|
||||
fieldName := col.FieldName
|
||||
for {
|
||||
parts := strings.SplitN(fieldName, ".", 2)
|
||||
if len(parts) == 1 {
|
||||
break
|
||||
}
|
||||
|
||||
v = v.FieldByName(parts[0])
|
||||
if v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
}
|
||||
if v.Kind() != reflect.Struct {
|
||||
return nil, fmt.Errorf("Unsupported read value of column %s from field %s", col.Name, col.FieldName)
|
||||
}
|
||||
fieldName = parts[1]
|
||||
}
|
||||
|
||||
pkField := v.FieldByName(fieldName)
|
||||
switch pkField.Kind() {
|
||||
case reflect.String:
|
||||
pk[i], err = col.ConvertID(pkField.String())
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
pk[i], err = col.ConvertID(strconv.FormatInt(pkField.Int(), 10))
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
// id of uint will be converted to int64
|
||||
pk[i], err = col.ConvertID(strconv.FormatUint(pkField.Uint(), 10))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return PK(pk), nil
|
||||
}
|
||||
|
|
|
@ -68,14 +68,21 @@ func (s *SQLType) IsJson() bool {
|
|||
return s.Name == Json || s.Name == Jsonb
|
||||
}
|
||||
|
||||
func (s *SQLType) IsXML() bool {
|
||||
return s.Name == XML
|
||||
}
|
||||
|
||||
var (
|
||||
Bit = "BIT"
|
||||
TinyInt = "TINYINT"
|
||||
SmallInt = "SMALLINT"
|
||||
MediumInt = "MEDIUMINT"
|
||||
Int = "INT"
|
||||
Integer = "INTEGER"
|
||||
BigInt = "BIGINT"
|
||||
Bit = "BIT"
|
||||
UnsignedBit = "UNSIGNED BIT"
|
||||
TinyInt = "TINYINT"
|
||||
SmallInt = "SMALLINT"
|
||||
MediumInt = "MEDIUMINT"
|
||||
Int = "INT"
|
||||
UnsignedInt = "UNSIGNED INT"
|
||||
Integer = "INTEGER"
|
||||
BigInt = "BIGINT"
|
||||
UnsignedBigInt = "UNSIGNED BIGINT"
|
||||
|
||||
Enum = "ENUM"
|
||||
Set = "SET"
|
||||
|
@ -128,22 +135,28 @@ var (
|
|||
Json = "JSON"
|
||||
Jsonb = "JSONB"
|
||||
|
||||
XML = "XML"
|
||||
Array = "ARRAY"
|
||||
|
||||
SqlTypes = map[string]int{
|
||||
Bit: NUMERIC_TYPE,
|
||||
TinyInt: NUMERIC_TYPE,
|
||||
SmallInt: NUMERIC_TYPE,
|
||||
MediumInt: NUMERIC_TYPE,
|
||||
Int: NUMERIC_TYPE,
|
||||
Integer: NUMERIC_TYPE,
|
||||
BigInt: NUMERIC_TYPE,
|
||||
Bit: NUMERIC_TYPE,
|
||||
UnsignedBit: NUMERIC_TYPE,
|
||||
TinyInt: NUMERIC_TYPE,
|
||||
SmallInt: NUMERIC_TYPE,
|
||||
MediumInt: NUMERIC_TYPE,
|
||||
Int: NUMERIC_TYPE,
|
||||
UnsignedInt: NUMERIC_TYPE,
|
||||
Integer: NUMERIC_TYPE,
|
||||
BigInt: NUMERIC_TYPE,
|
||||
UnsignedBigInt: NUMERIC_TYPE,
|
||||
|
||||
Enum: TEXT_TYPE,
|
||||
Set: TEXT_TYPE,
|
||||
Json: TEXT_TYPE,
|
||||
Jsonb: TEXT_TYPE,
|
||||
|
||||
XML: TEXT_TYPE,
|
||||
|
||||
Char: TEXT_TYPE,
|
||||
NChar: TEXT_TYPE,
|
||||
Varchar: TEXT_TYPE,
|
||||
|
@ -273,10 +286,14 @@ var (
|
|||
// Type2SQLType generate SQLType acorrding Go's type
|
||||
func Type2SQLType(t reflect.Type) (st SQLType) {
|
||||
switch k := t.Kind(); k {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32:
|
||||
st = SQLType{Int, 0, 0}
|
||||
case reflect.Int64, reflect.Uint64:
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
|
||||
st = SQLType{UnsignedInt, 0, 0}
|
||||
case reflect.Int64:
|
||||
st = SQLType{BigInt, 0, 0}
|
||||
case reflect.Uint64:
|
||||
st = SQLType{UnsignedBigInt, 0, 0}
|
||||
case reflect.Float32:
|
||||
st = SQLType{Float, 0, 0}
|
||||
case reflect.Float64:
|
||||
|
|
17
session.go
17
session.go
|
@ -107,7 +107,7 @@ func newSession(engine *Engine) *Session {
|
|||
ctx = engine.defaultContext
|
||||
}
|
||||
|
||||
return &Session{
|
||||
session := &Session{
|
||||
ctx: ctx,
|
||||
engine: engine,
|
||||
tx: nil,
|
||||
|
@ -136,6 +136,10 @@ func newSession(engine *Engine) *Session {
|
|||
|
||||
sessionType: engineSession,
|
||||
}
|
||||
if engine.logSessionID {
|
||||
session.ctx = context.WithValue(session.ctx, log.SessionKey, session)
|
||||
}
|
||||
return session
|
||||
}
|
||||
|
||||
// Close release the connection from pool
|
||||
|
@ -165,6 +169,11 @@ func (session *Session) db() *core.DB {
|
|||
return session.engine.db
|
||||
}
|
||||
|
||||
// Engine returns session Engine
|
||||
func (session *Session) Engine() *Engine {
|
||||
return session.engine
|
||||
}
|
||||
|
||||
func (session *Session) getQueryer() core.Queryer {
|
||||
if session.tx != nil {
|
||||
return session.tx
|
||||
|
@ -495,7 +504,7 @@ func (session *Session) slice2Bean(scanResults []interface{}, fields []string, b
|
|||
fieldType := fieldValue.Type()
|
||||
hasAssigned := false
|
||||
|
||||
if col.SQLType.IsJson() {
|
||||
if col.IsJSON {
|
||||
var bs []byte
|
||||
if rawValueType.Kind() == reflect.String {
|
||||
bs = []byte(vv.String())
|
||||
|
@ -675,7 +684,7 @@ func (session *Session) slice2Bean(scanResults []interface{}, fields []string, b
|
|||
session.engine.logger.Errorf("sql.Sanner error: %v", err)
|
||||
hasAssigned = false
|
||||
}
|
||||
} else if col.SQLType.IsJson() {
|
||||
} else if col.IsJSON {
|
||||
if rawValueType.Kind() == reflect.String {
|
||||
hasAssigned = true
|
||||
x := reflect.New(fieldType)
|
||||
|
@ -887,7 +896,7 @@ func (session *Session) incrVersionFieldValue(fieldValue *reflect.Value) {
|
|||
}
|
||||
}
|
||||
|
||||
// ContextHook sets the context on this session
|
||||
// Context sets the context on this session
|
||||
func (session *Session) Context(ctx context.Context) *Session {
|
||||
session.ctx = ctx
|
||||
return session
|
||||
|
|
|
@ -57,9 +57,18 @@ func (session *Session) FindAndCount(rowsSlicePtr interface{}, condiBean ...inte
|
|||
if session.statement.SelectStr != "" {
|
||||
session.statement.SelectStr = ""
|
||||
}
|
||||
if len(session.statement.ColumnMap) > 0 {
|
||||
session.statement.ColumnMap = []string{}
|
||||
}
|
||||
if session.statement.OrderStr != "" {
|
||||
session.statement.OrderStr = ""
|
||||
}
|
||||
if session.statement.LimitN != nil {
|
||||
session.statement.LimitN = nil
|
||||
}
|
||||
if session.statement.Start > 0 {
|
||||
session.statement.Start = 0
|
||||
}
|
||||
|
||||
// session has stored the conditions so we use `unscoped` to avoid duplicated condition.
|
||||
return session.Unscoped().Count(reflect.New(sliceElementType).Interface())
|
||||
|
@ -108,8 +117,11 @@ func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{})
|
|||
)
|
||||
if tp == tpStruct {
|
||||
if !session.statement.NoAutoCondition && len(condiBean) > 0 {
|
||||
var err error
|
||||
autoCond, err = session.statement.BuildConds(table, condiBean[0], true, true, false, true, addedTableName)
|
||||
condTable, err := session.engine.tagParser.Parse(reflect.ValueOf(condiBean[0]))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
autoCond, err = session.statement.BuildConds(condTable, condiBean[0], true, true, false, true, addedTableName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -317,7 +329,7 @@ func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr in
|
|||
}
|
||||
var pk schemas.PK = make([]interface{}, len(table.PrimaryKeys))
|
||||
for i, col := range table.PKColumns() {
|
||||
pk[i], err = session.engine.idTypeAssertion(col, res[i])
|
||||
pk[i], err = col.ConvertID(res[i])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -367,7 +379,7 @@ func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr in
|
|||
} else {
|
||||
session.engine.logger.Debugf("[cache] cache hit bean: %v, %v, %v", tableName, id, bean)
|
||||
|
||||
pk, err := session.engine.IDOf(bean)
|
||||
pk, err := table.IDOfV(reflect.ValueOf(bean))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -416,7 +428,6 @@ func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr in
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
session.statement = statement
|
||||
|
||||
vs := reflect.Indirect(reflect.ValueOf(beans))
|
||||
|
@ -425,7 +436,7 @@ func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr in
|
|||
if rv.Kind() != reflect.Ptr {
|
||||
rv = rv.Addr()
|
||||
}
|
||||
id, err := session.engine.idOfV(rv)
|
||||
id, err := table.IDOfV(rv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -16,6 +16,11 @@ import (
|
|||
"xorm.io/xorm/schemas"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrObjectIsNil return error of object is nil
|
||||
ErrObjectIsNil = errors.New("object should not be nil")
|
||||
)
|
||||
|
||||
// Get retrieve one record from database, bean's non-empty fields
|
||||
// will be as conditions
|
||||
func (session *Session) Get(bean interface{}) (bool, error) {
|
||||
|
@ -37,6 +42,8 @@ func (session *Session) get(bean interface{}) (bool, error) {
|
|||
return false, errors.New("needs a pointer to a value")
|
||||
} else if beanValue.Elem().Kind() == reflect.Ptr {
|
||||
return false, errors.New("a pointer to a pointer is not allowed")
|
||||
} else if beanValue.IsNil() {
|
||||
return false, ErrObjectIsNil
|
||||
}
|
||||
|
||||
if beanValue.Elem().Kind() == reflect.Struct {
|
||||
|
|
|
@ -448,27 +448,43 @@ func (session *Session) ImportFile(ddlPath string) ([]sql.Result, error) {
|
|||
|
||||
// Import SQL DDL from io.Reader
|
||||
func (session *Session) Import(r io.Reader) ([]sql.Result, error) {
|
||||
var results []sql.Result
|
||||
var lastError error
|
||||
scanner := bufio.NewScanner(r)
|
||||
var (
|
||||
results []sql.Result
|
||||
lastError error
|
||||
inSingleQuote bool
|
||||
startComment bool
|
||||
)
|
||||
|
||||
var inSingleQuote bool
|
||||
scanner := bufio.NewScanner(r)
|
||||
semiColSpliter := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
|
||||
if atEOF && len(data) == 0 {
|
||||
return 0, nil, nil
|
||||
}
|
||||
var oriInSingleQuote = inSingleQuote
|
||||
for i, b := range data {
|
||||
if b == '\'' {
|
||||
inSingleQuote = !inSingleQuote
|
||||
}
|
||||
if !inSingleQuote && b == ';' {
|
||||
return i + 1, data[0:i], nil
|
||||
if startComment {
|
||||
if b == '\n' {
|
||||
startComment = false
|
||||
}
|
||||
} else {
|
||||
if i > 0 && data[i-1] == '-' && data[i] == '-' {
|
||||
startComment = true
|
||||
continue
|
||||
}
|
||||
|
||||
if b == '\'' {
|
||||
inSingleQuote = !inSingleQuote
|
||||
}
|
||||
if !inSingleQuote && b == ';' {
|
||||
return i + 1, data[0:i], nil
|
||||
}
|
||||
}
|
||||
}
|
||||
// If we're at EOF, we have a final, non-terminated line. Return it.
|
||||
if atEOF {
|
||||
return len(data), data, nil
|
||||
}
|
||||
inSingleQuote = oriInSingleQuote
|
||||
// Request more data.
|
||||
return 0, nil, nil
|
||||
}
|
||||
|
@ -479,10 +495,10 @@ func (session *Session) Import(r io.Reader) ([]sql.Result, error) {
|
|||
query := strings.Trim(scanner.Text(), " \t\n\r")
|
||||
if len(query) > 0 {
|
||||
result, err := session.Exec(query)
|
||||
results = append(results, result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
results = append(results, result)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,12 +4,6 @@
|
|||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm/log"
|
||||
)
|
||||
|
||||
// Begin a transaction
|
||||
func (session *Session) Begin() error {
|
||||
if session.isAutoCommit {
|
||||
|
@ -33,24 +27,7 @@ func (session *Session) Rollback() error {
|
|||
session.isCommitedOrRollbacked = true
|
||||
session.isAutoCommit = true
|
||||
|
||||
start := time.Now()
|
||||
needSQL := session.DB().NeedLogSQL(session.ctx)
|
||||
if needSQL {
|
||||
session.engine.logger.BeforeSQL(log.LogContext{
|
||||
Ctx: session.ctx,
|
||||
SQL: "ROLL BACK",
|
||||
})
|
||||
}
|
||||
err := session.tx.Rollback()
|
||||
if needSQL {
|
||||
session.engine.logger.AfterSQL(log.LogContext{
|
||||
Ctx: session.ctx,
|
||||
SQL: "ROLL BACK",
|
||||
ExecuteTime: time.Now().Sub(start),
|
||||
Err: err,
|
||||
})
|
||||
}
|
||||
return err
|
||||
return session.tx.Rollback()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -62,25 +39,7 @@ func (session *Session) Commit() error {
|
|||
session.isCommitedOrRollbacked = true
|
||||
session.isAutoCommit = true
|
||||
|
||||
start := time.Now()
|
||||
needSQL := session.DB().NeedLogSQL(session.ctx)
|
||||
if needSQL {
|
||||
session.engine.logger.BeforeSQL(log.LogContext{
|
||||
Ctx: session.ctx,
|
||||
SQL: "COMMIT",
|
||||
})
|
||||
}
|
||||
err := session.tx.Commit()
|
||||
if needSQL {
|
||||
session.engine.logger.AfterSQL(log.LogContext{
|
||||
Ctx: session.ctx,
|
||||
SQL: "COMMIT",
|
||||
ExecuteTime: time.Now().Sub(start),
|
||||
Err: err,
|
||||
})
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if err := session.tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -125,3 +84,8 @@ func (session *Session) Commit() error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsInTx if current session is in a transaction
|
||||
func (session *Session) IsInTx() bool {
|
||||
return !session.isAutoCommit
|
||||
}
|
||||
|
|
|
@ -206,7 +206,11 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
|
|||
colNames = append(colNames, session.engine.Quote(table.Updated)+" = ?")
|
||||
col := table.UpdatedColumn()
|
||||
val, t := session.engine.nowTime(col)
|
||||
args = append(args, val)
|
||||
if session.engine.dialect.URI().DBType == schemas.ORACLE {
|
||||
args = append(args, t)
|
||||
} else {
|
||||
args = append(args, val)
|
||||
}
|
||||
|
||||
var colName = col.Name
|
||||
if isStruct {
|
||||
|
@ -269,8 +273,15 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
|
|||
k = ct.Elem().Kind()
|
||||
}
|
||||
if k == reflect.Struct {
|
||||
var refTable = session.statement.RefTable
|
||||
if refTable == nil {
|
||||
refTable, err = session.engine.TableInfo(condiBean[0])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
var err error
|
||||
autoCond, err = session.statement.BuildConds(session.statement.RefTable, condiBean[0], true, true, false, true, false)
|
||||
autoCond, err = session.statement.BuildConds(refTable, condiBean[0], true, true, false, true, false)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
|
|
@ -63,6 +63,11 @@ func (parser *Parser) SetColumnMapper(mapper names.Mapper) {
|
|||
parser.columnMapper = mapper
|
||||
}
|
||||
|
||||
func (parser *Parser) SetIdentifier(identifier string) {
|
||||
parser.ClearCaches()
|
||||
parser.identifier = identifier
|
||||
}
|
||||
|
||||
func (parser *Parser) ParseWithCache(v reflect.Value) (*schemas.Table, error) {
|
||||
t := v.Type()
|
||||
tableI, ok := parser.tableCache.Load(t)
|
||||
|
@ -115,6 +120,7 @@ func (parser *Parser) Parse(v reflect.Value) (*schemas.Table, error) {
|
|||
t := v.Type()
|
||||
if t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
v = v.Elem()
|
||||
}
|
||||
if t.Kind() != reflect.Struct {
|
||||
return nil, ErrUnsupportedType
|
||||
|
@ -252,7 +258,7 @@ func (parser *Parser) Parse(v reflect.Value) (*schemas.Table, error) {
|
|||
addIndex(indexName, table, col, indexType)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
} else if fieldValue.CanSet() {
|
||||
var sqlType schemas.SQLType
|
||||
if fieldValue.CanAddr() {
|
||||
if _, ok := fieldValue.Addr().Interface().(convert.Conversion); ok {
|
||||
|
@ -271,6 +277,8 @@ func (parser *Parser) Parse(v reflect.Value) (*schemas.Table, error) {
|
|||
if fieldType.Kind() == reflect.Int64 && (strings.ToUpper(col.FieldName) == "ID" || strings.HasSuffix(strings.ToUpper(col.FieldName), ".ID")) {
|
||||
idFieldColName = col.Name
|
||||
}
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
if col.IsAutoIncrement {
|
||||
col.Nullable = false
|
||||
|
|
|
@ -42,3 +42,64 @@ func TestParseTableName(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "p_parseTableName", table.Name)
|
||||
}
|
||||
|
||||
func TestUnexportField(t *testing.T) {
|
||||
parser := NewParser(
|
||||
"xorm",
|
||||
dialects.QueryDialect("mysql"),
|
||||
names.SnakeMapper{},
|
||||
names.SnakeMapper{},
|
||||
caches.NewManager(),
|
||||
)
|
||||
|
||||
type VanilaStruct struct {
|
||||
private int
|
||||
Public int
|
||||
}
|
||||
table, err := parser.Parse(reflect.ValueOf(new(VanilaStruct)))
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "vanila_struct", table.Name)
|
||||
assert.EqualValues(t, 1, len(table.Columns()))
|
||||
|
||||
for _, col := range table.Columns() {
|
||||
assert.EqualValues(t, "public", col.Name)
|
||||
assert.NotEqual(t, "private", col.Name)
|
||||
}
|
||||
|
||||
type TaggedStruct struct {
|
||||
private int `xorm:"private"`
|
||||
Public int `xorm:"-"`
|
||||
}
|
||||
table, err = parser.Parse(reflect.ValueOf(new(TaggedStruct)))
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "tagged_struct", table.Name)
|
||||
assert.EqualValues(t, 1, len(table.Columns()))
|
||||
|
||||
for _, col := range table.Columns() {
|
||||
assert.EqualValues(t, "private", col.Name)
|
||||
assert.NotEqual(t, "public", col.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseWithOtherIdentifier(t *testing.T) {
|
||||
parser := NewParser(
|
||||
"xorm",
|
||||
dialects.QueryDialect("mysql"),
|
||||
names.GonicMapper{},
|
||||
names.SnakeMapper{},
|
||||
caches.NewManager(),
|
||||
)
|
||||
|
||||
type StructWithDBTag struct {
|
||||
FieldFoo string `db:"foo"`
|
||||
}
|
||||
parser.SetIdentifier("db")
|
||||
table, err := parser.Parse(reflect.ValueOf(new(StructWithDBTag)))
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "struct_with_db_tag", table.Name)
|
||||
assert.EqualValues(t, 1, len(table.Columns()))
|
||||
|
||||
for _, col := range table.Columns() {
|
||||
assert.EqualValues(t, "foo", col.Name)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -226,6 +226,9 @@ func CommentTagHandler(ctx *Context) error {
|
|||
// SQLTypeTagHandler describes SQL Type tag handler
|
||||
func SQLTypeTagHandler(ctx *Context) error {
|
||||
ctx.col.SQLType = schemas.SQLType{Name: ctx.tagName}
|
||||
if strings.EqualFold(ctx.tagName, "JSON") {
|
||||
ctx.col.IsJSON = true
|
||||
}
|
||||
if len(ctx.params) > 0 {
|
||||
if ctx.tagName == schemas.Enum {
|
||||
ctx.col.EnumOptions = make(map[string]int)
|
||||
|
|
Loading…
Reference in New Issue