Merge branch 'master' into DropTableCols_fromGitea
This commit is contained in:
commit
a5c3ebf418
|
|
@ -0,0 +1,53 @@
|
|||
# The full repository name
|
||||
repo: xorm/xorm
|
||||
|
||||
# Service type (gitea or github)
|
||||
service: gitea
|
||||
|
||||
# Base URL for Gitea instance if using gitea service type (optional)
|
||||
# Default: https://gitea.com
|
||||
base-url:
|
||||
|
||||
# Changelog groups and which labeled PRs to add to each group
|
||||
groups:
|
||||
-
|
||||
name: BREAKING
|
||||
labels:
|
||||
- kind/breaking
|
||||
-
|
||||
name: FEATURES
|
||||
labels:
|
||||
- kind/feature
|
||||
-
|
||||
name: SECURITY
|
||||
labels:
|
||||
- kind/security
|
||||
-
|
||||
name: BUGFIXES
|
||||
labels:
|
||||
- kind/bug
|
||||
-
|
||||
name: ENHANCEMENTS
|
||||
labels:
|
||||
- kind/enhancement
|
||||
- kind/refactor
|
||||
- kind/ui
|
||||
-
|
||||
name: TESTING
|
||||
labels:
|
||||
- kind/testing
|
||||
-
|
||||
name: BUILD
|
||||
labels:
|
||||
- kind/build
|
||||
- kind/lint
|
||||
-
|
||||
name: DOCS
|
||||
labels:
|
||||
- kind/docs
|
||||
-
|
||||
name: MISC
|
||||
default: true
|
||||
|
||||
# regex indicating which labels to skip for the changelog
|
||||
skip-labels: skip-changelog|backport\/.+
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
# Golang CircleCI 2.0 configuration file
|
||||
#
|
||||
# Check https://circleci.com/docs/2.0/language-go/ for more details
|
||||
version: 2
|
||||
jobs:
|
||||
build:
|
||||
docker:
|
||||
# specify the version
|
||||
- image: circleci/golang:1.10
|
||||
|
||||
- image: circleci/mysql:5.7
|
||||
environment:
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: true
|
||||
MYSQL_DATABASE: xorm_test
|
||||
MYSQL_HOST: 127.0.0.1
|
||||
MYSQL_ROOT_HOST: '%'
|
||||
MYSQL_USER: root
|
||||
|
||||
# CircleCI PostgreSQL images available at: https://hub.docker.com/r/circleci/postgres/
|
||||
- image: circleci/postgres:9.6.2-alpine
|
||||
environment:
|
||||
POSTGRES_USER: circleci
|
||||
POSTGRES_DB: xorm_test
|
||||
|
||||
- image: microsoft/mssql-server-linux:latest
|
||||
environment:
|
||||
ACCEPT_EULA: Y
|
||||
SA_PASSWORD: yourStrong(!)Password
|
||||
MSSQL_PID: Developer
|
||||
|
||||
- image: pingcap/tidb:v2.1.2
|
||||
|
||||
working_directory: /go/src/github.com/go-xorm/xorm
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
- run: go get -t -d -v ./...
|
||||
- run: go get -u xorm.io/core
|
||||
- run: go get -u xorm.io/builder
|
||||
- run: GO111MODULE=off go build -v
|
||||
- run: GO111MODULE=on go build -v
|
||||
|
||||
- run: go get -u github.com/wadey/gocovmerge
|
||||
|
||||
- run: go test -v -race -db="sqlite3" -conn_str="./test.db" -coverprofile=coverage1-1.txt -covermode=atomic
|
||||
- run: go test -v -race -db="sqlite3" -conn_str="./test.db" -cache=true -coverprofile=coverage1-2.txt -covermode=atomic
|
||||
- run: go test -v -race -db="mysql" -conn_str="root:@/xorm_test" -coverprofile=coverage2-1.txt -covermode=atomic
|
||||
- run: go test -v -race -db="mysql" -conn_str="root:@/xorm_test" -cache=true -coverprofile=coverage2-2.txt -covermode=atomic
|
||||
- run: go test -v -race -db="mymysql" -conn_str="xorm_test/root/" -coverprofile=coverage3-1.txt -covermode=atomic
|
||||
- run: go test -v -race -db="mymysql" -conn_str="xorm_test/root/" -cache=true -coverprofile=coverage3-2.txt -covermode=atomic
|
||||
- run: go test -v -race -db="postgres" -conn_str="dbname=xorm_test sslmode=disable" -coverprofile=coverage4-1.txt -covermode=atomic
|
||||
- run: go test -v -race -db="postgres" -conn_str="dbname=xorm_test sslmode=disable" -cache=true -coverprofile=coverage4-2.txt -covermode=atomic
|
||||
- run: go test -v -race -db="postgres" -conn_str="dbname=xorm_test sslmode=disable" -schema=xorm -coverprofile=coverage5-1.txt -covermode=atomic
|
||||
- run: go test -v -race -db="postgres" -conn_str="dbname=xorm_test sslmode=disable" -schema=xorm -cache=true -coverprofile=coverage5-2.txt -covermode=atomic
|
||||
- run: go test -v -race -db="mssql" -conn_str="server=localhost;user id=sa;password=yourStrong(!)Password;database=xorm_test" -coverprofile=coverage6-1.txt -covermode=atomic
|
||||
- run: go test -v -race -db="mssql" -conn_str="server=localhost;user id=sa;password=yourStrong(!)Password;database=xorm_test" -cache=true -coverprofile=coverage6-2.txt -covermode=atomic
|
||||
- run: go test -v -race -db="mysql" -conn_str="root:@tcp(localhost:4000)/xorm_test" -ignore_select_update=true -coverprofile=coverage7-1.txt -covermode=atomic
|
||||
- run: go test -v -race -db="mysql" -conn_str="root:@tcp(localhost:4000)/xorm_test" -ignore_select_update=true -cache=true -coverprofile=coverage7-2.txt -covermode=atomic
|
||||
- run: gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt coverage6-1.txt coverage6-2.txt coverage7-1.txt coverage7-2.txt > coverage.txt
|
||||
|
||||
- run: bash <(curl -s https://codecov.io/bash)
|
||||
382
.drone.yml
382
.drone.yml
|
|
@ -1,249 +1,88 @@
|
|||
---
|
||||
kind: pipeline
|
||||
name: go1.10-test
|
||||
workspace:
|
||||
base: /go
|
||||
path: src/gitea.com/xorm/xorm
|
||||
|
||||
name: testing
|
||||
steps:
|
||||
- name: build
|
||||
pull: default
|
||||
image: golang:1.10
|
||||
- name: test-vet
|
||||
image: golang:1.11 # The lowest golang requirement
|
||||
environment:
|
||||
GO111MODULE: "on"
|
||||
GOPROXY: "https://goproxy.cn"
|
||||
commands:
|
||||
- go get -t -d -v
|
||||
- go build -v
|
||||
- make vet
|
||||
- make test
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- pull_request
|
||||
|
||||
- name: test-sqlite
|
||||
pull: default
|
||||
image: golang:1.10
|
||||
depends_on:
|
||||
- build
|
||||
image: golang:1.12
|
||||
environment:
|
||||
GO111MODULE: "on"
|
||||
GOPROXY: "https://goproxy.cn"
|
||||
commands:
|
||||
- "go test -v -race -db=\"sqlite3\" -conn_str=\"./test.db\" -coverprofile=coverage1-1.txt -covermode=atomic"
|
||||
- "go test -v -race -db=\"sqlite3\" -conn_str=\"./test.db\" -cache=true -coverprofile=coverage1-2.txt -covermode=atomic"
|
||||
- make test-sqlite
|
||||
- TEST_CACHE_ENABLE=true make test-sqlite
|
||||
- TEST_QUOTE_POLICY=reserved make test-sqlite
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- pull_request
|
||||
|
||||
- name: test-mysql
|
||||
pull: default
|
||||
image: golang:1.10
|
||||
depends_on:
|
||||
- build
|
||||
image: golang:1.12
|
||||
environment:
|
||||
GO111MODULE: "on"
|
||||
GOPROXY: "https://goproxy.cn"
|
||||
TEST_MYSQL_HOST: mysql
|
||||
TEST_MYSQL_CHARSET: utf8
|
||||
TEST_MYSQL_DBNAME: xorm_test
|
||||
TEST_MYSQL_USERNAME: root
|
||||
TEST_MYSQL_PASSWORD:
|
||||
commands:
|
||||
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test\" -coverprofile=coverage2-1.txt -covermode=atomic"
|
||||
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test\" -cache=true -coverprofile=coverage2-2.txt -covermode=atomic"
|
||||
- make test-mysql
|
||||
- TEST_CACHE_ENABLE=true make test-mysql
|
||||
- TEST_QUOTE_POLICY=reserved make test-mysql
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- pull_request
|
||||
|
||||
- name: test-mysql8
|
||||
image: golang:1.12
|
||||
environment:
|
||||
GO111MODULE: "on"
|
||||
GOPROXY: "https://goproxy.cn"
|
||||
TEST_MYSQL_HOST: mysql8
|
||||
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
|
||||
|
||||
- name: test-mysql-utf8mb4
|
||||
pull: default
|
||||
image: golang:1.10
|
||||
image: golang:1.12
|
||||
depends_on:
|
||||
- test-mysql
|
||||
commands:
|
||||
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test?charset=utf8mb4\" -coverprofile=coverage2.1-1.txt -covermode=atomic"
|
||||
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test?charset=utf8mb4\" -cache=true -coverprofile=coverage2.1-2.txt -covermode=atomic"
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- pull_request
|
||||
|
||||
- name: test-mymysql
|
||||
pull: default
|
||||
image: golang:1.10
|
||||
depends_on:
|
||||
- test-mysql-utf8mb4
|
||||
commands:
|
||||
- "go test -v -race -db=\"mymysql\" -conn_str=\"tcp:mysql:3306*xorm_test/root/\" -coverprofile=coverage3-1.txt -covermode=atomic"
|
||||
- "go test -v -race -db=\"mymysql\" -conn_str=\"tcp:mysql:3306*xorm_test/root/\" -cache=true -coverprofile=coverage3-2.txt -covermode=atomic"
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- pull_request
|
||||
|
||||
- name: test-postgres
|
||||
pull: default
|
||||
image: golang:1.10
|
||||
depends_on:
|
||||
- build
|
||||
commands:
|
||||
- "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -coverprofile=coverage4-1.txt -covermode=atomic"
|
||||
- "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -cache=true -coverprofile=coverage4-2.txt -covermode=atomic"
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- pull_request
|
||||
|
||||
- name: test-postgres-schema
|
||||
pull: default
|
||||
image: golang:1.10
|
||||
depends_on:
|
||||
- build
|
||||
commands:
|
||||
- "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -schema=xorm -coverprofile=coverage5-1.txt -covermode=atomic"
|
||||
- "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -schema=xorm -cache=true -coverprofile=coverage5-2.txt -covermode=atomic"
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- pull_request
|
||||
|
||||
- name: test-mssql
|
||||
pull: default
|
||||
image: golang:1.10
|
||||
depends_on:
|
||||
- build
|
||||
commands:
|
||||
- "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -coverprofile=coverage6-1.txt -covermode=atomic"
|
||||
- "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -cache=true -coverprofile=coverage6-2.txt -covermode=atomic"
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- pull_request
|
||||
|
||||
- name: test-tidb
|
||||
pull: default
|
||||
image: golang:1.10
|
||||
depends_on:
|
||||
- build
|
||||
commands:
|
||||
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(tidb:4000)/xorm_test\" -ignore_select_update=true -coverprofile=coverage7-1.txt -covermode=atomic"
|
||||
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(tidb:4000)/xorm_test\" -ignore_select_update=true -cache=true -coverprofile=coverage7-2.txt -covermode=atomic"
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- pull_request
|
||||
|
||||
- name: test-end
|
||||
pull: default
|
||||
image: golang:1.10
|
||||
depends_on:
|
||||
- test-sqlite
|
||||
- test-mysql
|
||||
- test-mysql-utf8mb4
|
||||
- test-mymysql
|
||||
- test-postgres
|
||||
- test-postgres-schema
|
||||
- test-mssql
|
||||
- test-tidb
|
||||
commands:
|
||||
- echo "go1.10 build end"
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- pull_request
|
||||
|
||||
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: pgsql
|
||||
pull: default
|
||||
image: postgres:9.5
|
||||
environment:
|
||||
POSTGRES_DB: xorm_test
|
||||
POSTGRES_USER: postgres
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- tag
|
||||
- pull_request
|
||||
|
||||
- name: mssql
|
||||
pull: default
|
||||
image: microsoft/mssql-server-linux:latest
|
||||
environment:
|
||||
ACCEPT_EULA: Y
|
||||
SA_PASSWORD: yourStrong(!)Password
|
||||
MSSQL_PID: Developer
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- tag
|
||||
- pull_request
|
||||
|
||||
- name: tidb
|
||||
pull: default
|
||||
image: pingcap/tidb:v3.0.3
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- tag
|
||||
- pull_request
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
name: go1.13-test
|
||||
steps:
|
||||
- name: build
|
||||
pull: default
|
||||
image: golang:1.13
|
||||
environment:
|
||||
GO111MODULE: "on"
|
||||
GOPROXY: "https://goproxy.cn"
|
||||
TEST_MYSQL_HOST: mysql
|
||||
TEST_MYSQL_CHARSET: utf8mb4
|
||||
TEST_MYSQL_DBNAME: xorm_test
|
||||
TEST_MYSQL_USERNAME: root
|
||||
TEST_MYSQL_PASSWORD:
|
||||
commands:
|
||||
- go build -v
|
||||
- go vet
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- pull_request
|
||||
|
||||
- name: test-sqlite
|
||||
pull: default
|
||||
image: golang:1.13
|
||||
environment:
|
||||
GO111MODULE: "on"
|
||||
GOPROXY: "https://goproxy.cn"
|
||||
commands:
|
||||
- "go test -v -race -db=\"sqlite3\" -conn_str=\"./test.db\" -coverprofile=coverage1-1.txt -covermode=atomic"
|
||||
- "go test -v -race -db=\"sqlite3\" -conn_str=\"./test.db\" -cache=true -coverprofile=coverage1-2.txt -covermode=atomic"
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- pull_request
|
||||
|
||||
- name: test-mysql
|
||||
pull: default
|
||||
image: golang:1.13
|
||||
environment:
|
||||
GO111MODULE: "on"
|
||||
GOPROXY: "https://goproxy.cn"
|
||||
commands:
|
||||
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test\" -coverprofile=coverage2-1.txt -covermode=atomic"
|
||||
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test\" -cache=true -coverprofile=coverage2-2.txt -covermode=atomic"
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- pull_request
|
||||
|
||||
- name: test-mysql-utf8mb4
|
||||
pull: default
|
||||
image: golang:1.13
|
||||
depends_on:
|
||||
- test-mysql
|
||||
environment:
|
||||
GO111MODULE: "on"
|
||||
GOPROXY: "https://goproxy.cn"
|
||||
commands:
|
||||
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test?charset=utf8mb4\" -coverprofile=coverage2.1-1.txt -covermode=atomic"
|
||||
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test?charset=utf8mb4\" -cache=true -coverprofile=coverage2.1-2.txt -covermode=atomic"
|
||||
- make test-mysql
|
||||
- TEST_CACHE_ENABLE=true make test-mysql
|
||||
- TEST_QUOTE_POLICY=reserved make test-mysql
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
|
|
@ -251,15 +90,20 @@ steps:
|
|||
|
||||
- name: test-mymysql
|
||||
pull: default
|
||||
image: golang:1.13
|
||||
image: golang:1.12
|
||||
depends_on:
|
||||
- test-mysql-utf8mb4
|
||||
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:
|
||||
- "go test -v -race -db=\"mymysql\" -conn_str=\"tcp:mysql:3306*xorm_test/root/\" -coverprofile=coverage3-1.txt -covermode=atomic"
|
||||
- "go test -v -race -db=\"mymysql\" -conn_str=\"tcp:mysql:3306*xorm_test/root/\" -cache=true -coverprofile=coverage3-2.txt -covermode=atomic"
|
||||
- make test-mymysql
|
||||
- TEST_CACHE_ENABLE=true make test-mymysql
|
||||
- TEST_QUOTE_POLICY=reserved make test-mymysql
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
|
|
@ -267,13 +111,18 @@ steps:
|
|||
|
||||
- name: test-postgres
|
||||
pull: default
|
||||
image: golang:1.13
|
||||
image: golang:1.12
|
||||
environment:
|
||||
GO111MODULE: "on"
|
||||
GOPROXY: "https://goproxy.cn"
|
||||
TEST_PGSQL_HOST: pgsql
|
||||
TEST_PGSQL_DBNAME: xorm_test
|
||||
TEST_PGSQL_USERNAME: postgres
|
||||
TEST_PGSQL_PASSWORD: postgres
|
||||
commands:
|
||||
- "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -coverprofile=coverage4-1.txt -covermode=atomic"
|
||||
- "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -cache=true -coverprofile=coverage4-2.txt -covermode=atomic"
|
||||
- make test-postgres
|
||||
- TEST_CACHE_ENABLE=true make test-postgres
|
||||
- TEST_QUOTE_POLICY=reserved make test-postgres
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
|
|
@ -281,13 +130,21 @@ steps:
|
|||
|
||||
- name: test-postgres-schema
|
||||
pull: default
|
||||
image: golang:1.13
|
||||
image: golang:1.12
|
||||
depends_on:
|
||||
- test-postgres
|
||||
environment:
|
||||
GO111MODULE: "on"
|
||||
GOPROXY: "https://goproxy.cn"
|
||||
TEST_PGSQL_HOST: pgsql
|
||||
TEST_PGSQL_SCHEMA: xorm
|
||||
TEST_PGSQL_DBNAME: xorm_test
|
||||
TEST_PGSQL_USERNAME: postgres
|
||||
TEST_PGSQL_PASSWORD: postgres
|
||||
commands:
|
||||
- "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -schema=xorm -coverprofile=coverage5-1.txt -covermode=atomic"
|
||||
- "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -schema=xorm -cache=true -coverprofile=coverage5-2.txt -covermode=atomic"
|
||||
- make test-postgres
|
||||
- TEST_CACHE_ENABLE=true make test-postgres
|
||||
- TEST_QUOTE_POLICY=reserved make test-postgres
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
|
|
@ -295,27 +152,56 @@ steps:
|
|||
|
||||
- name: test-mssql
|
||||
pull: default
|
||||
image: golang:1.13
|
||||
image: golang:1.12
|
||||
environment:
|
||||
GO111MODULE: "on"
|
||||
GOPROXY: "https://goproxy.cn"
|
||||
TEST_MSSQL_HOST: mssql
|
||||
TEST_MSSQL_DBNAME: xorm_test
|
||||
TEST_MSSQL_USERNAME: sa
|
||||
TEST_MSSQL_PASSWORD: "yourStrong(!)Password"
|
||||
commands:
|
||||
- "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -coverprofile=coverage6-1.txt -covermode=atomic"
|
||||
- "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -cache=true -coverprofile=coverage6-2.txt -covermode=atomic"
|
||||
- make test-mssql
|
||||
- TEST_CACHE_ENABLE=true make test-mssql
|
||||
- TEST_QUOTE_POLICY=reserved make test-mssql
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- pull_request
|
||||
|
||||
- name: test-tidb
|
||||
pull: default
|
||||
image: golang:1.12
|
||||
environment:
|
||||
GO111MODULE: "on"
|
||||
GOPROXY: "https://goproxy.cn"
|
||||
TEST_TIDB_HOST: "tidb:4000"
|
||||
TEST_TIDB_DBNAME: xorm_test
|
||||
TEST_TIDB_USERNAME: root
|
||||
TEST_TIDB_PASSWORD:
|
||||
commands:
|
||||
- make test-tidb
|
||||
- TEST_CACHE_ENABLE=true make test-tidb
|
||||
- TEST_QUOTE_POLICY=reserved make test-tidb
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- pull_request
|
||||
|
||||
- name: test-cockroach
|
||||
pull: default
|
||||
image: golang:1.13
|
||||
environment:
|
||||
GO111MODULE: "on"
|
||||
GOPROXY: "https://goproxy.cn"
|
||||
TEST_COCKROACH_HOST: "cockroach:26257"
|
||||
TEST_COCKROACH_DBNAME: xorm_test
|
||||
TEST_COCKROACH_USERNAME: root
|
||||
TEST_COCKROACH_PASSWORD:
|
||||
commands:
|
||||
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(tidb:4000)/xorm_test\" -ignore_select_update=true -coverprofile=coverage7-1.txt -covermode=atomic"
|
||||
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(tidb:4000)/xorm_test\" -ignore_select_update=true -cache=true -coverprofile=coverage7-2.txt -covermode=atomic"
|
||||
- sleep 10
|
||||
- make test-cockroach
|
||||
- TEST_CACHE_ENABLE=true make test-cockroach
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
|
|
@ -323,23 +209,23 @@ steps:
|
|||
|
||||
- name: merge_coverage
|
||||
pull: default
|
||||
image: golang:1.13
|
||||
image: golang:1.12
|
||||
environment:
|
||||
GO111MODULE: "on"
|
||||
GOPROXY: "https://goproxy.cn"
|
||||
depends_on:
|
||||
- build
|
||||
- test-vet
|
||||
- test-sqlite
|
||||
- test-mysql
|
||||
- test-mysql-utf8mb4
|
||||
- test-mysql8
|
||||
- test-mymysql
|
||||
- test-postgres
|
||||
- test-postgres-schema
|
||||
- test-mssql
|
||||
- test-tidb
|
||||
- test-cockroach
|
||||
commands:
|
||||
- go get github.com/wadey/gocovmerge
|
||||
- gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage2.1-1.txt coverage2.1-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt coverage6-1.txt coverage6-2.txt coverage7-1.txt coverage7-2.txt > coverage.txt
|
||||
- make coverage
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
|
|
@ -359,12 +245,25 @@ services:
|
|||
- 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
|
||||
|
|
@ -391,4 +290,15 @@ services:
|
|||
event:
|
||||
- push
|
||||
- tag
|
||||
- pull_request
|
||||
- pull_request
|
||||
|
||||
- name: cockroach
|
||||
pull: default
|
||||
image: cockroachdb/cockroach:v19.2.4
|
||||
commands:
|
||||
- /cockroach/cockroach start --insecure
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- tag
|
||||
- pull_request
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
# Folders
|
||||
_obj
|
||||
_test
|
||||
vendor/
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
|
|
@ -31,3 +32,7 @@ xorm.test
|
|||
test.db.sql
|
||||
|
||||
.idea/
|
||||
|
||||
*coverage.out
|
||||
test.db
|
||||
integrations/*.sql
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
ignoreGeneratedHeader = false
|
||||
severity = "warning"
|
||||
confidence = 0.8
|
||||
errorCode = 1
|
||||
warningCode = 1
|
||||
|
||||
[rule.blank-imports]
|
||||
[rule.context-as-argument]
|
||||
[rule.context-keys-type]
|
||||
[rule.dot-imports]
|
||||
[rule.error-return]
|
||||
[rule.error-strings]
|
||||
[rule.error-naming]
|
||||
[rule.exported]
|
||||
[rule.if-return]
|
||||
[rule.increment-decrement]
|
||||
[rule.var-naming]
|
||||
[rule.var-declaration]
|
||||
[rule.package-comments]
|
||||
[rule.range]
|
||||
[rule.receiver-naming]
|
||||
[rule.time-naming]
|
||||
[rule.unexported-return]
|
||||
[rule.indent-error-flow]
|
||||
[rule.errorf]
|
||||
|
|
@ -0,0 +1,197 @@
|
|||
# Changelog
|
||||
|
||||
This changelog goes through all the changes that have been made in each release
|
||||
without substantial changes to our git log.
|
||||
|
||||
## [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
|
||||
* Oracle : Local Naming Method (#1515)
|
||||
* Fix find and count bug (#1618)
|
||||
* Fix duplicated deleted condition on FindAndCount (#1619)
|
||||
* Fix find and count bug with cache (#1622)
|
||||
* Fix postgres schema problem (#1624)
|
||||
* Fix quote with blank (#1626)
|
||||
|
||||
## [1.0.0](https://gitea.com/xorm/xorm/pulls?q=&type=all&state=closed&milestone=1242) - 2020-03-22
|
||||
|
||||
* BREAKING
|
||||
* Add context for dialects (#1558)
|
||||
* Move zero functions to a standalone package (#1548)
|
||||
* Merge core package back into the main repository and split into serval sub packages. (#1543)
|
||||
* FEATURES
|
||||
* Use a new ContextLogger interface to implement logger (#1557)
|
||||
* BUGFIXES
|
||||
* Fix setschema (#1606)
|
||||
* Fix dump/import bug (#1603)
|
||||
* Fix pk bug (#1602)
|
||||
* Fix master/slave bug (#1601)
|
||||
* Fix bug when dump (#1597)
|
||||
* Ignore schema when dbtype is not postgres (#1593)
|
||||
* Fix table name (#1590)
|
||||
* Fix find alias bug (#1581)
|
||||
* Fix rows bug (#1576)
|
||||
* Fix map with cols (#1575)
|
||||
* Fix bug on deleted with join (#1570)
|
||||
* Improve quote policy (#1567)
|
||||
* Fix break session sql enable feature (#1566)
|
||||
* Fix mssql quote (#1535)
|
||||
* Fix join table name quote bug (#1534)
|
||||
* Fix mssql issue with duplicate columns. (#1225)
|
||||
* Fix mysql8.0 sync failed (#808)
|
||||
* ENHANCEMENTS
|
||||
* Fix batch insert interface slice be panic (#1598)
|
||||
* Move some codes to statement sub package (#1574)
|
||||
* Remove circle file (#1569)
|
||||
* Move statement as a sub package (#1564)
|
||||
* Move maptype to tag parser (#1561)
|
||||
* Move caches to manager (#1553)
|
||||
* Improve code (#1552)
|
||||
* Improve some codes (#1551)
|
||||
* Improve statement (#1549)
|
||||
* Move tag parser related codes as a standalone sub package (#1547)
|
||||
* Move reserve words related files into dialects sub package (#1544)
|
||||
* Fix `Conversion` method `ToDB() ([]byte, error)` return type is nil (#1296)
|
||||
* Check driver.Valuer response, and skip the column if nil (#1167)
|
||||
* Add cockroach support and tests (#896)
|
||||
* TESTING
|
||||
* Improve tests (#1572)
|
||||
* BUILD
|
||||
* Add changelog file and tool configuration (#1546)
|
||||
* DOCS
|
||||
* Fix outdate changelog (#1565)
|
||||
|
||||
## old changelog
|
||||
|
||||
* **v0.6.5**
|
||||
* Postgres schema support
|
||||
* vgo support
|
||||
* Add FindAndCount
|
||||
* Database special params support via NewEngineWithParams
|
||||
* Some bugs fixed
|
||||
|
||||
* **v0.6.4**
|
||||
* Automatical Read/Write seperatelly
|
||||
* Query/QueryString/QueryInterface and action with Where/And
|
||||
* Get support non-struct variables
|
||||
* BufferSize on Iterate
|
||||
* fix some other bugs.
|
||||
|
||||
* **v0.6.3**
|
||||
* merge tests to main project
|
||||
* add `Exist` function
|
||||
* add `SumInt` function
|
||||
* Mysql now support read and create column comment.
|
||||
* fix time related bugs.
|
||||
* fix some other bugs.
|
||||
|
||||
* **v0.6.2**
|
||||
* refactor tag parse methods
|
||||
* add Scan features to Get
|
||||
* add QueryString method
|
||||
|
||||
* **v0.4.5**
|
||||
* many bugs fixed
|
||||
* extends support unlimited deep
|
||||
* Delete Limit support
|
||||
|
||||
* **v0.4.4**
|
||||
* ql database expriment support
|
||||
* tidb database expriment support
|
||||
* sql.NullString and etc. field support
|
||||
* select ForUpdate support
|
||||
* many bugs fixed
|
||||
|
||||
* **v0.4.3**
|
||||
* Json column type support
|
||||
* oracle expirement support
|
||||
* bug fixed
|
||||
|
||||
* **v0.4.2**
|
||||
* Transaction will auto rollback if not Rollback or Commit be called.
|
||||
* Gonic Mapper support
|
||||
* bug fixed
|
||||
|
||||
* **v0.4.1**
|
||||
* deleted tag support for soft delete
|
||||
* bug fixed
|
||||
|
||||
* **v0.4.0 RC1**
|
||||
Changes:
|
||||
* moved xorm cmd to [github.com/go-xorm/cmd](github.com/go-xorm/cmd)
|
||||
* refactored general DB operation a core lib at [github.com/go-xorm/core](https://github.com/go-xorm/core)
|
||||
* moved tests to github.com/go-xorm/tests [github.com/go-xorm/tests](github.com/go-xorm/tests)
|
||||
|
||||
Improvements:
|
||||
* Prepared statement cache
|
||||
* Add Incr API
|
||||
* Specify Timezone Location
|
||||
|
||||
* **v0.3.2**
|
||||
Improvements:
|
||||
* Add AllCols & MustCols function
|
||||
* Add TableName for custom table name
|
||||
|
||||
Bug Fixes:
|
||||
* #46
|
||||
* #51
|
||||
* #53
|
||||
* #89
|
||||
* #86
|
||||
* #92
|
||||
|
||||
* **v0.3.1**
|
||||
|
||||
Features:
|
||||
* Support MSSQL DB via ODBC driver ([github.com/lunny/godbc](https://github.com/lunny/godbc));
|
||||
* Composite Key, using multiple pk xorm tag
|
||||
* Added Row() API as alternative to Iterate() API for traversing result set, provide similar usages to sql.Rows type
|
||||
* ORM struct allowed declaration of pointer builtin type as members to allow null DB fields
|
||||
* Before and After Event processors
|
||||
|
||||
Improvements:
|
||||
* Allowed int/int32/int64/uint/uint32/uint64/string as Primary Key type
|
||||
* Performance improvement for Get()/Find()/Iterate()
|
||||
|
||||
|
||||
* **v0.2.3** : Improved documents; Optimistic Locking support; Timestamp with time zone support; Mapper change to tableMapper and columnMapper & added PrefixMapper & SuffixMapper support custom table or column name's prefix and suffix;Insert now return affected, err instead of id, err; Added UseBool & Distinct;
|
||||
|
||||
* **v0.2.2** : Postgres drivers now support lib/pq; Added method Iterate for record by record to handler;Added SetMaxConns(go1.2+) support; some bugs fixed.
|
||||
|
||||
* **v0.2.1** : Added database reverse tool, now support generate go & c++ codes, see [Xorm Tool README](https://github.com/go-xorm/xorm/blob/master/xorm/README.md); some bug fixed.
|
||||
|
||||
* **v0.2.0** : Added Cache supported, select is speeder up 3~5x; Added SameMapper for same name between struct and table; Added Sync method for auto added tables, columns, indexes;
|
||||
|
||||
* **v0.1.9** : Added postgres and mymysql supported; Added ` and ? supported on Raw SQL even if postgres; Added Cols, StoreEngine, Charset function, Added many column data type supported, please see [Mapping Rules](#mapping).
|
||||
|
||||
* **v0.1.8** : Added union index and union unique supported, please see [Mapping Rules](#mapping).
|
||||
|
||||
* **v0.1.7** : Added IConnectPool interface and NoneConnectPool, SysConnectPool, SimpleConnectPool the three implements. You can choose one of them and the default is SysConnectPool. You can customrize your own connection pool. struct Engine added Close method, It should be invoked before system exit.
|
||||
|
||||
* **v0.1.6** : Added conversion interface support; added struct derive support; added single mapping support
|
||||
|
||||
* **v0.1.5** : Added multi threads support; added Sql() function for struct query; Get function changed return inteface; MakeSession and Create are instead with NewSession and NewEngine.
|
||||
|
||||
* **v0.1.4** : Added simple cascade load support; added more data type supports.
|
||||
|
||||
* **v0.1.3** : Find function now supports both slice and map; Add Table function for multi tables and temperory tables support
|
||||
|
||||
* **v0.1.2** : Insert function now supports both struct and slice pointer parameters, batch inserting and auto transaction
|
||||
|
||||
* **v0.1.1** : Add Id, In functions and improved README
|
||||
|
||||
* **v0.1.0** : Initial release.
|
||||
|
|
@ -22,6 +22,47 @@ e.g.,
|
|||
// !lunny! this is comments made by lunny
|
||||
```
|
||||
|
||||
### Build xorm and test it locally
|
||||
|
||||
Once you write some codes on your feature branch, you could build and test locally at first. Just
|
||||
|
||||
```
|
||||
make build
|
||||
```
|
||||
and
|
||||
```
|
||||
make test
|
||||
```
|
||||
|
||||
The `make test` is an alias of `make test-sqlite`, it will run the tests on a sqlite database file. No extra thing needed to do except you need to cgo compile enviroment.
|
||||
|
||||
If you write a new test method, you could run
|
||||
|
||||
```
|
||||
make test-sqlite#TestMyNewMethod
|
||||
```
|
||||
|
||||
that will only run the special test method.
|
||||
|
||||
If you want to run another datase, you have to prepare a running database at first, and then, you could
|
||||
|
||||
```
|
||||
TEST_MYSQL_HOST= TEST_MYSQL_CHARSET= TEST_MYSQL_DBNAME= TEST_MYSQL_USERNAME= TEST_MYSQL_PASSWORD= make test-mysql
|
||||
```
|
||||
|
||||
or other databases:
|
||||
```
|
||||
TEST_MSSQL_HOST= TEST_MSSQL_DBNAME= TEST_MSSQL_USERNAME= TEST_MSSQL_PASSWORD= make test-mssql
|
||||
```
|
||||
```
|
||||
TEST_PGSQL_HOST= TEST_PGSQL_SCHEMA= TEST_PGSQL_DBNAME= TEST_PGSQL_USERNAME= TEST_PGSQL_PASSWORD= make test-postgres
|
||||
```
|
||||
```
|
||||
TEST_TIDB_HOST= TEST_TIDB_DBNAME= TEST_TIDB_USERNAME= TEST_TIDB_PASSWORD= make test-tidb
|
||||
```
|
||||
|
||||
And if your branch is related with cache, you could also enable it via `TEST_CACHE_ENABLE=true`.
|
||||
|
||||
### Patch review
|
||||
|
||||
Help review existing open [pull requests](https://help.github.com/articles/using-pull-requests) by commenting on the code or
|
||||
|
|
|
|||
|
|
@ -0,0 +1,220 @@
|
|||
IMPORT := xorm.io/xorm
|
||||
export GO111MODULE=on
|
||||
|
||||
GO ?= go
|
||||
GOFMT ?= gofmt -s
|
||||
TAGS ?=
|
||||
SED_INPLACE := sed -i
|
||||
|
||||
GOFILES := $(shell find . -name "*.go" -type f)
|
||||
INTEGRATION_PACKAGES := xorm.io/xorm/integrations
|
||||
PACKAGES ?= $(filter-out $(INTEGRATION_PACKAGES),$(shell $(GO) list ./...))
|
||||
|
||||
TEST_COCKROACH_HOST ?= cockroach:26257
|
||||
TEST_COCKROACH_SCHEMA ?=
|
||||
TEST_COCKROACH_DBNAME ?= xorm_test
|
||||
TEST_COCKROACH_USERNAME ?= postgres
|
||||
TEST_COCKROACH_PASSWORD ?=
|
||||
|
||||
TEST_MSSQL_HOST ?= mssql:1433
|
||||
TEST_MSSQL_DBNAME ?= gitea
|
||||
TEST_MSSQL_USERNAME ?= sa
|
||||
TEST_MSSQL_PASSWORD ?= MwantsaSecurePassword1
|
||||
|
||||
TEST_MYSQL_HOST ?= mysql:3306
|
||||
TEST_MYSQL_CHARSET ?= utf8
|
||||
TEST_MYSQL_DBNAME ?= xorm_test
|
||||
TEST_MYSQL_USERNAME ?= root
|
||||
TEST_MYSQL_PASSWORD ?=
|
||||
|
||||
TEST_PGSQL_HOST ?= pgsql:5432
|
||||
TEST_PGSQL_SCHEMA ?=
|
||||
TEST_PGSQL_DBNAME ?= xorm_test
|
||||
TEST_PGSQL_USERNAME ?= postgres
|
||||
TEST_PGSQL_PASSWORD ?= mysecretpassword
|
||||
|
||||
TEST_TIDB_HOST ?= tidb:4000
|
||||
TEST_TIDB_DBNAME ?= xorm_test
|
||||
TEST_TIDB_USERNAME ?= root
|
||||
TEST_TIDB_PASSWORD ?=
|
||||
|
||||
TEST_CACHE_ENABLE ?= false
|
||||
TEST_QUOTE_POLICY ?= always
|
||||
|
||||
.PHONY: all
|
||||
all: build
|
||||
|
||||
.PHONY: build
|
||||
build: go-check $(GO_SOURCES)
|
||||
$(GO) build $(PACKAGES)
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
$(GO) clean -i ./...
|
||||
rm -rf *.sql *.log test.db *coverage.out coverage.all integrations/*.sql
|
||||
|
||||
.PHONY: coverage
|
||||
coverage:
|
||||
@hash gocovmerge > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) get -u github.com/wadey/gocovmerge; \
|
||||
fi
|
||||
gocovmerge $(shell find . -type f -name "coverage.out") > coverage.all;\
|
||||
|
||||
.PHONY: fmt
|
||||
fmt:
|
||||
$(GOFMT) -w $(GOFILES)
|
||||
|
||||
.PHONY: fmt-check
|
||||
fmt-check:
|
||||
# get all go files and run go fmt on them
|
||||
@diff=$$($(GOFMT) -d $(GOFILES)); \
|
||||
if [ -n "$$diff" ]; then \
|
||||
echo "Please run 'make fmt' and commit the result:"; \
|
||||
echo "$${diff}"; \
|
||||
exit 1; \
|
||||
fi;
|
||||
|
||||
.PHONY: go-check
|
||||
go-check:
|
||||
$(eval GO_VERSION := $(shell printf "%03d%03d%03d" $(shell go version | grep -Eo '[0-9]+\.?[0-9]+?\.?[0-9]?\s' | tr '.' ' ');))
|
||||
@if [ "$(GO_VERSION)" -lt "001011000" ]; then \
|
||||
echo "Gitea requires Go 1.11.0 or greater to build. You can get it at https://golang.org/dl/"; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
.PHONY: help
|
||||
help:
|
||||
@echo "Make Routines:"
|
||||
@echo " - equivalent to \"build\""
|
||||
@echo " - build creates the entire project"
|
||||
@echo " - clean delete integration files and build files but not css and js files"
|
||||
@echo " - fmt format the code"
|
||||
@echo " - lint run code linter revive"
|
||||
@echo " - misspell check if a word is written wrong"
|
||||
@echo " - test run default unit test"
|
||||
@echo " - test-cockroach run integration tests for cockroach"
|
||||
@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-tidb run integration tests for tidb"
|
||||
@echo " - vet examines Go source code and reports suspicious constructs"
|
||||
|
||||
.PHONY: lint
|
||||
lint: revive
|
||||
|
||||
.PHONY: revive
|
||||
revive:
|
||||
@hash revive > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) get -u github.com/mgechev/revive; \
|
||||
fi
|
||||
revive -config .revive.toml -exclude=./vendor/... ./... || exit 1
|
||||
|
||||
.PHONY: misspell
|
||||
misspell:
|
||||
@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) get -u github.com/client9/misspell/cmd/misspell; \
|
||||
fi
|
||||
misspell -w -i unknwon $(GOFILES)
|
||||
|
||||
.PHONY: misspell-check
|
||||
misspell-check:
|
||||
@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) get -u github.com/client9/misspell/cmd/misspell; \
|
||||
fi
|
||||
misspell -error -i unknwon,destory $(GOFILES)
|
||||
|
||||
.PHONY: test
|
||||
test: go-check
|
||||
$(GO) test $(PACKAGES)
|
||||
|
||||
.PNONY: test-cockroach
|
||||
test-cockroach: go-check
|
||||
$(GO) test $(INTEGRATION_PACKAGES) -v -race -db=postgres -schema='$(TEST_COCKROACH_SCHEMA)' -cache=$(TEST_CACHE_ENABLE) \
|
||||
-conn_str="postgres://$(TEST_COCKROACH_USERNAME):$(TEST_COCKROACH_PASSWORD)@$(TEST_COCKROACH_HOST)/$(TEST_COCKROACH_DBNAME)?sslmode=disable&experimental_serial_normalization=sql_sequence" \
|
||||
-ignore_update_limit=true -coverprofile=cockroach.$(TEST_COCKROACH_SCHEMA).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
||||
|
||||
.PHONY: test-cockroach\#%
|
||||
test-cockroach\#%: go-check
|
||||
$(GO) test $(INTEGRATION_PACKAGES) -v -race -run $* -db=postgres -schema='$(TEST_COCKROACH_SCHEMA)' -cache=$(TEST_CACHE_ENABLE) \
|
||||
-conn_str="postgres://$(TEST_COCKROACH_USERNAME):$(TEST_COCKROACH_PASSWORD)@$(TEST_COCKROACH_HOST)/$(TEST_COCKROACH_DBNAME)?sslmode=disable&experimental_serial_normalization=sql_sequence" \
|
||||
-ignore_update_limit=true -coverprofile=cockroach.$(TEST_COCKROACH_SCHEMA).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
||||
|
||||
.PNONY: test-mssql
|
||||
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)" \
|
||||
-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)" \
|
||||
-coverprofile=mssql.$(TEST_QUOTE_POLICY).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
||||
|
||||
.PNONY: test-mymysql
|
||||
test-mymysql: go-check
|
||||
$(GO) test $(INTEGRATION_PACKAGES) -v -race -db=mymysql -cache=$(TEST_CACHE_ENABLE) -quote=$(TEST_QUOTE_POLICY) \
|
||||
-conn_str="tcp:$(TEST_MYSQL_HOST)*$(TEST_MYSQL_DBNAME)/$(TEST_MYSQL_USERNAME)/$(TEST_MYSQL_PASSWORD)" \
|
||||
-coverprofile=mymysql.$(TEST_QUOTE_POLICY).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
||||
|
||||
.PNONY: test-mymysql\#%
|
||||
test-mymysql\#%: go-check
|
||||
$(GO) test $(INTEGRATION_PACKAGES) -v -race -run $* -db=mymysql -cache=$(TEST_CACHE_ENABLE) -quote=$(TEST_QUOTE_POLICY) \
|
||||
-conn_str="tcp:$(TEST_MYSQL_HOST)*$(TEST_MYSQL_DBNAME)/$(TEST_MYSQL_USERNAME)/$(TEST_MYSQL_PASSWORD)" \
|
||||
-coverprofile=mymysql.$(TEST_QUOTE_POLICY).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
||||
|
||||
.PNONY: test-mysql
|
||||
test-mysql: go-check
|
||||
$(GO) test $(INTEGRATION_PACKAGES) -v -race -db=mysql -cache=$(TEST_CACHE_ENABLE) -quote=$(TEST_QUOTE_POLICY) \
|
||||
-conn_str="$(TEST_MYSQL_USERNAME):$(TEST_MYSQL_PASSWORD)@tcp($(TEST_MYSQL_HOST))/$(TEST_MYSQL_DBNAME)?charset=$(TEST_MYSQL_CHARSET)" \
|
||||
-coverprofile=mysql.$(TEST_QUOTE_POLICY).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
||||
|
||||
.PHONY: test-mysql\#%
|
||||
test-mysql\#%: go-check
|
||||
$(GO) test $(INTEGRATION_PACKAGES) -v -race -run $* -db=mysql -cache=$(TEST_CACHE_ENABLE) -quote=$(TEST_QUOTE_POLICY) \
|
||||
-conn_str="$(TEST_MYSQL_USERNAME):$(TEST_MYSQL_PASSWORD)@tcp($(TEST_MYSQL_HOST))/$(TEST_MYSQL_DBNAME)?charset=$(TEST_MYSQL_CHARSET)" \
|
||||
-coverprofile=mysql.$(TEST_QUOTE_POLICY).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
||||
|
||||
.PNONY: test-postgres
|
||||
test-postgres: go-check
|
||||
$(GO) test $(INTEGRATION_PACKAGES) -v -race -db=postgres -schema='$(TEST_PGSQL_SCHEMA)' -cache=$(TEST_CACHE_ENABLE) \
|
||||
-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-postgres\#%
|
||||
test-postgres\#%: go-check
|
||||
$(GO) test $(INTEGRATION_PACKAGES) -v -race -run $* -db=postgres -schema='$(TEST_PGSQL_SCHEMA)' -cache=$(TEST_CACHE_ENABLE) \
|
||||
-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-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" \
|
||||
-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" \
|
||||
-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" \
|
||||
-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 \
|
||||
-conn_str="$(TEST_TIDB_USERNAME):$(TEST_TIDB_PASSWORD)@tcp($(TEST_TIDB_HOST))/$(TEST_TIDB_DBNAME)" \
|
||||
-quote=$(TEST_QUOTE_POLICY) -coverprofile=tidb.$(TEST_QUOTE_POLICY).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
||||
|
||||
.PHONY: test-tidb\#%
|
||||
test-tidb\#%: go-check
|
||||
$(GO) test $(INTEGRATION_PACKAGES) -v -race -run $* -db=mysql -cache=$(TEST_CACHE_ENABLE) -ignore_select_update=true \
|
||||
-conn_str="$(TEST_TIDB_USERNAME):$(TEST_TIDB_PASSWORD)@tcp($(TEST_TIDB_HOST))/$(TEST_TIDB_DBNAME)" \
|
||||
-quote=$(TEST_QUOTE_POLICY) -coverprofile=tidb.$(TEST_QUOTE_POLICY).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
||||
|
||||
.PHONY: vet
|
||||
vet:
|
||||
$(GO) vet $(shell $(GO) list ./...)
|
||||
75
README.md
75
README.md
|
|
@ -4,55 +4,52 @@
|
|||
|
||||
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
|
||||
|
||||
v1.0.0 has some break changes from v0.8.2.
|
||||
|
||||
- Removed some non gonic function name `Id`, `Sql`, please use `ID`, `SQL` instead.
|
||||
- Removed the dependent from `xorm.io/core` and moved the codes to `xorm.io/xorm/core`, `xorm.io/xorm/names`, `xorm.io/xorm/schemas` and others.
|
||||
- Renamed some interface names. i.e. `core.IMapper` -> `names.Mapper`, `core.ILogger` -> `log.Logger`.
|
||||
|
||||
## Features
|
||||
|
||||
* Struct <-> Table Mapping Support
|
||||
|
||||
* Chainable APIs
|
||||
|
||||
* Transaction Support
|
||||
|
||||
* Both ORM and raw SQL operation Support
|
||||
|
||||
* Sync database schema Support
|
||||
|
||||
* Query Cache speed up
|
||||
|
||||
* Database Reverse support, See [Xorm Tool README](https://github.com/go-xorm/cmd/blob/master/README.md)
|
||||
|
||||
* Database Reverse support via [xorm.io/reverse](https://xorm.io/reverse)
|
||||
* Simple cascade loading support
|
||||
|
||||
* Optimistic Locking support
|
||||
|
||||
* SQL Builder support via [xorm.io/builder](https://xorm.io/builder)
|
||||
|
||||
* Automatical Read/Write seperatelly
|
||||
|
||||
* Postgres schema support
|
||||
|
||||
* Context Cache support
|
||||
* Support log/SQLLog context
|
||||
|
||||
## Drivers Support
|
||||
|
||||
Drivers for Go's sql package which currently support database/sql includes:
|
||||
|
||||
* Mysql: [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql)
|
||||
* [Mysql5.*](https://github.com/mysql/mysql-server/tree/5.7) / [Mysql8.*](https://github.com/mysql/mysql-server) / [Mariadb](https://github.com/MariaDB/server) / [Tidb](https://github.com/pingcap/tidb)
|
||||
- [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql)
|
||||
- [github.com/ziutek/mymysql/godrv](https://github.com/ziutek/mymysql/godrv)
|
||||
|
||||
* MyMysql: [github.com/ziutek/mymysql/godrv](https://github.com/ziutek/mymysql/tree/master/godrv)
|
||||
* [Postgres](https://github.com/postgres/postgres) / [Cockroach](https://github.com/cockroachdb/cockroach)
|
||||
- [github.com/lib/pq](https://github.com/lib/pq)
|
||||
|
||||
* Postgres: [github.com/lib/pq](https://github.com/lib/pq)
|
||||
* [SQLite](https://sqlite.org)
|
||||
- [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3)
|
||||
|
||||
* Tidb: [github.com/pingcap/tidb](https://github.com/pingcap/tidb)
|
||||
* MsSql
|
||||
- [github.com/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb)
|
||||
|
||||
* SQLite: [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3)
|
||||
|
||||
* MsSql: [github.com/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb)
|
||||
|
||||
* Oracle: [github.com/mattn/go-oci8](https://github.com/mattn/go-oci8) (experiment)
|
||||
* Oracle
|
||||
- [github.com/mattn/go-oci8](https://github.com/mattn/go-oci8) (experiment)
|
||||
|
||||
## Installation
|
||||
|
||||
|
|
@ -62,12 +59,14 @@ Drivers for Go's sql package which currently support database/sql includes:
|
|||
|
||||
* [Manual](http://xorm.io/docs)
|
||||
|
||||
* [GoDoc](http://godoc.org/xorm.io/xorm)
|
||||
* [GoDoc](http://pkg.go.dev/xorm.io/xorm)
|
||||
|
||||
## Quick Start
|
||||
|
||||
* Create Engine
|
||||
|
||||
Firstly, we should new an engine for a database.
|
||||
|
||||
```Go
|
||||
engine, err := xorm.NewEngine(driverName, dataSourceName)
|
||||
```
|
||||
|
|
@ -419,7 +418,7 @@ res, err := engine.Transaction(func(session *xorm.Session) (interface{}, error)
|
|||
|
||||
## Contributing
|
||||
|
||||
If you want to pull request, please see [CONTRIBUTING](https://gitea.com/xorm/xorm/src/branch/master/CONTRIBUTING.md). And we also provide [Xorm on Google Groups](https://groups.google.com/forum/#!forum/xorm) to discuss.
|
||||
If you want to pull request, please see [CONTRIBUTING](https://gitea.com/xorm/xorm/src/branch/master/CONTRIBUTING.md). And you can also go to [Xorm on discourse](https://xorm.discourse.group) to discuss.
|
||||
|
||||
## Credits
|
||||
|
||||
|
|
@ -440,27 +439,7 @@ Support this project by becoming a sponsor. Your logo will show up here with a l
|
|||
|
||||
## Changelog
|
||||
|
||||
* **v0.7.0**
|
||||
* Some bugs fixed
|
||||
|
||||
* **v0.6.6**
|
||||
* Some bugs fixed
|
||||
|
||||
* **v0.6.5**
|
||||
* Postgres schema support
|
||||
* vgo support
|
||||
* Add FindAndCount
|
||||
* Database special params support via NewEngineWithParams
|
||||
* Some bugs fixed
|
||||
|
||||
* **v0.6.4**
|
||||
* Automatical Read/Write seperatelly
|
||||
* Query/QueryString/QueryInterface and action with Where/And
|
||||
* Get support non-struct variables
|
||||
* BufferSize on Iterate
|
||||
* fix some other bugs.
|
||||
|
||||
[More changes ...](https://github.com/go-xorm/manual-en-US/tree/master/chapter-16)
|
||||
You can find all the changelog [here](CHANGELOG.md)
|
||||
|
||||
## Cases
|
||||
|
||||
|
|
|
|||
84
README_CN.md
84
README_CN.md
|
|
@ -2,57 +2,53 @@
|
|||
|
||||
[English](https://gitea.com/xorm/xorm/src/branch/master/README.md)
|
||||
|
||||
xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作非常简便。
|
||||
xorm 是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作非常简便。
|
||||
|
||||
[](https://drone.gitea.com/xorm/builder) [](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
|
||||
|
||||
v1.0.0 相对于 v0.8.2 有以下不兼容的变更:
|
||||
|
||||
- 移除了部分不符合Go语言命名的函数,如 `Id`, `Sql`,请使用 `ID`, `SQL` 替代。
|
||||
- 删除了对 `xorm.io/core` 的依赖。大部分代码迁移到了 `xorm.io/xorm/core`, `xorm.io/xorm/names`, `xorm.io/xorm/schemas` 等等几个包中.
|
||||
- 重命名了几个结构体,如: `core.IMapper` -> `names.Mapper`, `core.ILogger` -> `log.Logger`.
|
||||
|
||||
## 特性
|
||||
|
||||
* 支持Struct和数据库表之间的灵活映射,并支持自动同步
|
||||
|
||||
* 支持 Struct 和数据库表之间的灵活映射,并支持自动同步
|
||||
* 事务支持
|
||||
|
||||
* 同时支持原始SQL语句和ORM操作的混合执行
|
||||
|
||||
* 使用连写来简化调用
|
||||
|
||||
* 支持使用Id, In, Where, Limit, Join, Having, Table, Sql, Cols等函数和结构体等方式作为条件
|
||||
|
||||
* 支持使用ID, In, Where, Limit, Join, Having, Table, SQL, Cols等函数和结构体等方式作为条件
|
||||
* 支持级联加载Struct
|
||||
|
||||
* Schema支持(仅Postgres)
|
||||
|
||||
* 支持缓存
|
||||
|
||||
* 支持根据数据库自动生成xorm的结构体
|
||||
|
||||
* 通过 [xorm.io/reverse](https://xorm.io/reverse) 支持根据数据库自动生成 xorm 结构体
|
||||
* 支持记录版本(即乐观锁)
|
||||
|
||||
* 内置SQL Builder支持
|
||||
|
||||
* 通过 [xorm.io/builder](https://xorm.io/builder) 内置 SQL Builder 支持
|
||||
* 上下文缓存支持
|
||||
* 支持日志上下文
|
||||
|
||||
## 驱动支持
|
||||
|
||||
目前支持的Go数据库驱动和对应的数据库如下:
|
||||
|
||||
* Mysql: [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql)
|
||||
* [Mysql5.*](https://github.com/mysql/mysql-server/tree/5.7) / [Mysql8.*](https://github.com/mysql/mysql-server) / [Mariadb](https://github.com/MariaDB/server) / [Tidb](https://github.com/pingcap/tidb)
|
||||
- [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql)
|
||||
- [github.com/ziutek/mymysql/godrv](https://github.com/ziutek/mymysql/godrv)
|
||||
|
||||
* MyMysql: [github.com/ziutek/mymysql/godrv](https://github.com/ziutek/mymysql/godrv)
|
||||
* [Postgres](https://github.com/postgres/postgres) / [Cockroach](https://github.com/cockroachdb/cockroach)
|
||||
- [github.com/lib/pq](https://github.com/lib/pq)
|
||||
|
||||
* Postgres: [github.com/lib/pq](https://github.com/lib/pq)
|
||||
* [SQLite](https://sqlite.org)
|
||||
- [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3)
|
||||
|
||||
* Tidb: [github.com/pingcap/tidb](https://github.com/pingcap/tidb)
|
||||
* MsSql
|
||||
- [github.com/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb)
|
||||
|
||||
* SQLite: [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3)
|
||||
|
||||
* MsSql: [github.com/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb)
|
||||
|
||||
* MsSql: [github.com/lunny/godbc](https://github.com/lunny/godbc)
|
||||
|
||||
* Oracle: [github.com/mattn/go-oci8](https://github.com/mattn/go-oci8) (试验性支持)
|
||||
* Oracle
|
||||
- [github.com/mattn/go-oci8](https://github.com/mattn/go-oci8) (试验性支持)
|
||||
|
||||
## 安装
|
||||
|
||||
|
|
@ -62,7 +58,7 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作
|
|||
|
||||
* [操作指南](http://xorm.io/docs)
|
||||
|
||||
* [Godoc代码文档](http://godoc.org/xorm.io/xorm)
|
||||
* [Godoc代码文档](http://pkg.go.dev/xorm.io/xorm)
|
||||
|
||||
# 快速开始
|
||||
|
||||
|
|
@ -435,14 +431,14 @@ res, err := engine.Transaction(func(session *xorm.Session) (interface{}, error)
|
|||
|
||||
# 案例
|
||||
|
||||
* [Go语言中文网](http://studygolang.com/) - [github.com/studygolang/studygolang](https://github.com/studygolang/studygolang)
|
||||
|
||||
* [Gitea](http://gitea.io) - [github.com/go-gitea/gitea](http://github.com/go-gitea/gitea)
|
||||
|
||||
* [Gogs](http://try.gogits.org) - [github.com/gogits/gogs](http://github.com/gogits/gogs)
|
||||
|
||||
* [grafana](https://grafana.com/) - [github.com/grafana/grafana](http://github.com/grafana/grafana)
|
||||
|
||||
* [Go语言中文网](http://studygolang.com/) - [github.com/studygolang/studygolang](https://github.com/studygolang/studygolang)
|
||||
|
||||
* [github.com/m3ng9i/qreader](https://github.com/m3ng9i/qreader)
|
||||
|
||||
* [Wego](http://github.com/go-tango/wego)
|
||||
|
|
@ -470,27 +466,7 @@ res, err := engine.Transaction(func(session *xorm.Session) (interface{}, error)
|
|||
|
||||
## 更新日志
|
||||
|
||||
* **v0.7.0**
|
||||
* 修正部分Bug
|
||||
|
||||
* **v0.6.6**
|
||||
* 修正部分Bug
|
||||
|
||||
* **v0.6.5**
|
||||
* 通过 engine.SetSchema 来支持 schema,当前仅支持Postgres
|
||||
* vgo 支持
|
||||
* 新增 `FindAndCount` 函数
|
||||
* 通过 `NewEngineWithParams` 支持数据库特别参数
|
||||
* 修正部分Bug
|
||||
|
||||
* **v0.6.4**
|
||||
* 自动读写分离支持
|
||||
* Query/QueryString/QueryInterface 支持与 Where/And 合用
|
||||
* `Get` 支持获取非结构体变量
|
||||
* `Iterate` 支持 `BufferSize`
|
||||
* 修正部分Bug
|
||||
|
||||
[更多更新日志...](https://github.com/go-xorm/manual-zh-CN/tree/master/chapter-16)
|
||||
请访问 [CHANGELOG.md](CHANGELOG.md) 获得更新日志。
|
||||
|
||||
## LICENSE
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,99 @@
|
|||
// Copyright 2019 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package caches
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm/schemas"
|
||||
)
|
||||
|
||||
const (
|
||||
// CacheExpired is default cache expired time
|
||||
CacheExpired = 60 * time.Minute
|
||||
// CacheMaxMemory is not use now
|
||||
CacheMaxMemory = 256
|
||||
// CacheGcInterval represents interval time to clear all expired nodes
|
||||
CacheGcInterval = 10 * time.Minute
|
||||
// CacheGcMaxRemoved represents max nodes removed when gc
|
||||
CacheGcMaxRemoved = 20
|
||||
)
|
||||
|
||||
// list all the errors
|
||||
var (
|
||||
ErrCacheMiss = errors.New("xorm/cache: key not found")
|
||||
ErrNotStored = errors.New("xorm/cache: not stored")
|
||||
// ErrNotExist record does not exist error
|
||||
ErrNotExist = errors.New("Record does not exist")
|
||||
)
|
||||
|
||||
// CacheStore is a interface to store cache
|
||||
type CacheStore interface {
|
||||
// key is primary key or composite primary key
|
||||
// value is struct's pointer
|
||||
// key format : <tablename>-p-<pk1>-<pk2>...
|
||||
Put(key string, value interface{}) error
|
||||
Get(key string) (interface{}, error)
|
||||
Del(key string) error
|
||||
}
|
||||
|
||||
// Cacher is an interface to provide cache
|
||||
// id format : u-<pk1>-<pk2>...
|
||||
type Cacher interface {
|
||||
GetIds(tableName, sql string) interface{}
|
||||
GetBean(tableName string, id string) interface{}
|
||||
PutIds(tableName, sql string, ids interface{})
|
||||
PutBean(tableName string, id string, obj interface{})
|
||||
DelIds(tableName, sql string)
|
||||
DelBean(tableName string, id string)
|
||||
ClearIds(tableName string)
|
||||
ClearBeans(tableName string)
|
||||
}
|
||||
|
||||
func encodeIds(ids []schemas.PK) (string, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
enc := gob.NewEncoder(buf)
|
||||
err := enc.Encode(ids)
|
||||
|
||||
return buf.String(), err
|
||||
}
|
||||
|
||||
func decodeIds(s string) ([]schemas.PK, error) {
|
||||
pks := make([]schemas.PK, 0)
|
||||
|
||||
dec := gob.NewDecoder(strings.NewReader(s))
|
||||
err := dec.Decode(&pks)
|
||||
|
||||
return pks, err
|
||||
}
|
||||
|
||||
// GetCacheSql returns cacher PKs via SQL
|
||||
func GetCacheSql(m Cacher, tableName, sql string, args interface{}) ([]schemas.PK, error) {
|
||||
bytes := m.GetIds(tableName, GenSqlKey(sql, args))
|
||||
if bytes == nil {
|
||||
return nil, errors.New("Not Exist")
|
||||
}
|
||||
return decodeIds(bytes.(string))
|
||||
}
|
||||
|
||||
// PutCacheSql puts cacher SQL and PKs
|
||||
func PutCacheSql(m Cacher, ids []schemas.PK, tableName, sql string, args interface{}) error {
|
||||
bytes, err := encodeIds(ids)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.PutIds(tableName, GenSqlKey(sql, args), bytes)
|
||||
return nil
|
||||
}
|
||||
|
||||
// GenSqlKey generates cache key
|
||||
func GenSqlKey(sql string, args interface{}) string {
|
||||
return fmt.Sprintf("%v-%v", sql, args)
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
// Copyright 2020 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package caches
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/md5"
|
||||
"encoding/gob"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// md5 hash string
|
||||
func Md5(str string) string {
|
||||
m := md5.New()
|
||||
io.WriteString(m, str)
|
||||
return fmt.Sprintf("%x", m.Sum(nil))
|
||||
}
|
||||
func Encode(data interface{}) ([]byte, error) {
|
||||
//return JsonEncode(data)
|
||||
return GobEncode(data)
|
||||
}
|
||||
|
||||
func Decode(data []byte, to interface{}) error {
|
||||
//return JsonDecode(data, to)
|
||||
return GobDecode(data, to)
|
||||
}
|
||||
|
||||
func GobEncode(data interface{}) ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
enc := gob.NewEncoder(&buf)
|
||||
err := enc.Encode(&data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func GobDecode(data []byte, to interface{}) error {
|
||||
buf := bytes.NewBuffer(data)
|
||||
dec := gob.NewDecoder(buf)
|
||||
return dec.Decode(to)
|
||||
}
|
||||
|
||||
func JsonEncode(data interface{}) ([]byte, error) {
|
||||
val, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return val, nil
|
||||
}
|
||||
|
||||
func JsonDecode(data []byte, to interface{}) error {
|
||||
return json.Unmarshal(data, to)
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
// Copyright 2020 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package caches
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/syndtr/goleveldb/leveldb"
|
||||
)
|
||||
|
||||
// LevelDBStore implements CacheStore provide local machine
|
||||
type LevelDBStore struct {
|
||||
store *leveldb.DB
|
||||
Debug bool
|
||||
v interface{}
|
||||
}
|
||||
|
||||
var _ CacheStore = &LevelDBStore{}
|
||||
|
||||
func NewLevelDBStore(dbfile string) (*LevelDBStore, error) {
|
||||
db := &LevelDBStore{}
|
||||
h, err := leveldb.OpenFile(dbfile, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
db.store = h
|
||||
return db, nil
|
||||
}
|
||||
|
||||
func (s *LevelDBStore) Put(key string, value interface{}) error {
|
||||
val, err := Encode(value)
|
||||
if err != nil {
|
||||
if s.Debug {
|
||||
log.Println("[LevelDB]EncodeErr: ", err, "Key:", key)
|
||||
}
|
||||
return err
|
||||
}
|
||||
err = s.store.Put([]byte(key), val, nil)
|
||||
if err != nil {
|
||||
if s.Debug {
|
||||
log.Println("[LevelDB]PutErr: ", err, "Key:", key)
|
||||
}
|
||||
return err
|
||||
}
|
||||
if s.Debug {
|
||||
log.Println("[LevelDB]Put: ", key)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *LevelDBStore) Get(key string) (interface{}, error) {
|
||||
data, err := s.store.Get([]byte(key), nil)
|
||||
if err != nil {
|
||||
if s.Debug {
|
||||
log.Println("[LevelDB]GetErr: ", err, "Key:", key)
|
||||
}
|
||||
if err == leveldb.ErrNotFound {
|
||||
return nil, ErrNotExist
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = Decode(data, &s.v)
|
||||
if err != nil {
|
||||
if s.Debug {
|
||||
log.Println("[LevelDB]DecodeErr: ", err, "Key:", key)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if s.Debug {
|
||||
log.Println("[LevelDB]Get: ", key, s.v)
|
||||
}
|
||||
return s.v, err
|
||||
}
|
||||
|
||||
func (s *LevelDBStore) Del(key string) error {
|
||||
err := s.store.Delete([]byte(key), nil)
|
||||
if err != nil {
|
||||
if s.Debug {
|
||||
log.Println("[LevelDB]DelErr: ", err, "Key:", key)
|
||||
}
|
||||
return err
|
||||
}
|
||||
if s.Debug {
|
||||
log.Println("[LevelDB]Del: ", key)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *LevelDBStore) Close() {
|
||||
s.store.Close()
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
// Copyright 2020 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package caches
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestLevelDBStore(t *testing.T) {
|
||||
store, err := NewLevelDBStore("./level.db")
|
||||
assert.NoError(t, err)
|
||||
|
||||
var kvs = map[string]interface{}{
|
||||
"a": "b",
|
||||
}
|
||||
for k, v := range kvs {
|
||||
assert.NoError(t, store.Put(k, v))
|
||||
}
|
||||
|
||||
for k, v := range kvs {
|
||||
val, err := store.Get(k)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, v, val)
|
||||
}
|
||||
|
||||
for k := range kvs {
|
||||
err := store.Del(k)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
for k := range kvs {
|
||||
_, err := store.Get(k)
|
||||
assert.EqualValues(t, ErrNotExist, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -2,15 +2,13 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
package caches
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
// LRUCacher implments cache object facilities
|
||||
|
|
@ -19,7 +17,7 @@ type LRUCacher struct {
|
|||
sqlList *list.List
|
||||
idIndex map[string]map[string]*list.Element
|
||||
sqlIndex map[string]map[string]*list.Element
|
||||
store core.CacheStore
|
||||
store CacheStore
|
||||
mutex sync.Mutex
|
||||
MaxElementSize int
|
||||
Expired time.Duration
|
||||
|
|
@ -27,15 +25,15 @@ type LRUCacher struct {
|
|||
}
|
||||
|
||||
// NewLRUCacher creates a cacher
|
||||
func NewLRUCacher(store core.CacheStore, maxElementSize int) *LRUCacher {
|
||||
func NewLRUCacher(store CacheStore, maxElementSize int) *LRUCacher {
|
||||
return NewLRUCacher2(store, 3600*time.Second, maxElementSize)
|
||||
}
|
||||
|
||||
// NewLRUCacher2 creates a cache include different params
|
||||
func NewLRUCacher2(store core.CacheStore, expired time.Duration, maxElementSize int) *LRUCacher {
|
||||
func NewLRUCacher2(store CacheStore, expired time.Duration, maxElementSize int) *LRUCacher {
|
||||
cacher := &LRUCacher{store: store, idList: list.New(),
|
||||
sqlList: list.New(), Expired: expired,
|
||||
GcInterval: core.CacheGcInterval, MaxElementSize: maxElementSize,
|
||||
GcInterval: CacheGcInterval, MaxElementSize: maxElementSize,
|
||||
sqlIndex: make(map[string]map[string]*list.Element),
|
||||
idIndex: make(map[string]map[string]*list.Element),
|
||||
}
|
||||
|
|
@ -57,7 +55,7 @@ func (m *LRUCacher) GC() {
|
|||
defer m.mutex.Unlock()
|
||||
var removedNum int
|
||||
for e := m.idList.Front(); e != nil; {
|
||||
if removedNum <= core.CacheGcMaxRemoved &&
|
||||
if removedNum <= CacheGcMaxRemoved &&
|
||||
time.Now().Sub(e.Value.(*idNode).lastVisit) > m.Expired {
|
||||
removedNum++
|
||||
next := e.Next()
|
||||
|
|
@ -71,7 +69,7 @@ func (m *LRUCacher) GC() {
|
|||
|
||||
removedNum = 0
|
||||
for e := m.sqlList.Front(); e != nil; {
|
||||
if removedNum <= core.CacheGcMaxRemoved &&
|
||||
if removedNum <= CacheGcMaxRemoved &&
|
||||
time.Now().Sub(e.Value.(*sqlNode).lastVisit) > m.Expired {
|
||||
removedNum++
|
||||
next := e.Next()
|
||||
|
|
@ -268,11 +266,11 @@ type sqlNode struct {
|
|||
}
|
||||
|
||||
func genSQLKey(sql string, args interface{}) string {
|
||||
return fmt.Sprintf("%v-%v", sql, args)
|
||||
return fmt.Sprintf("%s-%v", sql, args)
|
||||
}
|
||||
|
||||
func genID(prefix string, id string) string {
|
||||
return fmt.Sprintf("%v-%v", prefix, id)
|
||||
return fmt.Sprintf("%s-%s", prefix, id)
|
||||
}
|
||||
|
||||
func newIDNode(tbName string, id string) *idNode {
|
||||
|
|
@ -2,13 +2,13 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
package caches
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"xorm.io/core"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"xorm.io/xorm/schemas"
|
||||
)
|
||||
|
||||
func TestLRUCache(t *testing.T) {
|
||||
|
|
@ -20,7 +20,7 @@ func TestLRUCache(t *testing.T) {
|
|||
cacher := NewLRUCacher(store, 10000)
|
||||
|
||||
tableName := "cache_object1"
|
||||
pks := []core.PK{
|
||||
pks := []schemas.PK{
|
||||
{1},
|
||||
{2},
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
// Copyright 2020 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package caches
|
||||
|
||||
import "sync"
|
||||
|
||||
type Manager struct {
|
||||
cacher Cacher
|
||||
disableGlobalCache bool
|
||||
|
||||
cachers map[string]Cacher
|
||||
cacherLock sync.RWMutex
|
||||
}
|
||||
|
||||
func NewManager() *Manager {
|
||||
return &Manager{
|
||||
cachers: make(map[string]Cacher),
|
||||
}
|
||||
}
|
||||
|
||||
// SetDisableGlobalCache disable global cache or not
|
||||
func (mgr *Manager) SetDisableGlobalCache(disable bool) {
|
||||
if mgr.disableGlobalCache != disable {
|
||||
mgr.disableGlobalCache = disable
|
||||
}
|
||||
}
|
||||
|
||||
func (mgr *Manager) SetCacher(tableName string, cacher Cacher) {
|
||||
mgr.cacherLock.Lock()
|
||||
mgr.cachers[tableName] = cacher
|
||||
mgr.cacherLock.Unlock()
|
||||
}
|
||||
|
||||
func (mgr *Manager) GetCacher(tableName string) Cacher {
|
||||
var cacher Cacher
|
||||
var ok bool
|
||||
mgr.cacherLock.RLock()
|
||||
cacher, ok = mgr.cachers[tableName]
|
||||
mgr.cacherLock.RUnlock()
|
||||
if !ok && !mgr.disableGlobalCache {
|
||||
cacher = mgr.cacher
|
||||
}
|
||||
return cacher
|
||||
}
|
||||
|
||||
// SetDefaultCacher set the default cacher. Xorm's default not enable cacher.
|
||||
func (mgr *Manager) SetDefaultCacher(cacher Cacher) {
|
||||
mgr.cacher = cacher
|
||||
}
|
||||
|
||||
// GetDefaultCacher returns the default cacher
|
||||
func (mgr *Manager) GetDefaultCacher() Cacher {
|
||||
return mgr.cacher
|
||||
}
|
||||
|
|
@ -2,15 +2,13 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
package caches
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
var _ core.CacheStore = NewMemoryStore()
|
||||
var _ CacheStore = NewMemoryStore()
|
||||
|
||||
// MemoryStore represents in-memory store
|
||||
type MemoryStore struct {
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
package caches
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
|
@ -25,12 +25,12 @@ func TestMemoryStore(t *testing.T) {
|
|||
assert.EqualValues(t, v, val)
|
||||
}
|
||||
|
||||
for k, _ := range kvs {
|
||||
for k := range kvs {
|
||||
err := store.Del(k)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
for k, _ := range kvs {
|
||||
for k := range kvs {
|
||||
_, err := store.Get(k)
|
||||
assert.EqualValues(t, ErrNotExist, err)
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
package contexts
|
||||
|
||||
// ContextCache is the interface that operates the cache data.
|
||||
type ContextCache interface {
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
// Copyright 2020 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package contexts
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ContextHook represents a hook context
|
||||
type ContextHook struct {
|
||||
start time.Time
|
||||
Ctx context.Context
|
||||
SQL string // log content or SQL
|
||||
Args []interface{} // if it's a SQL, it's the arguments
|
||||
Result sql.Result
|
||||
ExecuteTime time.Duration
|
||||
Err error // SQL executed error
|
||||
}
|
||||
|
||||
// NewContextHook return context for hook
|
||||
func NewContextHook(ctx context.Context, sql string, args []interface{}) *ContextHook {
|
||||
return &ContextHook{
|
||||
start: time.Now(),
|
||||
Ctx: ctx,
|
||||
SQL: sql,
|
||||
Args: args,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ContextHook) End(ctx context.Context, result sql.Result, err error) {
|
||||
c.Ctx = ctx
|
||||
c.Result = result
|
||||
c.Err = err
|
||||
c.ExecuteTime = time.Now().Sub(c.start)
|
||||
}
|
||||
|
||||
type Hook interface {
|
||||
BeforeProcess(c *ContextHook) (context.Context, error)
|
||||
AfterProcess(c *ContextHook) error
|
||||
}
|
||||
|
||||
type Hooks struct {
|
||||
hooks []Hook
|
||||
}
|
||||
|
||||
func (h *Hooks) AddHook(hooks ...Hook) {
|
||||
h.hooks = append(h.hooks, hooks...)
|
||||
}
|
||||
|
||||
func (h *Hooks) BeforeProcess(c *ContextHook) (context.Context, error) {
|
||||
ctx := c.Ctx
|
||||
for _, h := range h.hooks {
|
||||
var err error
|
||||
ctx, err = h.BeforeProcess(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
func (h *Hooks) AfterProcess(c *ContextHook) error {
|
||||
firstErr := c.Err
|
||||
for _, h := range h.hooks {
|
||||
err := h.AfterProcess(c)
|
||||
if err != nil && firstErr == nil {
|
||||
firstErr = err
|
||||
}
|
||||
}
|
||||
return firstErr
|
||||
}
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
package contexts
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type testHook struct {
|
||||
before func(c *ContextHook) (context.Context, error)
|
||||
after func(c *ContextHook) error
|
||||
}
|
||||
|
||||
func (h *testHook) BeforeProcess(c *ContextHook) (context.Context, error) {
|
||||
if h.before != nil {
|
||||
return h.before(c)
|
||||
}
|
||||
return c.Ctx, nil
|
||||
}
|
||||
|
||||
func (h *testHook) AfterProcess(c *ContextHook) error {
|
||||
if h.after != nil {
|
||||
return h.after(c)
|
||||
}
|
||||
return c.Err
|
||||
}
|
||||
|
||||
var _ Hook = &testHook{}
|
||||
|
||||
func TestBeforeProcess(t *testing.T) {
|
||||
expectErr := errors.New("before error")
|
||||
tests := []struct {
|
||||
msg string
|
||||
hooks []Hook
|
||||
expect error
|
||||
}{
|
||||
{
|
||||
msg: "first hook return err",
|
||||
hooks: []Hook{
|
||||
&testHook{
|
||||
before: func(c *ContextHook) (ctx context.Context, err error) {
|
||||
return c.Ctx, expectErr
|
||||
},
|
||||
},
|
||||
&testHook{
|
||||
before: func(c *ContextHook) (ctx context.Context, err error) {
|
||||
return c.Ctx, nil
|
||||
},
|
||||
},
|
||||
},
|
||||
expect: expectErr,
|
||||
},
|
||||
{
|
||||
msg: "second hook return err",
|
||||
hooks: []Hook{
|
||||
&testHook{
|
||||
before: func(c *ContextHook) (ctx context.Context, err error) {
|
||||
return c.Ctx, nil
|
||||
},
|
||||
},
|
||||
&testHook{
|
||||
before: func(c *ContextHook) (ctx context.Context, err error) {
|
||||
return c.Ctx, expectErr
|
||||
},
|
||||
},
|
||||
},
|
||||
expect: expectErr,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.msg, func(t *testing.T) {
|
||||
hooks := Hooks{}
|
||||
hooks.AddHook(tt.hooks...)
|
||||
_, err := hooks.BeforeProcess(&ContextHook{
|
||||
Ctx: context.Background(),
|
||||
})
|
||||
if err != tt.expect {
|
||||
t.Errorf("got %v, expect %v", err, tt.expect)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAfterProcess(t *testing.T) {
|
||||
expectErr := errors.New("expect err")
|
||||
tests := []struct {
|
||||
msg string
|
||||
ctx *ContextHook
|
||||
hooks []Hook
|
||||
expect error
|
||||
}{
|
||||
{
|
||||
msg: "context has err",
|
||||
ctx: &ContextHook{
|
||||
Ctx: context.Background(),
|
||||
Err: expectErr,
|
||||
},
|
||||
hooks: []Hook{
|
||||
&testHook{
|
||||
after: func(c *ContextHook) error {
|
||||
return errors.New("hook err")
|
||||
},
|
||||
},
|
||||
},
|
||||
expect: expectErr,
|
||||
},
|
||||
{
|
||||
msg: "last hook has err",
|
||||
ctx: &ContextHook{
|
||||
Ctx: context.Background(),
|
||||
Err: nil,
|
||||
},
|
||||
hooks: []Hook{
|
||||
&testHook{
|
||||
after: func(c *ContextHook) error {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
&testHook{
|
||||
after: func(c *ContextHook) error {
|
||||
return expectErr
|
||||
},
|
||||
},
|
||||
},
|
||||
expect: expectErr,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.msg, func(t *testing.T) {
|
||||
hooks := Hooks{}
|
||||
hooks.AddHook(tt.hooks...)
|
||||
err := hooks.AfterProcess(tt.ctx)
|
||||
if err != tt.expect {
|
||||
t.Errorf("got %v, expect %v", err, tt.expect)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
182
convert.go
182
convert.go
|
|
@ -25,11 +25,10 @@ func strconvErr(err error) error {
|
|||
func cloneBytes(b []byte) []byte {
|
||||
if b == nil {
|
||||
return nil
|
||||
} else {
|
||||
c := make([]byte, len(b))
|
||||
copy(c, b)
|
||||
return c
|
||||
}
|
||||
c := make([]byte, len(b))
|
||||
copy(c, b)
|
||||
return c
|
||||
}
|
||||
|
||||
func asString(src interface{}) string {
|
||||
|
|
@ -285,56 +284,6 @@ func asKind(vv reflect.Value, tp reflect.Type) (interface{}, error) {
|
|||
return nil, fmt.Errorf("unsupported primary key type: %v, %v", tp, vv)
|
||||
}
|
||||
|
||||
func convertFloat(v interface{}) (float64, error) {
|
||||
switch v.(type) {
|
||||
case float32:
|
||||
return float64(v.(float32)), nil
|
||||
case float64:
|
||||
return v.(float64), nil
|
||||
case string:
|
||||
i, err := strconv.ParseFloat(v.(string), 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return i, nil
|
||||
case []byte:
|
||||
i, err := strconv.ParseFloat(string(v.([]byte)), 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
return 0, fmt.Errorf("unsupported type: %v", v)
|
||||
}
|
||||
|
||||
func convertInt(v interface{}) (int64, error) {
|
||||
switch v.(type) {
|
||||
case int:
|
||||
return int64(v.(int)), nil
|
||||
case int8:
|
||||
return int64(v.(int8)), nil
|
||||
case int16:
|
||||
return int64(v.(int16)), nil
|
||||
case int32:
|
||||
return int64(v.(int32)), nil
|
||||
case int64:
|
||||
return v.(int64), nil
|
||||
case []byte:
|
||||
i, err := strconv.ParseInt(string(v.([]byte)), 10, 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return i, nil
|
||||
case string:
|
||||
i, err := strconv.ParseInt(v.(string), 10, 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
return 0, fmt.Errorf("unsupported type: %v", v)
|
||||
}
|
||||
|
||||
func asBool(bs []byte) (bool, error) {
|
||||
if len(bs) == 0 {
|
||||
return false, nil
|
||||
|
|
@ -346,3 +295,128 @@ func asBool(bs []byte) (bool, error) {
|
|||
}
|
||||
return strconv.ParseBool(string(bs))
|
||||
}
|
||||
|
||||
// str2PK convert string value to primary key value according to tp
|
||||
func str2PKValue(s string, tp reflect.Type) (reflect.Value, error) {
|
||||
var err error
|
||||
var result interface{}
|
||||
var defReturn = reflect.Zero(tp)
|
||||
|
||||
switch tp.Kind() {
|
||||
case reflect.Int:
|
||||
result, err = strconv.Atoi(s)
|
||||
if err != nil {
|
||||
return defReturn, fmt.Errorf("convert %s as int: %s", s, err.Error())
|
||||
}
|
||||
case reflect.Int8:
|
||||
x, err := strconv.Atoi(s)
|
||||
if err != nil {
|
||||
return defReturn, fmt.Errorf("convert %s as int8: %s", s, err.Error())
|
||||
}
|
||||
result = int8(x)
|
||||
case reflect.Int16:
|
||||
x, err := strconv.Atoi(s)
|
||||
if err != nil {
|
||||
return defReturn, fmt.Errorf("convert %s as int16: %s", s, err.Error())
|
||||
}
|
||||
result = int16(x)
|
||||
case reflect.Int32:
|
||||
x, err := strconv.Atoi(s)
|
||||
if err != nil {
|
||||
return defReturn, fmt.Errorf("convert %s as int32: %s", s, err.Error())
|
||||
}
|
||||
result = int32(x)
|
||||
case reflect.Int64:
|
||||
result, err = strconv.ParseInt(s, 10, 64)
|
||||
if err != nil {
|
||||
return defReturn, fmt.Errorf("convert %s as int64: %s", s, err.Error())
|
||||
}
|
||||
case reflect.Uint:
|
||||
x, err := strconv.ParseUint(s, 10, 64)
|
||||
if err != nil {
|
||||
return defReturn, fmt.Errorf("convert %s as uint: %s", s, err.Error())
|
||||
}
|
||||
result = uint(x)
|
||||
case reflect.Uint8:
|
||||
x, err := strconv.ParseUint(s, 10, 64)
|
||||
if err != nil {
|
||||
return defReturn, fmt.Errorf("convert %s as uint8: %s", s, err.Error())
|
||||
}
|
||||
result = uint8(x)
|
||||
case reflect.Uint16:
|
||||
x, err := strconv.ParseUint(s, 10, 64)
|
||||
if err != nil {
|
||||
return defReturn, fmt.Errorf("convert %s as uint16: %s", s, err.Error())
|
||||
}
|
||||
result = uint16(x)
|
||||
case reflect.Uint32:
|
||||
x, err := strconv.ParseUint(s, 10, 64)
|
||||
if err != nil {
|
||||
return defReturn, fmt.Errorf("convert %s as uint32: %s", s, err.Error())
|
||||
}
|
||||
result = uint32(x)
|
||||
case reflect.Uint64:
|
||||
result, err = strconv.ParseUint(s, 10, 64)
|
||||
if err != nil {
|
||||
return defReturn, fmt.Errorf("convert %s as uint64: %s", s, err.Error())
|
||||
}
|
||||
case reflect.String:
|
||||
result = s
|
||||
default:
|
||||
return defReturn, errors.New("unsupported convert type")
|
||||
}
|
||||
return reflect.ValueOf(result).Convert(tp), nil
|
||||
}
|
||||
|
||||
func str2PK(s string, tp reflect.Type) (interface{}, error) {
|
||||
v, err := str2PKValue(s, tp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return v.Interface(), nil
|
||||
}
|
||||
|
||||
func int64ToIntValue(id int64, tp reflect.Type) reflect.Value {
|
||||
var v interface{}
|
||||
kind := tp.Kind()
|
||||
|
||||
if kind == reflect.Ptr {
|
||||
kind = tp.Elem().Kind()
|
||||
}
|
||||
|
||||
switch kind {
|
||||
case reflect.Int16:
|
||||
temp := int16(id)
|
||||
v = &temp
|
||||
case reflect.Int32:
|
||||
temp := int32(id)
|
||||
v = &temp
|
||||
case reflect.Int:
|
||||
temp := int(id)
|
||||
v = &temp
|
||||
case reflect.Int64:
|
||||
temp := id
|
||||
v = &temp
|
||||
case reflect.Uint16:
|
||||
temp := uint16(id)
|
||||
v = &temp
|
||||
case reflect.Uint32:
|
||||
temp := uint32(id)
|
||||
v = &temp
|
||||
case reflect.Uint64:
|
||||
temp := uint64(id)
|
||||
v = &temp
|
||||
case reflect.Uint:
|
||||
temp := uint(id)
|
||||
v = &temp
|
||||
}
|
||||
|
||||
if tp.Kind() == reflect.Ptr {
|
||||
return reflect.ValueOf(v).Convert(tp)
|
||||
}
|
||||
return reflect.ValueOf(v).Elem().Convert(tp)
|
||||
}
|
||||
|
||||
func int64ToInt(id int64, tp reflect.Type) interface{} {
|
||||
return int64ToIntValue(id, tp).Interface()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
// Copyright 2017 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package convert
|
||||
|
||||
// Conversion is an interface. A type implements Conversion will according
|
||||
// the custom method to fill into database and retrieve from database.
|
||||
type Conversion interface {
|
||||
FromDB([]byte) error
|
||||
ToDB() ([]byte, error)
|
||||
}
|
||||
|
|
@ -0,0 +1,293 @@
|
|||
// Copyright 2019 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"sync"
|
||||
|
||||
"xorm.io/xorm/contexts"
|
||||
"xorm.io/xorm/log"
|
||||
"xorm.io/xorm/names"
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultCacheSize sets the default cache size
|
||||
DefaultCacheSize = 200
|
||||
)
|
||||
|
||||
func MapToSlice(query string, mp interface{}) (string, []interface{}, error) {
|
||||
vv := reflect.ValueOf(mp)
|
||||
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map {
|
||||
return "", []interface{}{}, ErrNoMapPointer
|
||||
}
|
||||
|
||||
args := make([]interface{}, 0, len(vv.Elem().MapKeys()))
|
||||
var err error
|
||||
query = re.ReplaceAllStringFunc(query, func(src string) string {
|
||||
v := vv.Elem().MapIndex(reflect.ValueOf(src[1:]))
|
||||
if !v.IsValid() {
|
||||
err = fmt.Errorf("map key %s is missing", src[1:])
|
||||
} else {
|
||||
args = append(args, v.Interface())
|
||||
}
|
||||
return "?"
|
||||
})
|
||||
|
||||
return query, args, err
|
||||
}
|
||||
|
||||
func StructToSlice(query string, st interface{}) (string, []interface{}, error) {
|
||||
vv := reflect.ValueOf(st)
|
||||
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct {
|
||||
return "", []interface{}{}, ErrNoStructPointer
|
||||
}
|
||||
|
||||
args := make([]interface{}, 0)
|
||||
var err error
|
||||
query = re.ReplaceAllStringFunc(query, func(src string) string {
|
||||
fv := vv.Elem().FieldByName(src[1:]).Interface()
|
||||
if v, ok := fv.(driver.Valuer); ok {
|
||||
var value driver.Value
|
||||
value, err = v.Value()
|
||||
if err != nil {
|
||||
return "?"
|
||||
}
|
||||
args = append(args, value)
|
||||
} else {
|
||||
args = append(args, fv)
|
||||
}
|
||||
return "?"
|
||||
})
|
||||
if err != nil {
|
||||
return "", []interface{}{}, err
|
||||
}
|
||||
return query, args, nil
|
||||
}
|
||||
|
||||
type cacheStruct struct {
|
||||
value reflect.Value
|
||||
idx int
|
||||
}
|
||||
|
||||
var (
|
||||
_ QueryExecuter = &DB{}
|
||||
)
|
||||
|
||||
// DB is a wrap of sql.DB with extra contents
|
||||
type DB struct {
|
||||
*sql.DB
|
||||
Mapper names.Mapper
|
||||
reflectCache map[reflect.Type]*cacheStruct
|
||||
reflectCacheMutex sync.RWMutex
|
||||
Logger log.ContextLogger
|
||||
hooks contexts.Hooks
|
||||
}
|
||||
|
||||
// Open opens a database
|
||||
func Open(driverName, dataSourceName string) (*DB, error) {
|
||||
db, err := sql.Open(driverName, dataSourceName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &DB{
|
||||
DB: db,
|
||||
Mapper: names.NewCacheMapper(&names.SnakeMapper{}),
|
||||
reflectCache: make(map[reflect.Type]*cacheStruct),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// FromDB creates a DB from a sql.DB
|
||||
func FromDB(db *sql.DB) *DB {
|
||||
return &DB{
|
||||
DB: db,
|
||||
Mapper: names.NewCacheMapper(&names.SnakeMapper{}),
|
||||
reflectCache: make(map[reflect.Type]*cacheStruct),
|
||||
}
|
||||
}
|
||||
|
||||
// NeedLogSQL returns true if need to log SQL
|
||||
func (db *DB) NeedLogSQL(ctx context.Context) bool {
|
||||
if db.Logger == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
v := ctx.Value(log.SessionShowSQLKey)
|
||||
if showSQL, ok := v.(bool); ok {
|
||||
return showSQL
|
||||
}
|
||||
return db.Logger.IsShowSQL()
|
||||
}
|
||||
|
||||
func (db *DB) reflectNew(typ reflect.Type) reflect.Value {
|
||||
db.reflectCacheMutex.Lock()
|
||||
defer db.reflectCacheMutex.Unlock()
|
||||
cs, ok := db.reflectCache[typ]
|
||||
if !ok || cs.idx+1 > DefaultCacheSize-1 {
|
||||
cs = &cacheStruct{reflect.MakeSlice(reflect.SliceOf(typ), DefaultCacheSize, DefaultCacheSize), 0}
|
||||
db.reflectCache[typ] = cs
|
||||
} else {
|
||||
cs.idx = cs.idx + 1
|
||||
}
|
||||
return cs.value.Index(cs.idx).Addr()
|
||||
}
|
||||
|
||||
// QueryContext overwrites sql.DB.QueryContext
|
||||
func (db *DB) QueryContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) {
|
||||
hookCtx := contexts.NewContextHook(ctx, query, args)
|
||||
ctx, err := db.beforeProcess(hookCtx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rows, err := db.DB.QueryContext(ctx, query, args...)
|
||||
hookCtx.End(ctx, nil, err)
|
||||
if err := db.afterProcess(hookCtx); err != nil {
|
||||
if rows != nil {
|
||||
rows.Close()
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &Rows{rows, db}, nil
|
||||
}
|
||||
|
||||
// Query overwrites sql.DB.Query
|
||||
func (db *DB) Query(query string, args ...interface{}) (*Rows, error) {
|
||||
return db.QueryContext(context.Background(), query, args...)
|
||||
}
|
||||
|
||||
// QueryMapContext executes query with parameters via map and context
|
||||
func (db *DB) QueryMapContext(ctx context.Context, query string, mp interface{}) (*Rows, error) {
|
||||
query, args, err := MapToSlice(query, mp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return db.QueryContext(ctx, query, args...)
|
||||
}
|
||||
|
||||
// QueryMap executes query with parameters via map
|
||||
func (db *DB) QueryMap(query string, mp interface{}) (*Rows, error) {
|
||||
return db.QueryMapContext(context.Background(), query, mp)
|
||||
}
|
||||
|
||||
func (db *DB) QueryStructContext(ctx context.Context, query string, st interface{}) (*Rows, error) {
|
||||
query, args, err := StructToSlice(query, st)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return db.QueryContext(ctx, query, args...)
|
||||
}
|
||||
|
||||
func (db *DB) QueryStruct(query string, st interface{}) (*Rows, error) {
|
||||
return db.QueryStructContext(context.Background(), query, st)
|
||||
}
|
||||
|
||||
func (db *DB) QueryRowContext(ctx context.Context, query string, args ...interface{}) *Row {
|
||||
rows, err := db.QueryContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
return &Row{nil, err}
|
||||
}
|
||||
return &Row{rows, nil}
|
||||
}
|
||||
|
||||
func (db *DB) QueryRow(query string, args ...interface{}) *Row {
|
||||
return db.QueryRowContext(context.Background(), query, args...)
|
||||
}
|
||||
|
||||
func (db *DB) QueryRowMapContext(ctx context.Context, query string, mp interface{}) *Row {
|
||||
query, args, err := MapToSlice(query, mp)
|
||||
if err != nil {
|
||||
return &Row{nil, err}
|
||||
}
|
||||
return db.QueryRowContext(ctx, query, args...)
|
||||
}
|
||||
|
||||
func (db *DB) QueryRowMap(query string, mp interface{}) *Row {
|
||||
return db.QueryRowMapContext(context.Background(), query, mp)
|
||||
}
|
||||
|
||||
func (db *DB) QueryRowStructContext(ctx context.Context, query string, st interface{}) *Row {
|
||||
query, args, err := StructToSlice(query, st)
|
||||
if err != nil {
|
||||
return &Row{nil, err}
|
||||
}
|
||||
return db.QueryRowContext(ctx, query, args...)
|
||||
}
|
||||
|
||||
func (db *DB) QueryRowStruct(query string, st interface{}) *Row {
|
||||
return db.QueryRowStructContext(context.Background(), query, st)
|
||||
}
|
||||
|
||||
var (
|
||||
re = regexp.MustCompile(`[?](\w+)`)
|
||||
)
|
||||
|
||||
// ExecMapContext exec map with context.ContextHook
|
||||
// insert into (name) values (?)
|
||||
// insert into (name) values (?name)
|
||||
func (db *DB) ExecMapContext(ctx context.Context, query string, mp interface{}) (sql.Result, error) {
|
||||
query, args, err := MapToSlice(query, mp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return db.ExecContext(ctx, query, args...)
|
||||
}
|
||||
|
||||
func (db *DB) ExecMap(query string, mp interface{}) (sql.Result, error) {
|
||||
return db.ExecMapContext(context.Background(), query, mp)
|
||||
}
|
||||
|
||||
func (db *DB) ExecStructContext(ctx context.Context, query string, st interface{}) (sql.Result, error) {
|
||||
query, args, err := StructToSlice(query, st)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return db.ExecContext(ctx, query, args...)
|
||||
}
|
||||
|
||||
func (db *DB) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) {
|
||||
hookCtx := contexts.NewContextHook(ctx, query, args)
|
||||
ctx, err := db.beforeProcess(hookCtx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, err := db.DB.ExecContext(ctx, query, args...)
|
||||
hookCtx.End(ctx, res, err)
|
||||
if err := db.afterProcess(hookCtx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (db *DB) ExecStruct(query string, st interface{}) (sql.Result, error) {
|
||||
return db.ExecStructContext(context.Background(), query, st)
|
||||
}
|
||||
|
||||
func (db *DB) beforeProcess(c *contexts.ContextHook) (context.Context, error) {
|
||||
if db.NeedLogSQL(c.Ctx) {
|
||||
db.Logger.BeforeSQL(log.LogContext(*c))
|
||||
}
|
||||
ctx, err := db.hooks.BeforeProcess(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
func (db *DB) afterProcess(c *contexts.ContextHook) error {
|
||||
err := db.hooks.AfterProcess(c)
|
||||
if db.NeedLogSQL(c.Ctx) {
|
||||
db.Logger.AfterSQL(log.LogContext(*c))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *DB) AddHook(h ...contexts.Hook) {
|
||||
db.hooks.AddHook(h...)
|
||||
}
|
||||
|
|
@ -0,0 +1,685 @@
|
|||
// Copyright 2019 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package core
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"flag"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm/names"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
var (
|
||||
dbtype = flag.String("dbtype", "sqlite3", "database type")
|
||||
dbConn = flag.String("dbConn", "./db_test.db", "database connect string")
|
||||
createTableSql string
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
flag.Parse()
|
||||
|
||||
switch *dbtype {
|
||||
case "sqlite3":
|
||||
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":
|
||||
fallthrough
|
||||
default:
|
||||
createTableSql = "CREATE TABLE IF NOT EXISTS `user` (`id` INTEGER PRIMARY KEY AUTO_INCREMENT NOT NULL, `name` TEXT NULL, " +
|
||||
"`title` TEXT NULL, `age` FLOAT NULL, `alias` TEXT NULL, `nick_name` TEXT NULL, `created` datetime);"
|
||||
}
|
||||
|
||||
exitCode := m.Run()
|
||||
|
||||
os.Exit(exitCode)
|
||||
}
|
||||
|
||||
func testOpen() (*DB, error) {
|
||||
switch *dbtype {
|
||||
case "sqlite3":
|
||||
os.Remove("./test.db")
|
||||
return Open("sqlite3", "./test.db")
|
||||
case "mysql":
|
||||
return Open("mysql", *dbConn)
|
||||
default:
|
||||
panic("no db type")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkOriQuery(b *testing.B) {
|
||||
b.StopTimer()
|
||||
db, err := testOpen()
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec(createTableSql)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
|
||||
for i := 0; i < 50; i++ {
|
||||
_, err = db.Exec("insert into user (`name`, title, age, alias, nick_name, created) values (?,?,?,?,?, ?)",
|
||||
"xlw", "tester", 1.2, "lunny", "lunny xiao", time.Now())
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
rows, err := db.Query("select * from user")
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
|
||||
for rows.Next() {
|
||||
var Id int64
|
||||
var Name, Title, Alias, NickName string
|
||||
var Age float32
|
||||
var Created NullTime
|
||||
err = rows.Scan(&Id, &Name, &Title, &Age, &Alias, &NickName, &Created)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
//fmt.Println(Id, Name, Title, Age, Alias, NickName)
|
||||
}
|
||||
rows.Close()
|
||||
}
|
||||
}
|
||||
|
||||
type User struct {
|
||||
Id int64
|
||||
Name string
|
||||
Title string
|
||||
Age float32
|
||||
Alias string
|
||||
NickName string
|
||||
Created NullTime
|
||||
}
|
||||
|
||||
func BenchmarkStructQuery(b *testing.B) {
|
||||
b.StopTimer()
|
||||
|
||||
db, err := testOpen()
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec(createTableSql)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
|
||||
for i := 0; i < 50; i++ {
|
||||
_, err = db.Exec("insert into user (`name`, title, age, alias, nick_name, created) values (?,?,?,?,?, ?)",
|
||||
"xlw", "tester", 1.2, "lunny", "lunny xiao", time.Now())
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
rows, err := db.Query("select * from user")
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
|
||||
for rows.Next() {
|
||||
var user User
|
||||
err = rows.ScanStructByIndex(&user)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
if user.Name != "xlw" {
|
||||
b.Log(user)
|
||||
b.Error(errors.New("name should be xlw"))
|
||||
}
|
||||
}
|
||||
rows.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkStruct2Query(b *testing.B) {
|
||||
b.StopTimer()
|
||||
|
||||
db, err := testOpen()
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec(createTableSql)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
|
||||
for i := 0; i < 50; i++ {
|
||||
_, err = db.Exec("insert into user (`name`, title, age, alias, nick_name, created) values (?,?,?,?,?,?)",
|
||||
"xlw", "tester", 1.2, "lunny", "lunny xiao", time.Now())
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
db.Mapper = names.NewCacheMapper(&names.SnakeMapper{})
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
rows, err := db.Query("select * from user")
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
|
||||
for rows.Next() {
|
||||
var user User
|
||||
err = rows.ScanStructByName(&user)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
if user.Name != "xlw" {
|
||||
b.Log(user)
|
||||
b.Error(errors.New("name should be xlw"))
|
||||
}
|
||||
}
|
||||
rows.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSliceInterfaceQuery(b *testing.B) {
|
||||
b.StopTimer()
|
||||
|
||||
db, err := testOpen()
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec(createTableSql)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
|
||||
for i := 0; i < 50; i++ {
|
||||
_, err = db.Exec("insert into user (`name`, title, age, alias, nick_name,created) values (?,?,?,?,?,?)",
|
||||
"xlw", "tester", 1.2, "lunny", "lunny xiao", time.Now())
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
rows, err := db.Query("select * from user")
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
|
||||
cols, err := rows.Columns()
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
|
||||
for rows.Next() {
|
||||
slice := make([]interface{}, len(cols))
|
||||
err = rows.ScanSlice(&slice)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
b.Log(slice)
|
||||
switch slice[1].(type) {
|
||||
case *string:
|
||||
if *slice[1].(*string) != "xlw" {
|
||||
b.Error(errors.New("name should be xlw"))
|
||||
}
|
||||
case []byte:
|
||||
if string(slice[1].([]byte)) != "xlw" {
|
||||
b.Error(errors.New("name should be xlw"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rows.Close()
|
||||
}
|
||||
}
|
||||
|
||||
/*func BenchmarkSliceBytesQuery(b *testing.B) {
|
||||
b.StopTimer()
|
||||
os.Remove("./test.db")
|
||||
db, err := Open("sqlite3", "./test.db")
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec(createTableSql)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
|
||||
for i := 0; i < 50; i++ {
|
||||
_, err = db.Exec("insert into user (name, title, age, alias, nick_name,created) values (?,?,?,?,?,?)",
|
||||
"xlw", "tester", 1.2, "lunny", "lunny xiao", time.Now())
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
rows, err := db.Query("select * from user")
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
|
||||
cols, err := rows.Columns()
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
|
||||
for rows.Next() {
|
||||
slice := make([][]byte, len(cols))
|
||||
err = rows.ScanSlice(&slice)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
if string(slice[1]) != "xlw" {
|
||||
fmt.Println(slice)
|
||||
b.Error(errors.New("name should be xlw"))
|
||||
}
|
||||
}
|
||||
|
||||
rows.Close()
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
func BenchmarkSliceStringQuery(b *testing.B) {
|
||||
b.StopTimer()
|
||||
db, err := testOpen()
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec(createTableSql)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
|
||||
for i := 0; i < 50; i++ {
|
||||
_, err = db.Exec("insert into user (name, title, age, alias, nick_name, created) values (?,?,?,?,?,?)",
|
||||
"xlw", "tester", 1.2, "lunny", "lunny xiao", time.Now())
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
rows, err := db.Query("select * from user")
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
|
||||
cols, err := rows.Columns()
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
|
||||
for rows.Next() {
|
||||
slice := make([]*string, len(cols))
|
||||
err = rows.ScanSlice(&slice)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
if (*slice[1]) != "xlw" {
|
||||
b.Log(slice)
|
||||
b.Error(errors.New("name should be xlw"))
|
||||
}
|
||||
}
|
||||
|
||||
rows.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMapInterfaceQuery(b *testing.B) {
|
||||
b.StopTimer()
|
||||
|
||||
db, err := testOpen()
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec(createTableSql)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
|
||||
for i := 0; i < 50; i++ {
|
||||
_, err = db.Exec("insert into user (name, title, age, alias, nick_name,created) values (?,?,?,?,?,?)",
|
||||
"xlw", "tester", 1.2, "lunny", "lunny xiao", time.Now())
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
rows, err := db.Query("select * from user")
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
|
||||
for rows.Next() {
|
||||
m := make(map[string]interface{})
|
||||
err = rows.ScanMap(&m)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
switch m["name"].(type) {
|
||||
case string:
|
||||
if m["name"].(string) != "xlw" {
|
||||
b.Log(m)
|
||||
b.Error(errors.New("name should be xlw"))
|
||||
}
|
||||
case []byte:
|
||||
if string(m["name"].([]byte)) != "xlw" {
|
||||
b.Log(m)
|
||||
b.Error(errors.New("name should be xlw"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rows.Close()
|
||||
}
|
||||
}
|
||||
|
||||
/*func BenchmarkMapBytesQuery(b *testing.B) {
|
||||
b.StopTimer()
|
||||
os.Remove("./test.db")
|
||||
db, err := Open("sqlite3", "./test.db")
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec(createTableSql)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
|
||||
for i := 0; i < 50; i++ {
|
||||
_, err = db.Exec("insert into user (name, title, age, alias, nick_name,created) values (?,?,?,?,?,?)",
|
||||
"xlw", "tester", 1.2, "lunny", "lunny xiao", time.Now())
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
rows, err := db.Query("select * from user")
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
|
||||
for rows.Next() {
|
||||
m := make(map[string][]byte)
|
||||
err = rows.ScanMap(&m)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
if string(m["name"]) != "xlw" {
|
||||
fmt.Println(m)
|
||||
b.Error(errors.New("name should be xlw"))
|
||||
}
|
||||
}
|
||||
|
||||
rows.Close()
|
||||
}
|
||||
}
|
||||
*/
|
||||
/*
|
||||
func BenchmarkMapStringQuery(b *testing.B) {
|
||||
b.StopTimer()
|
||||
os.Remove("./test.db")
|
||||
db, err := Open("sqlite3", "./test.db")
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec(createTableSql)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
|
||||
for i := 0; i < 50; i++ {
|
||||
_, err = db.Exec("insert into user (name, title, age, alias, nick_name,created) values (?,?,?,?,?,?)",
|
||||
"xlw", "tester", 1.2, "lunny", "lunny xiao", time.Now())
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
rows, err := db.Query("select * from user")
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
|
||||
for rows.Next() {
|
||||
m := make(map[string]string)
|
||||
err = rows.ScanMap(&m)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
if m["name"] != "xlw" {
|
||||
fmt.Println(m)
|
||||
b.Error(errors.New("name should be xlw"))
|
||||
}
|
||||
}
|
||||
|
||||
rows.Close()
|
||||
}
|
||||
}*/
|
||||
|
||||
func BenchmarkExec(b *testing.B) {
|
||||
b.StopTimer()
|
||||
|
||||
db, err := testOpen()
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec(createTableSql)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err = db.Exec("insert into user (`name`, title, age, alias, nick_name,created) values (?,?,?,?,?,?)",
|
||||
"xlw", "tester", 1.2, "lunny", "lunny xiao", time.Now())
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkExecMap(b *testing.B) {
|
||||
b.StopTimer()
|
||||
|
||||
db, err := testOpen()
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec(createTableSql)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
|
||||
b.StartTimer()
|
||||
|
||||
mp := map[string]interface{}{
|
||||
"name": "xlw",
|
||||
"title": "tester",
|
||||
"age": 1.2,
|
||||
"alias": "lunny",
|
||||
"nick_name": "lunny xiao",
|
||||
"created": time.Now(),
|
||||
}
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err = db.ExecMap("insert into user (`name`, title, age, alias, nick_name, created) "+
|
||||
"values (?name,?title,?age,?alias,?nick_name,?created)",
|
||||
&mp)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestExecMap(t *testing.T) {
|
||||
db, err := testOpen()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec(createTableSql)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
mp := map[string]interface{}{
|
||||
"name": "xlw",
|
||||
"title": "tester",
|
||||
"age": 1.2,
|
||||
"alias": "lunny",
|
||||
"nick_name": "lunny xiao",
|
||||
"created": time.Now(),
|
||||
}
|
||||
|
||||
_, err = db.ExecMap("insert into user (`name`, title, age, alias, nick_name,created) "+
|
||||
"values (?name,?title,?age,?alias,?nick_name,?created)",
|
||||
&mp)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
rows, err := db.Query("select * from user")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
for rows.Next() {
|
||||
var user User
|
||||
err = rows.ScanStructByName(&user)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
t.Log("--", user)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExecStruct(t *testing.T) {
|
||||
db, err := testOpen()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec(createTableSql)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
user := User{Name: "xlw",
|
||||
Title: "tester",
|
||||
Age: 1.2,
|
||||
Alias: "lunny",
|
||||
NickName: "lunny xiao",
|
||||
Created: NullTime(time.Now()),
|
||||
}
|
||||
|
||||
_, err = db.ExecStruct("insert into user (`name`, title, age, alias, nick_name,created) "+
|
||||
"values (?Name,?Title,?Age,?Alias,?NickName,?Created)",
|
||||
&user)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
rows, err := db.QueryStruct("select * from user where `name` = ?Name", &user)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
for rows.Next() {
|
||||
var user User
|
||||
err = rows.ScanStructByName(&user)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
t.Log("1--", user)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkExecStruct(b *testing.B) {
|
||||
b.StopTimer()
|
||||
db, err := testOpen()
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec(createTableSql)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
|
||||
b.StartTimer()
|
||||
|
||||
user := User{Name: "xlw",
|
||||
Title: "tester",
|
||||
Age: 1.2,
|
||||
Alias: "lunny",
|
||||
NickName: "lunny xiao",
|
||||
Created: NullTime(time.Now()),
|
||||
}
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err = db.ExecStruct("insert into user (`name`, title, age, alias, nick_name,created) "+
|
||||
"values (?Name,?Title,?Age,?Alias,?NickName,?Created)",
|
||||
&user)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
// Copyright 2019 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package core
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
// ErrNoMapPointer represents error when no map pointer
|
||||
ErrNoMapPointer = errors.New("mp should be a map's pointer")
|
||||
// ErrNoStructPointer represents error when no struct pointer
|
||||
ErrNoStructPointer = errors.New("mp should be a struct's pointer")
|
||||
)
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
)
|
||||
|
||||
// Queryer represents an interface to query a SQL to get data from database
|
||||
type Queryer interface {
|
||||
QueryContext(ctx context.Context, query string, args ...interface{}) (*Rows, error)
|
||||
}
|
||||
|
||||
// Executer represents an interface to execute a SQL
|
||||
type Executer interface {
|
||||
ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
|
||||
}
|
||||
|
||||
// QueryExecuter combines the Queryer and Executer
|
||||
type QueryExecuter interface {
|
||||
Queryer
|
||||
Executer
|
||||
}
|
||||
|
|
@ -0,0 +1,338 @@
|
|||
// Copyright 2019 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package core
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"reflect"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Rows struct {
|
||||
*sql.Rows
|
||||
db *DB
|
||||
}
|
||||
|
||||
func (rs *Rows) ToMapString() ([]map[string]string, error) {
|
||||
cols, err := rs.Columns()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var results = make([]map[string]string, 0, 10)
|
||||
for rs.Next() {
|
||||
var record = make(map[string]string, len(cols))
|
||||
err = rs.ScanMap(&record)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
results = append(results, record)
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// scan data to a struct's pointer according field index
|
||||
func (rs *Rows) ScanStructByIndex(dest ...interface{}) error {
|
||||
if len(dest) == 0 {
|
||||
return errors.New("at least one struct")
|
||||
}
|
||||
|
||||
vvvs := make([]reflect.Value, len(dest))
|
||||
for i, s := range dest {
|
||||
vv := reflect.ValueOf(s)
|
||||
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct {
|
||||
return errors.New("dest should be a struct's pointer")
|
||||
}
|
||||
|
||||
vvvs[i] = vv.Elem()
|
||||
}
|
||||
|
||||
cols, err := rs.Columns()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newDest := make([]interface{}, len(cols))
|
||||
|
||||
var i = 0
|
||||
for _, vvv := range vvvs {
|
||||
for j := 0; j < vvv.NumField(); j++ {
|
||||
newDest[i] = vvv.Field(j).Addr().Interface()
|
||||
i = i + 1
|
||||
}
|
||||
}
|
||||
|
||||
return rs.Rows.Scan(newDest...)
|
||||
}
|
||||
|
||||
var (
|
||||
fieldCache = make(map[reflect.Type]map[string]int)
|
||||
fieldCacheMutex sync.RWMutex
|
||||
)
|
||||
|
||||
func fieldByName(v reflect.Value, name string) reflect.Value {
|
||||
t := v.Type()
|
||||
fieldCacheMutex.RLock()
|
||||
cache, ok := fieldCache[t]
|
||||
fieldCacheMutex.RUnlock()
|
||||
if !ok {
|
||||
cache = make(map[string]int)
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
cache[t.Field(i).Name] = i
|
||||
}
|
||||
fieldCacheMutex.Lock()
|
||||
fieldCache[t] = cache
|
||||
fieldCacheMutex.Unlock()
|
||||
}
|
||||
|
||||
if i, ok := cache[name]; ok {
|
||||
return v.Field(i)
|
||||
}
|
||||
|
||||
return reflect.Zero(t)
|
||||
}
|
||||
|
||||
// scan data to a struct's pointer according field name
|
||||
func (rs *Rows) ScanStructByName(dest interface{}) error {
|
||||
vv := reflect.ValueOf(dest)
|
||||
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct {
|
||||
return errors.New("dest should be a struct's pointer")
|
||||
}
|
||||
|
||||
cols, err := rs.Columns()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newDest := make([]interface{}, len(cols))
|
||||
var v EmptyScanner
|
||||
for j, name := range cols {
|
||||
f := fieldByName(vv.Elem(), rs.db.Mapper.Table2Obj(name))
|
||||
if f.IsValid() {
|
||||
newDest[j] = f.Addr().Interface()
|
||||
} else {
|
||||
newDest[j] = &v
|
||||
}
|
||||
}
|
||||
|
||||
return rs.Rows.Scan(newDest...)
|
||||
}
|
||||
|
||||
// scan data to a slice's pointer, slice's length should equal to columns' number
|
||||
func (rs *Rows) ScanSlice(dest interface{}) error {
|
||||
vv := reflect.ValueOf(dest)
|
||||
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Slice {
|
||||
return errors.New("dest should be a slice's pointer")
|
||||
}
|
||||
|
||||
vvv := vv.Elem()
|
||||
cols, err := rs.Columns()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newDest := make([]interface{}, len(cols))
|
||||
|
||||
for j := 0; j < len(cols); j++ {
|
||||
if j >= vvv.Len() {
|
||||
newDest[j] = reflect.New(vvv.Type().Elem()).Interface()
|
||||
} else {
|
||||
newDest[j] = vvv.Index(j).Addr().Interface()
|
||||
}
|
||||
}
|
||||
|
||||
err = rs.Rows.Scan(newDest...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
srcLen := vvv.Len()
|
||||
for i := srcLen; i < len(cols); i++ {
|
||||
vvv = reflect.Append(vvv, reflect.ValueOf(newDest[i]).Elem())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// scan data to a map's pointer
|
||||
func (rs *Rows) ScanMap(dest interface{}) error {
|
||||
vv := reflect.ValueOf(dest)
|
||||
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map {
|
||||
return errors.New("dest should be a map's pointer")
|
||||
}
|
||||
|
||||
cols, err := rs.Columns()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newDest := make([]interface{}, len(cols))
|
||||
vvv := vv.Elem()
|
||||
|
||||
for i := range cols {
|
||||
newDest[i] = rs.db.reflectNew(vvv.Type().Elem()).Interface()
|
||||
}
|
||||
|
||||
err = rs.Rows.Scan(newDest...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i, name := range cols {
|
||||
vname := reflect.ValueOf(name)
|
||||
vvv.SetMapIndex(vname, reflect.ValueOf(newDest[i]).Elem())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type Row struct {
|
||||
rows *Rows
|
||||
// One of these two will be non-nil:
|
||||
err error // deferred error for easy chaining
|
||||
}
|
||||
|
||||
// ErrorRow return an error row
|
||||
func ErrorRow(err error) *Row {
|
||||
return &Row{
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
|
||||
// NewRow from rows
|
||||
func NewRow(rows *Rows, err error) *Row {
|
||||
return &Row{rows, err}
|
||||
}
|
||||
|
||||
func (row *Row) Columns() ([]string, error) {
|
||||
if row.err != nil {
|
||||
return nil, row.err
|
||||
}
|
||||
return row.rows.Columns()
|
||||
}
|
||||
|
||||
func (row *Row) Scan(dest ...interface{}) error {
|
||||
if row.err != nil {
|
||||
return row.err
|
||||
}
|
||||
defer row.rows.Close()
|
||||
|
||||
for _, dp := range dest {
|
||||
if _, ok := dp.(*sql.RawBytes); ok {
|
||||
return errors.New("sql: RawBytes isn't allowed on Row.Scan")
|
||||
}
|
||||
}
|
||||
|
||||
if !row.rows.Next() {
|
||||
if err := row.rows.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
return sql.ErrNoRows
|
||||
}
|
||||
err := row.rows.Scan(dest...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Make sure the query can be processed to completion with no errors.
|
||||
return row.rows.Close()
|
||||
}
|
||||
|
||||
func (row *Row) ScanStructByName(dest interface{}) error {
|
||||
if row.err != nil {
|
||||
return row.err
|
||||
}
|
||||
defer row.rows.Close()
|
||||
|
||||
if !row.rows.Next() {
|
||||
if err := row.rows.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
return sql.ErrNoRows
|
||||
}
|
||||
err := row.rows.ScanStructByName(dest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Make sure the query can be processed to completion with no errors.
|
||||
return row.rows.Close()
|
||||
}
|
||||
|
||||
func (row *Row) ScanStructByIndex(dest interface{}) error {
|
||||
if row.err != nil {
|
||||
return row.err
|
||||
}
|
||||
defer row.rows.Close()
|
||||
|
||||
if !row.rows.Next() {
|
||||
if err := row.rows.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
return sql.ErrNoRows
|
||||
}
|
||||
err := row.rows.ScanStructByIndex(dest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Make sure the query can be processed to completion with no errors.
|
||||
return row.rows.Close()
|
||||
}
|
||||
|
||||
// scan data to a slice's pointer, slice's length should equal to columns' number
|
||||
func (row *Row) ScanSlice(dest interface{}) error {
|
||||
if row.err != nil {
|
||||
return row.err
|
||||
}
|
||||
defer row.rows.Close()
|
||||
|
||||
if !row.rows.Next() {
|
||||
if err := row.rows.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
return sql.ErrNoRows
|
||||
}
|
||||
err := row.rows.ScanSlice(dest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Make sure the query can be processed to completion with no errors.
|
||||
return row.rows.Close()
|
||||
}
|
||||
|
||||
// scan data to a map's pointer
|
||||
func (row *Row) ScanMap(dest interface{}) error {
|
||||
if row.err != nil {
|
||||
return row.err
|
||||
}
|
||||
defer row.rows.Close()
|
||||
|
||||
if !row.rows.Next() {
|
||||
if err := row.rows.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
return sql.ErrNoRows
|
||||
}
|
||||
err := row.rows.ScanMap(dest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Make sure the query can be processed to completion with no errors.
|
||||
return row.rows.Close()
|
||||
}
|
||||
|
||||
func (row *Row) ToMapString() (map[string]string, error) {
|
||||
cols, err := row.Columns()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var record = make(map[string]string, len(cols))
|
||||
err = row.ScanMap(&record)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return record, nil
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
// Copyright 2019 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package core
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
type NullTime time.Time
|
||||
|
||||
var (
|
||||
_ driver.Valuer = NullTime{}
|
||||
)
|
||||
|
||||
func (ns *NullTime) Scan(value interface{}) error {
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
return convertTime(ns, value)
|
||||
}
|
||||
|
||||
// Value implements the driver Valuer interface.
|
||||
func (ns NullTime) Value() (driver.Value, error) {
|
||||
if (time.Time)(ns).IsZero() {
|
||||
return nil, nil
|
||||
}
|
||||
return (time.Time)(ns).Format("2006-01-02 15:04:05"), nil
|
||||
}
|
||||
|
||||
func convertTime(dest *NullTime, src interface{}) error {
|
||||
// Common cases, without reflect.
|
||||
switch s := src.(type) {
|
||||
case string:
|
||||
t, err := time.Parse("2006-01-02 15:04:05", s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*dest = NullTime(t)
|
||||
return nil
|
||||
case []uint8:
|
||||
t, err := time.Parse("2006-01-02 15:04:05", string(s))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*dest = NullTime(t)
|
||||
return nil
|
||||
case time.Time:
|
||||
*dest = NullTime(s)
|
||||
return nil
|
||||
case nil:
|
||||
default:
|
||||
return fmt.Errorf("unsupported driver -> Scan pair: %T -> %T", src, dest)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type EmptyScanner struct {
|
||||
}
|
||||
|
||||
func (EmptyScanner) Scan(src interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -0,0 +1,194 @@
|
|||
// Copyright 2019 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"reflect"
|
||||
|
||||
"xorm.io/xorm/contexts"
|
||||
)
|
||||
|
||||
// Stmt reprents a stmt objects
|
||||
type Stmt struct {
|
||||
*sql.Stmt
|
||||
db *DB
|
||||
names map[string]int
|
||||
query string
|
||||
}
|
||||
|
||||
func (db *DB) PrepareContext(ctx context.Context, query string) (*Stmt, error) {
|
||||
names := make(map[string]int)
|
||||
var i int
|
||||
query = re.ReplaceAllStringFunc(query, func(src string) string {
|
||||
names[src[1:]] = i
|
||||
i++
|
||||
return "?"
|
||||
})
|
||||
hookCtx := contexts.NewContextHook(ctx, "PREPARE", nil)
|
||||
ctx, err := db.beforeProcess(hookCtx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stmt, err := db.DB.PrepareContext(ctx, query)
|
||||
hookCtx.End(ctx, nil, err)
|
||||
if err := db.afterProcess(hookCtx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Stmt{stmt, db, names, query}, nil
|
||||
}
|
||||
|
||||
func (db *DB) Prepare(query string) (*Stmt, error) {
|
||||
return db.PrepareContext(context.Background(), query)
|
||||
}
|
||||
|
||||
func (s *Stmt) ExecMapContext(ctx context.Context, mp interface{}) (sql.Result, error) {
|
||||
vv := reflect.ValueOf(mp)
|
||||
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map {
|
||||
return nil, errors.New("mp should be a map's pointer")
|
||||
}
|
||||
|
||||
args := make([]interface{}, len(s.names))
|
||||
for k, i := range s.names {
|
||||
args[i] = vv.Elem().MapIndex(reflect.ValueOf(k)).Interface()
|
||||
}
|
||||
return s.ExecContext(ctx, args...)
|
||||
}
|
||||
|
||||
func (s *Stmt) ExecMap(mp interface{}) (sql.Result, error) {
|
||||
return s.ExecMapContext(context.Background(), mp)
|
||||
}
|
||||
|
||||
func (s *Stmt) ExecStructContext(ctx context.Context, st interface{}) (sql.Result, error) {
|
||||
vv := reflect.ValueOf(st)
|
||||
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct {
|
||||
return nil, errors.New("mp should be a map's pointer")
|
||||
}
|
||||
|
||||
args := make([]interface{}, len(s.names))
|
||||
for k, i := range s.names {
|
||||
args[i] = vv.Elem().FieldByName(k).Interface()
|
||||
}
|
||||
return s.ExecContext(ctx, args...)
|
||||
}
|
||||
|
||||
func (s *Stmt) ExecStruct(st interface{}) (sql.Result, error) {
|
||||
return s.ExecStructContext(context.Background(), st)
|
||||
}
|
||||
|
||||
func (s *Stmt) ExecContext(ctx context.Context, args ...interface{}) (sql.Result, error) {
|
||||
hookCtx := contexts.NewContextHook(ctx, s.query, args)
|
||||
ctx, err := s.db.beforeProcess(hookCtx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, err := s.Stmt.ExecContext(ctx, args)
|
||||
hookCtx.End(ctx, res, err)
|
||||
if err := s.db.afterProcess(hookCtx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (s *Stmt) QueryContext(ctx context.Context, args ...interface{}) (*Rows, error) {
|
||||
hookCtx := contexts.NewContextHook(ctx, s.query, args)
|
||||
ctx, err := s.db.beforeProcess(hookCtx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rows, err := s.Stmt.QueryContext(ctx, args...)
|
||||
hookCtx.End(ctx, nil, err)
|
||||
if err := s.db.afterProcess(hookCtx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Rows{rows, s.db}, nil
|
||||
}
|
||||
|
||||
func (s *Stmt) Query(args ...interface{}) (*Rows, error) {
|
||||
return s.QueryContext(context.Background(), args...)
|
||||
}
|
||||
|
||||
func (s *Stmt) QueryMapContext(ctx context.Context, mp interface{}) (*Rows, error) {
|
||||
vv := reflect.ValueOf(mp)
|
||||
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map {
|
||||
return nil, errors.New("mp should be a map's pointer")
|
||||
}
|
||||
|
||||
args := make([]interface{}, len(s.names))
|
||||
for k, i := range s.names {
|
||||
args[i] = vv.Elem().MapIndex(reflect.ValueOf(k)).Interface()
|
||||
}
|
||||
|
||||
return s.QueryContext(ctx, args...)
|
||||
}
|
||||
|
||||
func (s *Stmt) QueryMap(mp interface{}) (*Rows, error) {
|
||||
return s.QueryMapContext(context.Background(), mp)
|
||||
}
|
||||
|
||||
func (s *Stmt) QueryStructContext(ctx context.Context, st interface{}) (*Rows, error) {
|
||||
vv := reflect.ValueOf(st)
|
||||
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct {
|
||||
return nil, errors.New("mp should be a map's pointer")
|
||||
}
|
||||
|
||||
args := make([]interface{}, len(s.names))
|
||||
for k, i := range s.names {
|
||||
args[i] = vv.Elem().FieldByName(k).Interface()
|
||||
}
|
||||
|
||||
return s.QueryContext(ctx, args...)
|
||||
}
|
||||
|
||||
func (s *Stmt) QueryStruct(st interface{}) (*Rows, error) {
|
||||
return s.QueryStructContext(context.Background(), st)
|
||||
}
|
||||
|
||||
func (s *Stmt) QueryRowContext(ctx context.Context, args ...interface{}) *Row {
|
||||
rows, err := s.QueryContext(ctx, args...)
|
||||
return &Row{rows, err}
|
||||
}
|
||||
|
||||
func (s *Stmt) QueryRow(args ...interface{}) *Row {
|
||||
return s.QueryRowContext(context.Background(), args...)
|
||||
}
|
||||
|
||||
func (s *Stmt) QueryRowMapContext(ctx context.Context, mp interface{}) *Row {
|
||||
vv := reflect.ValueOf(mp)
|
||||
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map {
|
||||
return &Row{nil, errors.New("mp should be a map's pointer")}
|
||||
}
|
||||
|
||||
args := make([]interface{}, len(s.names))
|
||||
for k, i := range s.names {
|
||||
args[i] = vv.Elem().MapIndex(reflect.ValueOf(k)).Interface()
|
||||
}
|
||||
|
||||
return s.QueryRowContext(ctx, args...)
|
||||
}
|
||||
|
||||
func (s *Stmt) QueryRowMap(mp interface{}) *Row {
|
||||
return s.QueryRowMapContext(context.Background(), mp)
|
||||
}
|
||||
|
||||
func (s *Stmt) QueryRowStructContext(ctx context.Context, st interface{}) *Row {
|
||||
vv := reflect.ValueOf(st)
|
||||
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct {
|
||||
return &Row{nil, errors.New("st should be a struct's pointer")}
|
||||
}
|
||||
|
||||
args := make([]interface{}, len(s.names))
|
||||
for k, i := range s.names {
|
||||
args[i] = vv.Elem().FieldByName(k).Interface()
|
||||
}
|
||||
|
||||
return s.QueryRowContext(ctx, args...)
|
||||
}
|
||||
|
||||
func (s *Stmt) QueryRowStruct(st interface{}) *Row {
|
||||
return s.QueryRowStructContext(context.Background(), st)
|
||||
}
|
||||
|
|
@ -0,0 +1,190 @@
|
|||
// Copyright 2019 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"xorm.io/xorm/contexts"
|
||||
)
|
||||
|
||||
var (
|
||||
_ QueryExecuter = &Tx{}
|
||||
)
|
||||
|
||||
// Tx represents a transaction
|
||||
type Tx struct {
|
||||
*sql.Tx
|
||||
db *DB
|
||||
}
|
||||
|
||||
func (db *DB) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) {
|
||||
hookCtx := contexts.NewContextHook(ctx, "BEGIN TRANSACTION", nil)
|
||||
ctx, err := db.beforeProcess(hookCtx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tx, err := db.DB.BeginTx(ctx, opts)
|
||||
hookCtx.End(ctx, nil, err)
|
||||
if err := db.afterProcess(hookCtx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Tx{tx, db}, nil
|
||||
}
|
||||
|
||||
func (db *DB) Begin() (*Tx, error) {
|
||||
return db.BeginTx(context.Background(), nil)
|
||||
}
|
||||
|
||||
func (tx *Tx) PrepareContext(ctx context.Context, query string) (*Stmt, error) {
|
||||
names := make(map[string]int)
|
||||
var i int
|
||||
query = re.ReplaceAllStringFunc(query, func(src string) string {
|
||||
names[src[1:]] = i
|
||||
i++
|
||||
return "?"
|
||||
})
|
||||
hookCtx := contexts.NewContextHook(ctx, "PREPARE", nil)
|
||||
ctx, err := tx.db.beforeProcess(hookCtx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stmt, err := tx.Tx.PrepareContext(ctx, query)
|
||||
hookCtx.End(ctx, nil, err)
|
||||
if err := tx.db.afterProcess(hookCtx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Stmt{stmt, tx.db, names, query}, nil
|
||||
}
|
||||
|
||||
func (tx *Tx) Prepare(query string) (*Stmt, error) {
|
||||
return tx.PrepareContext(context.Background(), query)
|
||||
}
|
||||
|
||||
func (tx *Tx) StmtContext(ctx context.Context, stmt *Stmt) *Stmt {
|
||||
stmt.Stmt = tx.Tx.StmtContext(ctx, stmt.Stmt)
|
||||
return stmt
|
||||
}
|
||||
|
||||
func (tx *Tx) Stmt(stmt *Stmt) *Stmt {
|
||||
return tx.StmtContext(context.Background(), stmt)
|
||||
}
|
||||
|
||||
func (tx *Tx) ExecMapContext(ctx context.Context, query string, mp interface{}) (sql.Result, error) {
|
||||
query, args, err := MapToSlice(query, mp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tx.ExecContext(ctx, query, args...)
|
||||
}
|
||||
|
||||
func (tx *Tx) ExecMap(query string, mp interface{}) (sql.Result, error) {
|
||||
return tx.ExecMapContext(context.Background(), query, mp)
|
||||
}
|
||||
|
||||
func (tx *Tx) ExecStructContext(ctx context.Context, query string, st interface{}) (sql.Result, error) {
|
||||
query, args, err := StructToSlice(query, st)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tx.ExecContext(ctx, query, args...)
|
||||
}
|
||||
|
||||
func (tx *Tx) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) {
|
||||
hookCtx := contexts.NewContextHook(ctx, query, args)
|
||||
ctx, err := tx.db.beforeProcess(hookCtx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, err := tx.Tx.ExecContext(ctx, query, args...)
|
||||
hookCtx.End(ctx, res, err)
|
||||
if err := tx.db.afterProcess(hookCtx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (tx *Tx) ExecStruct(query string, st interface{}) (sql.Result, error) {
|
||||
return tx.ExecStructContext(context.Background(), query, st)
|
||||
}
|
||||
|
||||
func (tx *Tx) QueryContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) {
|
||||
hookCtx := contexts.NewContextHook(ctx, query, args)
|
||||
ctx, err := tx.db.beforeProcess(hookCtx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rows, err := tx.Tx.QueryContext(ctx, query, args...)
|
||||
hookCtx.End(ctx, nil, err)
|
||||
if err := tx.db.afterProcess(hookCtx); err != nil {
|
||||
if rows != nil {
|
||||
rows.Close()
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &Rows{rows, tx.db}, nil
|
||||
}
|
||||
|
||||
func (tx *Tx) Query(query string, args ...interface{}) (*Rows, error) {
|
||||
return tx.QueryContext(context.Background(), query, args...)
|
||||
}
|
||||
|
||||
func (tx *Tx) QueryMapContext(ctx context.Context, query string, mp interface{}) (*Rows, error) {
|
||||
query, args, err := MapToSlice(query, mp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tx.QueryContext(ctx, query, args...)
|
||||
}
|
||||
|
||||
func (tx *Tx) QueryMap(query string, mp interface{}) (*Rows, error) {
|
||||
return tx.QueryMapContext(context.Background(), query, mp)
|
||||
}
|
||||
|
||||
func (tx *Tx) QueryStructContext(ctx context.Context, query string, st interface{}) (*Rows, error) {
|
||||
query, args, err := StructToSlice(query, st)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tx.QueryContext(ctx, query, args...)
|
||||
}
|
||||
|
||||
func (tx *Tx) QueryStruct(query string, st interface{}) (*Rows, error) {
|
||||
return tx.QueryStructContext(context.Background(), query, st)
|
||||
}
|
||||
|
||||
func (tx *Tx) QueryRowContext(ctx context.Context, query string, args ...interface{}) *Row {
|
||||
rows, err := tx.QueryContext(ctx, query, args...)
|
||||
return &Row{rows, err}
|
||||
}
|
||||
|
||||
func (tx *Tx) QueryRow(query string, args ...interface{}) *Row {
|
||||
return tx.QueryRowContext(context.Background(), query, args...)
|
||||
}
|
||||
|
||||
func (tx *Tx) QueryRowMapContext(ctx context.Context, query string, mp interface{}) *Row {
|
||||
query, args, err := MapToSlice(query, mp)
|
||||
if err != nil {
|
||||
return &Row{nil, err}
|
||||
}
|
||||
return tx.QueryRowContext(ctx, query, args...)
|
||||
}
|
||||
|
||||
func (tx *Tx) QueryRowMap(query string, mp interface{}) *Row {
|
||||
return tx.QueryRowMapContext(context.Background(), query, mp)
|
||||
}
|
||||
|
||||
func (tx *Tx) QueryRowStructContext(ctx context.Context, query string, st interface{}) *Row {
|
||||
query, args, err := StructToSlice(query, st)
|
||||
if err != nil {
|
||||
return &Row{nil, err}
|
||||
}
|
||||
return tx.QueryRowContext(ctx, query, args...)
|
||||
}
|
||||
|
||||
func (tx *Tx) QueryRowStruct(query string, st interface{}) *Row {
|
||||
return tx.QueryRowStructContext(context.Background(), query, st)
|
||||
}
|
||||
|
|
@ -0,0 +1,284 @@
|
|||
// Copyright 2019 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package dialects
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm/core"
|
||||
"xorm.io/xorm/schemas"
|
||||
)
|
||||
|
||||
// URI represents an uri to visit database
|
||||
type URI struct {
|
||||
DBType schemas.DBType
|
||||
Proto string
|
||||
Host string
|
||||
Port string
|
||||
DBName string
|
||||
User string
|
||||
Passwd string
|
||||
Charset string
|
||||
Laddr string
|
||||
Raddr string
|
||||
Timeout time.Duration
|
||||
Schema string
|
||||
}
|
||||
|
||||
// SetSchema set schema
|
||||
func (uri *URI) SetSchema(schema string) {
|
||||
// hack me
|
||||
if uri.DBType == schemas.POSTGRES {
|
||||
uri.Schema = strings.TrimSpace(schema)
|
||||
}
|
||||
}
|
||||
|
||||
// Dialect represents a kind of database
|
||||
type Dialect interface {
|
||||
Init(*URI) error
|
||||
URI() *URI
|
||||
SQLType(*schemas.Column) string
|
||||
FormatBytes(b []byte) string
|
||||
|
||||
IsReserved(string) bool
|
||||
Quoter() schemas.Quoter
|
||||
SetQuotePolicy(quotePolicy QuotePolicy)
|
||||
|
||||
AutoIncrStr() string
|
||||
|
||||
GetIndexes(queryer core.Queryer, ctx context.Context, tableName string) (map[string]*schemas.Index, error)
|
||||
IndexCheckSQL(tableName, idxName string) (string, []interface{})
|
||||
CreateIndexSQL(tableName string, index *schemas.Index) string
|
||||
DropIndexSQL(tableName string, index *schemas.Index) string
|
||||
|
||||
GetTables(queryer core.Queryer, ctx context.Context) ([]*schemas.Table, error)
|
||||
IsTableExist(queryer core.Queryer, ctx context.Context, tableName string) (bool, error)
|
||||
CreateTableSQL(table *schemas.Table, tableName string) ([]string, bool)
|
||||
DropTableSQL(tableName string) (string, bool)
|
||||
|
||||
GetColumns(queryer core.Queryer, ctx context.Context, tableName string) ([]string, map[string]*schemas.Column, error)
|
||||
IsColumnExist(queryer core.Queryer, ctx context.Context, tableName string, colName string) (bool, error)
|
||||
AddColumnSQL(tableName string, col *schemas.Column) string
|
||||
ModifyColumnSQL(tableName string, col *schemas.Column) string
|
||||
|
||||
ForUpdateSQL(query string) string
|
||||
|
||||
Filters() []Filter
|
||||
SetParams(params map[string]string)
|
||||
}
|
||||
|
||||
// Base represents a basic dialect and all real dialects could embed this struct
|
||||
type Base struct {
|
||||
dialect Dialect
|
||||
uri *URI
|
||||
quoter schemas.Quoter
|
||||
}
|
||||
|
||||
func (b *Base) Quoter() schemas.Quoter {
|
||||
return b.quoter
|
||||
}
|
||||
|
||||
func (b *Base) Init(dialect Dialect, uri *URI) error {
|
||||
b.dialect, b.uri = dialect, uri
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Base) URI() *URI {
|
||||
return b.uri
|
||||
}
|
||||
|
||||
func (b *Base) DBType() schemas.DBType {
|
||||
return b.uri.DBType
|
||||
}
|
||||
|
||||
func (b *Base) FormatBytes(bs []byte) string {
|
||||
return fmt.Sprintf("0x%x", bs)
|
||||
}
|
||||
|
||||
func (db *Base) DropTableSQL(tableName string) (string, bool) {
|
||||
quote := db.dialect.Quoter().Quote
|
||||
return fmt.Sprintf("DROP TABLE IF EXISTS %s", quote(tableName)), true
|
||||
}
|
||||
|
||||
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 {
|
||||
return false, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
if rows.Next() {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (db *Base) IsColumnExist(queryer core.Queryer, ctx context.Context, tableName, colName string) (bool, error) {
|
||||
quote := db.dialect.Quoter().Quote
|
||||
query := fmt.Sprintf(
|
||||
"SELECT %v FROM %v.%v WHERE %v = ? AND %v = ? AND %v = ?",
|
||||
quote("COLUMN_NAME"),
|
||||
quote("INFORMATION_SCHEMA"),
|
||||
quote("COLUMNS"),
|
||||
quote("TABLE_SCHEMA"),
|
||||
quote("TABLE_NAME"),
|
||||
quote("COLUMN_NAME"),
|
||||
)
|
||||
return db.HasRecords(queryer, ctx, query, db.uri.DBName, tableName, colName)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
func (db *Base) CreateIndexSQL(tableName string, index *schemas.Index) string {
|
||||
quoter := db.dialect.Quoter()
|
||||
var unique string
|
||||
var idxName string
|
||||
if index.Type == schemas.UniqueType {
|
||||
unique = " UNIQUE"
|
||||
}
|
||||
idxName = index.XName(tableName)
|
||||
return fmt.Sprintf("CREATE%s INDEX %v ON %v (%v)", unique,
|
||||
quoter.Quote(idxName), quoter.Quote(tableName),
|
||||
quoter.Join(index.Cols, ","))
|
||||
}
|
||||
|
||||
func (db *Base) DropIndexSQL(tableName string, index *schemas.Index) string {
|
||||
quote := db.dialect.Quoter().Quote
|
||||
var name string
|
||||
if index.IsRegular {
|
||||
name = index.XName(tableName)
|
||||
} else {
|
||||
name = index.Name
|
||||
}
|
||||
return fmt.Sprintf("DROP INDEX %v ON %s", quote(name), quote(tableName))
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
func (b *Base) ForUpdateSQL(query string) string {
|
||||
return query + " FOR UPDATE"
|
||||
}
|
||||
|
||||
func (b *Base) SetParams(params map[string]string) {
|
||||
}
|
||||
|
||||
var (
|
||||
dialects = map[string]func() Dialect{}
|
||||
)
|
||||
|
||||
// RegisterDialect register database dialect
|
||||
func RegisterDialect(dbName schemas.DBType, dialectFunc func() Dialect) {
|
||||
if dialectFunc == nil {
|
||||
panic("core: Register dialect is nil")
|
||||
}
|
||||
dialects[strings.ToLower(string(dbName))] = dialectFunc // !nashtsai! allow override dialect
|
||||
}
|
||||
|
||||
// QueryDialect query if registered database dialect
|
||||
func QueryDialect(dbName schemas.DBType) Dialect {
|
||||
if d, ok := dialects[strings.ToLower(string(dbName))]; ok {
|
||||
return d()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func regDrvsNDialects() bool {
|
||||
providedDrvsNDialects := map[string]struct {
|
||||
dbType schemas.DBType
|
||||
getDriver func() Driver
|
||||
getDialect func() Dialect
|
||||
}{
|
||||
"mssql": {"mssql", func() Driver { return &odbcDriver{} }, func() Dialect { return &mssql{} }},
|
||||
"odbc": {"mssql", func() Driver { return &odbcDriver{} }, func() Dialect { return &mssql{} }}, // !nashtsai! TODO change this when supporting MS Access
|
||||
"mysql": {"mysql", func() Driver { return &mysqlDriver{} }, func() Dialect { return &mysql{} }},
|
||||
"mymysql": {"mysql", func() Driver { return &mymysqlDriver{} }, func() Dialect { return &mysql{} }},
|
||||
"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{} }},
|
||||
"oci8": {"oracle", func() Driver { return &oci8Driver{} }, func() Dialect { return &oracle{} }},
|
||||
"goracle": {"oracle", func() Driver { return &goracleDriver{} }, func() Dialect { return &oracle{} }},
|
||||
}
|
||||
|
||||
for driverName, v := range providedDrvsNDialects {
|
||||
if driver := QueryDriver(driverName); driver == nil {
|
||||
RegisterDriver(driverName, v.getDriver())
|
||||
RegisterDialect(v.dbType, v.getDialect)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func init() {
|
||||
regDrvsNDialects()
|
||||
}
|
||||
|
||||
// ColumnString generate column description string according dialect
|
||||
func ColumnString(dialect Dialect, col *schemas.Column, includePrimaryKey bool) (string, error) {
|
||||
bd := strings.Builder{}
|
||||
|
||||
if err := dialect.Quoter().QuoteTo(&bd, col.Name); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if err := bd.WriteByte(' '); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if _, err := bd.WriteString(dialect.SQLType(col)); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if err := bd.WriteByte(' '); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if includePrimaryKey && col.IsPrimaryKey {
|
||||
if _, err := bd.WriteString("PRIMARY KEY "); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if col.IsAutoIncrement {
|
||||
if _, err := bd.WriteString(dialect.AutoIncrStr()); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err := bd.WriteByte(' '); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if col.Default != "" {
|
||||
if _, err := bd.WriteString("DEFAULT "); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if _, err := bd.WriteString(col.Default); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err := bd.WriteByte(' '); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
if col.Nullable {
|
||||
if _, err := bd.WriteString("NULL "); err != nil {
|
||||
return "", err
|
||||
}
|
||||
} else {
|
||||
if _, err := bd.WriteString("NOT NULL "); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
return bd.String(), nil
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
// Copyright 2019 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package dialects
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type Driver interface {
|
||||
Parse(string, string) (*URI, error)
|
||||
}
|
||||
|
||||
var (
|
||||
drivers = map[string]Driver{}
|
||||
)
|
||||
|
||||
func RegisterDriver(driverName string, driver Driver) {
|
||||
if driver == nil {
|
||||
panic("core: Register driver is nil")
|
||||
}
|
||||
if _, dup := drivers[driverName]; dup {
|
||||
panic("core: Register called twice for driver " + driverName)
|
||||
}
|
||||
drivers[driverName] = driver
|
||||
}
|
||||
|
||||
func QueryDriver(driverName string) Driver {
|
||||
return drivers[driverName]
|
||||
}
|
||||
|
||||
func RegisteredDriverSize() int {
|
||||
return len(drivers)
|
||||
}
|
||||
|
||||
// OpenDialect opens a dialect via driver name and connection string
|
||||
func OpenDialect(driverName, connstr string) (Dialect, error) {
|
||||
driver := QueryDriver(driverName)
|
||||
if driver == nil {
|
||||
return nil, fmt.Errorf("Unsupported driver name: %v", driverName)
|
||||
}
|
||||
|
||||
uri, err := driver.Parse(driverName, connstr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dialect := QueryDialect(uri.DBType)
|
||||
if dialect == nil {
|
||||
return nil, fmt.Errorf("Unsupported dialect type: %v", uri.DBType)
|
||||
}
|
||||
|
||||
dialect.Init(uri)
|
||||
|
||||
return dialect, nil
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
// Copyright 2019 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package dialects
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Filter is an interface to filter SQL
|
||||
type Filter interface {
|
||||
Do(sql string) string
|
||||
}
|
||||
|
||||
// SeqFilter filter SQL replace ?, ? ... to $1, $2 ...
|
||||
type SeqFilter struct {
|
||||
Prefix string
|
||||
Start int
|
||||
}
|
||||
|
||||
func convertQuestionMark(sql, prefix string, start int) string {
|
||||
var buf strings.Builder
|
||||
var beginSingleQuote bool
|
||||
var index = start
|
||||
for _, c := range sql {
|
||||
if !beginSingleQuote && c == '?' {
|
||||
buf.WriteString(fmt.Sprintf("%s%v", prefix, index))
|
||||
index++
|
||||
} else {
|
||||
if c == '\'' {
|
||||
beginSingleQuote = !beginSingleQuote
|
||||
}
|
||||
buf.WriteRune(c)
|
||||
}
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func (s *SeqFilter) Do(sql string) string {
|
||||
return convertQuestionMark(sql, s.Prefix, s.Start)
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package dialects
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSeqFilter(t *testing.T) {
|
||||
var kases = map[string]string{
|
||||
"SELECT * FROM TABLE1 WHERE a=? AND b=?": "SELECT * FROM TABLE1 WHERE a=$1 AND b=$2",
|
||||
"SELECT 1, '???', '2006-01-02 15:04:05' FROM TABLE1 WHERE a=? AND b=?": "SELECT 1, '???', '2006-01-02 15:04:05' FROM TABLE1 WHERE a=$1 AND b=$2",
|
||||
"select '1''?' from issue": "select '1''?' from issue",
|
||||
"select '1\\??' from issue": "select '1\\??' from issue",
|
||||
"select '1\\\\',? from issue": "select '1\\\\',$1 from issue",
|
||||
"select '1\\''?',? from issue": "select '1\\''?',$1 from issue",
|
||||
}
|
||||
for sql, result := range kases {
|
||||
assert.EqualValues(t, result, convertQuestionMark(sql, "$", 1))
|
||||
}
|
||||
}
|
||||
|
|
@ -2,16 +2,18 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
package dialects
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"xorm.io/core"
|
||||
"xorm.io/xorm/core"
|
||||
"xorm.io/xorm/schemas"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -202,67 +204,74 @@ var (
|
|||
"EXIT": true,
|
||||
"PROC": true,
|
||||
}
|
||||
|
||||
mssqlQuoter = schemas.Quoter{
|
||||
Prefix: '[',
|
||||
Suffix: ']',
|
||||
IsReserved: schemas.AlwaysReserve,
|
||||
}
|
||||
)
|
||||
|
||||
type mssql struct {
|
||||
core.Base
|
||||
Base
|
||||
}
|
||||
|
||||
func (db *mssql) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error {
|
||||
return db.Base.Init(d, db, uri, drivername, dataSourceName)
|
||||
func (db *mssql) Init(uri *URI) error {
|
||||
db.quoter = mssqlQuoter
|
||||
return db.Base.Init(db, uri)
|
||||
}
|
||||
|
||||
func (db *mssql) SqlType(c *core.Column) string {
|
||||
func (db *mssql) SQLType(c *schemas.Column) string {
|
||||
var res string
|
||||
switch t := c.SQLType.Name; t {
|
||||
case core.Bool:
|
||||
res = core.Bit
|
||||
case schemas.Bool:
|
||||
res = schemas.Bit
|
||||
if strings.EqualFold(c.Default, "true") {
|
||||
c.Default = "1"
|
||||
} else if strings.EqualFold(c.Default, "false") {
|
||||
c.Default = "0"
|
||||
}
|
||||
case core.Serial:
|
||||
case schemas.Serial:
|
||||
c.IsAutoIncrement = true
|
||||
c.IsPrimaryKey = true
|
||||
c.Nullable = false
|
||||
res = core.Int
|
||||
case core.BigSerial:
|
||||
res = schemas.Int
|
||||
case schemas.BigSerial:
|
||||
c.IsAutoIncrement = true
|
||||
c.IsPrimaryKey = true
|
||||
c.Nullable = false
|
||||
res = core.BigInt
|
||||
case core.Bytea, core.Blob, core.Binary, core.TinyBlob, core.MediumBlob, core.LongBlob:
|
||||
res = core.VarBinary
|
||||
res = schemas.BigInt
|
||||
case schemas.Bytea, schemas.Blob, schemas.Binary, schemas.TinyBlob, schemas.MediumBlob, schemas.LongBlob:
|
||||
res = schemas.VarBinary
|
||||
if c.Length == 0 {
|
||||
c.Length = 50
|
||||
}
|
||||
case core.TimeStamp:
|
||||
res = core.DateTime
|
||||
case core.TimeStampz:
|
||||
case schemas.TimeStamp:
|
||||
res = schemas.DateTime
|
||||
case schemas.TimeStampz:
|
||||
res = "DATETIMEOFFSET"
|
||||
c.Length = 7
|
||||
case core.MediumInt:
|
||||
res = core.Int
|
||||
case core.Text, core.MediumText, core.TinyText, core.LongText, core.Json:
|
||||
res = core.Varchar + "(MAX)"
|
||||
case core.Double:
|
||||
res = core.Real
|
||||
case core.Uuid:
|
||||
res = core.Varchar
|
||||
case schemas.MediumInt:
|
||||
res = schemas.Int
|
||||
case schemas.Text, schemas.MediumText, schemas.TinyText, schemas.LongText, schemas.Json:
|
||||
res = schemas.Varchar + "(MAX)"
|
||||
case schemas.Double:
|
||||
res = schemas.Real
|
||||
case schemas.Uuid:
|
||||
res = schemas.Varchar
|
||||
c.Length = 40
|
||||
case core.TinyInt:
|
||||
res = core.TinyInt
|
||||
case schemas.TinyInt:
|
||||
res = schemas.TinyInt
|
||||
c.Length = 0
|
||||
case core.BigInt:
|
||||
res = core.BigInt
|
||||
case schemas.BigInt:
|
||||
res = schemas.BigInt
|
||||
c.Length = 0
|
||||
default:
|
||||
res = t
|
||||
}
|
||||
|
||||
if res == core.Int {
|
||||
return core.Int
|
||||
if res == schemas.Int {
|
||||
return schemas.Int
|
||||
}
|
||||
|
||||
hasLen1 := (c.Length > 0)
|
||||
|
|
@ -276,88 +285,78 @@ func (db *mssql) SqlType(c *core.Column) string {
|
|||
return res
|
||||
}
|
||||
|
||||
func (db *mssql) SupportInsertMany() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (db *mssql) IsReserved(name string) bool {
|
||||
_, ok := mssqlReservedWords[name]
|
||||
_, ok := mssqlReservedWords[strings.ToUpper(name)]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (db *mssql) Quote(name string) string {
|
||||
return "\"" + name + "\""
|
||||
}
|
||||
|
||||
func (db *mssql) SupportEngine() bool {
|
||||
return false
|
||||
func (db *mssql) SetQuotePolicy(quotePolicy QuotePolicy) {
|
||||
switch quotePolicy {
|
||||
case QuotePolicyNone:
|
||||
var q = mssqlQuoter
|
||||
q.IsReserved = schemas.AlwaysNoReserve
|
||||
db.quoter = q
|
||||
case QuotePolicyReserved:
|
||||
var q = mssqlQuoter
|
||||
q.IsReserved = db.IsReserved
|
||||
db.quoter = q
|
||||
case QuotePolicyAlways:
|
||||
fallthrough
|
||||
default:
|
||||
db.quoter = mssqlQuoter
|
||||
}
|
||||
}
|
||||
|
||||
func (db *mssql) AutoIncrStr() string {
|
||||
return "IDENTITY"
|
||||
}
|
||||
|
||||
func (db *mssql) DropTableSql(tableName string) string {
|
||||
func (db *mssql) DropTableSQL(tableName string) (string, bool) {
|
||||
return fmt.Sprintf("IF EXISTS (SELECT * FROM sysobjects WHERE id = "+
|
||||
"object_id(N'%s') and OBJECTPROPERTY(id, N'IsUserTable') = 1) "+
|
||||
"DROP TABLE \"%s\"", tableName, tableName)
|
||||
"DROP TABLE \"%s\"", tableName, tableName), true
|
||||
}
|
||||
|
||||
func (db *mssql) SupportCharset() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (db *mssql) IndexOnTable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (db *mssql) IndexCheckSql(tableName, idxName string) (string, []interface{}) {
|
||||
func (db *mssql) IndexCheckSQL(tableName, idxName string) (string, []interface{}) {
|
||||
args := []interface{}{idxName}
|
||||
sql := "select name from sysindexes where id=object_id('" + tableName + "') and name=?"
|
||||
return sql, args
|
||||
}
|
||||
|
||||
/*func (db *mssql) ColumnCheckSql(tableName, colName string) (string, []interface{}) {
|
||||
args := []interface{}{tableName, colName}
|
||||
sql := `SELECT "COLUMN_NAME" FROM "INFORMATION_SCHEMA"."COLUMNS" WHERE "TABLE_NAME" = ? AND "COLUMN_NAME" = ?`
|
||||
return sql, args
|
||||
}*/
|
||||
|
||||
func (db *mssql) IsColumnExist(tableName, colName string) (bool, error) {
|
||||
func (db *mssql) IsColumnExist(queryer core.Queryer, ctx context.Context, tableName, colName string) (bool, error) {
|
||||
query := `SELECT "COLUMN_NAME" FROM "INFORMATION_SCHEMA"."COLUMNS" WHERE "TABLE_NAME" = ? AND "COLUMN_NAME" = ?`
|
||||
|
||||
return db.HasRecords(query, tableName, colName)
|
||||
return db.HasRecords(queryer, ctx, query, tableName, colName)
|
||||
}
|
||||
|
||||
func (db *mssql) TableCheckSql(tableName string) (string, []interface{}) {
|
||||
args := []interface{}{}
|
||||
func (db *mssql) IsTableExist(queryer core.Queryer, ctx context.Context, tableName string) (bool, error) {
|
||||
sql := "select * from sysobjects where id = object_id(N'" + tableName + "') and OBJECTPROPERTY(id, N'IsUserTable') = 1"
|
||||
return sql, args
|
||||
return db.HasRecords(queryer, ctx, sql)
|
||||
}
|
||||
|
||||
func (db *mssql) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
|
||||
func (db *mssql) GetColumns(queryer core.Queryer, ctx context.Context, tableName string) ([]string, map[string]*schemas.Column, error) {
|
||||
args := []interface{}{}
|
||||
s := `select a.name as name, b.name as ctype,a.max_length,a.precision,a.scale,a.is_nullable as nullable,
|
||||
"default_is_null" = (CASE WHEN c.text is null THEN 1 ELSE 0 END),
|
||||
replace(replace(isnull(c.text,''),'(',''),')','') as vdefault,
|
||||
ISNULL(i.is_primary_key, 0), a.is_identity as is_identity
|
||||
ISNULL(p.is_primary_key, 0), a.is_identity as is_identity
|
||||
from sys.columns a
|
||||
left join sys.types b on a.user_type_id=b.user_type_id
|
||||
left join sys.syscomments c on a.default_object_id=c.id
|
||||
LEFT OUTER JOIN
|
||||
sys.index_columns ic ON ic.object_id = a.object_id AND ic.column_id = a.column_id
|
||||
LEFT OUTER JOIN
|
||||
sys.indexes i ON ic.object_id = i.object_id AND ic.index_id = i.index_id
|
||||
LEFT OUTER JOIN (SELECT i.object_id, ic.column_id, i.is_primary_key
|
||||
FROM sys.indexes i
|
||||
LEFT JOIN sys.index_columns ic ON ic.object_id = i.object_id AND ic.index_id = i.index_id
|
||||
WHERE i.is_primary_key = 1
|
||||
) as p on p.object_id = a.object_id AND p.column_id = a.column_id
|
||||
where a.object_id=object_id('` + tableName + `')`
|
||||
db.LogSQL(s, args)
|
||||
|
||||
rows, err := db.DB().Query(s, args...)
|
||||
rows, err := queryer.QueryContext(ctx, s, args...)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
cols := make(map[string]*core.Column)
|
||||
cols := make(map[string]*schemas.Column)
|
||||
colSeq := make([]string, 0)
|
||||
for rows.Next() {
|
||||
var name, ctype, vdefault string
|
||||
|
|
@ -368,7 +367,7 @@ func (db *mssql) GetColumns(tableName string) ([]string, map[string]*core.Column
|
|||
return nil, nil, err
|
||||
}
|
||||
|
||||
col := new(core.Column)
|
||||
col := new(schemas.Column)
|
||||
col.Indexes = make(map[string]int)
|
||||
col.Name = strings.Trim(name, "` ")
|
||||
col.Nullable = nullable
|
||||
|
|
@ -387,14 +386,14 @@ func (db *mssql) GetColumns(tableName string) ([]string, map[string]*core.Column
|
|||
}
|
||||
switch ct {
|
||||
case "DATETIMEOFFSET":
|
||||
col.SQLType = core.SQLType{Name: core.TimeStampz, DefaultLength: 0, DefaultLength2: 0}
|
||||
col.SQLType = schemas.SQLType{Name: schemas.TimeStampz, DefaultLength: 0, DefaultLength2: 0}
|
||||
case "NVARCHAR":
|
||||
col.SQLType = core.SQLType{Name: core.NVarchar, DefaultLength: 0, DefaultLength2: 0}
|
||||
col.SQLType = schemas.SQLType{Name: schemas.NVarchar, DefaultLength: 0, DefaultLength2: 0}
|
||||
case "IMAGE":
|
||||
col.SQLType = core.SQLType{Name: core.VarBinary, DefaultLength: 0, DefaultLength2: 0}
|
||||
col.SQLType = schemas.SQLType{Name: schemas.VarBinary, DefaultLength: 0, DefaultLength2: 0}
|
||||
default:
|
||||
if _, ok := core.SqlTypes[ct]; ok {
|
||||
col.SQLType = core.SQLType{Name: ct, DefaultLength: 0, DefaultLength2: 0}
|
||||
if _, ok := schemas.SqlTypes[ct]; ok {
|
||||
col.SQLType = schemas.SQLType{Name: ct, DefaultLength: 0, DefaultLength2: 0}
|
||||
} else {
|
||||
return nil, nil, fmt.Errorf("Unknown colType %v for %v - %v", ct, tableName, col.Name)
|
||||
}
|
||||
|
|
@ -406,20 +405,19 @@ func (db *mssql) GetColumns(tableName string) ([]string, map[string]*core.Column
|
|||
return colSeq, cols, nil
|
||||
}
|
||||
|
||||
func (db *mssql) GetTables() ([]*core.Table, error) {
|
||||
func (db *mssql) GetTables(queryer core.Queryer, ctx context.Context) ([]*schemas.Table, error) {
|
||||
args := []interface{}{}
|
||||
s := `select name from sysobjects where xtype ='U'`
|
||||
db.LogSQL(s, args)
|
||||
|
||||
rows, err := db.DB().Query(s, args...)
|
||||
rows, err := queryer.QueryContext(ctx, s, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
tables := make([]*core.Table, 0)
|
||||
tables := make([]*schemas.Table, 0)
|
||||
for rows.Next() {
|
||||
table := core.NewEmptyTable()
|
||||
table := schemas.NewEmptyTable()
|
||||
var name string
|
||||
err = rows.Scan(&name)
|
||||
if err != nil {
|
||||
|
|
@ -431,7 +429,7 @@ func (db *mssql) GetTables() ([]*core.Table, error) {
|
|||
return tables, nil
|
||||
}
|
||||
|
||||
func (db *mssql) GetIndexes(tableName string) (map[string]*core.Index, error) {
|
||||
func (db *mssql) GetIndexes(queryer core.Queryer, ctx context.Context, tableName string) (map[string]*schemas.Index, error) {
|
||||
args := []interface{}{tableName}
|
||||
s := `SELECT
|
||||
IXS.NAME AS [INDEX_NAME],
|
||||
|
|
@ -444,15 +442,14 @@ INNER JOIN SYS.COLUMNS C ON IXS.OBJECT_ID=C.OBJECT_ID
|
|||
AND IXCS.COLUMN_ID=C.COLUMN_ID
|
||||
WHERE IXS.TYPE_DESC='NONCLUSTERED' and OBJECT_NAME(IXS.OBJECT_ID) =?
|
||||
`
|
||||
db.LogSQL(s, args)
|
||||
|
||||
rows, err := db.DB().Query(s, args...)
|
||||
rows, err := queryer.QueryContext(ctx, s, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
indexes := make(map[string]*core.Index, 0)
|
||||
indexes := make(map[string]*schemas.Index, 0)
|
||||
for rows.Next() {
|
||||
var indexType int
|
||||
var indexName, colName, isUnique string
|
||||
|
|
@ -468,9 +465,9 @@ WHERE IXS.TYPE_DESC='NONCLUSTERED' and OBJECT_NAME(IXS.OBJECT_ID) =?
|
|||
}
|
||||
|
||||
if i {
|
||||
indexType = core.UniqueType
|
||||
indexType = schemas.UniqueType
|
||||
} else {
|
||||
indexType = core.IndexType
|
||||
indexType = schemas.IndexType
|
||||
}
|
||||
|
||||
colName = strings.Trim(colName, "` ")
|
||||
|
|
@ -480,10 +477,10 @@ WHERE IXS.TYPE_DESC='NONCLUSTERED' and OBJECT_NAME(IXS.OBJECT_ID) =?
|
|||
isRegular = true
|
||||
}
|
||||
|
||||
var index *core.Index
|
||||
var index *schemas.Index
|
||||
var ok bool
|
||||
if index, ok = indexes[indexName]; !ok {
|
||||
index = new(core.Index)
|
||||
index = new(schemas.Index)
|
||||
index.Type = indexType
|
||||
index.Name = indexName
|
||||
index.IsRegular = isRegular
|
||||
|
|
@ -494,7 +491,7 @@ WHERE IXS.TYPE_DESC='NONCLUSTERED' and OBJECT_NAME(IXS.OBJECT_ID) =?
|
|||
return indexes, nil
|
||||
}
|
||||
|
||||
func (db *mssql) CreateTableSql(table *core.Table, tableName, storeEngine, charset string) string {
|
||||
func (db *mssql) CreateTableSQL(table *schemas.Table, tableName string) ([]string, bool) {
|
||||
var sql string
|
||||
if tableName == "" {
|
||||
tableName = table.Name
|
||||
|
|
@ -502,17 +499,14 @@ func (db *mssql) CreateTableSql(table *core.Table, tableName, storeEngine, chars
|
|||
|
||||
sql = "IF NOT EXISTS (SELECT [name] FROM sys.tables WHERE [name] = '" + tableName + "' ) CREATE TABLE "
|
||||
|
||||
sql += db.Quote(tableName) + " ("
|
||||
sql += db.Quoter().Quote(tableName) + " ("
|
||||
|
||||
pkList := table.PrimaryKeys
|
||||
|
||||
for _, colName := range table.ColumnsSeq() {
|
||||
col := table.GetColumn(colName)
|
||||
if col.IsPrimaryKey && len(pkList) == 1 {
|
||||
sql += col.String(db)
|
||||
} else {
|
||||
sql += col.StringNoPk(db)
|
||||
}
|
||||
s, _ := ColumnString(db, col, col.IsPrimaryKey && len(pkList) == 1)
|
||||
sql += s
|
||||
sql = strings.TrimSpace(sql)
|
||||
sql += ", "
|
||||
}
|
||||
|
|
@ -525,21 +519,21 @@ func (db *mssql) CreateTableSql(table *core.Table, tableName, storeEngine, chars
|
|||
|
||||
sql = sql[:len(sql)-2] + ")"
|
||||
sql += ";"
|
||||
return sql
|
||||
return []string{sql}, true
|
||||
}
|
||||
|
||||
func (db *mssql) ForUpdateSql(query string) string {
|
||||
func (db *mssql) ForUpdateSQL(query string) string {
|
||||
return query
|
||||
}
|
||||
|
||||
func (db *mssql) Filters() []core.Filter {
|
||||
return []core.Filter{&core.IdFilter{}, &core.QuoteFilter{}}
|
||||
func (db *mssql) Filters() []Filter {
|
||||
return []Filter{}
|
||||
}
|
||||
|
||||
type odbcDriver struct {
|
||||
}
|
||||
|
||||
func (p *odbcDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
|
||||
func (p *odbcDriver) Parse(driverName, dataSourceName string) (*URI, error) {
|
||||
var dbName string
|
||||
|
||||
if strings.HasPrefix(dataSourceName, "sqlserver://") {
|
||||
|
|
@ -563,5 +557,5 @@ func (p *odbcDriver) Parse(driverName, dataSourceName string) (*core.Uri, error)
|
|||
if dbName == "" {
|
||||
return nil, errors.New("no db name provided")
|
||||
}
|
||||
return &core.Uri{DbName: dbName, DbType: core.MSSQL}, nil
|
||||
return &URI{DBName: dbName, DBType: schemas.MSSQL}, nil
|
||||
}
|
||||
|
|
@ -2,13 +2,11 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
package dialects
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
func TestParseMSSQL(t *testing.T) {
|
||||
|
|
@ -21,15 +19,15 @@ func TestParseMSSQL(t *testing.T) {
|
|||
{"server=localhost;user id=sa;password=yourStrong(!)Password;database=db", "db", true},
|
||||
}
|
||||
|
||||
driver := core.QueryDriver("mssql")
|
||||
driver := QueryDriver("mssql")
|
||||
|
||||
for _, test := range tests {
|
||||
uri, err := driver.Parse("mssql", test.in)
|
||||
|
||||
if err != nil && test.valid {
|
||||
t.Errorf("%q got unexpected error: %s", test.in, err)
|
||||
} else if err == nil && !reflect.DeepEqual(test.expected, uri.DbName) {
|
||||
t.Errorf("%q got: %#v want: %#v", test.in, uri.DbName, test.expected)
|
||||
} else if err == nil && !reflect.DeepEqual(test.expected, uri.DBName) {
|
||||
t.Errorf("%q got: %#v want: %#v", test.in, uri.DBName, test.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,9 +2,10 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
package dialects
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
|
@ -13,7 +14,8 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"xorm.io/core"
|
||||
"xorm.io/xorm/core"
|
||||
"xorm.io/xorm/schemas"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -159,10 +161,16 @@ var (
|
|||
"YEAR_MONTH": true,
|
||||
"ZEROFILL": true,
|
||||
}
|
||||
|
||||
mysqlQuoter = schemas.Quoter{
|
||||
Prefix: '`',
|
||||
Suffix: '`',
|
||||
IsReserved: schemas.AlwaysReserve,
|
||||
}
|
||||
)
|
||||
|
||||
type mysql struct {
|
||||
core.Base
|
||||
Base
|
||||
net string
|
||||
addr string
|
||||
params map[string]string
|
||||
|
|
@ -175,8 +183,9 @@ type mysql struct {
|
|||
rowFormat string
|
||||
}
|
||||
|
||||
func (db *mysql) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error {
|
||||
return db.Base.Init(d, db, uri, drivername, dataSourceName)
|
||||
func (db *mysql) Init(uri *URI) error {
|
||||
db.quoter = mysqlQuoter
|
||||
return db.Base.Init(db, uri)
|
||||
}
|
||||
|
||||
func (db *mysql) SetParams(params map[string]string) {
|
||||
|
|
@ -199,29 +208,29 @@ func (db *mysql) SetParams(params map[string]string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (db *mysql) SqlType(c *core.Column) string {
|
||||
func (db *mysql) SQLType(c *schemas.Column) string {
|
||||
var res string
|
||||
switch t := c.SQLType.Name; t {
|
||||
case core.Bool:
|
||||
res = core.TinyInt
|
||||
case schemas.Bool:
|
||||
res = schemas.TinyInt
|
||||
c.Length = 1
|
||||
case core.Serial:
|
||||
case schemas.Serial:
|
||||
c.IsAutoIncrement = true
|
||||
c.IsPrimaryKey = true
|
||||
c.Nullable = false
|
||||
res = core.Int
|
||||
case core.BigSerial:
|
||||
res = schemas.Int
|
||||
case schemas.BigSerial:
|
||||
c.IsAutoIncrement = true
|
||||
c.IsPrimaryKey = true
|
||||
c.Nullable = false
|
||||
res = core.BigInt
|
||||
case core.Bytea:
|
||||
res = core.Blob
|
||||
case core.TimeStampz:
|
||||
res = core.Char
|
||||
res = schemas.BigInt
|
||||
case schemas.Bytea:
|
||||
res = schemas.Blob
|
||||
case schemas.TimeStampz:
|
||||
res = schemas.Char
|
||||
c.Length = 64
|
||||
case core.Enum: // mysql enum
|
||||
res = core.Enum
|
||||
case schemas.Enum: // mysql enum
|
||||
res = schemas.Enum
|
||||
res += "("
|
||||
opts := ""
|
||||
for v := range c.EnumOptions {
|
||||
|
|
@ -229,8 +238,8 @@ func (db *mysql) SqlType(c *core.Column) string {
|
|||
}
|
||||
res += strings.TrimLeft(opts, ",")
|
||||
res += ")"
|
||||
case core.Set: // mysql set
|
||||
res = core.Set
|
||||
case schemas.Set: // mysql set
|
||||
res = schemas.Set
|
||||
res += "("
|
||||
opts := ""
|
||||
for v := range c.SetOptions {
|
||||
|
|
@ -238,13 +247,13 @@ func (db *mysql) SqlType(c *core.Column) string {
|
|||
}
|
||||
res += strings.TrimLeft(opts, ",")
|
||||
res += ")"
|
||||
case core.NVarchar:
|
||||
res = core.Varchar
|
||||
case core.Uuid:
|
||||
res = core.Varchar
|
||||
case schemas.NVarchar:
|
||||
res = schemas.Varchar
|
||||
case schemas.Uuid:
|
||||
res = schemas.Varchar
|
||||
c.Length = 40
|
||||
case core.Json:
|
||||
res = core.Text
|
||||
case schemas.Json:
|
||||
res = schemas.Text
|
||||
default:
|
||||
res = t
|
||||
}
|
||||
|
|
@ -252,7 +261,7 @@ func (db *mysql) SqlType(c *core.Column) string {
|
|||
hasLen1 := (c.Length > 0)
|
||||
hasLen2 := (c.Length2 > 0)
|
||||
|
||||
if res == core.BigInt && !hasLen1 && !hasLen2 {
|
||||
if res == schemas.BigInt && !hasLen1 && !hasLen2 {
|
||||
c.Length = 20
|
||||
hasLen1 = true
|
||||
}
|
||||
|
|
@ -265,70 +274,53 @@ func (db *mysql) SqlType(c *core.Column) string {
|
|||
return res
|
||||
}
|
||||
|
||||
func (db *mysql) SupportInsertMany() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (db *mysql) IsReserved(name string) bool {
|
||||
_, ok := mysqlReservedWords[name]
|
||||
_, ok := mysqlReservedWords[strings.ToUpper(name)]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (db *mysql) Quote(name string) string {
|
||||
return "`" + name + "`"
|
||||
}
|
||||
|
||||
func (db *mysql) SupportEngine() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (db *mysql) AutoIncrStr() string {
|
||||
return "AUTO_INCREMENT"
|
||||
}
|
||||
|
||||
func (db *mysql) SupportCharset() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (db *mysql) IndexOnTable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (db *mysql) IndexCheckSql(tableName, idxName string) (string, []interface{}) {
|
||||
args := []interface{}{db.DbName, tableName, idxName}
|
||||
func (db *mysql) IndexCheckSQL(tableName, idxName string) (string, []interface{}) {
|
||||
args := []interface{}{db.uri.DBName, tableName, idxName}
|
||||
sql := "SELECT `INDEX_NAME` FROM `INFORMATION_SCHEMA`.`STATISTICS`"
|
||||
sql += " WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? AND `INDEX_NAME`=?"
|
||||
return sql, args
|
||||
}
|
||||
|
||||
/*func (db *mysql) ColumnCheckSql(tableName, colName string) (string, []interface{}) {
|
||||
args := []interface{}{db.DbName, tableName, colName}
|
||||
sql := "SELECT `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? AND `COLUMN_NAME` = ?"
|
||||
return sql, args
|
||||
}*/
|
||||
|
||||
func (db *mysql) TableCheckSql(tableName string) (string, []interface{}) {
|
||||
args := []interface{}{db.DbName, tableName}
|
||||
func (db *mysql) IsTableExist(queryer core.Queryer, ctx context.Context, tableName string) (bool, error) {
|
||||
sql := "SELECT `TABLE_NAME` from `INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=? and `TABLE_NAME`=?"
|
||||
return sql, args
|
||||
return db.HasRecords(queryer, ctx, sql, db.uri.DBName, tableName)
|
||||
}
|
||||
|
||||
func (db *mysql) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
|
||||
args := []interface{}{db.DbName, tableName}
|
||||
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` = ?"
|
||||
db.LogSQL(s, args)
|
||||
func (db *mysql) AddColumnSQL(tableName string, col *schemas.Column) string {
|
||||
quoter := db.dialect.Quoter()
|
||||
s, _ := ColumnString(db, col, true)
|
||||
sql := fmt.Sprintf("ALTER TABLE %v ADD %v", quoter.Quote(tableName), s)
|
||||
if len(col.Comment) > 0 {
|
||||
sql += " COMMENT '" + col.Comment + "'"
|
||||
}
|
||||
return sql
|
||||
}
|
||||
|
||||
rows, err := db.DB().Query(s, args...)
|
||||
func (db *mysql) GetColumns(queryer core.Queryer, ctx context.Context, tableName string) ([]string, map[string]*schemas.Column, error) {
|
||||
args := []interface{}{db.uri.DBName, tableName}
|
||||
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` = ?" +
|
||||
" ORDER BY `INFORMATION_SCHEMA`.`COLUMNS`.ORDINAL_POSITION"
|
||||
|
||||
rows, err := queryer.QueryContext(ctx, s, args...)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
cols := make(map[string]*core.Column)
|
||||
cols := make(map[string]*schemas.Column)
|
||||
colSeq := make([]string, 0)
|
||||
for rows.Next() {
|
||||
col := new(core.Column)
|
||||
col := new(schemas.Column)
|
||||
col.Indexes = make(map[string]int)
|
||||
|
||||
var columnName, isNullable, colType, colKey, extra, comment string
|
||||
|
|
@ -356,7 +348,7 @@ func (db *mysql) GetColumns(tableName string) ([]string, map[string]*core.Column
|
|||
var len1, len2 int
|
||||
if len(cts) == 2 {
|
||||
idx := strings.Index(cts[1], ")")
|
||||
if colType == core.Enum && cts[1][0] == '\'' { // enum
|
||||
if colType == schemas.Enum && cts[1][0] == '\'' { // enum
|
||||
options := strings.Split(cts[1][0:idx], ",")
|
||||
col.EnumOptions = make(map[string]int)
|
||||
for k, v := range options {
|
||||
|
|
@ -364,7 +356,7 @@ func (db *mysql) GetColumns(tableName string) ([]string, map[string]*core.Column
|
|||
v = strings.Trim(v, "'")
|
||||
col.EnumOptions[v] = k
|
||||
}
|
||||
} else if colType == core.Set && cts[1][0] == '\'' {
|
||||
} else if colType == schemas.Set && cts[1][0] == '\'' {
|
||||
options := strings.Split(cts[1][0:idx], ",")
|
||||
col.SetOptions = make(map[string]int)
|
||||
for k, v := range options {
|
||||
|
|
@ -394,8 +386,8 @@ func (db *mysql) GetColumns(tableName string) ([]string, map[string]*core.Column
|
|||
}
|
||||
col.Length = len1
|
||||
col.Length2 = len2
|
||||
if _, ok := core.SqlTypes[colType]; ok {
|
||||
col.SQLType = core.SQLType{Name: colType, DefaultLength: len1, DefaultLength2: len2}
|
||||
if _, ok := schemas.SqlTypes[colType]; ok {
|
||||
col.SQLType = schemas.SQLType{Name: colType, DefaultLength: len1, DefaultLength2: len2}
|
||||
} else {
|
||||
return nil, nil, fmt.Errorf("Unknown colType %v", colType)
|
||||
}
|
||||
|
|
@ -424,48 +416,65 @@ func (db *mysql) GetColumns(tableName string) ([]string, map[string]*core.Column
|
|||
return colSeq, cols, nil
|
||||
}
|
||||
|
||||
func (db *mysql) GetTables() ([]*core.Table, error) {
|
||||
args := []interface{}{db.DbName}
|
||||
s := "SELECT `TABLE_NAME`, `ENGINE`, `TABLE_ROWS`, `AUTO_INCREMENT`, `TABLE_COMMENT` from " +
|
||||
func (db *mysql) GetTables(queryer core.Queryer, ctx context.Context) ([]*schemas.Table, error) {
|
||||
args := []interface{}{db.uri.DBName}
|
||||
s := "SELECT `TABLE_NAME`, `ENGINE`, `AUTO_INCREMENT`, `TABLE_COMMENT` from " +
|
||||
"`INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=? AND (`ENGINE`='MyISAM' OR `ENGINE` = 'InnoDB' OR `ENGINE` = 'TokuDB')"
|
||||
db.LogSQL(s, args)
|
||||
|
||||
rows, err := db.DB().Query(s, args...)
|
||||
rows, err := queryer.QueryContext(ctx, s, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
tables := make([]*core.Table, 0)
|
||||
tables := make([]*schemas.Table, 0)
|
||||
for rows.Next() {
|
||||
table := core.NewEmptyTable()
|
||||
var name, engine, tableRows, comment string
|
||||
var autoIncr *string
|
||||
err = rows.Scan(&name, &engine, &tableRows, &autoIncr, &comment)
|
||||
table := schemas.NewEmptyTable()
|
||||
var name, engine string
|
||||
var autoIncr, comment *string
|
||||
err = rows.Scan(&name, &engine, &autoIncr, &comment)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
table.Name = name
|
||||
table.Comment = comment
|
||||
if comment != nil {
|
||||
table.Comment = *comment
|
||||
}
|
||||
table.StoreEngine = engine
|
||||
tables = append(tables, table)
|
||||
}
|
||||
return tables, nil
|
||||
}
|
||||
|
||||
func (db *mysql) GetIndexes(tableName string) (map[string]*core.Index, error) {
|
||||
args := []interface{}{db.DbName, tableName}
|
||||
s := "SELECT `INDEX_NAME`, `NON_UNIQUE`, `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?"
|
||||
db.LogSQL(s, args)
|
||||
func (db *mysql) SetQuotePolicy(quotePolicy QuotePolicy) {
|
||||
switch quotePolicy {
|
||||
case QuotePolicyNone:
|
||||
var q = mysqlQuoter
|
||||
q.IsReserved = schemas.AlwaysNoReserve
|
||||
db.quoter = q
|
||||
case QuotePolicyReserved:
|
||||
var q = mysqlQuoter
|
||||
q.IsReserved = db.IsReserved
|
||||
db.quoter = q
|
||||
case QuotePolicyAlways:
|
||||
fallthrough
|
||||
default:
|
||||
db.quoter = mysqlQuoter
|
||||
}
|
||||
}
|
||||
|
||||
rows, err := db.DB().Query(s, args...)
|
||||
func (db *mysql) GetIndexes(queryer core.Queryer, ctx context.Context, tableName string) (map[string]*schemas.Index, error) {
|
||||
args := []interface{}{db.uri.DBName, tableName}
|
||||
s := "SELECT `INDEX_NAME`, `NON_UNIQUE`, `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?"
|
||||
|
||||
rows, err := queryer.QueryContext(ctx, s, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
indexes := make(map[string]*core.Index, 0)
|
||||
indexes := make(map[string]*schemas.Index, 0)
|
||||
for rows.Next() {
|
||||
var indexType int
|
||||
var indexName, colName, nonUnique string
|
||||
|
|
@ -479,9 +488,9 @@ func (db *mysql) GetIndexes(tableName string) (map[string]*core.Index, error) {
|
|||
}
|
||||
|
||||
if "YES" == nonUnique || nonUnique == "1" {
|
||||
indexType = core.IndexType
|
||||
indexType = schemas.IndexType
|
||||
} else {
|
||||
indexType = core.UniqueType
|
||||
indexType = schemas.UniqueType
|
||||
}
|
||||
|
||||
colName = strings.Trim(colName, "` ")
|
||||
|
|
@ -491,10 +500,10 @@ func (db *mysql) GetIndexes(tableName string) (map[string]*core.Index, error) {
|
|||
isRegular = true
|
||||
}
|
||||
|
||||
var index *core.Index
|
||||
var index *schemas.Index
|
||||
var ok bool
|
||||
if index, ok = indexes[indexName]; !ok {
|
||||
index = new(core.Index)
|
||||
index = new(schemas.Index)
|
||||
index.IsRegular = isRegular
|
||||
index.Type = indexType
|
||||
index.Name = indexName
|
||||
|
|
@ -505,14 +514,15 @@ func (db *mysql) GetIndexes(tableName string) (map[string]*core.Index, error) {
|
|||
return indexes, nil
|
||||
}
|
||||
|
||||
func (db *mysql) CreateTableSql(table *core.Table, tableName, storeEngine, charset string) string {
|
||||
var sql string
|
||||
sql = "CREATE TABLE IF NOT EXISTS "
|
||||
func (db *mysql) CreateTableSQL(table *schemas.Table, tableName string) ([]string, bool) {
|
||||
var sql = "CREATE TABLE IF NOT EXISTS "
|
||||
if tableName == "" {
|
||||
tableName = table.Name
|
||||
}
|
||||
|
||||
sql += db.Quote(tableName)
|
||||
quoter := db.Quoter()
|
||||
|
||||
sql += quoter.Quote(tableName)
|
||||
sql += " ("
|
||||
|
||||
if len(table.ColumnsSeq()) > 0 {
|
||||
|
|
@ -520,11 +530,8 @@ func (db *mysql) CreateTableSql(table *core.Table, tableName, storeEngine, chars
|
|||
|
||||
for _, colName := range table.ColumnsSeq() {
|
||||
col := table.GetColumn(colName)
|
||||
if col.IsPrimaryKey && len(pkList) == 1 {
|
||||
sql += col.String(db)
|
||||
} else {
|
||||
sql += col.StringNoPk(db)
|
||||
}
|
||||
s, _ := ColumnString(db, col, col.IsPrimaryKey && len(pkList) == 1)
|
||||
sql += s
|
||||
sql = strings.TrimSpace(sql)
|
||||
if len(col.Comment) > 0 {
|
||||
sql += " COMMENT '" + col.Comment + "'"
|
||||
|
|
@ -534,7 +541,7 @@ func (db *mysql) CreateTableSql(table *core.Table, tableName, storeEngine, chars
|
|||
|
||||
if len(pkList) > 1 {
|
||||
sql += "PRIMARY KEY ( "
|
||||
sql += db.Quote(strings.Join(pkList, db.Quote(",")))
|
||||
sql += quoter.Join(pkList, ",")
|
||||
sql += " ), "
|
||||
}
|
||||
|
||||
|
|
@ -542,10 +549,11 @@ func (db *mysql) CreateTableSql(table *core.Table, tableName, storeEngine, chars
|
|||
}
|
||||
sql += ")"
|
||||
|
||||
if storeEngine != "" {
|
||||
sql += " ENGINE=" + storeEngine
|
||||
if table.StoreEngine != "" {
|
||||
sql += " ENGINE=" + table.StoreEngine
|
||||
}
|
||||
|
||||
var charset = table.Charset
|
||||
if len(charset) == 0 {
|
||||
charset = db.URI().Charset
|
||||
}
|
||||
|
|
@ -556,18 +564,18 @@ func (db *mysql) CreateTableSql(table *core.Table, tableName, storeEngine, chars
|
|||
if db.rowFormat != "" {
|
||||
sql += " ROW_FORMAT=" + db.rowFormat
|
||||
}
|
||||
return sql
|
||||
return []string{sql}, true
|
||||
}
|
||||
|
||||
func (db *mysql) Filters() []core.Filter {
|
||||
return []core.Filter{&core.IdFilter{}}
|
||||
func (db *mysql) Filters() []Filter {
|
||||
return []Filter{}
|
||||
}
|
||||
|
||||
type mymysqlDriver struct {
|
||||
}
|
||||
|
||||
func (p *mymysqlDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
|
||||
db := &core.Uri{DbType: core.MYSQL}
|
||||
func (p *mymysqlDriver) Parse(driverName, dataSourceName string) (*URI, error) {
|
||||
uri := &URI{DBType: schemas.MYSQL}
|
||||
|
||||
pd := strings.SplitN(dataSourceName, "*", 2)
|
||||
if len(pd) == 2 {
|
||||
|
|
@ -576,9 +584,9 @@ func (p *mymysqlDriver) Parse(driverName, dataSourceName string) (*core.Uri, err
|
|||
if len(p) != 2 {
|
||||
return nil, errors.New("Wrong protocol part of URI")
|
||||
}
|
||||
db.Proto = p[0]
|
||||
uri.Proto = p[0]
|
||||
options := strings.Split(p[1], ",")
|
||||
db.Raddr = options[0]
|
||||
uri.Raddr = options[0]
|
||||
for _, o := range options[1:] {
|
||||
kv := strings.SplitN(o, "=", 2)
|
||||
var k, v string
|
||||
|
|
@ -589,13 +597,13 @@ func (p *mymysqlDriver) Parse(driverName, dataSourceName string) (*core.Uri, err
|
|||
}
|
||||
switch k {
|
||||
case "laddr":
|
||||
db.Laddr = v
|
||||
uri.Laddr = v
|
||||
case "timeout":
|
||||
to, err := time.ParseDuration(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
db.Timeout = to
|
||||
uri.Timeout = to
|
||||
default:
|
||||
return nil, errors.New("Unknown option: " + k)
|
||||
}
|
||||
|
|
@ -608,17 +616,17 @@ func (p *mymysqlDriver) Parse(driverName, dataSourceName string) (*core.Uri, err
|
|||
if len(dup) != 3 {
|
||||
return nil, errors.New("Wrong database part of URI")
|
||||
}
|
||||
db.DbName = dup[0]
|
||||
db.User = dup[1]
|
||||
db.Passwd = dup[2]
|
||||
uri.DBName = dup[0]
|
||||
uri.User = dup[1]
|
||||
uri.Passwd = dup[2]
|
||||
|
||||
return db, nil
|
||||
return uri, nil
|
||||
}
|
||||
|
||||
type mysqlDriver struct {
|
||||
}
|
||||
|
||||
func (p *mysqlDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
|
||||
func (p *mysqlDriver) Parse(driverName, dataSourceName string) (*URI, error) {
|
||||
dsnPattern := regexp.MustCompile(
|
||||
`^(?:(?P<user>.*?)(?::(?P<passwd>.*))?@)?` + // [user[:password]@]
|
||||
`(?:(?P<net>[^\(]*)(?:\((?P<addr>[^\)]*)\))?)?` + // [net[(addr)]]
|
||||
|
|
@ -628,12 +636,12 @@ func (p *mysqlDriver) Parse(driverName, dataSourceName string) (*core.Uri, error
|
|||
// tlsConfigRegister := make(map[string]*tls.Config)
|
||||
names := dsnPattern.SubexpNames()
|
||||
|
||||
uri := &core.Uri{DbType: core.MYSQL}
|
||||
uri := &URI{DBType: schemas.MYSQL}
|
||||
|
||||
for i, match := range matches {
|
||||
switch names[i] {
|
||||
case "dbname":
|
||||
uri.DbName = match
|
||||
uri.DBName = match
|
||||
case "params":
|
||||
if len(match) > 0 {
|
||||
kvs := strings.Split(match, "&")
|
||||
|
|
@ -2,16 +2,18 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
package dialects
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"xorm.io/core"
|
||||
"xorm.io/xorm/core"
|
||||
"xorm.io/xorm/schemas"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -496,32 +498,39 @@ var (
|
|||
"YEAR": true,
|
||||
"ZONE": true,
|
||||
}
|
||||
|
||||
oracleQuoter = schemas.Quoter{
|
||||
Prefix: '"',
|
||||
Suffix: '"',
|
||||
IsReserved: schemas.AlwaysReserve,
|
||||
}
|
||||
)
|
||||
|
||||
type oracle struct {
|
||||
core.Base
|
||||
Base
|
||||
}
|
||||
|
||||
func (db *oracle) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error {
|
||||
return db.Base.Init(d, db, uri, drivername, dataSourceName)
|
||||
func (db *oracle) Init(uri *URI) error {
|
||||
db.quoter = oracleQuoter
|
||||
return db.Base.Init(db, uri)
|
||||
}
|
||||
|
||||
func (db *oracle) SqlType(c *core.Column) string {
|
||||
func (db *oracle) SQLType(c *schemas.Column) string {
|
||||
var res string
|
||||
switch t := c.SQLType.Name; t {
|
||||
case core.Bit, core.TinyInt, core.SmallInt, core.MediumInt, core.Int, core.Integer, core.BigInt, core.Bool, core.Serial, core.BigSerial:
|
||||
case schemas.Bit, schemas.TinyInt, schemas.SmallInt, schemas.MediumInt, schemas.Int, schemas.Integer, schemas.BigInt, schemas.Bool, schemas.Serial, schemas.BigSerial:
|
||||
res = "NUMBER"
|
||||
case core.Binary, core.VarBinary, core.Blob, core.TinyBlob, core.MediumBlob, core.LongBlob, core.Bytea:
|
||||
return core.Blob
|
||||
case core.Time, core.DateTime, core.TimeStamp:
|
||||
res = core.TimeStamp
|
||||
case core.TimeStampz:
|
||||
case schemas.Binary, schemas.VarBinary, schemas.Blob, schemas.TinyBlob, schemas.MediumBlob, schemas.LongBlob, schemas.Bytea:
|
||||
return schemas.Blob
|
||||
case schemas.Time, schemas.DateTime, schemas.TimeStamp:
|
||||
res = schemas.TimeStamp
|
||||
case schemas.TimeStampz:
|
||||
res = "TIMESTAMP WITH TIME ZONE"
|
||||
case core.Float, core.Double, core.Numeric, core.Decimal:
|
||||
case schemas.Float, schemas.Double, schemas.Numeric, schemas.Decimal:
|
||||
res = "NUMBER"
|
||||
case core.Text, core.MediumText, core.LongText, core.Json:
|
||||
case schemas.Text, schemas.MediumText, schemas.LongText, schemas.Json:
|
||||
res = "CLOB"
|
||||
case core.Char, core.Varchar, core.TinyText:
|
||||
case schemas.Char, schemas.Varchar, schemas.TinyText:
|
||||
res = "VARCHAR2"
|
||||
default:
|
||||
res = t
|
||||
|
|
@ -542,47 +551,23 @@ func (db *oracle) AutoIncrStr() string {
|
|||
return "AUTO_INCREMENT"
|
||||
}
|
||||
|
||||
func (db *oracle) SupportInsertMany() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (db *oracle) IsReserved(name string) bool {
|
||||
_, ok := oracleReservedWords[name]
|
||||
_, ok := oracleReservedWords[strings.ToUpper(name)]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (db *oracle) Quote(name string) string {
|
||||
return "[" + name + "]"
|
||||
func (db *oracle) DropTableSQL(tableName string) (string, bool) {
|
||||
return fmt.Sprintf("DROP TABLE `%s`", tableName), false
|
||||
}
|
||||
|
||||
func (db *oracle) SupportEngine() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (db *oracle) SupportCharset() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (db *oracle) SupportDropIfExists() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (db *oracle) IndexOnTable() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (db *oracle) DropTableSql(tableName string) string {
|
||||
return fmt.Sprintf("DROP TABLE `%s`", tableName)
|
||||
}
|
||||
|
||||
func (db *oracle) CreateTableSql(table *core.Table, tableName, storeEngine, charset string) string {
|
||||
var sql string
|
||||
sql = "CREATE TABLE "
|
||||
func (db *oracle) CreateTableSQL(table *schemas.Table, tableName string) ([]string, bool) {
|
||||
var sql = "CREATE TABLE "
|
||||
if tableName == "" {
|
||||
tableName = table.Name
|
||||
}
|
||||
|
||||
sql += db.Quote(tableName) + " ("
|
||||
quoter := db.Quoter()
|
||||
sql += quoter.Quote(tableName) + " ("
|
||||
|
||||
pkList := table.PrimaryKeys
|
||||
|
||||
|
|
@ -591,7 +576,8 @@ func (db *oracle) CreateTableSql(table *core.Table, tableName, storeEngine, char
|
|||
/*if col.IsPrimaryKey && len(pkList) == 1 {
|
||||
sql += col.String(b.dialect)
|
||||
} else {*/
|
||||
sql += col.StringNoPk(db)
|
||||
s, _ := ColumnString(db, col, false)
|
||||
sql += s
|
||||
// }
|
||||
sql = strings.TrimSpace(sql)
|
||||
sql += ", "
|
||||
|
|
@ -599,97 +585,63 @@ func (db *oracle) CreateTableSql(table *core.Table, tableName, storeEngine, char
|
|||
|
||||
if len(pkList) > 0 {
|
||||
sql += "PRIMARY KEY ( "
|
||||
sql += db.Quote(strings.Join(pkList, db.Quote(",")))
|
||||
sql += quoter.Join(pkList, ",")
|
||||
sql += " ), "
|
||||
}
|
||||
|
||||
sql = sql[:len(sql)-2] + ")"
|
||||
if db.SupportEngine() && storeEngine != "" {
|
||||
sql += " ENGINE=" + storeEngine
|
||||
}
|
||||
if db.SupportCharset() {
|
||||
if len(charset) == 0 {
|
||||
charset = db.URI().Charset
|
||||
}
|
||||
if len(charset) > 0 {
|
||||
sql += " DEFAULT CHARSET " + charset
|
||||
}
|
||||
}
|
||||
return sql
|
||||
return []string{sql}, false
|
||||
}
|
||||
|
||||
func (db *oracle) IndexCheckSql(tableName, idxName string) (string, []interface{}) {
|
||||
func (db *oracle) SetQuotePolicy(quotePolicy QuotePolicy) {
|
||||
switch quotePolicy {
|
||||
case QuotePolicyNone:
|
||||
var q = oracleQuoter
|
||||
q.IsReserved = schemas.AlwaysNoReserve
|
||||
db.quoter = q
|
||||
case QuotePolicyReserved:
|
||||
var q = oracleQuoter
|
||||
q.IsReserved = db.IsReserved
|
||||
db.quoter = q
|
||||
case QuotePolicyAlways:
|
||||
fallthrough
|
||||
default:
|
||||
db.quoter = oracleQuoter
|
||||
}
|
||||
}
|
||||
|
||||
func (db *oracle) IndexCheckSQL(tableName, idxName string) (string, []interface{}) {
|
||||
args := []interface{}{tableName, idxName}
|
||||
return `SELECT INDEX_NAME FROM USER_INDEXES ` +
|
||||
`WHERE TABLE_NAME = :1 AND INDEX_NAME = :2`, args
|
||||
}
|
||||
|
||||
func (db *oracle) TableCheckSql(tableName string) (string, []interface{}) {
|
||||
args := []interface{}{tableName}
|
||||
return `SELECT table_name FROM user_tables WHERE table_name = :1`, args
|
||||
func (db *oracle) IsTableExist(queryer core.Queryer, ctx context.Context, tableName string) (bool, error) {
|
||||
return db.HasRecords(queryer, ctx, `SELECT table_name FROM user_tables WHERE table_name = :1`, tableName)
|
||||
}
|
||||
|
||||
func (db *oracle) MustDropTable(tableName string) error {
|
||||
sql, args := db.TableCheckSql(tableName)
|
||||
db.LogSQL(sql, args)
|
||||
|
||||
rows, err := db.DB().Query(sql, args...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
if !rows.Next() {
|
||||
return nil
|
||||
}
|
||||
|
||||
sql = "Drop Table \"" + tableName + "\""
|
||||
db.LogSQL(sql, args)
|
||||
|
||||
_, err = db.DB().Exec(sql)
|
||||
return err
|
||||
}
|
||||
|
||||
/*func (db *oracle) ColumnCheckSql(tableName, colName string) (string, []interface{}) {
|
||||
args := []interface{}{strings.ToUpper(tableName), strings.ToUpper(colName)}
|
||||
return "SELECT column_name FROM USER_TAB_COLUMNS WHERE table_name = ?" +
|
||||
" AND column_name = ?", args
|
||||
}*/
|
||||
|
||||
func (db *oracle) IsColumnExist(tableName, colName string) (bool, error) {
|
||||
func (db *oracle) IsColumnExist(queryer core.Queryer, ctx context.Context, tableName, colName string) (bool, error) {
|
||||
args := []interface{}{tableName, colName}
|
||||
query := "SELECT column_name FROM USER_TAB_COLUMNS WHERE table_name = :1" +
|
||||
" AND column_name = :2"
|
||||
db.LogSQL(query, args)
|
||||
|
||||
rows, err := db.DB().Query(query, args...)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
if rows.Next() {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
return db.HasRecords(queryer, ctx, query, args...)
|
||||
}
|
||||
|
||||
func (db *oracle) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
|
||||
func (db *oracle) GetColumns(queryer core.Queryer, ctx context.Context, tableName string) ([]string, map[string]*schemas.Column, error) {
|
||||
args := []interface{}{tableName}
|
||||
s := "SELECT column_name,data_default,data_type,data_length,data_precision,data_scale," +
|
||||
"nullable FROM USER_TAB_COLUMNS WHERE table_name = :1"
|
||||
db.LogSQL(s, args)
|
||||
|
||||
rows, err := db.DB().Query(s, args...)
|
||||
rows, err := queryer.QueryContext(ctx, s, args...)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
cols := make(map[string]*core.Column)
|
||||
cols := make(map[string]*schemas.Column)
|
||||
colSeq := make([]string, 0)
|
||||
for rows.Next() {
|
||||
col := new(core.Column)
|
||||
col := new(schemas.Column)
|
||||
col.Indexes = make(map[string]int)
|
||||
|
||||
var colName, colDefault, nullable, dataType, dataPrecision, dataScale *string
|
||||
|
|
@ -731,30 +683,30 @@ func (db *oracle) GetColumns(tableName string) ([]string, map[string]*core.Colum
|
|||
|
||||
switch dt {
|
||||
case "VARCHAR2":
|
||||
col.SQLType = core.SQLType{Name: core.Varchar, DefaultLength: len1, DefaultLength2: len2}
|
||||
col.SQLType = schemas.SQLType{Name: schemas.Varchar, DefaultLength: len1, DefaultLength2: len2}
|
||||
case "NVARCHAR2":
|
||||
col.SQLType = core.SQLType{Name: core.NVarchar, DefaultLength: len1, DefaultLength2: len2}
|
||||
col.SQLType = schemas.SQLType{Name: schemas.NVarchar, DefaultLength: len1, DefaultLength2: len2}
|
||||
case "TIMESTAMP WITH TIME ZONE":
|
||||
col.SQLType = core.SQLType{Name: core.TimeStampz, DefaultLength: 0, DefaultLength2: 0}
|
||||
col.SQLType = schemas.SQLType{Name: schemas.TimeStampz, DefaultLength: 0, DefaultLength2: 0}
|
||||
case "NUMBER":
|
||||
col.SQLType = core.SQLType{Name: core.Double, DefaultLength: len1, DefaultLength2: len2}
|
||||
col.SQLType = schemas.SQLType{Name: schemas.Double, DefaultLength: len1, DefaultLength2: len2}
|
||||
case "LONG", "LONG RAW":
|
||||
col.SQLType = core.SQLType{Name: core.Text, DefaultLength: 0, DefaultLength2: 0}
|
||||
col.SQLType = schemas.SQLType{Name: schemas.Text, DefaultLength: 0, DefaultLength2: 0}
|
||||
case "RAW":
|
||||
col.SQLType = core.SQLType{Name: core.Binary, DefaultLength: 0, DefaultLength2: 0}
|
||||
col.SQLType = schemas.SQLType{Name: schemas.Binary, DefaultLength: 0, DefaultLength2: 0}
|
||||
case "ROWID":
|
||||
col.SQLType = core.SQLType{Name: core.Varchar, DefaultLength: 18, DefaultLength2: 0}
|
||||
col.SQLType = schemas.SQLType{Name: schemas.Varchar, DefaultLength: 18, DefaultLength2: 0}
|
||||
case "AQ$_SUBSCRIBERS":
|
||||
ignore = true
|
||||
default:
|
||||
col.SQLType = core.SQLType{Name: strings.ToUpper(dt), DefaultLength: len1, DefaultLength2: len2}
|
||||
col.SQLType = schemas.SQLType{Name: strings.ToUpper(dt), DefaultLength: len1, DefaultLength2: len2}
|
||||
}
|
||||
|
||||
if ignore {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, ok := core.SqlTypes[col.SQLType.Name]; !ok {
|
||||
if _, ok := schemas.SqlTypes[col.SQLType.Name]; !ok {
|
||||
return nil, nil, fmt.Errorf("Unknown colType %v %v", *dataType, col.SQLType)
|
||||
}
|
||||
|
||||
|
|
@ -772,20 +724,19 @@ func (db *oracle) GetColumns(tableName string) ([]string, map[string]*core.Colum
|
|||
return colSeq, cols, nil
|
||||
}
|
||||
|
||||
func (db *oracle) GetTables() ([]*core.Table, error) {
|
||||
func (db *oracle) GetTables(queryer core.Queryer, ctx context.Context) ([]*schemas.Table, error) {
|
||||
args := []interface{}{}
|
||||
s := "SELECT table_name FROM user_tables"
|
||||
db.LogSQL(s, args)
|
||||
|
||||
rows, err := db.DB().Query(s, args...)
|
||||
rows, err := queryer.QueryContext(ctx, s, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
tables := make([]*core.Table, 0)
|
||||
tables := make([]*schemas.Table, 0)
|
||||
for rows.Next() {
|
||||
table := core.NewEmptyTable()
|
||||
table := schemas.NewEmptyTable()
|
||||
err = rows.Scan(&table.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -796,19 +747,18 @@ func (db *oracle) GetTables() ([]*core.Table, error) {
|
|||
return tables, nil
|
||||
}
|
||||
|
||||
func (db *oracle) GetIndexes(tableName string) (map[string]*core.Index, error) {
|
||||
func (db *oracle) GetIndexes(queryer core.Queryer, ctx context.Context, tableName string) (map[string]*schemas.Index, error) {
|
||||
args := []interface{}{tableName}
|
||||
s := "SELECT t.column_name,i.uniqueness,i.index_name FROM user_ind_columns t,user_indexes i " +
|
||||
"WHERE t.index_name = i.index_name and t.table_name = i.table_name and t.table_name =:1"
|
||||
db.LogSQL(s, args)
|
||||
|
||||
rows, err := db.DB().Query(s, args...)
|
||||
rows, err := queryer.QueryContext(ctx, s, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
indexes := make(map[string]*core.Index, 0)
|
||||
indexes := make(map[string]*schemas.Index, 0)
|
||||
for rows.Next() {
|
||||
var indexType int
|
||||
var indexName, colName, uniqueness string
|
||||
|
|
@ -827,15 +777,15 @@ func (db *oracle) GetIndexes(tableName string) (map[string]*core.Index, error) {
|
|||
}
|
||||
|
||||
if uniqueness == "UNIQUE" {
|
||||
indexType = core.UniqueType
|
||||
indexType = schemas.UniqueType
|
||||
} else {
|
||||
indexType = core.IndexType
|
||||
indexType = schemas.IndexType
|
||||
}
|
||||
|
||||
var index *core.Index
|
||||
var index *schemas.Index
|
||||
var ok bool
|
||||
if index, ok = indexes[indexName]; !ok {
|
||||
index = new(core.Index)
|
||||
index = new(schemas.Index)
|
||||
index.Type = indexType
|
||||
index.Name = indexName
|
||||
index.IsRegular = isRegular
|
||||
|
|
@ -846,15 +796,17 @@ func (db *oracle) GetIndexes(tableName string) (map[string]*core.Index, error) {
|
|||
return indexes, nil
|
||||
}
|
||||
|
||||
func (db *oracle) Filters() []core.Filter {
|
||||
return []core.Filter{&core.QuoteFilter{}, &core.SeqFilter{Prefix: ":", Start: 1}, &core.IdFilter{}}
|
||||
func (db *oracle) Filters() []Filter {
|
||||
return []Filter{
|
||||
&SeqFilter{Prefix: ":", Start: 1},
|
||||
}
|
||||
}
|
||||
|
||||
type goracleDriver struct {
|
||||
}
|
||||
|
||||
func (cfg *goracleDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
|
||||
db := &core.Uri{DbType: core.ORACLE}
|
||||
func (cfg *goracleDriver) Parse(driverName, dataSourceName string) (*URI, error) {
|
||||
db := &URI{DBType: schemas.ORACLE}
|
||||
dsnPattern := regexp.MustCompile(
|
||||
`^(?:(?P<user>.*?)(?::(?P<passwd>.*))?@)?` + // [user[:password]@]
|
||||
`(?:(?P<net>[^\(]*)(?:\((?P<addr>[^\)]*)\))?)?` + // [net[(addr)]]
|
||||
|
|
@ -867,10 +819,10 @@ func (cfg *goracleDriver) Parse(driverName, dataSourceName string) (*core.Uri, e
|
|||
for i, match := range matches {
|
||||
switch names[i] {
|
||||
case "dbname":
|
||||
db.DbName = match
|
||||
db.DBName = match
|
||||
}
|
||||
}
|
||||
if db.DbName == "" {
|
||||
if db.DBName == "" {
|
||||
return nil, errors.New("dbname is empty")
|
||||
}
|
||||
return db, nil
|
||||
|
|
@ -881,8 +833,8 @@ type oci8Driver struct {
|
|||
|
||||
// dataSourceName=user/password@ipv4:port/dbname
|
||||
// dataSourceName=user/password@[ipv6]:port/dbname
|
||||
func (p *oci8Driver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
|
||||
db := &core.Uri{DbType: core.ORACLE}
|
||||
func (p *oci8Driver) Parse(driverName, dataSourceName string) (*URI, error) {
|
||||
db := &URI{DBType: schemas.ORACLE}
|
||||
dsnPattern := regexp.MustCompile(
|
||||
`^(?P<user>.*)\/(?P<password>.*)@` + // user:password@
|
||||
`(?P<net>.*)` + // ip:port
|
||||
|
|
@ -892,10 +844,10 @@ func (p *oci8Driver) Parse(driverName, dataSourceName string) (*core.Uri, error)
|
|||
for i, match := range matches {
|
||||
switch names[i] {
|
||||
case "dbname":
|
||||
db.DbName = match
|
||||
db.DBName = match
|
||||
}
|
||||
}
|
||||
if db.DbName == "" {
|
||||
if db.DBName == "" && len(matches) != 0 {
|
||||
return nil, errors.New("dbname is empty")
|
||||
}
|
||||
return db, nil
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package dialects
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParseOracleConnStr(t *testing.T) {
|
||||
tests := []struct {
|
||||
in string
|
||||
expected string
|
||||
valid bool
|
||||
}{
|
||||
{"user/pass@tcp(server:1521)/db", "db", true},
|
||||
{"user/pass@server:1521/db", "db", true},
|
||||
// test for net service name : https://docs.oracle.com/cd/B13789_01/network.101/b10775/glossary.htm#i998113
|
||||
{"user/pass@server:1521", "", true},
|
||||
{"user/pass@", "", false},
|
||||
{"user/pass", "", false},
|
||||
{"", "", false},
|
||||
}
|
||||
driver := QueryDriver("oci8")
|
||||
for _, test := range tests {
|
||||
t.Run(test.in, func(t *testing.T) {
|
||||
driver := driver
|
||||
uri, err := driver.Parse("oci8", test.in)
|
||||
if err != nil && test.valid {
|
||||
t.Errorf("%q got unexpected error: %s", test.in, err)
|
||||
} else if err == nil && !reflect.DeepEqual(test.expected, uri.DBName) {
|
||||
t.Errorf("%q got: %#v want: %#v", test.in, uri.DBName, test.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -2,16 +2,18 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
package dialects
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"xorm.io/core"
|
||||
"xorm.io/xorm/core"
|
||||
"xorm.io/xorm/schemas"
|
||||
)
|
||||
|
||||
// from http://www.postgresql.org/docs/current/static/sql-keywords-appendix.html
|
||||
|
|
@ -765,71 +767,107 @@ var (
|
|||
"ZONE": true,
|
||||
}
|
||||
|
||||
postgresQuoter = schemas.Quoter{
|
||||
Prefix: '"',
|
||||
Suffix: '"',
|
||||
IsReserved: schemas.AlwaysReserve,
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultPostgresSchema default postgres schema
|
||||
DefaultPostgresSchema = "public"
|
||||
)
|
||||
|
||||
const postgresPublicSchema = "public"
|
||||
|
||||
type postgres struct {
|
||||
core.Base
|
||||
Base
|
||||
}
|
||||
|
||||
func (db *postgres) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error {
|
||||
err := db.Base.Init(d, db, uri, drivername, dataSourceName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if db.Schema == "" {
|
||||
db.Schema = DefaultPostgresSchema
|
||||
}
|
||||
return nil
|
||||
func (db *postgres) Init(uri *URI) error {
|
||||
db.quoter = postgresQuoter
|
||||
return db.Base.Init(db, uri)
|
||||
}
|
||||
|
||||
func (db *postgres) SqlType(c *core.Column) string {
|
||||
func (db *postgres) getSchema() string {
|
||||
if db.uri.Schema != "" {
|
||||
return db.uri.Schema
|
||||
}
|
||||
return DefaultPostgresSchema
|
||||
}
|
||||
|
||||
func (db *postgres) needQuote(name string) bool {
|
||||
if db.IsReserved(name) {
|
||||
return true
|
||||
}
|
||||
for _, c := range name {
|
||||
if c >= 'A' && c <= 'Z' {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (db *postgres) SetQuotePolicy(quotePolicy QuotePolicy) {
|
||||
switch quotePolicy {
|
||||
case QuotePolicyNone:
|
||||
var q = postgresQuoter
|
||||
q.IsReserved = schemas.AlwaysNoReserve
|
||||
db.quoter = q
|
||||
case QuotePolicyReserved:
|
||||
var q = postgresQuoter
|
||||
q.IsReserved = db.needQuote
|
||||
db.quoter = q
|
||||
case QuotePolicyAlways:
|
||||
fallthrough
|
||||
default:
|
||||
db.quoter = postgresQuoter
|
||||
}
|
||||
}
|
||||
|
||||
func (db *postgres) SQLType(c *schemas.Column) string {
|
||||
var res string
|
||||
switch t := c.SQLType.Name; t {
|
||||
case core.TinyInt:
|
||||
res = core.SmallInt
|
||||
case schemas.TinyInt:
|
||||
res = schemas.SmallInt
|
||||
return res
|
||||
case core.Bit:
|
||||
res = core.Boolean
|
||||
case schemas.Bit:
|
||||
res = schemas.Boolean
|
||||
return res
|
||||
case core.MediumInt, core.Int, core.Integer:
|
||||
case schemas.MediumInt, schemas.Int, schemas.Integer:
|
||||
if c.IsAutoIncrement {
|
||||
return core.Serial
|
||||
return schemas.Serial
|
||||
}
|
||||
return core.Integer
|
||||
case core.BigInt:
|
||||
return schemas.Integer
|
||||
case schemas.BigInt:
|
||||
if c.IsAutoIncrement {
|
||||
return core.BigSerial
|
||||
return schemas.BigSerial
|
||||
}
|
||||
return core.BigInt
|
||||
case core.Serial, core.BigSerial:
|
||||
return schemas.BigInt
|
||||
case schemas.Serial, schemas.BigSerial:
|
||||
c.IsAutoIncrement = true
|
||||
c.Nullable = false
|
||||
res = t
|
||||
case core.Binary, core.VarBinary:
|
||||
return core.Bytea
|
||||
case core.DateTime:
|
||||
res = core.TimeStamp
|
||||
case core.TimeStampz:
|
||||
case schemas.Binary, schemas.VarBinary:
|
||||
return schemas.Bytea
|
||||
case schemas.DateTime:
|
||||
res = schemas.TimeStamp
|
||||
case schemas.TimeStampz:
|
||||
return "timestamp with time zone"
|
||||
case core.Float:
|
||||
res = core.Real
|
||||
case core.TinyText, core.MediumText, core.LongText:
|
||||
res = core.Text
|
||||
case core.NVarchar:
|
||||
res = core.Varchar
|
||||
case core.Uuid:
|
||||
return core.Uuid
|
||||
case core.Blob, core.TinyBlob, core.MediumBlob, core.LongBlob:
|
||||
return core.Bytea
|
||||
case core.Double:
|
||||
case schemas.Float:
|
||||
res = schemas.Real
|
||||
case schemas.TinyText, schemas.MediumText, schemas.LongText:
|
||||
res = schemas.Text
|
||||
case schemas.NVarchar:
|
||||
res = schemas.Varchar
|
||||
case schemas.Uuid:
|
||||
return schemas.Uuid
|
||||
case schemas.Blob, schemas.TinyBlob, schemas.MediumBlob, schemas.LongBlob:
|
||||
return schemas.Bytea
|
||||
case schemas.Double:
|
||||
return "DOUBLE PRECISION"
|
||||
default:
|
||||
if c.IsAutoIncrement {
|
||||
return core.Serial
|
||||
return schemas.Serial
|
||||
}
|
||||
res = t
|
||||
}
|
||||
|
|
@ -849,99 +887,110 @@ func (db *postgres) SqlType(c *core.Column) string {
|
|||
return res
|
||||
}
|
||||
|
||||
func (db *postgres) SupportInsertMany() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (db *postgres) IsReserved(name string) bool {
|
||||
_, ok := postgresReservedWords[name]
|
||||
_, ok := postgresReservedWords[strings.ToUpper(name)]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (db *postgres) Quote(name string) string {
|
||||
name = strings.Replace(name, ".", `"."`, -1)
|
||||
return "\"" + name + "\""
|
||||
}
|
||||
|
||||
func (db *postgres) AutoIncrStr() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (db *postgres) SupportEngine() bool {
|
||||
return false
|
||||
func (db *postgres) CreateTableSQL(table *schemas.Table, tableName string) ([]string, bool) {
|
||||
var sql string
|
||||
sql = "CREATE TABLE IF NOT EXISTS "
|
||||
if tableName == "" {
|
||||
tableName = table.Name
|
||||
}
|
||||
|
||||
quoter := db.Quoter()
|
||||
sql += quoter.Quote(tableName)
|
||||
sql += " ("
|
||||
|
||||
if len(table.ColumnsSeq()) > 0 {
|
||||
pkList := table.PrimaryKeys
|
||||
|
||||
for _, colName := range table.ColumnsSeq() {
|
||||
col := table.GetColumn(colName)
|
||||
s, _ := ColumnString(db, col, col.IsPrimaryKey && len(pkList) == 1)
|
||||
sql += s
|
||||
sql = strings.TrimSpace(sql)
|
||||
sql += ", "
|
||||
}
|
||||
|
||||
if len(pkList) > 1 {
|
||||
sql += "PRIMARY KEY ( "
|
||||
sql += quoter.Join(pkList, ",")
|
||||
sql += " ), "
|
||||
}
|
||||
|
||||
sql = sql[:len(sql)-2]
|
||||
}
|
||||
sql += ")"
|
||||
|
||||
return []string{sql}, true
|
||||
}
|
||||
|
||||
func (db *postgres) SupportCharset() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (db *postgres) IndexOnTable() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (db *postgres) IndexCheckSql(tableName, idxName string) (string, []interface{}) {
|
||||
if len(db.Schema) == 0 {
|
||||
func (db *postgres) IndexCheckSQL(tableName, idxName string) (string, []interface{}) {
|
||||
if len(db.getSchema()) == 0 {
|
||||
args := []interface{}{tableName, idxName}
|
||||
return `SELECT indexname FROM pg_indexes WHERE tablename = ? AND indexname = ?`, args
|
||||
}
|
||||
|
||||
args := []interface{}{db.Schema, tableName, idxName}
|
||||
args := []interface{}{db.getSchema(), tableName, idxName}
|
||||
return `SELECT indexname FROM pg_indexes ` +
|
||||
`WHERE schemaname = ? AND tablename = ? AND indexname = ?`, args
|
||||
}
|
||||
|
||||
func (db *postgres) TableCheckSql(tableName string) (string, []interface{}) {
|
||||
if len(db.Schema) == 0 {
|
||||
args := []interface{}{tableName}
|
||||
return `SELECT tablename FROM pg_tables WHERE tablename = ?`, args
|
||||
func (db *postgres) IsTableExist(queryer core.Queryer, ctx context.Context, tableName string) (bool, error) {
|
||||
if len(db.getSchema()) == 0 {
|
||||
return db.HasRecords(queryer, ctx, `SELECT tablename FROM pg_tables WHERE tablename = $1`, tableName)
|
||||
}
|
||||
|
||||
args := []interface{}{db.Schema, tableName}
|
||||
return `SELECT tablename FROM pg_tables WHERE schemaname = ? AND tablename = ?`, args
|
||||
return db.HasRecords(queryer, ctx, `SELECT tablename FROM pg_tables WHERE schemaname = $1 AND tablename = $2`,
|
||||
db.getSchema(), tableName)
|
||||
}
|
||||
|
||||
func (db *postgres) ModifyColumnSql(tableName string, col *core.Column) string {
|
||||
if len(db.Schema) == 0 {
|
||||
func (db *postgres) ModifyColumnSQL(tableName string, col *schemas.Column) string {
|
||||
if len(db.getSchema()) == 0 || strings.Contains(tableName, ".") {
|
||||
return fmt.Sprintf("alter table %s ALTER COLUMN %s TYPE %s",
|
||||
tableName, col.Name, db.SqlType(col))
|
||||
tableName, col.Name, db.SQLType(col))
|
||||
}
|
||||
return fmt.Sprintf("alter table %s.%s ALTER COLUMN %s TYPE %s",
|
||||
db.Schema, tableName, col.Name, db.SqlType(col))
|
||||
db.getSchema(), tableName, col.Name, db.SQLType(col))
|
||||
}
|
||||
|
||||
func (db *postgres) DropIndexSql(tableName string, index *core.Index) string {
|
||||
quote := db.Quote
|
||||
func (db *postgres) DropIndexSQL(tableName string, index *schemas.Index) string {
|
||||
idxName := index.Name
|
||||
|
||||
tableName = strings.Replace(tableName, `"`, "", -1)
|
||||
tableName = strings.Replace(tableName, `.`, "_", -1)
|
||||
tableParts := strings.Split(strings.Replace(tableName, `"`, "", -1), ".")
|
||||
tableName = tableParts[len(tableParts)-1]
|
||||
|
||||
if !strings.HasPrefix(idxName, "UQE_") &&
|
||||
!strings.HasPrefix(idxName, "IDX_") {
|
||||
if index.Type == core.UniqueType {
|
||||
if index.Type == schemas.UniqueType {
|
||||
idxName = fmt.Sprintf("UQE_%v_%v", tableName, index.Name)
|
||||
} else {
|
||||
idxName = fmt.Sprintf("IDX_%v_%v", tableName, index.Name)
|
||||
}
|
||||
}
|
||||
if db.Uri.Schema != "" {
|
||||
idxName = db.Uri.Schema + "." + idxName
|
||||
if db.getSchema() != "" {
|
||||
idxName = db.getSchema() + "." + idxName
|
||||
}
|
||||
return fmt.Sprintf("DROP INDEX %v", quote(idxName))
|
||||
return fmt.Sprintf("DROP INDEX %v", db.Quoter().Quote(idxName))
|
||||
}
|
||||
|
||||
func (db *postgres) IsColumnExist(tableName, colName string) (bool, error) {
|
||||
args := []interface{}{db.Schema, tableName, colName}
|
||||
func (db *postgres) IsColumnExist(queryer core.Queryer, ctx context.Context, tableName, colName string) (bool, error) {
|
||||
args := []interface{}{db.getSchema(), tableName, colName}
|
||||
query := "SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = $1 AND table_name = $2" +
|
||||
" AND column_name = $3"
|
||||
if len(db.Schema) == 0 {
|
||||
if len(db.getSchema()) == 0 {
|
||||
args = []interface{}{tableName, colName}
|
||||
query = "SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = $1" +
|
||||
" AND column_name = $2"
|
||||
}
|
||||
db.LogSQL(query, args)
|
||||
|
||||
rows, err := db.DB().Query(query, args...)
|
||||
rows, err := queryer.QueryContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
|
@ -950,7 +999,7 @@ func (db *postgres) IsColumnExist(tableName, colName string) (bool, error) {
|
|||
return rows.Next(), nil
|
||||
}
|
||||
|
||||
func (db *postgres) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
|
||||
func (db *postgres) GetColumns(queryer core.Queryer, ctx context.Context, tableName string) ([]string, map[string]*schemas.Column, error) {
|
||||
args := []interface{}{tableName}
|
||||
s := `SELECT column_name, column_default, is_nullable, data_type, character_maximum_length,
|
||||
CASE WHEN p.contype = 'p' THEN true ELSE false END AS primarykey,
|
||||
|
|
@ -962,28 +1011,27 @@ FROM pg_attribute f
|
|||
LEFT JOIN pg_constraint p ON p.conrelid = c.oid AND f.attnum = ANY (p.conkey)
|
||||
LEFT JOIN pg_class AS g ON p.confrelid = g.oid
|
||||
LEFT JOIN INFORMATION_SCHEMA.COLUMNS s ON s.column_name=f.attname AND c.relname=s.table_name
|
||||
WHERE c.relkind = 'r'::char AND c.relname = $1%s AND f.attnum > 0 ORDER BY f.attnum;`
|
||||
WHERE n.nspname= s.table_schema AND c.relkind = 'r'::char AND c.relname = $1%s AND f.attnum > 0 ORDER BY f.attnum;`
|
||||
|
||||
var f string
|
||||
if len(db.Schema) != 0 {
|
||||
args = append(args, db.Schema)
|
||||
f = " AND s.table_schema = $2"
|
||||
schema := db.getSchema()
|
||||
if schema != "" {
|
||||
s = fmt.Sprintf(s, "AND s.table_schema = $2")
|
||||
args = append(args, schema)
|
||||
} else {
|
||||
s = fmt.Sprintf(s, "")
|
||||
}
|
||||
s = fmt.Sprintf(s, f)
|
||||
|
||||
db.LogSQL(s, args)
|
||||
|
||||
rows, err := db.DB().Query(s, args...)
|
||||
rows, err := queryer.QueryContext(ctx, s, args...)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
cols := make(map[string]*core.Column)
|
||||
cols := make(map[string]*schemas.Column)
|
||||
colSeq := make([]string, 0)
|
||||
|
||||
for rows.Next() {
|
||||
col := new(core.Column)
|
||||
col := new(schemas.Column)
|
||||
col.Indexes = make(map[string]int)
|
||||
|
||||
var colName, isNullable, dataType string
|
||||
|
|
@ -994,7 +1042,6 @@ WHERE c.relkind = 'r'::char AND c.relname = $1%s AND f.attnum > 0 ORDER BY f.att
|
|||
return nil, nil, err
|
||||
}
|
||||
|
||||
// fmt.Println(args, colName, isNullable, dataType, maxLenStr, colDefault, isPK, isUnique)
|
||||
var maxLen int
|
||||
if maxLenStr != nil {
|
||||
maxLen, err = strconv.Atoi(*maxLenStr)
|
||||
|
|
@ -1006,10 +1053,27 @@ WHERE c.relkind = 'r'::char AND c.relname = $1%s AND f.attnum > 0 ORDER BY f.att
|
|||
col.Name = strings.Trim(colName, `" `)
|
||||
|
||||
if colDefault != nil {
|
||||
col.Default = *colDefault
|
||||
var theDefault = *colDefault
|
||||
// cockroach has type with the default value with :::
|
||||
// and postgres with ::, we should remove them before store them
|
||||
idx := strings.Index(theDefault, ":::")
|
||||
if idx == -1 {
|
||||
idx = strings.Index(theDefault, "::")
|
||||
}
|
||||
if idx > -1 {
|
||||
theDefault = theDefault[:idx]
|
||||
}
|
||||
|
||||
if strings.HasSuffix(theDefault, "+00:00'") {
|
||||
theDefault = theDefault[:len(theDefault)-7] + "'"
|
||||
}
|
||||
|
||||
col.Default = theDefault
|
||||
col.DefaultIsEmpty = false
|
||||
if strings.HasPrefix(col.Default, "nextval(") {
|
||||
col.IsAutoIncrement = true
|
||||
col.Default = ""
|
||||
col.DefaultIsEmpty = true
|
||||
}
|
||||
} else {
|
||||
col.DefaultIsEmpty = true
|
||||
|
|
@ -1021,26 +1085,37 @@ WHERE c.relkind = 'r'::char AND c.relname = $1%s AND f.attnum > 0 ORDER BY f.att
|
|||
|
||||
col.Nullable = (isNullable == "YES")
|
||||
|
||||
switch dataType {
|
||||
case "character varying", "character":
|
||||
col.SQLType = core.SQLType{Name: core.Varchar, DefaultLength: 0, DefaultLength2: 0}
|
||||
switch strings.ToLower(dataType) {
|
||||
case "character varying", "character", "string":
|
||||
col.SQLType = schemas.SQLType{Name: schemas.Varchar, DefaultLength: 0, DefaultLength2: 0}
|
||||
case "timestamp without time zone":
|
||||
col.SQLType = core.SQLType{Name: core.DateTime, DefaultLength: 0, DefaultLength2: 0}
|
||||
col.SQLType = schemas.SQLType{Name: schemas.DateTime, DefaultLength: 0, DefaultLength2: 0}
|
||||
case "timestamp with time zone":
|
||||
col.SQLType = core.SQLType{Name: core.TimeStampz, DefaultLength: 0, DefaultLength2: 0}
|
||||
col.SQLType = schemas.SQLType{Name: schemas.TimeStampz, DefaultLength: 0, DefaultLength2: 0}
|
||||
case "double precision":
|
||||
col.SQLType = core.SQLType{Name: core.Double, DefaultLength: 0, DefaultLength2: 0}
|
||||
col.SQLType = schemas.SQLType{Name: schemas.Double, DefaultLength: 0, DefaultLength2: 0}
|
||||
case "boolean":
|
||||
col.SQLType = core.SQLType{Name: core.Bool, DefaultLength: 0, DefaultLength2: 0}
|
||||
col.SQLType = schemas.SQLType{Name: schemas.Bool, DefaultLength: 0, DefaultLength2: 0}
|
||||
case "time without time zone":
|
||||
col.SQLType = core.SQLType{Name: core.Time, DefaultLength: 0, DefaultLength2: 0}
|
||||
col.SQLType = schemas.SQLType{Name: schemas.Time, DefaultLength: 0, DefaultLength2: 0}
|
||||
case "bytes":
|
||||
col.SQLType = schemas.SQLType{Name: schemas.Binary, DefaultLength: 0, DefaultLength2: 0}
|
||||
case "oid":
|
||||
col.SQLType = core.SQLType{Name: core.BigInt, DefaultLength: 0, DefaultLength2: 0}
|
||||
col.SQLType = schemas.SQLType{Name: schemas.BigInt, DefaultLength: 0, DefaultLength2: 0}
|
||||
case "array":
|
||||
col.SQLType = schemas.SQLType{Name: schemas.Array, DefaultLength: 0, DefaultLength2: 0}
|
||||
default:
|
||||
col.SQLType = core.SQLType{Name: strings.ToUpper(dataType), DefaultLength: 0, DefaultLength2: 0}
|
||||
startIdx := strings.Index(strings.ToLower(dataType), "string(")
|
||||
if startIdx != -1 && strings.HasSuffix(dataType, ")") {
|
||||
length := dataType[startIdx+8 : len(dataType)-1]
|
||||
l, _ := strconv.Atoi(length)
|
||||
col.SQLType = schemas.SQLType{Name: "STRING", DefaultLength: l, DefaultLength2: 0}
|
||||
} else {
|
||||
col.SQLType = schemas.SQLType{Name: strings.ToUpper(dataType), DefaultLength: 0, DefaultLength2: 0}
|
||||
}
|
||||
}
|
||||
if _, ok := core.SqlTypes[col.SQLType.Name]; !ok {
|
||||
return nil, nil, fmt.Errorf("Unknown colType: %v", dataType)
|
||||
if _, ok := schemas.SqlTypes[col.SQLType.Name]; !ok {
|
||||
return nil, nil, fmt.Errorf("Unknown colType: %s - %s", dataType, col.SQLType.Name)
|
||||
}
|
||||
|
||||
col.Length = maxLen
|
||||
|
|
@ -1065,25 +1140,24 @@ WHERE c.relkind = 'r'::char AND c.relname = $1%s AND f.attnum > 0 ORDER BY f.att
|
|||
return colSeq, cols, nil
|
||||
}
|
||||
|
||||
func (db *postgres) GetTables() ([]*core.Table, error) {
|
||||
func (db *postgres) GetTables(queryer core.Queryer, ctx context.Context) ([]*schemas.Table, error) {
|
||||
args := []interface{}{}
|
||||
s := "SELECT tablename FROM pg_tables"
|
||||
if len(db.Schema) != 0 {
|
||||
args = append(args, db.Schema)
|
||||
schema := db.getSchema()
|
||||
if schema != "" {
|
||||
args = append(args, schema)
|
||||
s = s + " WHERE schemaname = $1"
|
||||
}
|
||||
|
||||
db.LogSQL(s, args)
|
||||
|
||||
rows, err := db.DB().Query(s, args...)
|
||||
rows, err := queryer.QueryContext(ctx, s, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
tables := make([]*core.Table, 0)
|
||||
tables := make([]*schemas.Table, 0)
|
||||
for rows.Next() {
|
||||
table := core.NewEmptyTable()
|
||||
table := schemas.NewEmptyTable()
|
||||
var name string
|
||||
err = rows.Scan(&name)
|
||||
if err != nil {
|
||||
|
|
@ -1106,22 +1180,21 @@ func getIndexColName(indexdef string) []string {
|
|||
return colNames
|
||||
}
|
||||
|
||||
func (db *postgres) GetIndexes(tableName string) (map[string]*core.Index, error) {
|
||||
func (db *postgres) GetIndexes(queryer core.Queryer, ctx context.Context, tableName string) (map[string]*schemas.Index, error) {
|
||||
args := []interface{}{tableName}
|
||||
s := fmt.Sprintf("SELECT indexname, indexdef FROM pg_indexes WHERE tablename=$1")
|
||||
if len(db.Schema) != 0 {
|
||||
args = append(args, db.Schema)
|
||||
if len(db.getSchema()) != 0 {
|
||||
args = append(args, db.getSchema())
|
||||
s = s + " AND schemaname=$2"
|
||||
}
|
||||
db.LogSQL(s, args)
|
||||
|
||||
rows, err := db.DB().Query(s, args...)
|
||||
rows, err := queryer.QueryContext(ctx, s, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
indexes := make(map[string]*core.Index, 0)
|
||||
indexes := make(map[string]*schemas.Index, 0)
|
||||
for rows.Next() {
|
||||
var indexType int
|
||||
var indexName, indexdef string
|
||||
|
|
@ -1130,14 +1203,18 @@ func (db *postgres) GetIndexes(tableName string) (map[string]*core.Index, error)
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if indexName == "primary" {
|
||||
continue
|
||||
}
|
||||
indexName = strings.Trim(indexName, `" `)
|
||||
if strings.HasSuffix(indexName, "_pkey") {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(indexdef, "CREATE UNIQUE INDEX") {
|
||||
indexType = core.UniqueType
|
||||
indexType = schemas.UniqueType
|
||||
} else {
|
||||
indexType = core.IndexType
|
||||
indexType = schemas.IndexType
|
||||
}
|
||||
colNames = getIndexColName(indexdef)
|
||||
var isRegular bool
|
||||
|
|
@ -1149,9 +1226,9 @@ func (db *postgres) GetIndexes(tableName string) (map[string]*core.Index, error)
|
|||
}
|
||||
}
|
||||
|
||||
index := &core.Index{Name: indexName, Type: indexType, Cols: make([]string, 0)}
|
||||
index := &schemas.Index{Name: indexName, Type: indexType, Cols: make([]string, 0)}
|
||||
for _, colName := range colNames {
|
||||
index.Cols = append(index.Cols, strings.Trim(colName, `" `))
|
||||
index.Cols = append(index.Cols, strings.TrimSpace(strings.Replace(colName, `"`, "", -1)))
|
||||
}
|
||||
index.IsRegular = isRegular
|
||||
indexes[index.Name] = index
|
||||
|
|
@ -1159,8 +1236,8 @@ func (db *postgres) GetIndexes(tableName string) (map[string]*core.Index, error)
|
|||
return indexes, nil
|
||||
}
|
||||
|
||||
func (db *postgres) Filters() []core.Filter {
|
||||
return []core.Filter{&core.IdFilter{}, &core.QuoteFilter{}, &core.SeqFilter{Prefix: "$", Start: 1}}
|
||||
func (db *postgres) Filters() []Filter {
|
||||
return []Filter{&SeqFilter{Prefix: "$", Start: 1}}
|
||||
}
|
||||
|
||||
type pqDriver struct {
|
||||
|
|
@ -1214,12 +1291,12 @@ func parseOpts(name string, o values) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (p *pqDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
|
||||
db := &core.Uri{DbType: core.POSTGRES}
|
||||
func (p *pqDriver) Parse(driverName, dataSourceName string) (*URI, error) {
|
||||
db := &URI{DBType: schemas.POSTGRES}
|
||||
var err error
|
||||
|
||||
if strings.HasPrefix(dataSourceName, "postgresql://") || strings.HasPrefix(dataSourceName, "postgres://") {
|
||||
db.DbName, err = parseURL(dataSourceName)
|
||||
db.DBName, err = parseURL(dataSourceName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -1230,10 +1307,10 @@ func (p *pqDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
db.DbName = o.Get("dbname")
|
||||
db.DBName = o.Get("dbname")
|
||||
}
|
||||
|
||||
if db.DbName == "" {
|
||||
if db.DBName == "" {
|
||||
return nil, errors.New("dbname is empty")
|
||||
}
|
||||
|
||||
|
|
@ -1244,10 +1321,29 @@ type pqDriverPgx struct {
|
|||
pqDriver
|
||||
}
|
||||
|
||||
func (pgx *pqDriverPgx) Parse(driverName, dataSourceName string) (*core.Uri, error) {
|
||||
func (pgx *pqDriverPgx) Parse(driverName, dataSourceName string) (*URI, error) {
|
||||
// Remove the leading characters for driver to work
|
||||
if len(dataSourceName) >= 9 && dataSourceName[0] == 0 {
|
||||
dataSourceName = dataSourceName[9:]
|
||||
}
|
||||
return pgx.pqDriver.Parse(driverName, dataSourceName)
|
||||
}
|
||||
|
||||
// QueryDefaultPostgresSchema returns the default postgres schema
|
||||
func QueryDefaultPostgresSchema(ctx context.Context, queryer core.Queryer) (string, error) {
|
||||
rows, err := queryer.QueryContext(ctx, "SHOW SEARCH_PATH")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer rows.Close()
|
||||
if rows.Next() {
|
||||
var defaultSchema string
|
||||
if err = rows.Scan(&defaultSchema); err != nil {
|
||||
return "", err
|
||||
}
|
||||
parts := strings.Split(defaultSchema, ",")
|
||||
return strings.TrimSpace(parts[len(parts)-1]), nil
|
||||
}
|
||||
|
||||
return "", errors.New("No default schema")
|
||||
}
|
||||
|
|
@ -1,11 +1,10 @@
|
|||
package xorm
|
||||
package dialects
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
func TestParsePostgres(t *testing.T) {
|
||||
|
|
@ -27,15 +26,15 @@ func TestParsePostgres(t *testing.T) {
|
|||
{"dbname=db =disable", "db", false},
|
||||
}
|
||||
|
||||
driver := core.QueryDriver("postgres")
|
||||
driver := QueryDriver("postgres")
|
||||
|
||||
for _, test := range tests {
|
||||
uri, err := driver.Parse("postgres", test.in)
|
||||
|
||||
if err != nil && test.valid {
|
||||
t.Errorf("%q got unexpected error: %s", test.in, err)
|
||||
} else if err == nil && !reflect.DeepEqual(test.expected, uri.DbName) {
|
||||
t.Errorf("%q got: %#v want: %#v", test.in, uri.DbName, test.expected)
|
||||
} else if err == nil && !reflect.DeepEqual(test.expected, uri.DBName) {
|
||||
t.Errorf("%q got: %#v want: %#v", test.in, uri.DBName, test.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -59,23 +58,23 @@ func TestParsePgx(t *testing.T) {
|
|||
{"dbname=db =disable", "db", false},
|
||||
}
|
||||
|
||||
driver := core.QueryDriver("pgx")
|
||||
driver := QueryDriver("pgx")
|
||||
|
||||
for _, test := range tests {
|
||||
uri, err := driver.Parse("pgx", test.in)
|
||||
|
||||
if err != nil && test.valid {
|
||||
t.Errorf("%q got unexpected error: %s", test.in, err)
|
||||
} else if err == nil && !reflect.DeepEqual(test.expected, uri.DbName) {
|
||||
t.Errorf("%q got: %#v want: %#v", test.in, uri.DbName, test.expected)
|
||||
} else if err == nil && !reflect.DeepEqual(test.expected, uri.DBName) {
|
||||
t.Errorf("%q got: %#v want: %#v", test.in, uri.DBName, test.expected)
|
||||
}
|
||||
|
||||
// Register DriverConfig
|
||||
uri, err = driver.Parse("pgx", test.in)
|
||||
if err != nil && test.valid {
|
||||
t.Errorf("%q got unexpected error: %s", test.in, err)
|
||||
} else if err == nil && !reflect.DeepEqual(test.expected, uri.DbName) {
|
||||
t.Errorf("%q got: %#v want: %#v", test.in, uri.DbName, test.expected)
|
||||
} else if err == nil && !reflect.DeepEqual(test.expected, uri.DBName) {
|
||||
t.Errorf("%q got: %#v want: %#v", test.in, uri.DBName, test.expected)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
// Copyright 2020 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package dialects
|
||||
|
||||
// QuotePolicy describes quote handle policy
|
||||
type QuotePolicy int
|
||||
|
||||
// All QuotePolicies
|
||||
const (
|
||||
QuotePolicyAlways QuotePolicy = iota
|
||||
QuotePolicyNone
|
||||
QuotePolicyReserved
|
||||
)
|
||||
|
|
@ -2,16 +2,18 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
package dialects
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"xorm.io/core"
|
||||
"xorm.io/xorm/core"
|
||||
"xorm.io/xorm/schemas"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -141,45 +143,69 @@ var (
|
|||
"WITH": true,
|
||||
"WITHOUT": true,
|
||||
}
|
||||
|
||||
sqlite3Quoter = schemas.Quoter{
|
||||
Prefix: '`',
|
||||
Suffix: '`',
|
||||
IsReserved: schemas.AlwaysReserve,
|
||||
}
|
||||
)
|
||||
|
||||
type sqlite3 struct {
|
||||
core.Base
|
||||
Base
|
||||
}
|
||||
|
||||
func (db *sqlite3) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error {
|
||||
return db.Base.Init(d, db, uri, drivername, dataSourceName)
|
||||
func (db *sqlite3) Init(uri *URI) error {
|
||||
db.quoter = sqlite3Quoter
|
||||
return db.Base.Init(db, uri)
|
||||
}
|
||||
|
||||
func (db *sqlite3) SqlType(c *core.Column) string {
|
||||
func (db *sqlite3) SetQuotePolicy(quotePolicy QuotePolicy) {
|
||||
switch quotePolicy {
|
||||
case QuotePolicyNone:
|
||||
var q = sqlite3Quoter
|
||||
q.IsReserved = schemas.AlwaysNoReserve
|
||||
db.quoter = q
|
||||
case QuotePolicyReserved:
|
||||
var q = sqlite3Quoter
|
||||
q.IsReserved = db.IsReserved
|
||||
db.quoter = q
|
||||
case QuotePolicyAlways:
|
||||
fallthrough
|
||||
default:
|
||||
db.quoter = sqlite3Quoter
|
||||
}
|
||||
}
|
||||
|
||||
func (db *sqlite3) SQLType(c *schemas.Column) string {
|
||||
switch t := c.SQLType.Name; t {
|
||||
case core.Bool:
|
||||
case schemas.Bool:
|
||||
if c.Default == "true" {
|
||||
c.Default = "1"
|
||||
} else if c.Default == "false" {
|
||||
c.Default = "0"
|
||||
}
|
||||
return core.Integer
|
||||
case core.Date, core.DateTime, core.TimeStamp, core.Time:
|
||||
return core.DateTime
|
||||
case core.TimeStampz:
|
||||
return core.Text
|
||||
case core.Char, core.Varchar, core.NVarchar, core.TinyText,
|
||||
core.Text, core.MediumText, core.LongText, core.Json:
|
||||
return core.Text
|
||||
case core.Bit, core.TinyInt, core.SmallInt, core.MediumInt, core.Int, core.Integer, core.BigInt:
|
||||
return core.Integer
|
||||
case core.Float, core.Double, core.Real:
|
||||
return core.Real
|
||||
case core.Decimal, core.Numeric:
|
||||
return core.Numeric
|
||||
case core.TinyBlob, core.Blob, core.MediumBlob, core.LongBlob, core.Bytea, core.Binary, core.VarBinary:
|
||||
return core.Blob
|
||||
case core.Serial, core.BigSerial:
|
||||
return schemas.Integer
|
||||
case schemas.Date, schemas.DateTime, schemas.TimeStamp, schemas.Time:
|
||||
return schemas.DateTime
|
||||
case schemas.TimeStampz:
|
||||
return schemas.Text
|
||||
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:
|
||||
return schemas.Integer
|
||||
case schemas.Float, schemas.Double, schemas.Real:
|
||||
return schemas.Real
|
||||
case schemas.Decimal, schemas.Numeric:
|
||||
return schemas.Numeric
|
||||
case schemas.TinyBlob, schemas.Blob, schemas.MediumBlob, schemas.LongBlob, schemas.Bytea, schemas.Binary, schemas.VarBinary:
|
||||
return schemas.Blob
|
||||
case schemas.Serial, schemas.BigSerial:
|
||||
c.IsPrimaryKey = true
|
||||
c.IsAutoIncrement = true
|
||||
c.Nullable = false
|
||||
return core.Integer
|
||||
return schemas.Integer
|
||||
default:
|
||||
return t
|
||||
}
|
||||
|
|
@ -189,84 +215,97 @@ func (db *sqlite3) FormatBytes(bs []byte) string {
|
|||
return fmt.Sprintf("X'%x'", bs)
|
||||
}
|
||||
|
||||
func (db *sqlite3) SupportInsertMany() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (db *sqlite3) IsReserved(name string) bool {
|
||||
_, ok := sqlite3ReservedWords[name]
|
||||
_, ok := sqlite3ReservedWords[strings.ToUpper(name)]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (db *sqlite3) Quote(name string) string {
|
||||
return "`" + name + "`"
|
||||
}
|
||||
|
||||
func (db *sqlite3) AutoIncrStr() string {
|
||||
return "AUTOINCREMENT"
|
||||
}
|
||||
|
||||
func (db *sqlite3) SupportEngine() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (db *sqlite3) SupportCharset() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (db *sqlite3) IndexOnTable() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (db *sqlite3) IndexCheckSql(tableName, idxName string) (string, []interface{}) {
|
||||
func (db *sqlite3) IndexCheckSQL(tableName, idxName string) (string, []interface{}) {
|
||||
args := []interface{}{idxName}
|
||||
return "SELECT name FROM sqlite_master WHERE type='index' and name = ?", args
|
||||
}
|
||||
|
||||
func (db *sqlite3) TableCheckSql(tableName string) (string, []interface{}) {
|
||||
args := []interface{}{tableName}
|
||||
return "SELECT name FROM sqlite_master WHERE type='table' and name = ?", args
|
||||
func (db *sqlite3) IsTableExist(queryer core.Queryer, ctx context.Context, tableName string) (bool, error) {
|
||||
return db.HasRecords(queryer, ctx, "SELECT name FROM sqlite_master WHERE type='table' and name = ?", tableName)
|
||||
}
|
||||
|
||||
func (db *sqlite3) DropIndexSql(tableName string, index *core.Index) string {
|
||||
func (db *sqlite3) DropIndexSQL(tableName string, index *schemas.Index) string {
|
||||
// var unique string
|
||||
quote := db.Quote
|
||||
idxName := index.Name
|
||||
|
||||
if !strings.HasPrefix(idxName, "UQE_") &&
|
||||
!strings.HasPrefix(idxName, "IDX_") {
|
||||
if index.Type == core.UniqueType {
|
||||
if index.Type == schemas.UniqueType {
|
||||
idxName = fmt.Sprintf("UQE_%v_%v", tableName, index.Name)
|
||||
} else {
|
||||
idxName = fmt.Sprintf("IDX_%v_%v", tableName, index.Name)
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("DROP INDEX %v", quote(idxName))
|
||||
return fmt.Sprintf("DROP INDEX %v", db.Quoter().Quote(idxName))
|
||||
}
|
||||
|
||||
func (db *sqlite3) ForUpdateSql(query string) string {
|
||||
func (db *sqlite3) CreateTableSQL(table *schemas.Table, tableName string) ([]string, bool) {
|
||||
var sql string
|
||||
sql = "CREATE TABLE IF NOT EXISTS "
|
||||
if tableName == "" {
|
||||
tableName = table.Name
|
||||
}
|
||||
|
||||
quoter := db.Quoter()
|
||||
sql += quoter.Quote(tableName)
|
||||
sql += " ("
|
||||
|
||||
if len(table.ColumnsSeq()) > 0 {
|
||||
pkList := table.PrimaryKeys
|
||||
|
||||
for _, colName := range table.ColumnsSeq() {
|
||||
col := table.GetColumn(colName)
|
||||
s, _ := ColumnString(db, col, col.IsPrimaryKey && len(pkList) == 1)
|
||||
sql += s
|
||||
sql = strings.TrimSpace(sql)
|
||||
sql += ", "
|
||||
}
|
||||
|
||||
if len(pkList) > 1 {
|
||||
sql += "PRIMARY KEY ( "
|
||||
sql += quoter.Join(pkList, ",")
|
||||
sql += " ), "
|
||||
}
|
||||
|
||||
sql = sql[:len(sql)-2]
|
||||
}
|
||||
sql += ")"
|
||||
|
||||
return []string{sql}, true
|
||||
}
|
||||
|
||||
func (db *sqlite3) ForUpdateSQL(query string) string {
|
||||
return query
|
||||
}
|
||||
|
||||
/*func (db *sqlite3) ColumnCheckSql(tableName, colName string) (string, []interface{}) {
|
||||
args := []interface{}{tableName}
|
||||
sql := "SELECT name FROM sqlite_master WHERE type='table' and name = ? and ((sql like '%`" + colName + "`%') or (sql like '%[" + colName + "]%'))"
|
||||
return sql, args
|
||||
}*/
|
||||
|
||||
func (db *sqlite3) IsColumnExist(tableName, colName string) (bool, error) {
|
||||
args := []interface{}{tableName}
|
||||
query := "SELECT name FROM sqlite_master WHERE type='table' and name = ? and ((sql like '%`" + colName + "`%') or (sql like '%[" + colName + "]%'))"
|
||||
db.LogSQL(query, args)
|
||||
rows, err := db.DB().Query(query, args...)
|
||||
func (db *sqlite3) IsColumnExist(queryer core.Queryer, ctx context.Context, tableName, colName string) (bool, error) {
|
||||
query := "SELECT * FROM " + tableName + " LIMIT 0"
|
||||
rows, err := queryer.QueryContext(ctx, query)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
if rows.Next() {
|
||||
return true, nil
|
||||
cols, err := rows.Columns()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
for _, col := range cols {
|
||||
if strings.EqualFold(col, colName) {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
|
|
@ -298,9 +337,9 @@ func splitColStr(colStr string) []string {
|
|||
return results
|
||||
}
|
||||
|
||||
func parseString(colStr string) (*core.Column, error) {
|
||||
func parseString(colStr string) (*schemas.Column, error) {
|
||||
fields := splitColStr(colStr)
|
||||
col := new(core.Column)
|
||||
col := new(schemas.Column)
|
||||
col.Indexes = make(map[string]int)
|
||||
col.Nullable = true
|
||||
col.DefaultIsEmpty = true
|
||||
|
|
@ -310,7 +349,7 @@ func parseString(colStr string) (*core.Column, error) {
|
|||
col.Name = strings.Trim(strings.Trim(field, "`[] "), `"`)
|
||||
continue
|
||||
} else if idx == 1 {
|
||||
col.SQLType = core.SQLType{Name: field, DefaultLength: 0, DefaultLength2: 0}
|
||||
col.SQLType = schemas.SQLType{Name: field, DefaultLength: 0, DefaultLength2: 0}
|
||||
continue
|
||||
}
|
||||
switch field {
|
||||
|
|
@ -332,11 +371,11 @@ func parseString(colStr string) (*core.Column, error) {
|
|||
return col, nil
|
||||
}
|
||||
|
||||
func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
|
||||
func (db *sqlite3) GetColumns(queryer core.Queryer, ctx context.Context, tableName string) ([]string, map[string]*schemas.Column, error) {
|
||||
args := []interface{}{tableName}
|
||||
s := "SELECT sql FROM sqlite_master WHERE type='table' and name = ?"
|
||||
db.LogSQL(s, args)
|
||||
rows, err := db.DB().Query(s, args...)
|
||||
|
||||
rows, err := queryer.QueryContext(ctx, s, args...)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
|
@ -359,7 +398,7 @@ func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*core.Colu
|
|||
nEnd := strings.LastIndex(name, ")")
|
||||
reg := regexp.MustCompile(`[^\(,\)]*(\([^\(]*\))?`)
|
||||
colCreates := reg.FindAllString(name[nStart+1:nEnd], -1)
|
||||
cols := make(map[string]*core.Column)
|
||||
cols := make(map[string]*schemas.Column)
|
||||
colSeq := make([]string, 0)
|
||||
|
||||
for _, colStr := range colCreates {
|
||||
|
|
@ -389,20 +428,19 @@ func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*core.Colu
|
|||
return colSeq, cols, nil
|
||||
}
|
||||
|
||||
func (db *sqlite3) GetTables() ([]*core.Table, error) {
|
||||
func (db *sqlite3) GetTables(queryer core.Queryer, ctx context.Context) ([]*schemas.Table, error) {
|
||||
args := []interface{}{}
|
||||
s := "SELECT name FROM sqlite_master WHERE type='table'"
|
||||
db.LogSQL(s, args)
|
||||
|
||||
rows, err := db.DB().Query(s, args...)
|
||||
rows, err := queryer.QueryContext(ctx, s, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
tables := make([]*core.Table, 0)
|
||||
tables := make([]*schemas.Table, 0)
|
||||
for rows.Next() {
|
||||
table := core.NewEmptyTable()
|
||||
table := schemas.NewEmptyTable()
|
||||
err = rows.Scan(&table.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -415,18 +453,17 @@ func (db *sqlite3) GetTables() ([]*core.Table, error) {
|
|||
return tables, nil
|
||||
}
|
||||
|
||||
func (db *sqlite3) GetIndexes(tableName string) (map[string]*core.Index, error) {
|
||||
func (db *sqlite3) GetIndexes(queryer core.Queryer, ctx context.Context, tableName string) (map[string]*schemas.Index, error) {
|
||||
args := []interface{}{tableName}
|
||||
s := "SELECT sql FROM sqlite_master WHERE type='index' and tbl_name = ?"
|
||||
db.LogSQL(s, args)
|
||||
|
||||
rows, err := db.DB().Query(s, args...)
|
||||
rows, err := queryer.QueryContext(ctx, s, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
indexes := make(map[string]*core.Index, 0)
|
||||
indexes := make(map[string]*schemas.Index, 0)
|
||||
for rows.Next() {
|
||||
var tmpSQL sql.NullString
|
||||
err = rows.Scan(&tmpSQL)
|
||||
|
|
@ -439,7 +476,7 @@ func (db *sqlite3) GetIndexes(tableName string) (map[string]*core.Index, error)
|
|||
}
|
||||
sql := tmpSQL.String
|
||||
|
||||
index := new(core.Index)
|
||||
index := new(schemas.Index)
|
||||
nNStart := strings.Index(sql, "INDEX")
|
||||
nNEnd := strings.Index(sql, "ON")
|
||||
if nNStart == -1 || nNEnd == -1 {
|
||||
|
|
@ -456,9 +493,9 @@ func (db *sqlite3) GetIndexes(tableName string) (map[string]*core.Index, error)
|
|||
}
|
||||
|
||||
if strings.HasPrefix(sql, "CREATE UNIQUE INDEX") {
|
||||
index.Type = core.UniqueType
|
||||
index.Type = schemas.UniqueType
|
||||
} else {
|
||||
index.Type = core.IndexType
|
||||
index.Type = schemas.IndexType
|
||||
}
|
||||
|
||||
nStart := strings.Index(sql, "(")
|
||||
|
|
@ -476,17 +513,17 @@ func (db *sqlite3) GetIndexes(tableName string) (map[string]*core.Index, error)
|
|||
return indexes, nil
|
||||
}
|
||||
|
||||
func (db *sqlite3) Filters() []core.Filter {
|
||||
return []core.Filter{&core.IdFilter{}}
|
||||
func (db *sqlite3) Filters() []Filter {
|
||||
return []Filter{}
|
||||
}
|
||||
|
||||
type sqlite3Driver struct {
|
||||
}
|
||||
|
||||
func (p *sqlite3Driver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
|
||||
func (p *sqlite3Driver) Parse(driverName, dataSourceName string) (*URI, error) {
|
||||
if strings.Contains(dataSourceName, "?") {
|
||||
dataSourceName = dataSourceName[:strings.Index(dataSourceName, "?")]
|
||||
}
|
||||
|
||||
return &core.Uri{DbType: core.SQLITE, DbName: dataSourceName}, nil
|
||||
return &URI{DBType: schemas.SQLITE, DBName: dataSourceName}, nil
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
package dialects
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
// Copyright 2015 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package dialects
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"xorm.io/xorm/internal/utils"
|
||||
"xorm.io/xorm/names"
|
||||
)
|
||||
|
||||
// TableNameWithSchema will add schema prefix on table name if possible
|
||||
func TableNameWithSchema(dialect Dialect, tableName string) string {
|
||||
// Add schema name as prefix of table name.
|
||||
// Only for postgres database.
|
||||
if dialect.URI().Schema != "" &&
|
||||
strings.Index(tableName, ".") == -1 {
|
||||
return fmt.Sprintf("%s.%s", dialect.URI().Schema, tableName)
|
||||
}
|
||||
return tableName
|
||||
}
|
||||
|
||||
// TableNameNoSchema returns table name with given tableName
|
||||
func TableNameNoSchema(dialect Dialect, mapper names.Mapper, tableName interface{}) string {
|
||||
quote := dialect.Quoter().Quote
|
||||
switch tableName.(type) {
|
||||
case []string:
|
||||
t := tableName.([]string)
|
||||
if len(t) > 1 {
|
||||
return fmt.Sprintf("%v AS %v", quote(t[0]), quote(t[1]))
|
||||
} else if len(t) == 1 {
|
||||
return quote(t[0])
|
||||
}
|
||||
case []interface{}:
|
||||
t := tableName.([]interface{})
|
||||
l := len(t)
|
||||
var table string
|
||||
if l > 0 {
|
||||
f := t[0]
|
||||
switch f.(type) {
|
||||
case string:
|
||||
table = f.(string)
|
||||
case names.TableName:
|
||||
table = f.(names.TableName).TableName()
|
||||
default:
|
||||
v := utils.ReflectValue(f)
|
||||
t := v.Type()
|
||||
if t.Kind() == reflect.Struct {
|
||||
table = names.GetTableName(mapper, v)
|
||||
} else {
|
||||
table = quote(fmt.Sprintf("%v", f))
|
||||
}
|
||||
}
|
||||
}
|
||||
if l > 1 {
|
||||
return fmt.Sprintf("%v AS %v", quote(table), quote(fmt.Sprintf("%v", t[1])))
|
||||
} else if l == 1 {
|
||||
return quote(table)
|
||||
}
|
||||
case names.TableName:
|
||||
return tableName.(names.TableName).TableName()
|
||||
case string:
|
||||
return tableName.(string)
|
||||
case reflect.Value:
|
||||
v := tableName.(reflect.Value)
|
||||
return names.GetTableName(mapper, v)
|
||||
default:
|
||||
v := utils.ReflectValue(tableName)
|
||||
t := v.Type()
|
||||
if t.Kind() == reflect.Struct {
|
||||
return names.GetTableName(mapper, v)
|
||||
}
|
||||
return quote(fmt.Sprintf("%v", tableName))
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// FullTableName returns table name with quote and schema according parameter
|
||||
func FullTableName(dialect Dialect, mapper names.Mapper, bean interface{}, includeSchema ...bool) string {
|
||||
tbName := TableNameNoSchema(dialect, mapper, bean)
|
||||
if len(includeSchema) > 0 && includeSchema[0] && !utils.IsSubQuery(tbName) {
|
||||
tbName = TableNameWithSchema(dialect, tbName)
|
||||
}
|
||||
return tbName
|
||||
}
|
||||
|
|
@ -2,11 +2,13 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
package dialects
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"xorm.io/xorm/names"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
|
@ -20,9 +22,9 @@ func (mcc *MCC) TableName() string {
|
|||
return "mcc"
|
||||
}
|
||||
|
||||
func TestTableName1(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
func TestFullTableName(t *testing.T) {
|
||||
dialect := QueryDialect("mysql")
|
||||
|
||||
assert.EqualValues(t, "mcc", testEngine.TableName(new(MCC)))
|
||||
assert.EqualValues(t, "mcc", testEngine.TableName("mcc"))
|
||||
assert.EqualValues(t, "mcc", FullTableName(dialect, names.SnakeMapper{}, &MCC{}))
|
||||
assert.EqualValues(t, "mcc", FullTableName(dialect, names.SnakeMapper{}, "mcc"))
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
// Copyright 2015 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package dialects
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm/schemas"
|
||||
)
|
||||
|
||||
// FormatTime format time as column type
|
||||
func FormatTime(dialect Dialect, sqlTypeName string, t time.Time) (v interface{}) {
|
||||
switch sqlTypeName {
|
||||
case schemas.Time:
|
||||
s := t.Format("2006-01-02 15:04:05") // time.RFC3339
|
||||
v = s[11:19]
|
||||
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")
|
||||
case schemas.TimeStampz:
|
||||
if dialect.URI().DBType == schemas.MSSQL {
|
||||
v = t.Format("2006-01-02T15:04:05.9999999Z07:00")
|
||||
} else {
|
||||
v = t.Format(time.RFC3339Nano)
|
||||
}
|
||||
case schemas.BigInt, schemas.Int:
|
||||
v = t.Unix()
|
||||
default:
|
||||
v = t
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func FormatColumnTime(dialect Dialect, defaultTimeZone *time.Location, col *schemas.Column, t time.Time) (v interface{}) {
|
||||
if t.IsZero() {
|
||||
if col.Nullable {
|
||||
return nil
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
if col.TimeZone != nil {
|
||||
return FormatTime(dialect, col.SQLType.Name, t.In(col.TimeZone))
|
||||
}
|
||||
return FormatTime(dialect, col.SQLType.Name, t.In(defaultTimeZone))
|
||||
}
|
||||
4
doc.go
4
doc.go
|
|
@ -8,7 +8,7 @@ Package xorm is a simple and powerful ORM for Go.
|
|||
|
||||
Installation
|
||||
|
||||
Make sure you have installed Go 1.6+ and then:
|
||||
Make sure you have installed Go 1.11+ and then:
|
||||
|
||||
go get xorm.io/xorm
|
||||
|
||||
|
|
@ -126,7 +126,7 @@ Attention: the above 8 methods should be the last chainable method.
|
|||
|
||||
engine.ID(1).Get(&user) // for single primary key
|
||||
// SELECT * FROM user WHERE id = 1
|
||||
engine.ID(core.PK{1, 2}).Get(&user) // for composite primary keys
|
||||
engine.ID(schemas.PK{1, 2}).Get(&user) // for composite primary keys
|
||||
// SELECT * FROM user WHERE id1 = 1 AND id2 = 2
|
||||
engine.In("id", 1, 2, 3).Find(&users)
|
||||
// SELECT * FROM user WHERE id IN (1, 2, 3)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
Before Width: | Height: | Size: 238 KiB |
232
engine_cond.go
232
engine_cond.go
|
|
@ -1,232 +0,0 @@
|
|||
// Copyright 2017 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"xorm.io/builder"
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
func (engine *Engine) buildConds(table *core.Table, bean interface{},
|
||||
includeVersion bool, includeUpdated bool, includeNil bool,
|
||||
includeAutoIncr bool, allUseBool bool, useAllCols bool, unscoped bool,
|
||||
mustColumnMap map[string]bool, tableName, aliasName string, addedTableName bool) (builder.Cond, error) {
|
||||
var conds []builder.Cond
|
||||
for _, col := range table.Columns() {
|
||||
if !includeVersion && col.IsVersion {
|
||||
continue
|
||||
}
|
||||
if !includeUpdated && col.IsUpdated {
|
||||
continue
|
||||
}
|
||||
if !includeAutoIncr && col.IsAutoIncrement {
|
||||
continue
|
||||
}
|
||||
|
||||
if engine.dialect.DBType() == core.MSSQL && (col.SQLType.Name == core.Text || col.SQLType.IsBlob() || col.SQLType.Name == core.TimeStampz) {
|
||||
continue
|
||||
}
|
||||
if col.SQLType.IsJson() {
|
||||
continue
|
||||
}
|
||||
|
||||
var colName string
|
||||
if addedTableName {
|
||||
var nm = tableName
|
||||
if len(aliasName) > 0 {
|
||||
nm = aliasName
|
||||
}
|
||||
colName = engine.Quote(nm) + "." + engine.Quote(col.Name)
|
||||
} else {
|
||||
colName = engine.Quote(col.Name)
|
||||
}
|
||||
|
||||
fieldValuePtr, err := col.ValueOf(bean)
|
||||
if err != nil {
|
||||
if !strings.Contains(err.Error(), "is not valid") {
|
||||
engine.logger.Warn(err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if col.IsDeleted && !unscoped { // tag "deleted" is enabled
|
||||
conds = append(conds, engine.CondDeleted(colName))
|
||||
}
|
||||
|
||||
fieldValue := *fieldValuePtr
|
||||
if fieldValue.Interface() == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
fieldType := reflect.TypeOf(fieldValue.Interface())
|
||||
requiredField := useAllCols
|
||||
|
||||
if b, ok := getFlagForColumn(mustColumnMap, col); ok {
|
||||
if b {
|
||||
requiredField = true
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if fieldType.Kind() == reflect.Ptr {
|
||||
if fieldValue.IsNil() {
|
||||
if includeNil {
|
||||
conds = append(conds, builder.Eq{colName: nil})
|
||||
}
|
||||
continue
|
||||
} else if !fieldValue.IsValid() {
|
||||
continue
|
||||
} else {
|
||||
// dereference ptr type to instance type
|
||||
fieldValue = fieldValue.Elem()
|
||||
fieldType = reflect.TypeOf(fieldValue.Interface())
|
||||
requiredField = true
|
||||
}
|
||||
}
|
||||
|
||||
var val interface{}
|
||||
switch fieldType.Kind() {
|
||||
case reflect.Bool:
|
||||
if allUseBool || requiredField {
|
||||
val = fieldValue.Interface()
|
||||
} else {
|
||||
// if a bool in a struct, it will not be as a condition because it default is false,
|
||||
// please use Where() instead
|
||||
continue
|
||||
}
|
||||
case reflect.String:
|
||||
if !requiredField && fieldValue.String() == "" {
|
||||
continue
|
||||
}
|
||||
// for MyString, should convert to string or panic
|
||||
if fieldType.String() != reflect.String.String() {
|
||||
val = fieldValue.String()
|
||||
} else {
|
||||
val = fieldValue.Interface()
|
||||
}
|
||||
case reflect.Int8, reflect.Int16, reflect.Int, reflect.Int32, reflect.Int64:
|
||||
if !requiredField && fieldValue.Int() == 0 {
|
||||
continue
|
||||
}
|
||||
val = fieldValue.Interface()
|
||||
case reflect.Float32, reflect.Float64:
|
||||
if !requiredField && fieldValue.Float() == 0.0 {
|
||||
continue
|
||||
}
|
||||
val = fieldValue.Interface()
|
||||
case reflect.Uint8, reflect.Uint16, reflect.Uint, reflect.Uint32, reflect.Uint64:
|
||||
if !requiredField && fieldValue.Uint() == 0 {
|
||||
continue
|
||||
}
|
||||
t := int64(fieldValue.Uint())
|
||||
val = reflect.ValueOf(&t).Interface()
|
||||
case reflect.Struct:
|
||||
if fieldType.ConvertibleTo(core.TimeType) {
|
||||
t := fieldValue.Convert(core.TimeType).Interface().(time.Time)
|
||||
if !requiredField && (t.IsZero() || !fieldValue.IsValid()) {
|
||||
continue
|
||||
}
|
||||
val = engine.formatColTime(col, t)
|
||||
} else if _, ok := reflect.New(fieldType).Interface().(core.Conversion); ok {
|
||||
continue
|
||||
} else if valNul, ok := fieldValue.Interface().(driver.Valuer); ok {
|
||||
val, _ = valNul.Value()
|
||||
if val == nil {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
if col.SQLType.IsJson() {
|
||||
if col.SQLType.IsText() {
|
||||
bytes, err := DefaultJSONHandler.Marshal(fieldValue.Interface())
|
||||
if err != nil {
|
||||
engine.logger.Error(err)
|
||||
continue
|
||||
}
|
||||
val = string(bytes)
|
||||
} else if col.SQLType.IsBlob() {
|
||||
var bytes []byte
|
||||
var err error
|
||||
bytes, err = DefaultJSONHandler.Marshal(fieldValue.Interface())
|
||||
if err != nil {
|
||||
engine.logger.Error(err)
|
||||
continue
|
||||
}
|
||||
val = bytes
|
||||
}
|
||||
} else {
|
||||
engine.autoMapType(fieldValue)
|
||||
if table, ok := engine.Tables[fieldValue.Type()]; ok {
|
||||
if len(table.PrimaryKeys) == 1 {
|
||||
pkField := reflect.Indirect(fieldValue).FieldByName(table.PKColumns()[0].FieldName)
|
||||
// fix non-int pk issues
|
||||
//if pkField.Int() != 0 {
|
||||
if pkField.IsValid() && !isZero(pkField.Interface()) {
|
||||
val = pkField.Interface()
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
//TODO: how to handler?
|
||||
return nil, fmt.Errorf("not supported %v as %v", fieldValue.Interface(), table.PrimaryKeys)
|
||||
}
|
||||
} else {
|
||||
val = fieldValue.Interface()
|
||||
}
|
||||
}
|
||||
}
|
||||
case reflect.Array:
|
||||
continue
|
||||
case reflect.Slice, reflect.Map:
|
||||
if fieldValue == reflect.Zero(fieldType) {
|
||||
continue
|
||||
}
|
||||
if fieldValue.IsNil() || !fieldValue.IsValid() || fieldValue.Len() == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if col.SQLType.IsText() {
|
||||
bytes, err := DefaultJSONHandler.Marshal(fieldValue.Interface())
|
||||
if err != nil {
|
||||
engine.logger.Error(err)
|
||||
continue
|
||||
}
|
||||
val = string(bytes)
|
||||
} else if col.SQLType.IsBlob() {
|
||||
var bytes []byte
|
||||
var err error
|
||||
if (fieldType.Kind() == reflect.Array || fieldType.Kind() == reflect.Slice) &&
|
||||
fieldType.Elem().Kind() == reflect.Uint8 {
|
||||
if fieldValue.Len() > 0 {
|
||||
val = fieldValue.Bytes()
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
bytes, err = DefaultJSONHandler.Marshal(fieldValue.Interface())
|
||||
if err != nil {
|
||||
engine.logger.Error(err)
|
||||
continue
|
||||
}
|
||||
val = bytes
|
||||
}
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
default:
|
||||
val = fieldValue.Interface()
|
||||
}
|
||||
|
||||
conds = append(conds, builder.Eq{colName: val})
|
||||
}
|
||||
|
||||
return builder.And(conds...), nil
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
// Copyright 2019 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build go1.8
|
||||
|
||||
package xorm
|
||||
|
||||
import "context"
|
||||
|
||||
// Context creates a session with the context
|
||||
func (engine *Engine) Context(ctx context.Context) *Session {
|
||||
session := engine.NewSession()
|
||||
session.isAutoClose = true
|
||||
return session.Context(ctx)
|
||||
}
|
||||
|
||||
// SetDefaultContext set the default context
|
||||
func (engine *Engine) SetDefaultContext(ctx context.Context) {
|
||||
engine.defaultContext = ctx
|
||||
}
|
||||
|
||||
// PingContext tests if database is alive
|
||||
func (engine *Engine) PingContext(ctx context.Context) error {
|
||||
session := engine.NewSession()
|
||||
defer session.Close()
|
||||
return session.PingContext(ctx)
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
// Copyright 2017 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build go1.8
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPingContext(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
|
||||
ctx, canceled := context.WithTimeout(context.Background(), time.Nanosecond)
|
||||
defer canceled()
|
||||
|
||||
time.Sleep(time.Nanosecond)
|
||||
|
||||
err := testEngine.(*Engine).PingContext(ctx)
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "context deadline exceeded")
|
||||
}
|
||||
|
|
@ -8,7 +8,11 @@ import (
|
|||
"context"
|
||||
"time"
|
||||
|
||||
"xorm.io/core"
|
||||
"xorm.io/xorm/caches"
|
||||
"xorm.io/xorm/contexts"
|
||||
"xorm.io/xorm/dialects"
|
||||
"xorm.io/xorm/log"
|
||||
"xorm.io/xorm/names"
|
||||
)
|
||||
|
||||
// EngineGroup defines an engine group
|
||||
|
|
@ -75,7 +79,7 @@ func (eg *EngineGroup) Close() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Context returned a group session
|
||||
// ContextHook returned a group session
|
||||
func (eg *EngineGroup) Context(ctx context.Context) *Session {
|
||||
sess := eg.NewSession()
|
||||
sess.isAutoClose = true
|
||||
|
|
@ -109,10 +113,10 @@ func (eg *EngineGroup) Ping() error {
|
|||
}
|
||||
|
||||
// SetColumnMapper set the column name mapping rule
|
||||
func (eg *EngineGroup) SetColumnMapper(mapper core.IMapper) {
|
||||
eg.Engine.ColumnMapper = mapper
|
||||
func (eg *EngineGroup) SetColumnMapper(mapper names.Mapper) {
|
||||
eg.Engine.SetColumnMapper(mapper)
|
||||
for i := 0; i < len(eg.slaves); i++ {
|
||||
eg.slaves[i].ColumnMapper = mapper
|
||||
eg.slaves[i].SetColumnMapper(mapper)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -125,7 +129,7 @@ func (eg *EngineGroup) SetConnMaxLifetime(d time.Duration) {
|
|||
}
|
||||
|
||||
// SetDefaultCacher set the default cacher
|
||||
func (eg *EngineGroup) SetDefaultCacher(cacher core.Cacher) {
|
||||
func (eg *EngineGroup) SetDefaultCacher(cacher caches.Cacher) {
|
||||
eg.Engine.SetDefaultCacher(cacher)
|
||||
for i := 0; i < len(eg.slaves); i++ {
|
||||
eg.slaves[i].SetDefaultCacher(cacher)
|
||||
|
|
@ -133,15 +137,22 @@ func (eg *EngineGroup) SetDefaultCacher(cacher core.Cacher) {
|
|||
}
|
||||
|
||||
// SetLogger set the new logger
|
||||
func (eg *EngineGroup) SetLogger(logger core.ILogger) {
|
||||
func (eg *EngineGroup) SetLogger(logger interface{}) {
|
||||
eg.Engine.SetLogger(logger)
|
||||
for i := 0; i < len(eg.slaves); i++ {
|
||||
eg.slaves[i].SetLogger(logger)
|
||||
}
|
||||
}
|
||||
|
||||
func (eg *EngineGroup) AddHook(hook contexts.Hook) {
|
||||
eg.Engine.AddHook(hook)
|
||||
for i := 0; i < len(eg.slaves); i++ {
|
||||
eg.slaves[i].AddHook(hook)
|
||||
}
|
||||
}
|
||||
|
||||
// SetLogLevel sets the logger level
|
||||
func (eg *EngineGroup) SetLogLevel(level core.LogLevel) {
|
||||
func (eg *EngineGroup) SetLogLevel(level log.LogLevel) {
|
||||
eg.Engine.SetLogLevel(level)
|
||||
for i := 0; i < len(eg.slaves); i++ {
|
||||
eg.slaves[i].SetLogLevel(level)
|
||||
|
|
@ -149,7 +160,7 @@ func (eg *EngineGroup) SetLogLevel(level core.LogLevel) {
|
|||
}
|
||||
|
||||
// SetMapper set the name mapping rules
|
||||
func (eg *EngineGroup) SetMapper(mapper core.IMapper) {
|
||||
func (eg *EngineGroup) SetMapper(mapper names.Mapper) {
|
||||
eg.Engine.SetMapper(mapper)
|
||||
for i := 0; i < len(eg.slaves); i++ {
|
||||
eg.slaves[i].SetMapper(mapper)
|
||||
|
|
@ -158,17 +169,17 @@ func (eg *EngineGroup) SetMapper(mapper core.IMapper) {
|
|||
|
||||
// SetMaxIdleConns set the max idle connections on pool, default is 2
|
||||
func (eg *EngineGroup) SetMaxIdleConns(conns int) {
|
||||
eg.Engine.db.SetMaxIdleConns(conns)
|
||||
eg.Engine.DB().SetMaxIdleConns(conns)
|
||||
for i := 0; i < len(eg.slaves); i++ {
|
||||
eg.slaves[i].db.SetMaxIdleConns(conns)
|
||||
eg.slaves[i].DB().SetMaxIdleConns(conns)
|
||||
}
|
||||
}
|
||||
|
||||
// SetMaxOpenConns is only available for go 1.2+
|
||||
func (eg *EngineGroup) SetMaxOpenConns(conns int) {
|
||||
eg.Engine.db.SetMaxOpenConns(conns)
|
||||
eg.Engine.DB().SetMaxOpenConns(conns)
|
||||
for i := 0; i < len(eg.slaves); i++ {
|
||||
eg.slaves[i].db.SetMaxOpenConns(conns)
|
||||
eg.slaves[i].DB().SetMaxOpenConns(conns)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -178,19 +189,19 @@ func (eg *EngineGroup) SetPolicy(policy GroupPolicy) *EngineGroup {
|
|||
return eg
|
||||
}
|
||||
|
||||
// SetTableMapper set the table name mapping rule
|
||||
func (eg *EngineGroup) SetTableMapper(mapper core.IMapper) {
|
||||
eg.Engine.TableMapper = mapper
|
||||
// SetQuotePolicy sets the special quote policy
|
||||
func (eg *EngineGroup) SetQuotePolicy(quotePolicy dialects.QuotePolicy) {
|
||||
eg.Engine.SetQuotePolicy(quotePolicy)
|
||||
for i := 0; i < len(eg.slaves); i++ {
|
||||
eg.slaves[i].TableMapper = mapper
|
||||
eg.slaves[i].SetQuotePolicy(quotePolicy)
|
||||
}
|
||||
}
|
||||
|
||||
// ShowExecTime show SQL statement and execute time or not on logger if log level is great than INFO
|
||||
func (eg *EngineGroup) ShowExecTime(show ...bool) {
|
||||
eg.Engine.ShowExecTime(show...)
|
||||
// SetTableMapper set the table name mapping rule
|
||||
func (eg *EngineGroup) SetTableMapper(mapper names.Mapper) {
|
||||
eg.Engine.SetTableMapper(mapper)
|
||||
for i := 0; i < len(eg.slaves); i++ {
|
||||
eg.slaves[i].ShowExecTime(show...)
|
||||
eg.slaves[i].SetTableMapper(mapper)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ func WeightRandomPolicy(weights []int) GroupPolicyHandler {
|
|||
}
|
||||
}
|
||||
|
||||
// RoundRobinPolicy returns a group policy handler
|
||||
func RoundRobinPolicy() GroupPolicyHandler {
|
||||
var pos = -1
|
||||
var lock sync.Mutex
|
||||
|
|
@ -68,6 +69,7 @@ func RoundRobinPolicy() GroupPolicyHandler {
|
|||
}
|
||||
}
|
||||
|
||||
// WeightRoundRobinPolicy returns a group policy handler
|
||||
func WeightRoundRobinPolicy(weights []int) GroupPolicyHandler {
|
||||
var rands = make([]int, 0, len(weights))
|
||||
for i := 0; i < len(weights); i++ {
|
||||
|
|
|
|||
113
engine_table.go
113
engine_table.go
|
|
@ -1,113 +0,0 @@
|
|||
// Copyright 2018 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
// tbNameWithSchema will automatically add schema prefix on table name
|
||||
func (engine *Engine) tbNameWithSchema(v string) string {
|
||||
// Add schema name as prefix of table name.
|
||||
// Only for postgres database.
|
||||
if engine.dialect.DBType() == core.POSTGRES &&
|
||||
engine.dialect.URI().Schema != "" &&
|
||||
engine.dialect.URI().Schema != postgresPublicSchema &&
|
||||
strings.Index(v, ".") == -1 {
|
||||
return engine.dialect.URI().Schema + "." + v
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// TableName returns table name with schema prefix if has
|
||||
func (engine *Engine) TableName(bean interface{}, includeSchema ...bool) string {
|
||||
tbName := engine.tbNameNoSchema(bean)
|
||||
if len(includeSchema) > 0 && includeSchema[0] {
|
||||
tbName = engine.tbNameWithSchema(tbName)
|
||||
}
|
||||
|
||||
return tbName
|
||||
}
|
||||
|
||||
// tbName get some table's table name
|
||||
func (session *Session) tbNameNoSchema(table *core.Table) string {
|
||||
if len(session.statement.AltTableName) > 0 {
|
||||
return session.statement.AltTableName
|
||||
}
|
||||
|
||||
return table.Name
|
||||
}
|
||||
|
||||
func (engine *Engine) tbNameForMap(v reflect.Value) string {
|
||||
if v.Type().Implements(tpTableName) {
|
||||
return v.Interface().(TableName).TableName()
|
||||
}
|
||||
if v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
if v.Type().Implements(tpTableName) {
|
||||
return v.Interface().(TableName).TableName()
|
||||
}
|
||||
}
|
||||
|
||||
return engine.TableMapper.Obj2Table(v.Type().Name())
|
||||
}
|
||||
|
||||
func (engine *Engine) tbNameNoSchema(tablename interface{}) string {
|
||||
switch tablename.(type) {
|
||||
case []string:
|
||||
t := tablename.([]string)
|
||||
if len(t) > 1 {
|
||||
return fmt.Sprintf("%v AS %v", engine.Quote(t[0]), engine.Quote(t[1]))
|
||||
} else if len(t) == 1 {
|
||||
return engine.Quote(t[0])
|
||||
}
|
||||
case []interface{}:
|
||||
t := tablename.([]interface{})
|
||||
l := len(t)
|
||||
var table string
|
||||
if l > 0 {
|
||||
f := t[0]
|
||||
switch f.(type) {
|
||||
case string:
|
||||
table = f.(string)
|
||||
case TableName:
|
||||
table = f.(TableName).TableName()
|
||||
default:
|
||||
v := rValue(f)
|
||||
t := v.Type()
|
||||
if t.Kind() == reflect.Struct {
|
||||
table = engine.tbNameForMap(v)
|
||||
} else {
|
||||
table = engine.Quote(fmt.Sprintf("%v", f))
|
||||
}
|
||||
}
|
||||
}
|
||||
if l > 1 {
|
||||
return fmt.Sprintf("%v AS %v", engine.Quote(table),
|
||||
engine.Quote(fmt.Sprintf("%v", t[1])))
|
||||
} else if l == 1 {
|
||||
return engine.Quote(table)
|
||||
}
|
||||
case TableName:
|
||||
return tablename.(TableName).TableName()
|
||||
case string:
|
||||
return tablename.(string)
|
||||
case reflect.Value:
|
||||
v := tablename.(reflect.Value)
|
||||
return engine.tbNameForMap(v)
|
||||
default:
|
||||
v := rValue(tablename)
|
||||
t := v.Type()
|
||||
if t.Kind() == reflect.Struct {
|
||||
return engine.tbNameForMap(v)
|
||||
}
|
||||
return engine.Quote(fmt.Sprintf("%v", tablename))
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
// Copyright 2019 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestQuoteTo(t *testing.T) {
|
||||
|
||||
test := func(t *testing.T, expected string, value string) {
|
||||
buf := &strings.Builder{}
|
||||
quoteTo(buf, "[]", value)
|
||||
assert.EqualValues(t, expected, buf.String())
|
||||
}
|
||||
|
||||
test(t, "[mytable]", "mytable")
|
||||
test(t, "[mytable]", "`mytable`")
|
||||
test(t, "[mytable]", `[mytable]`)
|
||||
|
||||
test(t, `["mytable"]`, `"mytable"`)
|
||||
|
||||
test(t, "[myschema].[mytable]", "myschema.mytable")
|
||||
test(t, "[myschema].[mytable]", "`myschema`.mytable")
|
||||
test(t, "[myschema].[mytable]", "myschema.`mytable`")
|
||||
test(t, "[myschema].[mytable]", "`myschema`.`mytable`")
|
||||
test(t, "[myschema].[mytable]", `[myschema].mytable`)
|
||||
test(t, "[myschema].[mytable]", `myschema.[mytable]`)
|
||||
test(t, "[myschema].[mytable]", `[myschema].[mytable]`)
|
||||
|
||||
test(t, `["myschema].[mytable"]`, `"myschema.mytable"`)
|
||||
|
||||
buf := &strings.Builder{}
|
||||
quoteTo(buf, "", "noquote")
|
||||
assert.EqualValues(t, "noquote", buf.String())
|
||||
}
|
||||
29
error.go
29
error.go
|
|
@ -6,10 +6,11 @@ package xorm
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrPtrSliceType represents a type error
|
||||
ErrPtrSliceType = errors.New("A point to a slice is needed")
|
||||
// ErrParamsType params error
|
||||
ErrParamsType = errors.New("Params type error")
|
||||
// ErrTableNotFound table not found error
|
||||
|
|
@ -20,32 +21,6 @@ var (
|
|||
ErrNotExist = errors.New("Record does not exist")
|
||||
// ErrCacheFailed cache failed error
|
||||
ErrCacheFailed = errors.New("Cache failed")
|
||||
// ErrNeedDeletedCond delete needs less one condition error
|
||||
ErrNeedDeletedCond = errors.New("Delete action needs at least one condition")
|
||||
// ErrNotImplemented not implemented
|
||||
ErrNotImplemented = errors.New("Not implemented")
|
||||
// ErrConditionType condition type unsupported
|
||||
ErrConditionType = errors.New("Unsupported condition type")
|
||||
// ErrUnSupportedSQLType parameter of SQL is not supported
|
||||
ErrUnSupportedSQLType = errors.New("unsupported sql type")
|
||||
)
|
||||
|
||||
// ErrFieldIsNotExist columns does not exist
|
||||
type ErrFieldIsNotExist struct {
|
||||
FieldName string
|
||||
TableName string
|
||||
}
|
||||
|
||||
func (e ErrFieldIsNotExist) Error() string {
|
||||
return fmt.Sprintf("field %s is not valid on table %s", e.FieldName, e.TableName)
|
||||
}
|
||||
|
||||
// ErrFieldIsNotValid is not valid
|
||||
type ErrFieldIsNotValid struct {
|
||||
FieldName string
|
||||
TableName string
|
||||
}
|
||||
|
||||
func (e ErrFieldIsNotValid) Error() string {
|
||||
return fmt.Sprintf("field %s is not valid on table %s", e.FieldName, e.TableName)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
# Xorm Examples
|
||||
|
||||
Notice: all the examples will ask you install extra package `github.com/mattn/go-sqlite3`, since it depends on cgo. You have to compile it after you install a c++ compile. Please see [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3).
|
||||
|
||||
And then, you can run the examples via `go run xxx.go`. Every go file is a standalone example.
|
||||
|
|
@ -1,109 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"xorm.io/xorm"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
// User describes a user
|
||||
type User struct {
|
||||
Id int64
|
||||
Name string
|
||||
}
|
||||
|
||||
func main() {
|
||||
f := "cache.db"
|
||||
os.Remove(f)
|
||||
|
||||
Orm, err := xorm.NewEngine("sqlite3", f)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
Orm.ShowSQL(true)
|
||||
cacher := xorm.NewLRUCacher(xorm.NewMemoryStore(), 1000)
|
||||
Orm.SetDefaultCacher(cacher)
|
||||
|
||||
err = Orm.CreateTables(&User{})
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = Orm.Insert(&User{Name: "xlw"})
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
var users []User
|
||||
err = Orm.Find(&users)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("users:", users)
|
||||
|
||||
var users2 []User
|
||||
err = Orm.Find(&users2)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("users2:", users2)
|
||||
|
||||
var users3 []User
|
||||
err = Orm.Find(&users3)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("users3:", users3)
|
||||
|
||||
user4 := new(User)
|
||||
has, err := Orm.ID(1).Get(user4)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("user4:", has, user4)
|
||||
|
||||
user4.Name = "xiaolunwen"
|
||||
_, err = Orm.ID(1).Update(user4)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Println("user4:", user4)
|
||||
|
||||
user5 := new(User)
|
||||
has, err = Orm.ID(1).Get(user5)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Println("user5:", has, user5)
|
||||
|
||||
_, err = Orm.ID(1).Delete(new(User))
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
for {
|
||||
user6 := new(User)
|
||||
has, err = Orm.ID(1).Get(user6)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Println("user6:", has, user6)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,108 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"xorm.io/xorm"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
// User describes a user
|
||||
type User struct {
|
||||
Id int64
|
||||
Name string
|
||||
}
|
||||
|
||||
func sqliteEngine() (*xorm.Engine, error) {
|
||||
os.Remove("./test.db")
|
||||
return xorm.NewEngine("sqlite3", "./goroutine.db")
|
||||
}
|
||||
|
||||
func mysqlEngine() (*xorm.Engine, error) {
|
||||
return xorm.NewEngine("mysql", "root:@/test?charset=utf8")
|
||||
}
|
||||
|
||||
var u = &User{}
|
||||
|
||||
func test(engine *xorm.Engine) {
|
||||
err := engine.CreateTables(u)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
size := 500
|
||||
queue := make(chan int, size)
|
||||
|
||||
for i := 0; i < size; i++ {
|
||||
go func(x int) {
|
||||
//x := i
|
||||
err := engine.Ping()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
} else {
|
||||
for j := 0; j < 10; j++ {
|
||||
if x+j < 2 {
|
||||
_, err = engine.Get(u)
|
||||
} else if x+j < 4 {
|
||||
users := make([]User, 0)
|
||||
err = engine.Find(&users)
|
||||
} else if x+j < 8 {
|
||||
_, err = engine.Count(u)
|
||||
} else if x+j < 16 {
|
||||
_, err = engine.Insert(&User{Name: "xlw"})
|
||||
} else if x+j < 32 {
|
||||
//_, err = engine.ID(1).Delete(u)
|
||||
_, err = engine.Delete(u)
|
||||
}
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
queue <- x
|
||||
return
|
||||
}
|
||||
}
|
||||
fmt.Printf("%v success!\n", x)
|
||||
}
|
||||
queue <- x
|
||||
}(i)
|
||||
}
|
||||
|
||||
for i := 0; i < size; i++ {
|
||||
<-queue
|
||||
}
|
||||
|
||||
//conns := atomic.LoadInt32(&xorm.ConnectionNum)
|
||||
//fmt.Println("connection number:", conns)
|
||||
fmt.Println("end")
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("-----start sqlite go routines-----")
|
||||
engine, err := sqliteEngine()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
engine.ShowSQL(true)
|
||||
cacher := xorm.NewLRUCacher2(xorm.NewMemoryStore(), time.Hour, 1000)
|
||||
engine.SetDefaultCacher(cacher)
|
||||
fmt.Println(engine)
|
||||
test(engine)
|
||||
fmt.Println("test end")
|
||||
engine.Close()
|
||||
|
||||
fmt.Println("-----start mysql go routines-----")
|
||||
engine, err = mysqlEngine()
|
||||
engine.ShowSQL(true)
|
||||
cacher = xorm.NewLRUCacher2(xorm.NewMemoryStore(), time.Hour, 1000)
|
||||
engine.SetDefaultCacher(cacher)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
defer engine.Close()
|
||||
test(engine)
|
||||
}
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"xorm.io/xorm"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
// Status describes a status
|
||||
type Status struct {
|
||||
Name string
|
||||
Color string
|
||||
}
|
||||
|
||||
// defines some statuses
|
||||
var (
|
||||
Registered = Status{"Registered", "white"}
|
||||
Approved = Status{"Approved", "green"}
|
||||
Removed = Status{"Removed", "red"}
|
||||
Statuses = map[string]Status{
|
||||
Registered.Name: Registered,
|
||||
Approved.Name: Approved,
|
||||
Removed.Name: Removed,
|
||||
}
|
||||
)
|
||||
|
||||
// FromDB implemented xorm.Conversion convent database data to self
|
||||
func (s *Status) FromDB(bytes []byte) error {
|
||||
if r, ok := Statuses[string(bytes)]; ok {
|
||||
*s = r
|
||||
return nil
|
||||
}
|
||||
return errors.New("no this data")
|
||||
}
|
||||
|
||||
// ToDB implemented xorm.Conversion convent to database data
|
||||
func (s *Status) ToDB() ([]byte, error) {
|
||||
return []byte(s.Name), nil
|
||||
}
|
||||
|
||||
// User describes a user
|
||||
type User struct {
|
||||
Id int64
|
||||
Name string
|
||||
Status Status `xorm:"varchar(40)"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
f := "conversion.db"
|
||||
os.Remove(f)
|
||||
|
||||
Orm, err := xorm.NewEngine("sqlite3", f)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
Orm.ShowSQL(true)
|
||||
err = Orm.CreateTables(&User{})
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = Orm.Insert(&User{1, "xlw", Registered})
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
users := make([]User, 0)
|
||||
err = Orm.Find(&users)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(users)
|
||||
}
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"xorm.io/xorm"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
// User describes a user
|
||||
type User struct {
|
||||
Id int64
|
||||
Name string
|
||||
}
|
||||
|
||||
// LoginInfo describes a login information
|
||||
type LoginInfo struct {
|
||||
Id int64
|
||||
IP string
|
||||
UserId int64
|
||||
}
|
||||
|
||||
// LoginInfo1 describes a login information
|
||||
type LoginInfo1 struct {
|
||||
LoginInfo `xorm:"extends"`
|
||||
UserName string
|
||||
}
|
||||
|
||||
func main() {
|
||||
f := "derive.db"
|
||||
os.Remove(f)
|
||||
|
||||
orm, err := xorm.NewEngine("sqlite3", f)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
defer orm.Close()
|
||||
orm.ShowSQL(true)
|
||||
err = orm.CreateTables(&User{}, &LoginInfo{})
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = orm.Insert(&User{1, "xlw"}, &LoginInfo{1, "127.0.0.1", 1})
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
info := LoginInfo{}
|
||||
_, err = orm.ID(1).Get(&info)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Println(info)
|
||||
|
||||
infos := make([]LoginInfo1, 0)
|
||||
err = orm.Sql(`select *, (select name from user where id = login_info.user_id) as user_name from
|
||||
login_info limit 10`).Find(&infos)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(infos)
|
||||
}
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
// User describes a user
|
||||
type User struct {
|
||||
Id int64
|
||||
Name string
|
||||
Created time.Time `xorm:"created"`
|
||||
Updated time.Time `xorm:"updated"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
f := "conversion.db"
|
||||
os.Remove(f)
|
||||
|
||||
orm, err := xorm.NewEngine("sqlite3", f)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
orm.ShowSQL(true)
|
||||
|
||||
err = orm.CreateTables(&User{})
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = orm.Insert(&User{Id: 1, Name: "xlw"})
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
users := make([]User, 0)
|
||||
err = orm.Find(&users)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(users)
|
||||
}
|
||||
|
|
@ -1,108 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"xorm.io/xorm"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
// User describes a user
|
||||
type User struct {
|
||||
Id int64
|
||||
Name string
|
||||
}
|
||||
|
||||
func sqliteEngine() (*xorm.Engine, error) {
|
||||
os.Remove("./test.db")
|
||||
return xorm.NewEngine("sqlite3", "./goroutine.db")
|
||||
}
|
||||
|
||||
func mysqlEngine() (*xorm.Engine, error) {
|
||||
return xorm.NewEngine("mysql", "root:@/test?charset=utf8")
|
||||
}
|
||||
|
||||
var u = &User{}
|
||||
|
||||
func test(engine *xorm.Engine) {
|
||||
err := engine.CreateTables(u)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
size := 100
|
||||
queue := make(chan int, size)
|
||||
|
||||
for i := 0; i < size; i++ {
|
||||
go func(x int) {
|
||||
//x := i
|
||||
err := engine.Ping()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
} else {
|
||||
/*err = engine.(u)
|
||||
if err != nil {
|
||||
fmt.Println("Map user failed")
|
||||
} else {*/
|
||||
for j := 0; j < 10; j++ {
|
||||
if x+j < 2 {
|
||||
_, err = engine.Get(u)
|
||||
} else if x+j < 4 {
|
||||
users := make([]User, 0)
|
||||
err = engine.Find(&users)
|
||||
} else if x+j < 8 {
|
||||
_, err = engine.Count(u)
|
||||
} else if x+j < 16 {
|
||||
_, err = engine.Insert(&User{Name: "xlw"})
|
||||
} else if x+j < 32 {
|
||||
_, err = engine.ID(1).Delete(u)
|
||||
}
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
queue <- x
|
||||
return
|
||||
}
|
||||
}
|
||||
fmt.Printf("%v success!\n", x)
|
||||
//}
|
||||
}
|
||||
queue <- x
|
||||
}(i)
|
||||
}
|
||||
|
||||
for i := 0; i < size; i++ {
|
||||
<-queue
|
||||
}
|
||||
|
||||
//conns := atomic.LoadInt32(&xorm.ConnectionNum)
|
||||
//fmt.Println("connection number:", conns)
|
||||
fmt.Println("end")
|
||||
}
|
||||
|
||||
func main() {
|
||||
runtime.GOMAXPROCS(2)
|
||||
fmt.Println("-----start sqlite go routines-----")
|
||||
engine, err := sqliteEngine()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
engine.ShowSQL(true)
|
||||
fmt.Println(engine)
|
||||
test(engine)
|
||||
fmt.Println("test end")
|
||||
engine.Close()
|
||||
|
||||
fmt.Println("-----start mysql go routines-----")
|
||||
engine, err = mysqlEngine()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
defer engine.Close()
|
||||
test(engine)
|
||||
}
|
||||
|
|
@ -1,108 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"xorm.io/xorm"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
// User describes a user
|
||||
type User struct {
|
||||
Id int64
|
||||
Name string
|
||||
}
|
||||
|
||||
func sqliteEngine() (*xorm.Engine, error) {
|
||||
os.Remove("./test.db")
|
||||
return xorm.NewEngine("sqlite3", "./goroutine.db")
|
||||
}
|
||||
|
||||
func mysqlEngine() (*xorm.Engine, error) {
|
||||
return xorm.NewEngine("mysql", "root:@/test?charset=utf8")
|
||||
}
|
||||
|
||||
var u = &User{}
|
||||
|
||||
func test(engine *xorm.Engine) {
|
||||
err := engine.CreateTables(u)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
engine.ShowSQL(true)
|
||||
engine.SetMaxOpenConns(5)
|
||||
|
||||
size := 1000
|
||||
queue := make(chan int, size)
|
||||
|
||||
for i := 0; i < size; i++ {
|
||||
go func(x int) {
|
||||
//x := i
|
||||
err := engine.Ping()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
} else {
|
||||
/*err = engine.Map(u)
|
||||
if err != nil {
|
||||
fmt.Println("Map user failed")
|
||||
} else {*/
|
||||
for j := 0; j < 10; j++ {
|
||||
if x+j < 2 {
|
||||
_, err = engine.Get(u)
|
||||
} else if x+j < 4 {
|
||||
users := make([]User, 0)
|
||||
err = engine.Find(&users)
|
||||
} else if x+j < 8 {
|
||||
_, err = engine.Count(u)
|
||||
} else if x+j < 16 {
|
||||
_, err = engine.Insert(&User{Name: "xlw"})
|
||||
} else if x+j < 32 {
|
||||
_, err = engine.ID(1).Delete(u)
|
||||
}
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
queue <- x
|
||||
return
|
||||
}
|
||||
}
|
||||
fmt.Printf("%v success!\n", x)
|
||||
//}
|
||||
}
|
||||
queue <- x
|
||||
}(i)
|
||||
}
|
||||
|
||||
for i := 0; i < size; i++ {
|
||||
<-queue
|
||||
}
|
||||
|
||||
fmt.Println("end")
|
||||
}
|
||||
|
||||
func main() {
|
||||
runtime.GOMAXPROCS(2)
|
||||
fmt.Println("create engine")
|
||||
engine, err := sqliteEngine()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
engine.ShowSQL(true)
|
||||
fmt.Println(engine)
|
||||
test(engine)
|
||||
fmt.Println("------------------------")
|
||||
engine.Close()
|
||||
|
||||
engine, err = mysqlEngine()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
defer engine.Close()
|
||||
test(engine)
|
||||
}
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"xorm.io/xorm"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
// User describes a user
|
||||
type User struct {
|
||||
Id int64
|
||||
Name string
|
||||
}
|
||||
|
||||
// LoginInfo describes a login information
|
||||
type LoginInfo struct {
|
||||
Id int64
|
||||
IP string
|
||||
UserId int64
|
||||
// timestamp should be updated by database, so only allow get from db
|
||||
TimeStamp string `xorm:"<-"`
|
||||
// assume
|
||||
Nonuse int `xorm:"->"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
f := "singleMapping.db"
|
||||
os.Remove(f)
|
||||
|
||||
orm, err := xorm.NewEngine("sqlite3", f)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
orm.ShowSQL(true)
|
||||
err = orm.CreateTables(&User{}, &LoginInfo{})
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = orm.Insert(&User{1, "xlw"}, &LoginInfo{1, "127.0.0.1", 1, "", 23})
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
info := LoginInfo{}
|
||||
_, err = orm.ID(1).Get(&info)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Println(info)
|
||||
}
|
||||
106
examples/sync.go
106
examples/sync.go
|
|
@ -1,106 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"xorm.io/xorm"
|
||||
_ "github.com/lib/pq"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
// SyncUser2 describes a user
|
||||
type SyncUser2 struct {
|
||||
Id int64
|
||||
Name string `xorm:"unique"`
|
||||
Age int `xorm:"index"`
|
||||
Title string
|
||||
Address string
|
||||
Genre string
|
||||
Area string
|
||||
Date int
|
||||
}
|
||||
|
||||
// SyncLoginInfo2 describes a login information
|
||||
type SyncLoginInfo2 struct {
|
||||
Id int64
|
||||
IP string `xorm:"index"`
|
||||
UserId int64
|
||||
AddedCol int
|
||||
// timestamp should be updated by database, so only allow get from db
|
||||
TimeStamp string
|
||||
// assume
|
||||
Nonuse int `xorm:"unique"`
|
||||
Newa string `xorm:"index"`
|
||||
}
|
||||
|
||||
func sync(engine *xorm.Engine) error {
|
||||
return engine.Sync(&SyncLoginInfo2{}, &SyncUser2{})
|
||||
}
|
||||
|
||||
func sqliteEngine() (*xorm.Engine, error) {
|
||||
f := "sync.db"
|
||||
//os.Remove(f)
|
||||
|
||||
return xorm.NewEngine("sqlite3", f)
|
||||
}
|
||||
|
||||
func mysqlEngine() (*xorm.Engine, error) {
|
||||
return xorm.NewEngine("mysql", "root:@/test?charset=utf8")
|
||||
}
|
||||
|
||||
func postgresEngine() (*xorm.Engine, error) {
|
||||
return xorm.NewEngine("postgres", "dbname=xorm_test sslmode=disable")
|
||||
}
|
||||
|
||||
type engineFunc func() (*xorm.Engine, error)
|
||||
|
||||
func main() {
|
||||
//engines := []engineFunc{sqliteEngine, mysqlEngine, postgresEngine}
|
||||
//engines := []engineFunc{sqliteEngine}
|
||||
//engines := []engineFunc{mysqlEngine}
|
||||
engines := []engineFunc{postgresEngine}
|
||||
for _, enginefunc := range engines {
|
||||
Orm, err := enginefunc()
|
||||
fmt.Println("--------", Orm.DriverName(), "----------")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
Orm.ShowSQL(true)
|
||||
err = sync(Orm)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
_, err = Orm.Where("id > 0").Delete(&SyncUser2{})
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
user := &SyncUser2{
|
||||
Name: "testsdf",
|
||||
Age: 15,
|
||||
Title: "newsfds",
|
||||
Address: "fasfdsafdsaf",
|
||||
Genre: "fsafd",
|
||||
Area: "fafdsafd",
|
||||
Date: 1000,
|
||||
}
|
||||
_, err = Orm.Insert(user)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
isexist, err := Orm.IsTableExist("sync_user2")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
if !isexist {
|
||||
fmt.Println("sync_user2 is not exist")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"xorm.io/xorm"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 2 {
|
||||
fmt.Println("need db path")
|
||||
return
|
||||
}
|
||||
|
||||
orm, err := xorm.NewEngine("sqlite3", os.Args[1])
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
defer orm.Close()
|
||||
orm.ShowSQL(true)
|
||||
|
||||
tables, err := orm.DBMetas()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, table := range tables {
|
||||
fmt.Println(table.Name)
|
||||
}
|
||||
}
|
||||
13
go.mod
13
go.mod
|
|
@ -3,13 +3,12 @@ module xorm.io/xorm
|
|||
go 1.11
|
||||
|
||||
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.0.0-20200428022330-06a60b6afbbc
|
||||
github.com/go-sql-driver/mysql v1.5.0
|
||||
github.com/lib/pq v1.7.0
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible
|
||||
github.com/stretchr/testify v1.4.0
|
||||
github.com/syndtr/goleveldb v1.0.0
|
||||
github.com/ziutek/mymysql v1.5.4
|
||||
xorm.io/builder v0.3.6
|
||||
xorm.io/core v0.7.2
|
||||
xorm.io/builder v0.3.7
|
||||
)
|
||||
|
|
|
|||
150
go.sum
150
go.sum
|
|
@ -1,149 +1,61 @@
|
|||
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=
|
||||
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=
|
||||
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/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.0.0-20200428022330-06a60b6afbbc h1:VRRKCwnzqk8QCaRC4os14xoKDdbHqqlJtJA0oc1ZAjg=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
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/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y=
|
||||
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM=
|
||||
github.com/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/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/lib/pq v1.7.0 h1:h93mCPfUSkaul3Ka/VG8uZdmW1uMHDGxzu0NWHuJmHY=
|
||||
github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
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/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/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/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA=
|
||||
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/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/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
|
||||
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/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/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs=
|
||||
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/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/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=
|
||||
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=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
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.6 h1:ha28mQ2M+TFx96Hxo+iq6tQgnkC9IZkM6D8w9sKHHF8=
|
||||
xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU=
|
||||
xorm.io/core v0.7.2 h1:mEO22A2Z7a3fPaZMk6gKL/jMD80iiyNwRrX5HOv3XLw=
|
||||
xorm.io/core v0.7.2/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM=
|
||||
xorm.io/builder v0.3.7 h1:2pETdKRK+2QG4mLX4oODHEhn5Z8j1m8sXa7jfu+/SZI=
|
||||
xorm.io/builder v0.3.7/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
|
||||
|
|
|
|||
332
helpers.go
332
helpers.go
|
|
@ -1,332 +0,0 @@
|
|||
// Copyright 2015 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
// str2PK convert string value to primary key value according to tp
|
||||
func str2PKValue(s string, tp reflect.Type) (reflect.Value, error) {
|
||||
var err error
|
||||
var result interface{}
|
||||
var defReturn = reflect.Zero(tp)
|
||||
|
||||
switch tp.Kind() {
|
||||
case reflect.Int:
|
||||
result, err = strconv.Atoi(s)
|
||||
if err != nil {
|
||||
return defReturn, fmt.Errorf("convert %s as int: %s", s, err.Error())
|
||||
}
|
||||
case reflect.Int8:
|
||||
x, err := strconv.Atoi(s)
|
||||
if err != nil {
|
||||
return defReturn, fmt.Errorf("convert %s as int8: %s", s, err.Error())
|
||||
}
|
||||
result = int8(x)
|
||||
case reflect.Int16:
|
||||
x, err := strconv.Atoi(s)
|
||||
if err != nil {
|
||||
return defReturn, fmt.Errorf("convert %s as int16: %s", s, err.Error())
|
||||
}
|
||||
result = int16(x)
|
||||
case reflect.Int32:
|
||||
x, err := strconv.Atoi(s)
|
||||
if err != nil {
|
||||
return defReturn, fmt.Errorf("convert %s as int32: %s", s, err.Error())
|
||||
}
|
||||
result = int32(x)
|
||||
case reflect.Int64:
|
||||
result, err = strconv.ParseInt(s, 10, 64)
|
||||
if err != nil {
|
||||
return defReturn, fmt.Errorf("convert %s as int64: %s", s, err.Error())
|
||||
}
|
||||
case reflect.Uint:
|
||||
x, err := strconv.ParseUint(s, 10, 64)
|
||||
if err != nil {
|
||||
return defReturn, fmt.Errorf("convert %s as uint: %s", s, err.Error())
|
||||
}
|
||||
result = uint(x)
|
||||
case reflect.Uint8:
|
||||
x, err := strconv.ParseUint(s, 10, 64)
|
||||
if err != nil {
|
||||
return defReturn, fmt.Errorf("convert %s as uint8: %s", s, err.Error())
|
||||
}
|
||||
result = uint8(x)
|
||||
case reflect.Uint16:
|
||||
x, err := strconv.ParseUint(s, 10, 64)
|
||||
if err != nil {
|
||||
return defReturn, fmt.Errorf("convert %s as uint16: %s", s, err.Error())
|
||||
}
|
||||
result = uint16(x)
|
||||
case reflect.Uint32:
|
||||
x, err := strconv.ParseUint(s, 10, 64)
|
||||
if err != nil {
|
||||
return defReturn, fmt.Errorf("convert %s as uint32: %s", s, err.Error())
|
||||
}
|
||||
result = uint32(x)
|
||||
case reflect.Uint64:
|
||||
result, err = strconv.ParseUint(s, 10, 64)
|
||||
if err != nil {
|
||||
return defReturn, fmt.Errorf("convert %s as uint64: %s", s, err.Error())
|
||||
}
|
||||
case reflect.String:
|
||||
result = s
|
||||
default:
|
||||
return defReturn, errors.New("unsupported convert type")
|
||||
}
|
||||
return reflect.ValueOf(result).Convert(tp), nil
|
||||
}
|
||||
|
||||
func str2PK(s string, tp reflect.Type) (interface{}, error) {
|
||||
v, err := str2PKValue(s, tp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return v.Interface(), nil
|
||||
}
|
||||
|
||||
func splitTag(tag string) (tags []string) {
|
||||
tag = strings.TrimSpace(tag)
|
||||
var hasQuote = false
|
||||
var lastIdx = 0
|
||||
for i, t := range tag {
|
||||
if t == '\'' {
|
||||
hasQuote = !hasQuote
|
||||
} else if t == ' ' {
|
||||
if lastIdx < i && !hasQuote {
|
||||
tags = append(tags, strings.TrimSpace(tag[lastIdx:i]))
|
||||
lastIdx = i + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
if lastIdx < len(tag) {
|
||||
tags = append(tags, strings.TrimSpace(tag[lastIdx:]))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type zeroable interface {
|
||||
IsZero() bool
|
||||
}
|
||||
|
||||
func isZero(k interface{}) bool {
|
||||
switch k.(type) {
|
||||
case int:
|
||||
return k.(int) == 0
|
||||
case int8:
|
||||
return k.(int8) == 0
|
||||
case int16:
|
||||
return k.(int16) == 0
|
||||
case int32:
|
||||
return k.(int32) == 0
|
||||
case int64:
|
||||
return k.(int64) == 0
|
||||
case uint:
|
||||
return k.(uint) == 0
|
||||
case uint8:
|
||||
return k.(uint8) == 0
|
||||
case uint16:
|
||||
return k.(uint16) == 0
|
||||
case uint32:
|
||||
return k.(uint32) == 0
|
||||
case uint64:
|
||||
return k.(uint64) == 0
|
||||
case float32:
|
||||
return k.(float32) == 0
|
||||
case float64:
|
||||
return k.(float64) == 0
|
||||
case bool:
|
||||
return k.(bool) == false
|
||||
case string:
|
||||
return k.(string) == ""
|
||||
case zeroable:
|
||||
return k.(zeroable).IsZero()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isStructZero(v reflect.Value) bool {
|
||||
if !v.IsValid() {
|
||||
return true
|
||||
}
|
||||
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
field := v.Field(i)
|
||||
switch field.Kind() {
|
||||
case reflect.Ptr:
|
||||
field = field.Elem()
|
||||
fallthrough
|
||||
case reflect.Struct:
|
||||
if !isStructZero(field) {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
if field.CanInterface() && !isZero(field.Interface()) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func isArrayValueZero(v reflect.Value) bool {
|
||||
if !v.IsValid() || v.Len() == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
if !isZero(v.Index(i).Interface()) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func int64ToIntValue(id int64, tp reflect.Type) reflect.Value {
|
||||
var v interface{}
|
||||
kind := tp.Kind()
|
||||
|
||||
if kind == reflect.Ptr {
|
||||
kind = tp.Elem().Kind()
|
||||
}
|
||||
|
||||
switch kind {
|
||||
case reflect.Int16:
|
||||
temp := int16(id)
|
||||
v = &temp
|
||||
case reflect.Int32:
|
||||
temp := int32(id)
|
||||
v = &temp
|
||||
case reflect.Int:
|
||||
temp := int(id)
|
||||
v = &temp
|
||||
case reflect.Int64:
|
||||
temp := id
|
||||
v = &temp
|
||||
case reflect.Uint16:
|
||||
temp := uint16(id)
|
||||
v = &temp
|
||||
case reflect.Uint32:
|
||||
temp := uint32(id)
|
||||
v = &temp
|
||||
case reflect.Uint64:
|
||||
temp := uint64(id)
|
||||
v = &temp
|
||||
case reflect.Uint:
|
||||
temp := uint(id)
|
||||
v = &temp
|
||||
}
|
||||
|
||||
if tp.Kind() == reflect.Ptr {
|
||||
return reflect.ValueOf(v).Convert(tp)
|
||||
}
|
||||
return reflect.ValueOf(v).Elem().Convert(tp)
|
||||
}
|
||||
|
||||
func int64ToInt(id int64, tp reflect.Type) interface{} {
|
||||
return int64ToIntValue(id, tp).Interface()
|
||||
}
|
||||
|
||||
func isPKZero(pk core.PK) bool {
|
||||
for _, k := range pk {
|
||||
if isZero(k) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func indexNoCase(s, sep string) int {
|
||||
return strings.Index(strings.ToLower(s), strings.ToLower(sep))
|
||||
}
|
||||
|
||||
func splitNoCase(s, sep string) []string {
|
||||
idx := indexNoCase(s, sep)
|
||||
if idx < 0 {
|
||||
return []string{s}
|
||||
}
|
||||
return strings.Split(s, s[idx:idx+len(sep)])
|
||||
}
|
||||
|
||||
func splitNNoCase(s, sep string, n int) []string {
|
||||
idx := indexNoCase(s, sep)
|
||||
if idx < 0 {
|
||||
return []string{s}
|
||||
}
|
||||
return strings.SplitN(s, s[idx:idx+len(sep)], n)
|
||||
}
|
||||
|
||||
func makeArray(elem string, count int) []string {
|
||||
res := make([]string, count)
|
||||
for i := 0; i < count; i++ {
|
||||
res[i] = elem
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func rValue(bean interface{}) reflect.Value {
|
||||
return reflect.Indirect(reflect.ValueOf(bean))
|
||||
}
|
||||
|
||||
func rType(bean interface{}) reflect.Type {
|
||||
sliceValue := reflect.Indirect(reflect.ValueOf(bean))
|
||||
// return reflect.TypeOf(sliceValue.Interface())
|
||||
return sliceValue.Type()
|
||||
}
|
||||
|
||||
func structName(v reflect.Type) string {
|
||||
for v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
}
|
||||
return v.Name()
|
||||
}
|
||||
|
||||
func sliceEq(left, right []string) bool {
|
||||
if len(left) != len(right) {
|
||||
return false
|
||||
}
|
||||
sort.Sort(sort.StringSlice(left))
|
||||
sort.Sort(sort.StringSlice(right))
|
||||
for i := 0; i < len(left); i++ {
|
||||
if left[i] != right[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func indexName(tableName, idxName string) string {
|
||||
return fmt.Sprintf("IDX_%v_%v", tableName, idxName)
|
||||
}
|
||||
|
||||
func eraseAny(value string, strToErase ...string) string {
|
||||
if len(strToErase) == 0 {
|
||||
return value
|
||||
}
|
||||
var replaceSeq []string
|
||||
for _, s := range strToErase {
|
||||
replaceSeq = append(replaceSeq, s, "")
|
||||
}
|
||||
|
||||
replacer := strings.NewReplacer(replaceSeq...)
|
||||
|
||||
return replacer.Replace(value)
|
||||
}
|
||||
|
||||
func quoteColumns(cols []string, quoteFunc func(string) string, sep string) string {
|
||||
for i := range cols {
|
||||
cols[i] = quoteFunc(cols[i])
|
||||
}
|
||||
return strings.Join(cols, sep+" ")
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
// Copyright 2017 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestEraseAny(t *testing.T) {
|
||||
raw := "SELECT * FROM `table`.[table_name]"
|
||||
assert.EqualValues(t, raw, eraseAny(raw))
|
||||
assert.EqualValues(t, "SELECT * FROM table.[table_name]", eraseAny(raw, "`"))
|
||||
assert.EqualValues(t, "SELECT * FROM table.table_name", eraseAny(raw, "`", "[", "]"))
|
||||
}
|
||||
|
||||
func TestQuoteColumns(t *testing.T) {
|
||||
cols := []string{"f1", "f2", "f3"}
|
||||
quoteFunc := func(value string) string {
|
||||
return "[" + value + "]"
|
||||
}
|
||||
|
||||
assert.EqualValues(t, "[f1], [f2], [f3]", quoteColumns(cols, quoteFunc, ","))
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
// Copyright 2017 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import "time"
|
||||
|
||||
const (
|
||||
zeroTime0 = "0000-00-00 00:00:00"
|
||||
zeroTime1 = "0001-01-01 00:00:00"
|
||||
)
|
||||
|
||||
func formatTime(t time.Time) string {
|
||||
return t.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
|
||||
func isTimeZero(t time.Time) bool {
|
||||
return t.IsZero() || formatTime(t) == zeroTime0 ||
|
||||
formatTime(t) == zeroTime1
|
||||
}
|
||||
|
|
@ -2,17 +2,19 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm/caches"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCacheFind(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type MailBox struct {
|
||||
Id int64 `xorm:"pk"`
|
||||
|
|
@ -21,7 +23,7 @@ func TestCacheFind(t *testing.T) {
|
|||
}
|
||||
|
||||
oldCacher := testEngine.GetDefaultCacher()
|
||||
cacher := NewLRUCacher2(NewMemoryStore(), time.Hour, 10000)
|
||||
cacher := caches.NewLRUCacher2(caches.NewMemoryStore(), time.Hour, 10000)
|
||||
testEngine.SetDefaultCacher(cacher)
|
||||
|
||||
assert.NoError(t, testEngine.Sync2(new(MailBox)))
|
||||
|
|
@ -87,7 +89,7 @@ func TestCacheFind(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestCacheFind2(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type MailBox2 struct {
|
||||
Id uint64 `xorm:"pk"`
|
||||
|
|
@ -96,7 +98,7 @@ func TestCacheFind2(t *testing.T) {
|
|||
}
|
||||
|
||||
oldCacher := testEngine.GetDefaultCacher()
|
||||
cacher := NewLRUCacher2(NewMemoryStore(), time.Hour, 10000)
|
||||
cacher := caches.NewLRUCacher2(caches.NewMemoryStore(), time.Hour, 10000)
|
||||
testEngine.SetDefaultCacher(cacher)
|
||||
|
||||
assert.NoError(t, testEngine.Sync2(new(MailBox2)))
|
||||
|
|
@ -138,7 +140,7 @@ func TestCacheFind2(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestCacheGet(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type MailBox3 struct {
|
||||
Id uint64
|
||||
|
|
@ -147,7 +149,7 @@ func TestCacheGet(t *testing.T) {
|
|||
}
|
||||
|
||||
oldCacher := testEngine.GetDefaultCacher()
|
||||
cacher := NewLRUCacher2(NewMemoryStore(), time.Hour, 10000)
|
||||
cacher := caches.NewLRUCacher2(caches.NewMemoryStore(), time.Hour, 10000)
|
||||
testEngine.SetDefaultCacher(cacher)
|
||||
|
||||
assert.NoError(t, testEngine.Sync2(new(MailBox3)))
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
// Copyright 2020 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"xorm.io/xorm"
|
||||
"xorm.io/xorm/log"
|
||||
"xorm.io/xorm/schemas"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestEngineGroup(t *testing.T) {
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
master := testEngine.(*xorm.Engine)
|
||||
if master.Dialect().URI().DBType == schemas.SQLITE {
|
||||
t.Skip()
|
||||
return
|
||||
}
|
||||
|
||||
eg, err := xorm.NewEngineGroup(master, []*xorm.Engine{master})
|
||||
assert.NoError(t, err)
|
||||
|
||||
eg.SetMaxIdleConns(10)
|
||||
eg.SetMaxOpenConns(100)
|
||||
eg.SetTableMapper(master.GetTableMapper())
|
||||
eg.SetColumnMapper(master.GetColumnMapper())
|
||||
eg.SetLogLevel(log.LOG_INFO)
|
||||
eg.ShowSQL(true)
|
||||
}
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
// Copyright 2017 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm"
|
||||
"xorm.io/xorm/schemas"
|
||||
|
||||
_ "github.com/denisenkom/go-mssqldb"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
_ "github.com/lib/pq"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
_ "github.com/ziutek/mymysql/godrv"
|
||||
)
|
||||
|
||||
func TestPing(t *testing.T) {
|
||||
if err := testEngine.Ping(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPingContext(t *testing.T) {
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
ctx, canceled := context.WithTimeout(context.Background(), time.Nanosecond)
|
||||
defer canceled()
|
||||
|
||||
time.Sleep(time.Nanosecond)
|
||||
|
||||
err := testEngine.(*xorm.Engine).PingContext(ctx)
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "context deadline exceeded")
|
||||
}
|
||||
|
||||
func TestAutoTransaction(t *testing.T) {
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type TestTx struct {
|
||||
Id int64 `xorm:"autoincr pk"`
|
||||
Msg string `xorm:"varchar(255)"`
|
||||
Created time.Time `xorm:"created"`
|
||||
}
|
||||
|
||||
assert.NoError(t, testEngine.Sync2(new(TestTx)))
|
||||
|
||||
engine := testEngine.(*xorm.Engine)
|
||||
|
||||
// will success
|
||||
engine.Transaction(func(session *xorm.Session) (interface{}, error) {
|
||||
_, err := session.Insert(TestTx{Msg: "hi"})
|
||||
assert.NoError(t, err)
|
||||
|
||||
return nil, nil
|
||||
})
|
||||
|
||||
has, err := engine.Exist(&TestTx{Msg: "hi"})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, true, has)
|
||||
|
||||
// will rollback
|
||||
_, err = engine.Transaction(func(session *xorm.Session) (interface{}, error) {
|
||||
_, err := session.Insert(TestTx{Msg: "hello"})
|
||||
assert.NoError(t, err)
|
||||
|
||||
return nil, fmt.Errorf("rollback")
|
||||
})
|
||||
assert.Error(t, err)
|
||||
|
||||
has, err = engine.Exist(&TestTx{Msg: "hello"})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, false, has)
|
||||
}
|
||||
|
||||
func assertSync(t *testing.T, beans ...interface{}) {
|
||||
for _, bean := range beans {
|
||||
t.Run(testEngine.TableName(bean, true), func(t *testing.T) {
|
||||
assert.NoError(t, testEngine.DropTables(bean))
|
||||
assert.NoError(t, testEngine.Sync2(bean))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDump(t *testing.T) {
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type TestDumpStruct struct {
|
||||
Id int64
|
||||
Name string
|
||||
}
|
||||
|
||||
assertSync(t, new(TestDumpStruct))
|
||||
|
||||
testEngine.Insert([]TestDumpStruct{
|
||||
{Name: "1"},
|
||||
{Name: "2\n"},
|
||||
{Name: "3;"},
|
||||
{Name: "4\n;\n''"},
|
||||
{Name: "5'\n"},
|
||||
})
|
||||
|
||||
fp := fmt.Sprintf("%v.sql", testEngine.Dialect().URI().DBType)
|
||||
os.Remove(fp)
|
||||
assert.NoError(t, testEngine.DumpAllToFile(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.sql", tp)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert.NoError(t, testEngine.DumpAllToFile(name, tp))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetSchema(t *testing.T) {
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
if testEngine.Dialect().URI().DBType == schemas.POSTGRES {
|
||||
oldSchema := testEngine.Dialect().URI().Schema
|
||||
testEngine.SetSchema("my_schema")
|
||||
assert.EqualValues(t, "my_schema", testEngine.Dialect().URI().Schema)
|
||||
testEngine.SetSchema(oldSchema)
|
||||
assert.EqualValues(t, oldSchema, testEngine.Dialect().URI().Schema)
|
||||
}
|
||||
}
|
||||
|
|
@ -2,15 +2,12 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"xorm.io/core"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var (
|
||||
ptrPkType = reflect.TypeOf(&core.PK{})
|
||||
pkType = reflect.TypeOf(core.PK{})
|
||||
)
|
||||
func TestMain(m *testing.M) {
|
||||
MainTest(m)
|
||||
}
|
||||
|
|
@ -2,18 +2,20 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"xorm.io/xorm"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestBefore_Get(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type BeforeTable struct {
|
||||
Id int64
|
||||
|
|
@ -40,7 +42,7 @@ func TestBefore_Get(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestBefore_Find(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type BeforeTable2 struct {
|
||||
Id int64
|
||||
|
|
@ -101,7 +103,7 @@ func (p *ProcessorsStruct) BeforeDelete() {
|
|||
p.B4DeleteFlag = 1
|
||||
}
|
||||
|
||||
func (p *ProcessorsStruct) BeforeSet(col string, cell Cell) {
|
||||
func (p *ProcessorsStruct) BeforeSet(col string, cell xorm.Cell) {
|
||||
p.BeforeSetFlag = p.BeforeSetFlag + 1
|
||||
}
|
||||
|
||||
|
|
@ -117,25 +119,19 @@ func (p *ProcessorsStruct) AfterDelete() {
|
|||
p.AfterDeletedFlag = 1
|
||||
}
|
||||
|
||||
func (p *ProcessorsStruct) AfterSet(col string, cell Cell) {
|
||||
func (p *ProcessorsStruct) AfterSet(col string, cell xorm.Cell) {
|
||||
p.AfterSetFlag = p.AfterSetFlag + 1
|
||||
}
|
||||
|
||||
func TestProcessors(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
err := testEngine.DropTables(&ProcessorsStruct{})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
panic(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
p := &ProcessorsStruct{}
|
||||
|
||||
err = testEngine.CreateTables(&ProcessorsStruct{})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
panic(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
|
||||
b4InsertFunc := func(bean interface{}) {
|
||||
if v, ok := (bean).(*ProcessorsStruct); ok {
|
||||
|
|
@ -259,42 +255,22 @@ func TestProcessors(t *testing.T) {
|
|||
_, err = testEngine.Before(b4UpdateFunc).After(afterUpdateFunc).Update(p)
|
||||
assert.NoError(t, err)
|
||||
|
||||
if p.B4UpdateFlag == 0 {
|
||||
t.Error(errors.New("B4UpdateFlag not set"))
|
||||
}
|
||||
if p.AfterUpdatedFlag == 0 {
|
||||
t.Error(errors.New("AfterUpdatedFlag not set"))
|
||||
}
|
||||
if p.B4UpdateViaExt == 0 {
|
||||
t.Error(errors.New("B4UpdateViaExt not set"))
|
||||
}
|
||||
if p.AfterUpdatedViaExt == 0 {
|
||||
t.Error(errors.New("AfterUpdatedViaExt not set"))
|
||||
}
|
||||
assert.False(t, p.B4UpdateFlag == 0, "B4UpdateFlag not set")
|
||||
assert.False(t, p.AfterUpdatedFlag == 0, "AfterUpdatedFlag not set")
|
||||
assert.False(t, p.B4UpdateViaExt == 0, "B4UpdateViaExt not set")
|
||||
assert.False(t, p.AfterUpdatedViaExt == 0, "AfterUpdatedViaExt not set")
|
||||
|
||||
p2 = &ProcessorsStruct{}
|
||||
has, err = testEngine.ID(p.Id).Get(p2)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
|
||||
if p2.B4UpdateFlag == 0 {
|
||||
t.Error(errors.New("B4UpdateFlag not set"))
|
||||
}
|
||||
if p2.AfterUpdatedFlag != 0 {
|
||||
t.Error(errors.New("AfterUpdatedFlag is set: " + string(p.AfterUpdatedFlag)))
|
||||
}
|
||||
if p2.B4UpdateViaExt == 0 {
|
||||
t.Error(errors.New("B4UpdateViaExt not set"))
|
||||
}
|
||||
if p2.AfterUpdatedViaExt != 0 {
|
||||
t.Error(errors.New("AfterUpdatedViaExt is set: " + string(p.AfterUpdatedViaExt)))
|
||||
}
|
||||
if p2.BeforeSetFlag != 9 {
|
||||
t.Error(fmt.Errorf("BeforeSetFlag is %d not 9", p2.BeforeSetFlag))
|
||||
}
|
||||
if p2.AfterSetFlag != 9 {
|
||||
t.Error(fmt.Errorf("AfterSetFlag is %d not 9", p2.BeforeSetFlag))
|
||||
}
|
||||
assert.False(t, p2.B4UpdateFlag == 0, "B4UpdateFlag not set")
|
||||
assert.False(t, p2.AfterUpdatedFlag != 0, fmt.Sprintf("AfterUpdatedFlag is set: %d", p.AfterUpdatedFlag))
|
||||
assert.False(t, p2.B4UpdateViaExt == 0, "B4UpdateViaExt not set")
|
||||
assert.False(t, p2.AfterUpdatedViaExt != 0, fmt.Sprintf("AfterUpdatedViaExt is set: %d", p.AfterUpdatedViaExt))
|
||||
assert.False(t, p2.BeforeSetFlag != 9, fmt.Sprintf("BeforeSetFlag is %d not 9", p2.BeforeSetFlag))
|
||||
assert.False(t, p2.AfterSetFlag != 9, fmt.Sprintf("AfterSetFlag is %d not 9", p2.BeforeSetFlag))
|
||||
// --
|
||||
|
||||
// test delete processors
|
||||
|
|
@ -382,7 +358,7 @@ func TestProcessors(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestProcessorsTx(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
err := testEngine.DropTables(&ProcessorsStruct{})
|
||||
assert.NoError(t, err)
|
||||
|
|
@ -450,12 +426,7 @@ func TestProcessorsTx(t *testing.T) {
|
|||
p2 := &ProcessorsStruct{}
|
||||
_, err = testEngine.ID(p.Id).Get(p2)
|
||||
assert.NoError(t, err)
|
||||
|
||||
if p2.Id > 0 {
|
||||
err = errors.New("tx got committed upon insert!?")
|
||||
t.Error(err)
|
||||
panic(err)
|
||||
}
|
||||
assert.False(t, p2.Id > 0, "tx got committed upon insert!?")
|
||||
// --
|
||||
|
||||
// test insert processors with tx commit
|
||||
|
|
@ -516,7 +487,7 @@ func TestProcessorsTx(t *testing.T) {
|
|||
t.Error(errors.New("AfterInsertedViaExt is set"))
|
||||
}
|
||||
|
||||
insertedId := p2.Id
|
||||
insertedID := p2.Id
|
||||
// --
|
||||
|
||||
// test update processors with tx rollback
|
||||
|
|
@ -544,7 +515,7 @@ func TestProcessorsTx(t *testing.T) {
|
|||
|
||||
p = p2 // reset
|
||||
|
||||
_, err = session.ID(insertedId).Before(b4UpdateFunc).After(afterUpdateFunc).Update(p)
|
||||
_, err = session.ID(insertedID).Before(b4UpdateFunc).After(afterUpdateFunc).Update(p)
|
||||
assert.NoError(t, err)
|
||||
|
||||
if p.B4UpdateFlag == 0 {
|
||||
|
|
@ -579,7 +550,7 @@ func TestProcessorsTx(t *testing.T) {
|
|||
session.Close()
|
||||
|
||||
p2 = &ProcessorsStruct{}
|
||||
_, err = testEngine.ID(insertedId).Get(p2)
|
||||
_, err = testEngine.ID(insertedID).Get(p2)
|
||||
assert.NoError(t, err)
|
||||
|
||||
if p2.B4UpdateFlag != 0 {
|
||||
|
|
@ -603,7 +574,7 @@ func TestProcessorsTx(t *testing.T) {
|
|||
err = session.Begin()
|
||||
assert.NoError(t, err)
|
||||
|
||||
p = &ProcessorsStruct{Id: insertedId}
|
||||
p = &ProcessorsStruct{Id: insertedID}
|
||||
|
||||
_, err = session.Update(p)
|
||||
assert.NoError(t, err)
|
||||
|
|
@ -642,7 +613,7 @@ func TestProcessorsTx(t *testing.T) {
|
|||
|
||||
p = &ProcessorsStruct{}
|
||||
|
||||
_, err = session.ID(insertedId).Before(b4UpdateFunc).After(afterUpdateFunc).Update(p)
|
||||
_, err = session.ID(insertedID).Before(b4UpdateFunc).After(afterUpdateFunc).Update(p)
|
||||
assert.NoError(t, err)
|
||||
|
||||
if p.B4UpdateFlag == 0 {
|
||||
|
|
@ -676,7 +647,7 @@ func TestProcessorsTx(t *testing.T) {
|
|||
|
||||
session.Close()
|
||||
p2 = &ProcessorsStruct{}
|
||||
_, err = testEngine.ID(insertedId).Get(p2)
|
||||
_, err = testEngine.ID(insertedID).Get(p2)
|
||||
assert.NoError(t, err)
|
||||
|
||||
if p.B4UpdateFlag == 0 {
|
||||
|
|
@ -718,7 +689,7 @@ func TestProcessorsTx(t *testing.T) {
|
|||
|
||||
p = &ProcessorsStruct{} // reset
|
||||
|
||||
_, err = session.ID(insertedId).Before(b4DeleteFunc).After(afterDeleteFunc).Delete(p)
|
||||
_, err = session.ID(insertedID).Before(b4DeleteFunc).After(afterDeleteFunc).Delete(p)
|
||||
assert.NoError(t, err)
|
||||
|
||||
if p.B4DeleteFlag == 0 {
|
||||
|
|
@ -752,7 +723,7 @@ func TestProcessorsTx(t *testing.T) {
|
|||
session.Close()
|
||||
|
||||
p2 = &ProcessorsStruct{}
|
||||
_, err = testEngine.ID(insertedId).Get(p2)
|
||||
_, err = testEngine.ID(insertedID).Get(p2)
|
||||
assert.NoError(t, err)
|
||||
|
||||
if p2.B4DeleteFlag != 0 {
|
||||
|
|
@ -778,7 +749,7 @@ func TestProcessorsTx(t *testing.T) {
|
|||
|
||||
p = &ProcessorsStruct{}
|
||||
|
||||
_, err = session.ID(insertedId).Before(b4DeleteFunc).After(afterDeleteFunc).Delete(p)
|
||||
_, err = session.ID(insertedID).Before(b4DeleteFunc).After(afterDeleteFunc).Delete(p)
|
||||
assert.NoError(t, err)
|
||||
|
||||
if p.B4DeleteFlag == 0 {
|
||||
|
|
@ -819,7 +790,7 @@ func TestProcessorsTx(t *testing.T) {
|
|||
err = session.Begin()
|
||||
assert.NoError(t, err)
|
||||
|
||||
p = &ProcessorsStruct{Id: insertedId}
|
||||
p = &ProcessorsStruct{Id: insertedID}
|
||||
_, err = session.Delete(p)
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
|
@ -846,7 +817,6 @@ func TestProcessorsTx(t *testing.T) {
|
|||
t.Error(errors.New("AfterUpdatedFlag set"))
|
||||
}
|
||||
session.Close()
|
||||
// --
|
||||
}
|
||||
|
||||
type AfterLoadStructA struct {
|
||||
|
|
@ -862,19 +832,19 @@ type AfterLoadStructB struct {
|
|||
Err error `xorm:"-"`
|
||||
}
|
||||
|
||||
func (s *AfterLoadStructB) AfterLoad(session *Session) {
|
||||
func (s *AfterLoadStructB) AfterLoad(session *xorm.Session) {
|
||||
has, err := session.ID(s.AId).NoAutoCondition().Get(&s.A)
|
||||
if err != nil {
|
||||
s.Err = err
|
||||
return
|
||||
}
|
||||
if !has {
|
||||
s.Err = ErrNotExist
|
||||
s.Err = xorm.ErrNotExist
|
||||
}
|
||||
}
|
||||
|
||||
func TestAfterLoadProcessor(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
assertSync(t, new(AfterLoadStructA), new(AfterLoadStructB))
|
||||
|
||||
|
|
@ -925,7 +895,7 @@ func (a *AfterInsertStruct) AfterInsert() {
|
|||
}
|
||||
|
||||
func TestAfterInsert(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
assertSync(t, new(AfterInsertStruct))
|
||||
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
|
@ -11,7 +11,7 @@ import (
|
|||
)
|
||||
|
||||
func TestRows(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type UserRows struct {
|
||||
Id int64
|
||||
|
|
@ -85,7 +85,7 @@ func TestRows(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestRowsMyTableName(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type UserRowsMyTable struct {
|
||||
Id int64
|
||||
|
|
@ -104,7 +104,6 @@ func TestRowsMyTableName(t *testing.T) {
|
|||
|
||||
rows, err := testEngine.Table(tableName).Rows(new(UserRowsMyTable))
|
||||
assert.NoError(t, err)
|
||||
defer rows.Close()
|
||||
|
||||
cnt = 0
|
||||
user := new(UserRowsMyTable)
|
||||
|
|
@ -114,6 +113,21 @@ func TestRowsMyTableName(t *testing.T) {
|
|||
cnt++
|
||||
}
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
rows.Close()
|
||||
|
||||
rows, err = testEngine.Table(tableName).Rows(&UserRowsMyTable{
|
||||
Id: 2,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
cnt = 0
|
||||
user = new(UserRowsMyTable)
|
||||
for rows.Next() {
|
||||
err = rows.Scan(user)
|
||||
assert.NoError(t, err)
|
||||
cnt++
|
||||
}
|
||||
assert.EqualValues(t, 0, cnt)
|
||||
}
|
||||
|
||||
type UserRowsSpecTable struct {
|
||||
|
|
@ -126,7 +140,7 @@ func (UserRowsSpecTable) TableName() string {
|
|||
}
|
||||
|
||||
func TestRowsSpecTableName(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assert.NoError(t, testEngine.Sync2(new(UserRowsSpecTable)))
|
||||
|
||||
cnt, err := testEngine.Insert(&UserRowsSpecTable{
|
||||
|
|
@ -2,18 +2,18 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"xorm.io/builder"
|
||||
"xorm.io/core"
|
||||
"xorm.io/xorm/schemas"
|
||||
)
|
||||
|
||||
func TestSetExpr(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type UserExprIssue struct {
|
||||
Id int64
|
||||
|
|
@ -45,7 +45,7 @@ func TestSetExpr(t *testing.T) {
|
|||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
var not = "NOT"
|
||||
if testEngine.Dialect().DBType() == core.MSSQL {
|
||||
if testEngine.Dialect().URI().DBType == schemas.MSSQL {
|
||||
not = "~"
|
||||
}
|
||||
cnt, err = testEngine.SetExpr("show", not+" `show`").ID(1).Update(new(UserExpr))
|
||||
|
|
@ -64,7 +64,7 @@ func TestSetExpr(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestCols(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type ColsTable struct {
|
||||
Id int64
|
||||
|
|
@ -96,7 +96,7 @@ func TestCols(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestMustCol(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type CustomerUpdate struct {
|
||||
Id int64 `form:"id" json:"id"`
|
||||
|
|
@ -2,19 +2,19 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"xorm.io/builder"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
func TestBuilder(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
const (
|
||||
OpEqual int = iota
|
||||
|
|
@ -102,7 +102,7 @@ func TestBuilder(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestIn(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assert.NoError(t, testEngine.Sync2(new(Userinfo)))
|
||||
|
||||
cnt, err := testEngine.Insert([]Userinfo{
|
||||
|
|
@ -137,15 +137,13 @@ func TestIn(t *testing.T) {
|
|||
idsStr = idsStr[:len(idsStr)-1]
|
||||
|
||||
users := make([]Userinfo, 0)
|
||||
err = testEngine.In("(id)", ids[0], ids[1], ids[2]).Find(&users)
|
||||
err = testEngine.In("id", ids[0], ids[1], ids[2]).Find(&users)
|
||||
assert.NoError(t, err)
|
||||
fmt.Println(users)
|
||||
assert.EqualValues(t, 3, len(users))
|
||||
|
||||
users = make([]Userinfo, 0)
|
||||
err = testEngine.In("(id)", ids).Find(&users)
|
||||
err = testEngine.In("id", ids).Find(&users)
|
||||
assert.NoError(t, err)
|
||||
fmt.Println(users)
|
||||
assert.EqualValues(t, 3, len(users))
|
||||
|
||||
for _, user := range users {
|
||||
|
|
@ -161,9 +159,8 @@ func TestIn(t *testing.T) {
|
|||
idsInterface = append(idsInterface, id)
|
||||
}
|
||||
|
||||
err = testEngine.Where(department+" = ?", "dev").In("(id)", idsInterface...).Find(&users)
|
||||
err = testEngine.Where(department+" = ?", "dev").In("id", idsInterface...).Find(&users)
|
||||
assert.NoError(t, err)
|
||||
fmt.Println(users)
|
||||
assert.EqualValues(t, 3, len(users))
|
||||
|
||||
for _, user := range users {
|
||||
|
|
@ -175,11 +172,10 @@ func TestIn(t *testing.T) {
|
|||
|
||||
dev := testEngine.GetColumnMapper().Obj2Table("Dev")
|
||||
|
||||
err = testEngine.In("(id)", 1).In("(id)", 2).In(department, dev).Find(&users)
|
||||
err = testEngine.In("id", 1).In("id", 2).In(department, dev).Find(&users)
|
||||
assert.NoError(t, err)
|
||||
fmt.Println(users)
|
||||
|
||||
cnt, err = testEngine.In("(id)", ids[0]).Update(&Userinfo{Departname: "dev-"})
|
||||
cnt, err = testEngine.In("id", ids[0]).Update(&Userinfo{Departname: "dev-"})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
|
|
@ -189,17 +185,17 @@ func TestIn(t *testing.T) {
|
|||
assert.True(t, has)
|
||||
assert.EqualValues(t, "dev-", user.Departname)
|
||||
|
||||
cnt, err = testEngine.In("(id)", ids[0]).Update(&Userinfo{Departname: "dev"})
|
||||
cnt, err = testEngine.In("id", ids[0]).Update(&Userinfo{Departname: "dev"})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
cnt, err = testEngine.In("(id)", ids[1]).Delete(&Userinfo{})
|
||||
cnt, err = testEngine.In("id", ids[1]).Delete(&Userinfo{})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
}
|
||||
|
||||
func TestFindAndCount(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type FindAndCount struct {
|
||||
Id int64
|
||||
|
|
@ -2,18 +2,20 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"xorm.io/core"
|
||||
"xorm.io/xorm/caches"
|
||||
"xorm.io/xorm/schemas"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestDelete(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type UserinfoDelete struct {
|
||||
Uid int64 `xorm:"id pk not null autoincr"`
|
||||
|
|
@ -26,7 +28,7 @@ func TestDelete(t *testing.T) {
|
|||
defer session.Close()
|
||||
|
||||
var err error
|
||||
if testEngine.Dialect().DBType() == core.MSSQL {
|
||||
if testEngine.Dialect().URI().DBType == schemas.MSSQL {
|
||||
err = session.Begin()
|
||||
assert.NoError(t, err)
|
||||
_, err = session.Exec("SET IDENTITY_INSERT userinfo_delete ON")
|
||||
|
|
@ -38,7 +40,7 @@ func TestDelete(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
if testEngine.Dialect().DBType() == core.MSSQL {
|
||||
if testEngine.Dialect().URI().DBType == schemas.MSSQL {
|
||||
err = session.Commit()
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
|
@ -69,7 +71,7 @@ func TestDelete(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestDeleted(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type Deleted struct {
|
||||
Id int64 `xorm:"pk"`
|
||||
|
|
@ -156,10 +158,10 @@ func TestDeleted(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestCacheDelete(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
oldCacher := testEngine.GetDefaultCacher()
|
||||
cacher := NewLRUCacher(NewMemoryStore(), 1000)
|
||||
cacher := caches.NewLRUCacher(caches.NewMemoryStore(), 1000)
|
||||
testEngine.SetDefaultCacher(cacher)
|
||||
|
||||
type CacheDeleteStruct struct {
|
||||
|
|
@ -188,7 +190,7 @@ func TestCacheDelete(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestUnscopeDelete(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type UnscopeDeleteStruct struct {
|
||||
Id int64
|
||||
|
|
@ -0,0 +1,208 @@
|
|||
// Copyright 2017 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestExistStruct(t *testing.T) {
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type RecordExist struct {
|
||||
Id int64
|
||||
Name string
|
||||
}
|
||||
|
||||
assertSync(t, new(RecordExist))
|
||||
|
||||
has, err := testEngine.Exist(new(RecordExist))
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, has)
|
||||
|
||||
cnt, err := testEngine.Insert(&RecordExist{
|
||||
Name: "test1",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
has, err = testEngine.Exist(new(RecordExist))
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
|
||||
has, err = testEngine.Exist(&RecordExist{
|
||||
Name: "test1",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
|
||||
has, err = testEngine.Exist(&RecordExist{
|
||||
Name: "test2",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, has)
|
||||
|
||||
has, err = testEngine.Where("name = ?", "test1").Exist(&RecordExist{})
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
|
||||
has, err = testEngine.Where("name = ?", "test2").Exist(&RecordExist{})
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, has)
|
||||
|
||||
has, err = testEngine.SQL("select * from "+testEngine.TableName("record_exist", true)+" where name = ?", "test1").Exist()
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
|
||||
has, err = testEngine.SQL("select * from "+testEngine.TableName("record_exist", true)+" where name = ?", "test2").Exist()
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, has)
|
||||
|
||||
has, err = testEngine.Table("record_exist").Exist()
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
|
||||
has, err = testEngine.Table("record_exist").Where("name = ?", "test1").Exist()
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
|
||||
has, err = testEngine.Table("record_exist").Where("name = ?", "test2").Exist()
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, has)
|
||||
}
|
||||
|
||||
func TestExistStructForJoin(t *testing.T) {
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type Number struct {
|
||||
Id int64
|
||||
Lid int64
|
||||
}
|
||||
|
||||
type OrderList struct {
|
||||
Id int64
|
||||
Eid int64
|
||||
}
|
||||
|
||||
type Player struct {
|
||||
Id int64
|
||||
Name string
|
||||
}
|
||||
|
||||
assert.NoError(t, testEngine.Sync2(new(Number), new(OrderList), new(Player)))
|
||||
|
||||
var ply Player
|
||||
cnt, err := testEngine.Insert(&ply)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
var orderlist = OrderList{
|
||||
Eid: ply.Id,
|
||||
}
|
||||
cnt, err = testEngine.Insert(&orderlist)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
var um = Number{
|
||||
Lid: orderlist.Id,
|
||||
}
|
||||
cnt, err = testEngine.Insert(&um)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
session := testEngine.NewSession()
|
||||
defer session.Close()
|
||||
|
||||
session.Table("number").
|
||||
Join("INNER", "order_list", "order_list.id = number.lid").
|
||||
Join("LEFT", "player", "player.id = order_list.eid").
|
||||
Where("number.lid = ?", 1)
|
||||
has, err := session.Exist()
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
|
||||
session.Table("number").
|
||||
Join("INNER", "order_list", "order_list.id = number.lid").
|
||||
Join("LEFT", "player", "player.id = order_list.eid").
|
||||
Where("number.lid = ?", 2)
|
||||
has, err = session.Exist()
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, has)
|
||||
|
||||
session.Table("number").
|
||||
Select("order_list.id").
|
||||
Join("INNER", "order_list", "order_list.id = number.lid").
|
||||
Join("LEFT", "player", "player.id = order_list.eid").
|
||||
Where("order_list.id = ?", 1)
|
||||
has, err = session.Exist()
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
|
||||
session.Table("number").
|
||||
Select("player.id").
|
||||
Join("INNER", "order_list", "order_list.id = number.lid").
|
||||
Join("LEFT", "player", "player.id = order_list.eid").
|
||||
Where("player.id = ?", 2)
|
||||
has, err = session.Exist()
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, has)
|
||||
|
||||
session.Table("number").
|
||||
Select("player.id").
|
||||
Join("INNER", "order_list", "order_list.id = number.lid").
|
||||
Join("LEFT", "player", "player.id = order_list.eid")
|
||||
has, err = session.Exist()
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
|
||||
err = session.DropTable("order_list")
|
||||
assert.NoError(t, err)
|
||||
|
||||
exist, err := session.IsTableExist("order_list")
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, exist)
|
||||
|
||||
session.Table("number").
|
||||
Select("player.id").
|
||||
Join("INNER", "order_list", "order_list.id = number.lid").
|
||||
Join("LEFT", "player", "player.id = order_list.eid")
|
||||
has, err = session.Exist()
|
||||
assert.Error(t, err)
|
||||
assert.False(t, has)
|
||||
|
||||
session.Table("number").
|
||||
Select("player.id").
|
||||
Join("LEFT", "player", "player.id = number.lid")
|
||||
has, err = session.Exist()
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
}
|
||||
|
||||
func TestExistContext(t *testing.T) {
|
||||
type ContextQueryStruct struct {
|
||||
Id int64
|
||||
Name string
|
||||
}
|
||||
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(ContextQueryStruct))
|
||||
|
||||
_, err := testEngine.Insert(&ContextQueryStruct{Name: "1"})
|
||||
assert.NoError(t, err)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Nanosecond)
|
||||
defer cancel()
|
||||
|
||||
time.Sleep(time.Nanosecond)
|
||||
|
||||
has, err := testEngine.Context(ctx).Exist(&ContextQueryStruct{Name: "1"})
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "context deadline exceeded")
|
||||
assert.False(t, has)
|
||||
}
|
||||
|
|
@ -2,20 +2,20 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"xorm.io/core"
|
||||
"xorm.io/xorm/internal/utils"
|
||||
"xorm.io/xorm/names"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestJoinLimit(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type Salary struct {
|
||||
Id int64
|
||||
|
|
@ -62,45 +62,27 @@ func TestJoinLimit(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func assertSync(t *testing.T, beans ...interface{}) {
|
||||
for _, bean := range beans {
|
||||
assert.NoError(t, testEngine.DropTables(bean))
|
||||
assert.NoError(t, testEngine.Sync2(bean))
|
||||
}
|
||||
}
|
||||
|
||||
func TestWhere(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
assertSync(t, new(Userinfo))
|
||||
|
||||
users := make([]Userinfo, 0)
|
||||
err := testEngine.Where("(id) > ?", 2).Find(&users)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(users)
|
||||
err := testEngine.Where("id > ?", 2).Find(&users)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = testEngine.Where("(id) > ?", 2).And("(id) < ?", 10).Find(&users)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(users)
|
||||
err = testEngine.Where("id > ?", 2).And("id < ?", 10).Find(&users)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestFind(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(Userinfo))
|
||||
|
||||
users := make([]Userinfo, 0)
|
||||
|
||||
err := testEngine.Find(&users)
|
||||
assert.NoError(t, err)
|
||||
for _, user := range users {
|
||||
fmt.Println(user)
|
||||
}
|
||||
|
||||
users2 := make([]Userinfo, 0)
|
||||
var tbName = testEngine.Quote(testEngine.TableName(new(Userinfo), true))
|
||||
|
|
@ -109,17 +91,13 @@ func TestFind(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestFind2(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
users := make([]*Userinfo, 0)
|
||||
|
||||
assertSync(t, new(Userinfo))
|
||||
|
||||
err := testEngine.Find(&users)
|
||||
assert.NoError(t, err)
|
||||
|
||||
for _, user := range users {
|
||||
fmt.Println(user)
|
||||
}
|
||||
}
|
||||
|
||||
type Team struct {
|
||||
|
|
@ -138,7 +116,7 @@ func (TeamUser) TableName() string {
|
|||
|
||||
func TestFind3(t *testing.T) {
|
||||
var teamUser = new(TeamUser)
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
err := testEngine.Sync2(new(Team), teamUser)
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
|
@ -192,37 +170,45 @@ func TestFind3(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestFindMap(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(Userinfo))
|
||||
|
||||
cnt, err := testEngine.Insert(&Userinfo{
|
||||
Username: "lunny",
|
||||
Departname: "depart1",
|
||||
IsMan: true,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
users := make(map[int64]Userinfo)
|
||||
err := testEngine.Find(&users)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
panic(err)
|
||||
}
|
||||
for _, user := range users {
|
||||
fmt.Println(user)
|
||||
}
|
||||
err = testEngine.Find(&users)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(users))
|
||||
assert.EqualValues(t, "lunny", users[1].Username)
|
||||
assert.EqualValues(t, "depart1", users[1].Departname)
|
||||
assert.True(t, users[1].IsMan)
|
||||
|
||||
users = make(map[int64]Userinfo)
|
||||
err = testEngine.Cols("username, departname").Find(&users)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(users))
|
||||
assert.EqualValues(t, "lunny", users[1].Username)
|
||||
assert.EqualValues(t, "depart1", users[1].Departname)
|
||||
assert.False(t, users[1].IsMan)
|
||||
}
|
||||
|
||||
func TestFindMap2(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(Userinfo))
|
||||
|
||||
users := make(map[int64]*Userinfo)
|
||||
err := testEngine.Find(&users)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
panic(err)
|
||||
}
|
||||
for id, user := range users {
|
||||
fmt.Println(id, user)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestDistinct(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(Userinfo))
|
||||
|
||||
_, err := testEngine.Insert(&Userinfo{
|
||||
|
|
@ -236,8 +222,6 @@ func TestDistinct(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(users))
|
||||
|
||||
fmt.Println(users)
|
||||
|
||||
type Depart struct {
|
||||
Departname string
|
||||
}
|
||||
|
|
@ -245,31 +229,24 @@ func TestDistinct(t *testing.T) {
|
|||
users2 := make([]Depart, 0)
|
||||
err = testEngine.Distinct(departname).Table(new(Userinfo)).Find(&users2)
|
||||
assert.NoError(t, err)
|
||||
if len(users2) != 1 {
|
||||
fmt.Println(len(users2))
|
||||
t.Error(err)
|
||||
panic(errors.New("should be one record"))
|
||||
}
|
||||
fmt.Println(users2)
|
||||
assert.EqualValues(t, 1, len(users2))
|
||||
}
|
||||
|
||||
func TestOrder(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(Userinfo))
|
||||
|
||||
users := make([]Userinfo, 0)
|
||||
err := testEngine.OrderBy("id desc").Find(&users)
|
||||
assert.NoError(t, err)
|
||||
fmt.Println(users)
|
||||
|
||||
users2 := make([]Userinfo, 0)
|
||||
err = testEngine.Asc("id", "username").Desc("height").Find(&users2)
|
||||
assert.NoError(t, err)
|
||||
fmt.Println(users2)
|
||||
}
|
||||
|
||||
func TestGroupBy(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(Userinfo))
|
||||
|
||||
users := make([]Userinfo, 0)
|
||||
|
|
@ -278,207 +255,151 @@ func TestGroupBy(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestHaving(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(Userinfo))
|
||||
|
||||
users := make([]Userinfo, 0)
|
||||
err := testEngine.GroupBy("username").Having("username='xlw'").Find(&users)
|
||||
assert.NoError(t, err)
|
||||
fmt.Println(users)
|
||||
|
||||
/*users = make([]Userinfo, 0)
|
||||
err = testEngine.Cols("id, username").GroupBy("username").Having("username='xlw'").Find(&users)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(users)*/
|
||||
}
|
||||
|
||||
func TestOrderSameMapper(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
testEngine.UnMapType(rValue(new(Userinfo)).Type())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
testEngine.UnMapType(utils.ReflectValue(new(Userinfo)).Type())
|
||||
|
||||
mapper := testEngine.GetTableMapper()
|
||||
testEngine.SetMapper(core.SameMapper{})
|
||||
testEngine.SetMapper(names.SameMapper{})
|
||||
|
||||
defer func() {
|
||||
testEngine.UnMapType(rValue(new(Userinfo)).Type())
|
||||
testEngine.UnMapType(utils.ReflectValue(new(Userinfo)).Type())
|
||||
testEngine.SetMapper(mapper)
|
||||
}()
|
||||
|
||||
assertSync(t, new(Userinfo))
|
||||
|
||||
users := make([]Userinfo, 0)
|
||||
err := testEngine.OrderBy("(id) desc").Find(&users)
|
||||
err := testEngine.OrderBy("id desc").Find(&users)
|
||||
assert.NoError(t, err)
|
||||
fmt.Println(users)
|
||||
|
||||
users2 := make([]Userinfo, 0)
|
||||
err = testEngine.Asc("(id)", "Username").Desc("Height").Find(&users2)
|
||||
err = testEngine.Asc("id", "Username").Desc("Height").Find(&users2)
|
||||
assert.NoError(t, err)
|
||||
fmt.Println(users2)
|
||||
}
|
||||
|
||||
func TestHavingSameMapper(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
testEngine.UnMapType(rValue(new(Userinfo)).Type())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
testEngine.UnMapType(utils.ReflectValue(new(Userinfo)).Type())
|
||||
|
||||
mapper := testEngine.GetTableMapper()
|
||||
testEngine.SetMapper(core.SameMapper{})
|
||||
testEngine.SetMapper(names.SameMapper{})
|
||||
defer func() {
|
||||
testEngine.UnMapType(rValue(new(Userinfo)).Type())
|
||||
testEngine.UnMapType(utils.ReflectValue(new(Userinfo)).Type())
|
||||
testEngine.SetMapper(mapper)
|
||||
}()
|
||||
assertSync(t, new(Userinfo))
|
||||
|
||||
users := make([]Userinfo, 0)
|
||||
err := testEngine.GroupBy("`Username`").Having("`Username`='xlw'").Find(&users)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fmt.Println(users)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestFindInts(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(Userinfo))
|
||||
|
||||
userinfo := testEngine.GetTableMapper().Obj2Table("Userinfo")
|
||||
var idsInt64 []int64
|
||||
err := testEngine.Table(userinfo).Cols("id").Desc("id").Find(&idsInt64)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fmt.Println(idsInt64)
|
||||
assert.NoError(t, err)
|
||||
|
||||
var idsInt32 []int32
|
||||
err = testEngine.Table(userinfo).Cols("id").Desc("id").Find(&idsInt32)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fmt.Println(idsInt32)
|
||||
assert.NoError(t, err)
|
||||
|
||||
var idsInt []int
|
||||
err = testEngine.Table(userinfo).Cols("id").Desc("id").Find(&idsInt)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fmt.Println(idsInt)
|
||||
assert.NoError(t, err)
|
||||
|
||||
var idsUint []uint
|
||||
err = testEngine.Table(userinfo).Cols("id").Desc("id").Find(&idsUint)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fmt.Println(idsUint)
|
||||
assert.NoError(t, err)
|
||||
|
||||
type MyInt int
|
||||
var idsMyInt []MyInt
|
||||
err = testEngine.Table(userinfo).Cols("id").Desc("id").Find(&idsMyInt)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fmt.Println(idsMyInt)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestFindStrings(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(Userinfo))
|
||||
userinfo := testEngine.GetTableMapper().Obj2Table("Userinfo")
|
||||
username := testEngine.GetColumnMapper().Obj2Table("Username")
|
||||
var idsString []string
|
||||
err := testEngine.Table(userinfo).Cols(username).Desc("id").Find(&idsString)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fmt.Println(idsString)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestFindMyString(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(Userinfo))
|
||||
userinfo := testEngine.GetTableMapper().Obj2Table("Userinfo")
|
||||
username := testEngine.GetColumnMapper().Obj2Table("Username")
|
||||
|
||||
var idsMyString []MyString
|
||||
err := testEngine.Table(userinfo).Cols(username).Desc("id").Find(&idsMyString)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fmt.Println(idsMyString)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestFindInterface(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(Userinfo))
|
||||
|
||||
userinfo := testEngine.GetTableMapper().Obj2Table("Userinfo")
|
||||
username := testEngine.GetColumnMapper().Obj2Table("Username")
|
||||
var idsInterface []interface{}
|
||||
err := testEngine.Table(userinfo).Cols(username).Desc("id").Find(&idsInterface)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fmt.Println(idsInterface)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestFindSliceBytes(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(Userinfo))
|
||||
|
||||
userinfo := testEngine.GetTableMapper().Obj2Table("Userinfo")
|
||||
var ids [][][]byte
|
||||
err := testEngine.Table(userinfo).Desc("id").Find(&ids)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, record := range ids {
|
||||
fmt.Println(record)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestFindSlicePtrString(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(Userinfo))
|
||||
|
||||
userinfo := testEngine.GetTableMapper().Obj2Table("Userinfo")
|
||||
var ids [][]*string
|
||||
err := testEngine.Table(userinfo).Desc("id").Find(&ids)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, record := range ids {
|
||||
fmt.Println(record)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestFindMapBytes(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(Userinfo))
|
||||
|
||||
userinfo := testEngine.GetTableMapper().Obj2Table("Userinfo")
|
||||
var ids []map[string][]byte
|
||||
err := testEngine.Table(userinfo).Desc("id").Find(&ids)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, record := range ids {
|
||||
fmt.Println(record)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestFindMapPtrString(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(Userinfo))
|
||||
|
||||
userinfo := testEngine.GetTableMapper().Obj2Table("Userinfo")
|
||||
var ids []map[string]*string
|
||||
err := testEngine.Table(userinfo).Desc("id").Find(&ids)
|
||||
assert.NoError(t, err)
|
||||
for _, record := range ids {
|
||||
fmt.Println(record)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFindBit(t *testing.T) {
|
||||
|
|
@ -487,7 +408,7 @@ func TestFindBit(t *testing.T) {
|
|||
Msg bool `xorm:"bit"`
|
||||
}
|
||||
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(FindBitStruct))
|
||||
|
||||
cnt, err := testEngine.Insert([]FindBitStruct{
|
||||
|
|
@ -515,7 +436,7 @@ func TestFindMark(t *testing.T) {
|
|||
MarkA string `xorm:"VARCHAR(1)"`
|
||||
}
|
||||
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(Mark))
|
||||
|
||||
cnt, err := testEngine.Insert([]Mark{
|
||||
|
|
@ -546,7 +467,7 @@ func TestFindAndCountOneFunc(t *testing.T) {
|
|||
Msg bool `xorm:"bit"`
|
||||
}
|
||||
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(FindAndCountStruct))
|
||||
|
||||
cnt, err := testEngine.Insert([]FindAndCountStruct{
|
||||
|
|
@ -563,6 +484,12 @@ func TestFindAndCountOneFunc(t *testing.T) {
|
|||
assert.EqualValues(t, 2, cnt)
|
||||
|
||||
var results = make([]FindAndCountStruct, 0, 2)
|
||||
cnt, err = testEngine.Limit(1).FindAndCount(&results)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(results))
|
||||
assert.EqualValues(t, 2, cnt)
|
||||
|
||||
results = make([]FindAndCountStruct, 0, 2)
|
||||
cnt, err = testEngine.FindAndCount(&results)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 2, len(results))
|
||||
|
|
@ -575,10 +502,48 @@ 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, 1, cnt)
|
||||
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").
|
||||
|
|
@ -589,10 +554,96 @@ func TestFindAndCountOneFunc(t *testing.T) {
|
|||
|
||||
results = make([]FindAndCountStruct, 0, 1)
|
||||
cnt, err = testEngine.Where("msg = ?", true).Desc("id").
|
||||
Limit(1).FindAndCount(&results)
|
||||
Limit(1).Cols("content").FindAndCount(&results)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(results))
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
ids := make([]int64, 0, 2)
|
||||
tableName := testEngine.GetTableMapper().Obj2Table("FindAndCountStruct")
|
||||
cnt, err = testEngine.Table(tableName).Limit(1).Cols("id").FindAndCount(&ids)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(ids))
|
||||
assert.EqualValues(t, 2, cnt)
|
||||
}
|
||||
|
||||
func TestFindAndCountOneFuncWithDeleted(t *testing.T) {
|
||||
type CommentWithDeleted struct {
|
||||
Id int `xorm:"pk autoincr"`
|
||||
DeletedAt int64 `xorm:"deleted notnull default(0) index"`
|
||||
}
|
||||
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(CommentWithDeleted))
|
||||
|
||||
var comments []CommentWithDeleted
|
||||
cnt, err := testEngine.FindAndCount(&comments)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 0, cnt)
|
||||
}
|
||||
|
||||
func TestFindAndCount2(t *testing.T) {
|
||||
// User
|
||||
type TestFindAndCountUser struct {
|
||||
Id int64 `xorm:"bigint(11) pk autoincr"`
|
||||
Name string `xorm:"'name'"`
|
||||
}
|
||||
|
||||
// Hotel
|
||||
type TestFindAndCountHotel struct {
|
||||
Id int64 `xorm:"bigint(11) pk autoincr"`
|
||||
Name string `xorm:"'name'"`
|
||||
Code string `xorm:"'code'"`
|
||||
Region string `xorm:"'region'"`
|
||||
CreateBy *TestFindAndCountUser `xorm:"'create_by'"`
|
||||
}
|
||||
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(TestFindAndCountUser), new(TestFindAndCountHotel))
|
||||
|
||||
var u = TestFindAndCountUser{
|
||||
Name: "myname",
|
||||
}
|
||||
cnt, err := testEngine.Insert(&u)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
var hotel = TestFindAndCountHotel{
|
||||
Name: "myhotel",
|
||||
Code: "111",
|
||||
Region: "222",
|
||||
CreateBy: &u,
|
||||
}
|
||||
cnt, err = testEngine.Insert(&hotel)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
hotels := make([]*TestFindAndCountHotel, 0)
|
||||
cnt, err = testEngine.
|
||||
Alias("t").
|
||||
Limit(10, 0).
|
||||
FindAndCount(&hotels)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
hotels = make([]*TestFindAndCountHotel, 0)
|
||||
cnt, err = testEngine.
|
||||
Table(new(TestFindAndCountHotel)).
|
||||
Alias("t").
|
||||
Limit(10, 0).
|
||||
FindAndCount(&hotels)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
hotels = make([]*TestFindAndCountHotel, 0)
|
||||
cnt, err = testEngine.
|
||||
Table(new(TestFindAndCountHotel)).
|
||||
Alias("t").
|
||||
Where("t.region like '6501%'").
|
||||
Limit(10, 0).
|
||||
FindAndCount(&hotels)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 0, cnt)
|
||||
}
|
||||
|
||||
type FindMapDevice struct {
|
||||
|
|
@ -605,7 +656,7 @@ func (device *FindMapDevice) TableName() string {
|
|||
}
|
||||
|
||||
func TestFindMapStringId(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(FindMapDevice))
|
||||
|
||||
cnt, err := testEngine.Insert(&FindMapDevice{
|
||||
|
|
@ -676,7 +727,7 @@ func TestFindExtends(t *testing.T) {
|
|||
FindExtendsB `xorm:"extends"`
|
||||
}
|
||||
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(FindExtendsA))
|
||||
|
||||
cnt, err := testEngine.Insert(&FindExtendsA{
|
||||
|
|
@ -695,6 +746,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) {
|
||||
|
|
@ -711,7 +769,7 @@ func TestFindExtends3(t *testing.T) {
|
|||
FindExtendsBB `xorm:"extends"`
|
||||
}
|
||||
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(FindExtendsAA))
|
||||
|
||||
cnt, err := testEngine.Insert(&FindExtendsAA{
|
||||
|
|
@ -747,7 +805,7 @@ func TestFindCacheLimit(t *testing.T) {
|
|||
Created time.Time `xorm:"created"`
|
||||
}
|
||||
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(InviteCode))
|
||||
|
||||
cnt, err := testEngine.Insert(&InviteCode{
|
||||
|
|
@ -788,8 +846,12 @@ func TestFindJoin(t *testing.T) {
|
|||
DeviceId int64
|
||||
}
|
||||
|
||||
assert.NoError(t, prepareEngine())
|
||||
assertSync(t, new(SceneItem), new(DeviceUserPrivrels))
|
||||
type Order struct {
|
||||
Id int64
|
||||
}
|
||||
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(SceneItem), new(DeviceUserPrivrels), new(Order))
|
||||
|
||||
var scenes []SceneItem
|
||||
err := testEngine.Join("LEFT OUTER", "device_user_privrels", "device_user_privrels.device_id=scene_item.device_id").
|
||||
|
|
@ -800,4 +862,96 @@ func TestFindJoin(t *testing.T) {
|
|||
err = testEngine.Join("LEFT OUTER", new(DeviceUserPrivrels), "device_user_privrels.device_id=scene_item.device_id").
|
||||
Where("scene_item.type=?", 3).Or("device_user_privrels.user_id=?", 339).Find(&scenes)
|
||||
assert.NoError(t, err)
|
||||
|
||||
scenes = make([]SceneItem, 0)
|
||||
err = testEngine.Join("INNER", "order", "`scene_item`.device_id=`order`.id").Find(&scenes)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestJoinFindLimit(t *testing.T) {
|
||||
type JoinFindLimit1 struct {
|
||||
Id int64
|
||||
Name string
|
||||
}
|
||||
|
||||
type JoinFindLimit2 struct {
|
||||
Id int64
|
||||
Eid int64 `xorm:"index"`
|
||||
Name string
|
||||
}
|
||||
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(JoinFindLimit1), new(JoinFindLimit2))
|
||||
|
||||
var finds []JoinFindLimit1
|
||||
err := testEngine.Join("INNER", new(JoinFindLimit2), "join_find_limit2.eid=join_find_limit1.id").
|
||||
Limit(10, 10).Find(&finds)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestMoreExtends(t *testing.T) {
|
||||
type MoreExtendsUsers struct {
|
||||
ID int64 `xorm:"id autoincr pk" json:"id"`
|
||||
Name string `xorm:"name not null" json:"name"`
|
||||
CreatedAt time.Time `xorm:"created not null" json:"created_at"`
|
||||
UpdatedAt time.Time `xorm:"updated not null" json:"updated_at"`
|
||||
DeletedAt time.Time `xorm:"deleted" json:"deleted_at"`
|
||||
}
|
||||
|
||||
type MoreExtendsBooks struct {
|
||||
ID int64 `xorm:"id autoincr pk" json:"id"`
|
||||
Name string `xorm:"name not null" json:"name"`
|
||||
UserID int64 `xorm:"user_id not null" json:"user_id"`
|
||||
CreatedAt time.Time `xorm:"created not null" json:"created_at"`
|
||||
UpdatedAt time.Time `xorm:"updated not null" json:"updated_at"`
|
||||
DeletedAt time.Time `xorm:"deleted" json:"deleted_at"`
|
||||
}
|
||||
|
||||
type MoreExtendsBooksExtend struct {
|
||||
MoreExtendsBooks `xorm:"extends"`
|
||||
Users MoreExtendsUsers `xorm:"extends" json:"users"`
|
||||
}
|
||||
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(MoreExtendsUsers), new(MoreExtendsBooks))
|
||||
|
||||
var books []MoreExtendsBooksExtend
|
||||
err := testEngine.Table("more_extends_books").Select("more_extends_books.*, more_extends_users.*").
|
||||
Join("INNER", "more_extends_users", "more_extends_books.user_id = more_extends_users.id").
|
||||
Where("more_extends_books.name LIKE ?", "abc").
|
||||
Limit(10, 10).
|
||||
Find(&books)
|
||||
assert.NoError(t, err)
|
||||
|
||||
books = make([]MoreExtendsBooksExtend, 0, len(books))
|
||||
err = testEngine.Table("more_extends_books").
|
||||
Alias("m").
|
||||
Select("m.*, more_extends_users.*").
|
||||
Join("INNER", "more_extends_users", "m.user_id = more_extends_users.id").
|
||||
Where("m.name LIKE ?", "abc").
|
||||
Limit(10, 10).
|
||||
Find(&books)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestDistinctAndCols(t *testing.T) {
|
||||
type DistinctAndCols struct {
|
||||
Id int64
|
||||
Name string
|
||||
}
|
||||
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(DistinctAndCols))
|
||||
|
||||
cnt, err := testEngine.Insert(&DistinctAndCols{
|
||||
Name: "test",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
var names []string
|
||||
err = testEngine.Table("distinct_and_cols").Cols("name").Distinct("name").Find(&names)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(names))
|
||||
assert.EqualValues(t, "test", names[0])
|
||||
}
|
||||
|
|
@ -2,20 +2,73 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm/contexts"
|
||||
"xorm.io/xorm/schemas"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
func convertInt(v interface{}) (int64, error) {
|
||||
switch v.(type) {
|
||||
case int:
|
||||
return int64(v.(int)), nil
|
||||
case int8:
|
||||
return int64(v.(int8)), nil
|
||||
case int16:
|
||||
return int64(v.(int16)), nil
|
||||
case int32:
|
||||
return int64(v.(int32)), nil
|
||||
case int64:
|
||||
return v.(int64), nil
|
||||
case []byte:
|
||||
i, err := strconv.ParseInt(string(v.([]byte)), 10, 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return i, nil
|
||||
case string:
|
||||
i, err := strconv.ParseInt(v.(string), 10, 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
return 0, fmt.Errorf("unsupported type: %v", v)
|
||||
}
|
||||
|
||||
func convertFloat(v interface{}) (float64, error) {
|
||||
switch v.(type) {
|
||||
case float32:
|
||||
return float64(v.(float32)), nil
|
||||
case float64:
|
||||
return v.(float64), nil
|
||||
case string:
|
||||
i, err := strconv.ParseFloat(v.(string), 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return i, nil
|
||||
case []byte:
|
||||
i, err := strconv.ParseFloat(string(v.([]byte)), 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
return 0, fmt.Errorf("unsupported type: %v", v)
|
||||
}
|
||||
|
||||
func TestGetVar(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type GetVar struct {
|
||||
Id int64 `xorm:"autoincr pk"`
|
||||
|
|
@ -153,7 +206,7 @@ func TestGetVar(t *testing.T) {
|
|||
assert.Equal(t, "1.5", fmt.Sprintf("%.1f", money))
|
||||
|
||||
var money2 float64
|
||||
if testEngine.Dialect().DBType() == core.MSSQL {
|
||||
if testEngine.Dialect().URI().DBType == schemas.MSSQL {
|
||||
has, err = testEngine.SQL("SELECT TOP 1 money FROM " + testEngine.TableName("get_var", true)).Get(&money2)
|
||||
} else {
|
||||
has, err = testEngine.SQL("SELECT money FROM " + testEngine.TableName("get_var", true) + " LIMIT 1").Get(&money2)
|
||||
|
|
@ -178,7 +231,7 @@ func TestGetVar(t *testing.T) {
|
|||
assert.Equal(t, "1.5", valuesString["money"])
|
||||
|
||||
// for mymysql driver, interface{} will be []byte, so ignore it currently
|
||||
if testEngine.Dialect().DriverName() != "mymysql" {
|
||||
if testEngine.DriverName() != "mymysql" {
|
||||
var valuesInter = make(map[string]interface{})
|
||||
has, err = testEngine.Table("get_var").Where("id = ?", 1).Select("*").Get(&valuesInter)
|
||||
assert.NoError(t, err)
|
||||
|
|
@ -220,7 +273,7 @@ func TestGetVar(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestGetStruct(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type UserinfoGet struct {
|
||||
Uid int `xorm:"pk autoincr"`
|
||||
|
|
@ -233,7 +286,7 @@ func TestGetStruct(t *testing.T) {
|
|||
defer session.Close()
|
||||
|
||||
var err error
|
||||
if testEngine.Dialect().DBType() == core.MSSQL {
|
||||
if testEngine.Dialect().URI().DBType == schemas.MSSQL {
|
||||
err = session.Begin()
|
||||
assert.NoError(t, err)
|
||||
_, err = session.Exec("SET IDENTITY_INSERT userinfo_get ON")
|
||||
|
|
@ -242,7 +295,7 @@ func TestGetStruct(t *testing.T) {
|
|||
cnt, err := session.Insert(&UserinfoGet{Uid: 2})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
if testEngine.Dialect().DBType() == core.MSSQL {
|
||||
if testEngine.Dialect().URI().DBType == schemas.MSSQL {
|
||||
err = session.Commit()
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
|
@ -275,7 +328,7 @@ func TestGetStruct(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestGetSlice(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type UserinfoSlice struct {
|
||||
Uid int `xorm:"pk autoincr"`
|
||||
|
|
@ -291,7 +344,7 @@ func TestGetSlice(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestGetError(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type GetError struct {
|
||||
Uid int `xorm:"pk autoincr"`
|
||||
|
|
@ -311,7 +364,7 @@ func TestGetError(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestJSONString(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type JsonString struct {
|
||||
Id int64
|
||||
|
|
@ -334,17 +387,17 @@ func TestJSONString(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
assert.EqualValues(t, 1, js.Id)
|
||||
assert.EqualValues(t, `["1","2"]`, js.Content)
|
||||
assert.True(t, `["1","2"]` == js.Content || `["1", "2"]` == js.Content)
|
||||
|
||||
var jss []JsonString
|
||||
err = testEngine.Table("json_json").Find(&jss)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(jss))
|
||||
assert.EqualValues(t, `["1","2"]`, jss[0].Content)
|
||||
assert.True(t, `["1","2"]` == jss[0].Content || `["1", "2"]` == jss[0].Content)
|
||||
}
|
||||
|
||||
func TestGetActionMapping(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type ActionMapping struct {
|
||||
ActionId string `xorm:"pk"`
|
||||
|
|
@ -381,7 +434,7 @@ func TestGetStructId(t *testing.T) {
|
|||
Id int64
|
||||
}
|
||||
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(TestGetStruct))
|
||||
|
||||
_, err := testEngine.Insert(&TestGetStruct{})
|
||||
|
|
@ -408,7 +461,7 @@ func TestContextGet(t *testing.T) {
|
|||
Name string
|
||||
}
|
||||
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(ContextGetStruct))
|
||||
|
||||
_, err := testEngine.Insert(&ContextGetStruct{Name: "1"})
|
||||
|
|
@ -417,7 +470,7 @@ func TestContextGet(t *testing.T) {
|
|||
sess := testEngine.NewSession()
|
||||
defer sess.Close()
|
||||
|
||||
context := NewMemoryContextCache()
|
||||
context := contexts.NewMemoryContextCache()
|
||||
|
||||
var c2 ContextGetStruct
|
||||
has, err := sess.ID(1).NoCache().ContextCache(context).Get(&c2)
|
||||
|
|
@ -446,13 +499,13 @@ func TestContextGet2(t *testing.T) {
|
|||
Name string
|
||||
}
|
||||
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(ContextGetStruct2))
|
||||
|
||||
_, err := testEngine.Insert(&ContextGetStruct2{Name: "1"})
|
||||
assert.NoError(t, err)
|
||||
|
||||
context := NewMemoryContextCache()
|
||||
context := contexts.NewMemoryContextCache()
|
||||
|
||||
var c2 ContextGetStruct2
|
||||
has, err := testEngine.ID(1).NoCache().ContextCache(context).Get(&c2)
|
||||
|
|
@ -480,12 +533,12 @@ type MyGetCustomTableImpletation struct {
|
|||
|
||||
const getCustomTableName = "GetCustomTableInterface"
|
||||
|
||||
func (m *MyGetCustomTableImpletation) TableName() string {
|
||||
func (MyGetCustomTableImpletation) TableName() string {
|
||||
return getCustomTableName
|
||||
}
|
||||
|
||||
func TestGetCustomTableInterface(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assert.NoError(t, testEngine.Table(getCustomTableName).Sync2(new(MyGetCustomTableImpletation)))
|
||||
|
||||
exist, err := testEngine.IsTableExist(getCustomTableName)
|
||||
|
|
@ -510,7 +563,7 @@ func TestGetNullVar(t *testing.T) {
|
|||
Age int
|
||||
}
|
||||
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(TestGetNullVarStruct))
|
||||
|
||||
affected, err := testEngine.Exec("insert into " + testEngine.TableName(new(TestGetNullVarStruct), true) + " (name,age) values (null,null)")
|
||||
|
|
@ -595,7 +648,7 @@ func TestCustomTypes(t *testing.T) {
|
|||
Age MyInt
|
||||
}
|
||||
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(TestCustomizeStruct))
|
||||
|
||||
var s = TestCustomizeStruct{
|
||||
|
|
@ -626,7 +679,7 @@ func TestGetViaMapCond(t *testing.T) {
|
|||
Index int
|
||||
}
|
||||
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(GetViaMapCond))
|
||||
|
||||
var (
|
||||
|
|
@ -2,20 +2,21 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestInsertOne(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type Test struct {
|
||||
Id int64 `xorm:"autoincr pk"`
|
||||
|
|
@ -32,7 +33,7 @@ func TestInsertOne(t *testing.T) {
|
|||
|
||||
func TestInsertMulti(t *testing.T) {
|
||||
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
type TestMulti struct {
|
||||
Id int64 `xorm:"int(11) pk"`
|
||||
Name string `xorm:"varchar(255)"`
|
||||
|
|
@ -107,7 +108,7 @@ func callbackLooper(datas interface{}, step int, actionFunc func(interface{}) er
|
|||
}
|
||||
|
||||
func TestInsertOneIfPkIsPoint(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type TestPoint struct {
|
||||
Id *int64 `xorm:"autoincr pk notnull 'id'"`
|
||||
|
|
@ -123,7 +124,7 @@ func TestInsertOneIfPkIsPoint(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestInsertOneIfPkIsPointRename(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
type ID *int64
|
||||
type TestPoint2 struct {
|
||||
Id ID `xorm:"autoincr pk notnull 'id'"`
|
||||
|
|
@ -139,7 +140,7 @@ func TestInsertOneIfPkIsPointRename(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestInsert(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(Userinfo))
|
||||
|
||||
user := Userinfo{0, "xiaolunwen", "dev", "lunny", time.Now(),
|
||||
|
|
@ -154,32 +155,19 @@ func TestInsert(t *testing.T) {
|
|||
// Username is unique, so this should return error
|
||||
assert.Error(t, err, "insert should fail but no error returned")
|
||||
assert.EqualValues(t, 0, cnt, "insert not returned 1")
|
||||
if err == nil {
|
||||
panic("should return err")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInsertAutoIncr(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(Userinfo))
|
||||
|
||||
// auto increment insert
|
||||
user := Userinfo{Username: "xiaolunwen2", Departname: "dev", Alias: "lunny", Created: time.Now(),
|
||||
Detail: Userdetail{Id: 1}, Height: 1.78, Avatar: []byte{1, 2, 3}, IsMan: true}
|
||||
cnt, err := testEngine.Insert(&user)
|
||||
fmt.Println(user.Uid)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
panic(err)
|
||||
}
|
||||
if cnt != 1 {
|
||||
err = errors.New("insert not returned 1")
|
||||
t.Error(err)
|
||||
panic(err)
|
||||
}
|
||||
if user.Uid <= 0 {
|
||||
t.Error(errors.New("not return id error"))
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
assert.Greater(t, user.Uid, int64(0))
|
||||
}
|
||||
|
||||
type DefaultInsert struct {
|
||||
|
|
@ -191,7 +179,7 @@ type DefaultInsert struct {
|
|||
}
|
||||
|
||||
func TestInsertDefault(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
di := new(DefaultInsert)
|
||||
err := testEngine.Sync2(di)
|
||||
|
|
@ -201,28 +189,12 @@ func TestInsertDefault(t *testing.T) {
|
|||
_, err = testEngine.Omit(testEngine.GetColumnMapper().Obj2Table("Status")).Insert(&di2)
|
||||
assert.NoError(t, err)
|
||||
|
||||
has, err := testEngine.Desc("(id)").Get(di)
|
||||
has, err := testEngine.Desc("id").Get(di)
|
||||
assert.NoError(t, err)
|
||||
if !has {
|
||||
err = errors.New("error with no data")
|
||||
t.Error(err)
|
||||
panic(err)
|
||||
}
|
||||
if di.Status != -1 {
|
||||
err = errors.New("inserted error data")
|
||||
t.Error(err)
|
||||
panic(err)
|
||||
}
|
||||
if di2.Updated.Unix() != di.Updated.Unix() {
|
||||
err = errors.New("updated should equal")
|
||||
t.Error(err, di.Updated, di2.Updated)
|
||||
panic(err)
|
||||
}
|
||||
if di2.Created.Unix() != di.Created.Unix() {
|
||||
err = errors.New("created should equal")
|
||||
t.Error(err, di.Created, di2.Created)
|
||||
panic(err)
|
||||
}
|
||||
assert.True(t, has)
|
||||
assert.EqualValues(t, -1, di.Status)
|
||||
assert.EqualValues(t, di2.Updated.Unix(), di.Updated.Unix())
|
||||
assert.EqualValues(t, di2.Created.Unix(), di.Created.Unix())
|
||||
}
|
||||
|
||||
type DefaultInsert2 struct {
|
||||
|
|
@ -233,57 +205,24 @@ type DefaultInsert2 struct {
|
|||
}
|
||||
|
||||
func TestInsertDefault2(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
di := new(DefaultInsert2)
|
||||
err := testEngine.Sync2(di)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
|
||||
var di2 = DefaultInsert2{Name: "test"}
|
||||
_, err = testEngine.Omit(testEngine.GetColumnMapper().Obj2Table("CheckTime")).Insert(&di2)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
|
||||
has, err := testEngine.Desc("(id)").Get(di)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if !has {
|
||||
err = errors.New("error with no data")
|
||||
t.Error(err)
|
||||
panic(err)
|
||||
}
|
||||
has, err := testEngine.Desc("id").Get(di)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
|
||||
has, err = testEngine.NoAutoCondition().Desc("(id)").Get(&di2)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if !has {
|
||||
err = errors.New("error with no data")
|
||||
t.Error(err)
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if *di != di2 {
|
||||
err = fmt.Errorf("%v is not equal to %v", di, di2)
|
||||
t.Error(err)
|
||||
panic(err)
|
||||
}
|
||||
|
||||
/*if di2.Updated.Unix() != di.Updated.Unix() {
|
||||
err = errors.New("updated should equal")
|
||||
t.Error(err, di.Updated, di2.Updated)
|
||||
panic(err)
|
||||
}
|
||||
if di2.Created.Unix() != di.Created.Unix() {
|
||||
err = errors.New("created should equal")
|
||||
t.Error(err, di.Created, di2.Created)
|
||||
panic(err)
|
||||
}*/
|
||||
has, err = testEngine.NoAutoCondition().Desc("id").Get(&di2)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
assert.EqualValues(t, *di, di2)
|
||||
}
|
||||
|
||||
type CreatedInsert struct {
|
||||
|
|
@ -317,147 +256,91 @@ type CreatedInsert6 struct {
|
|||
}
|
||||
|
||||
func TestInsertCreated(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
di := new(CreatedInsert)
|
||||
err := testEngine.Sync2(di)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
|
||||
ci := &CreatedInsert{}
|
||||
_, err = testEngine.Insert(ci)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
|
||||
has, err := testEngine.Desc("(id)").Get(di)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !has {
|
||||
t.Fatal(ErrNotExist)
|
||||
}
|
||||
if ci.Created.Unix() != di.Created.Unix() {
|
||||
t.Fatal("should equal:", ci, di)
|
||||
}
|
||||
fmt.Println("ci:", ci, "di:", di)
|
||||
has, err := testEngine.Desc("id").Get(di)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
assert.EqualValues(t, ci.Created.Unix(), di.Created.Unix())
|
||||
|
||||
di2 := new(CreatedInsert2)
|
||||
err = testEngine.Sync2(di2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
|
||||
ci2 := &CreatedInsert2{}
|
||||
_, err = testEngine.Insert(ci2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
has, err = testEngine.Desc("(id)").Get(di2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !has {
|
||||
t.Fatal(ErrNotExist)
|
||||
}
|
||||
if ci2.Created != di2.Created {
|
||||
t.Fatal("should equal:", ci2, di2)
|
||||
}
|
||||
fmt.Println("ci2:", ci2, "di2:", di2)
|
||||
assert.NoError(t, err)
|
||||
|
||||
has, err = testEngine.Desc("id").Get(di2)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
assert.EqualValues(t, ci2.Created, di2.Created)
|
||||
|
||||
di3 := new(CreatedInsert3)
|
||||
err = testEngine.Sync2(di3)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
|
||||
ci3 := &CreatedInsert3{}
|
||||
_, err = testEngine.Insert(ci3)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
has, err = testEngine.Desc("(id)").Get(di3)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !has {
|
||||
t.Fatal(ErrNotExist)
|
||||
}
|
||||
if ci3.Created != di3.Created {
|
||||
t.Fatal("should equal:", ci3, di3)
|
||||
}
|
||||
fmt.Println("ci3:", ci3, "di3:", di3)
|
||||
assert.NoError(t, err)
|
||||
|
||||
has, err = testEngine.Desc("id").Get(di3)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
assert.EqualValues(t, ci3.Created, di3.Created)
|
||||
|
||||
di4 := new(CreatedInsert4)
|
||||
err = testEngine.Sync2(di4)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
|
||||
ci4 := &CreatedInsert4{}
|
||||
_, err = testEngine.Insert(ci4)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
has, err = testEngine.Desc("(id)").Get(di4)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !has {
|
||||
t.Fatal(ErrNotExist)
|
||||
}
|
||||
if ci4.Created != di4.Created {
|
||||
t.Fatal("should equal:", ci4, di4)
|
||||
}
|
||||
fmt.Println("ci4:", ci4, "di4:", di4)
|
||||
assert.NoError(t, err)
|
||||
|
||||
has, err = testEngine.Desc("id").Get(di4)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
assert.EqualValues(t, ci4.Created, di4.Created)
|
||||
|
||||
di5 := new(CreatedInsert5)
|
||||
err = testEngine.Sync2(di5)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
|
||||
ci5 := &CreatedInsert5{}
|
||||
_, err = testEngine.Insert(ci5)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
has, err = testEngine.Desc("(id)").Get(di5)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !has {
|
||||
t.Fatal(ErrNotExist)
|
||||
}
|
||||
if ci5.Created.Unix() != di5.Created.Unix() {
|
||||
t.Fatal("should equal:", ci5, di5)
|
||||
}
|
||||
fmt.Println("ci5:", ci5, "di5:", di5)
|
||||
assert.NoError(t, err)
|
||||
|
||||
has, err = testEngine.Desc("id").Get(di5)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
assert.EqualValues(t, ci5.Created.Unix(), di5.Created.Unix())
|
||||
|
||||
di6 := new(CreatedInsert6)
|
||||
err = testEngine.Sync2(di6)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
|
||||
oldTime := time.Now().Add(-time.Hour)
|
||||
ci6 := &CreatedInsert6{Created: oldTime}
|
||||
_, err = testEngine.Insert(ci6)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
|
||||
has, err = testEngine.Desc("(id)").Get(di6)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !has {
|
||||
t.Fatal(ErrNotExist)
|
||||
}
|
||||
if ci6.Created.Unix() != di6.Created.Unix() {
|
||||
t.Fatal("should equal:", ci6, di6)
|
||||
}
|
||||
fmt.Println("ci6:", ci6, "di6:", di6)
|
||||
has, err = testEngine.Desc("id").Get(di6)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
assert.EqualValues(t, ci6.Created.Unix(), di6.Created.Unix())
|
||||
}
|
||||
|
||||
type JsonTime time.Time
|
||||
type JSONTime time.Time
|
||||
|
||||
func (j JsonTime) format() string {
|
||||
func (j JSONTime) format() string {
|
||||
t := time.Time(j)
|
||||
if t.IsZero() {
|
||||
return ""
|
||||
|
|
@ -466,11 +349,11 @@ func (j JsonTime) format() string {
|
|||
return t.Format("2006-01-02")
|
||||
}
|
||||
|
||||
func (j JsonTime) MarshalText() ([]byte, error) {
|
||||
func (j JSONTime) MarshalText() ([]byte, error) {
|
||||
return []byte(j.format()), nil
|
||||
}
|
||||
|
||||
func (j JsonTime) MarshalJSON() ([]byte, error) {
|
||||
func (j JSONTime) MarshalJSON() ([]byte, error) {
|
||||
return []byte(`"` + j.format() + `"`), nil
|
||||
}
|
||||
|
||||
|
|
@ -478,64 +361,55 @@ func TestDefaultTime3(t *testing.T) {
|
|||
type PrepareTask struct {
|
||||
Id int `xorm:"not null pk autoincr INT(11)" json:"id"`
|
||||
// ...
|
||||
StartTime JsonTime `xorm:"not null default '2006-01-02 15:04:05' TIMESTAMP index" json:"start_time"`
|
||||
EndTime JsonTime `xorm:"not null default '2006-01-02 15:04:05' TIMESTAMP" json:"end_time"`
|
||||
StartTime JSONTime `xorm:"not null default '2006-01-02 15:04:05' TIMESTAMP index" json:"start_time"`
|
||||
EndTime JSONTime `xorm:"not null default '2006-01-02 15:04:05' TIMESTAMP" json:"end_time"`
|
||||
Cuser string `xorm:"not null default '' VARCHAR(64) index" json:"cuser"`
|
||||
Muser string `xorm:"not null default '' VARCHAR(64)" json:"muser"`
|
||||
Ctime JsonTime `xorm:"not null default CURRENT_TIMESTAMP TIMESTAMP created" json:"ctime"`
|
||||
Mtime JsonTime `xorm:"not null default CURRENT_TIMESTAMP TIMESTAMP updated" json:"mtime"`
|
||||
Ctime JSONTime `xorm:"not null default CURRENT_TIMESTAMP TIMESTAMP created" json:"ctime"`
|
||||
Mtime JSONTime `xorm:"not null default CURRENT_TIMESTAMP TIMESTAMP updated" json:"mtime"`
|
||||
}
|
||||
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(PrepareTask))
|
||||
|
||||
prepareTask := &PrepareTask{
|
||||
StartTime: JsonTime(time.Now()),
|
||||
StartTime: JSONTime(time.Now()),
|
||||
Cuser: "userId",
|
||||
Muser: "userId",
|
||||
}
|
||||
cnt, err := testEngine.Omit("end_time").InsertOne(prepareTask)
|
||||
cnt, err := testEngine.Omit("end_time").Insert(prepareTask)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
}
|
||||
|
||||
type MyJsonTime struct {
|
||||
type MyJSONTime struct {
|
||||
Id int64 `json:"id"`
|
||||
Created JsonTime `xorm:"created" json:"created_at"`
|
||||
Created JSONTime `xorm:"created" json:"created_at"`
|
||||
}
|
||||
|
||||
func TestCreatedJsonTime(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
di5 := new(MyJsonTime)
|
||||
di5 := new(MyJSONTime)
|
||||
err := testEngine.Sync2(di5)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ci5 := &MyJsonTime{}
|
||||
_, err = testEngine.Insert(ci5)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
has, err := testEngine.Desc("(id)").Get(di5)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !has {
|
||||
t.Fatal(ErrNotExist)
|
||||
}
|
||||
if time.Time(ci5.Created).Unix() != time.Time(di5.Created).Unix() {
|
||||
t.Fatal("should equal:", time.Time(ci5.Created).Unix(), time.Time(di5.Created).Unix())
|
||||
}
|
||||
fmt.Println("ci5:", ci5, "di5:", di5)
|
||||
assert.NoError(t, err)
|
||||
|
||||
var dis = make([]MyJsonTime, 0)
|
||||
ci5 := &MyJSONTime{}
|
||||
_, err = testEngine.Insert(ci5)
|
||||
assert.NoError(t, err)
|
||||
|
||||
has, err := testEngine.Desc("id").Get(di5)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
assert.EqualValues(t, time.Time(ci5.Created).Unix(), time.Time(di5.Created).Unix())
|
||||
|
||||
var dis = make([]MyJSONTime, 0)
|
||||
err = testEngine.Find(&dis)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestInsertMulti2(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
assertSync(t, new(Userinfo))
|
||||
|
||||
|
|
@ -545,6 +419,34 @@ func TestInsertMulti2(t *testing.T) {
|
|||
{Username: "xlw11", Departname: "dev", Alias: "lunny2", Created: time.Now()},
|
||||
{Username: "xlw22", Departname: "dev", Alias: "lunny3", Created: time.Now()},
|
||||
}
|
||||
cnt, err := testEngine.Insert(&users)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, len(users), cnt)
|
||||
|
||||
users2 := []*Userinfo{
|
||||
{Username: "1xlw", Departname: "dev", Alias: "lunny2", Created: time.Now()},
|
||||
{Username: "1xlw2", Departname: "dev", Alias: "lunny3", Created: time.Now()},
|
||||
{Username: "1xlw11", Departname: "dev", Alias: "lunny2", Created: time.Now()},
|
||||
{Username: "1xlw22", Departname: "dev", Alias: "lunny3", Created: time.Now()},
|
||||
}
|
||||
|
||||
cnt, err = testEngine.Insert(&users2)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, len(users2), cnt)
|
||||
}
|
||||
|
||||
func TestInsertMulti2Interface(t *testing.T) {
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
assertSync(t, new(Userinfo))
|
||||
|
||||
users := []interface{}{
|
||||
Userinfo{Username: "xlw", Departname: "dev", Alias: "lunny2", Created: time.Now()},
|
||||
Userinfo{Username: "xlw2", Departname: "dev", Alias: "lunny3", Created: time.Now()},
|
||||
Userinfo{Username: "xlw11", Departname: "dev", Alias: "lunny2", Created: time.Now()},
|
||||
Userinfo{Username: "xlw22", Departname: "dev", Alias: "lunny3", Created: time.Now()},
|
||||
}
|
||||
|
||||
cnt, err := testEngine.Insert(&users)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
|
|
@ -552,7 +454,7 @@ func TestInsertMulti2(t *testing.T) {
|
|||
}
|
||||
assert.EqualValues(t, len(users), cnt)
|
||||
|
||||
users2 := []*Userinfo{
|
||||
users2 := []interface{}{
|
||||
&Userinfo{Username: "1xlw", Departname: "dev", Alias: "lunny2", Created: time.Now()},
|
||||
&Userinfo{Username: "1xlw2", Departname: "dev", Alias: "lunny3", Created: time.Now()},
|
||||
&Userinfo{Username: "1xlw11", Departname: "dev", Alias: "lunny2", Created: time.Now()},
|
||||
|
|
@ -565,7 +467,7 @@ func TestInsertMulti2(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestInsertTwoTable(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
assertSync(t, new(Userinfo), new(Userdetail))
|
||||
|
||||
|
|
@ -573,32 +475,14 @@ func TestInsertTwoTable(t *testing.T) {
|
|||
userinfo := Userinfo{Username: "xlw3", Departname: "dev", Alias: "lunny4", Created: time.Now(), Detail: userdetail}
|
||||
|
||||
cnt, err := testEngine.Insert(&userinfo, &userdetail)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if userinfo.Uid <= 0 {
|
||||
err = errors.New("not return id error")
|
||||
t.Error(err)
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if userdetail.Id <= 0 {
|
||||
err = errors.New("not return id error")
|
||||
t.Error(err)
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if cnt != 2 {
|
||||
err = errors.New("insert not returned 2")
|
||||
t.Error(err)
|
||||
panic(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
assert.Greater(t, userinfo.Uid, int64(0))
|
||||
assert.Greater(t, userdetail.Id, int64(0))
|
||||
assert.EqualValues(t, 2, cnt)
|
||||
}
|
||||
|
||||
func TestInsertCreatedInt64(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type TestCreatedInt64 struct {
|
||||
Id int64 `xorm:"autoincr pk"`
|
||||
|
|
@ -630,7 +514,7 @@ func (MyUserinfo) TableName() string {
|
|||
}
|
||||
|
||||
func TestInsertMulti3(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
testEngine.ShowSQL(true)
|
||||
assertSync(t, new(MyUserinfo))
|
||||
|
|
@ -646,10 +530,10 @@ func TestInsertMulti3(t *testing.T) {
|
|||
assert.EqualValues(t, len(users), cnt)
|
||||
|
||||
users2 := []*MyUserinfo{
|
||||
&MyUserinfo{Username: "1xlw", Departname: "dev", Alias: "lunny2", Created: time.Now()},
|
||||
&MyUserinfo{Username: "1xlw2", Departname: "dev", Alias: "lunny3", Created: time.Now()},
|
||||
&MyUserinfo{Username: "1xlw11", Departname: "dev", Alias: "lunny2", Created: time.Now()},
|
||||
&MyUserinfo{Username: "1xlw22", Departname: "dev", Alias: "lunny3", Created: time.Now()},
|
||||
{Username: "1xlw", Departname: "dev", Alias: "lunny2", Created: time.Now()},
|
||||
{Username: "1xlw2", Departname: "dev", Alias: "lunny3", Created: time.Now()},
|
||||
{Username: "1xlw11", Departname: "dev", Alias: "lunny2", Created: time.Now()},
|
||||
{Username: "1xlw22", Departname: "dev", Alias: "lunny3", Created: time.Now()},
|
||||
}
|
||||
|
||||
cnt, err = testEngine.Insert(&users2)
|
||||
|
|
@ -674,7 +558,7 @@ func (MyUserinfo2) TableName() string {
|
|||
}
|
||||
|
||||
func TestInsertMulti4(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
testEngine.ShowSQL(false)
|
||||
assertSync(t, new(MyUserinfo2))
|
||||
|
|
@ -691,10 +575,10 @@ func TestInsertMulti4(t *testing.T) {
|
|||
assert.EqualValues(t, len(users), cnt)
|
||||
|
||||
users2 := []*MyUserinfo2{
|
||||
&MyUserinfo2{Username: "1xlw", Departname: "dev", Alias: "lunny2", Created: time.Now()},
|
||||
&MyUserinfo2{Username: "1xlw2", Departname: "dev", Alias: "lunny3", Created: time.Now()},
|
||||
&MyUserinfo2{Username: "1xlw11", Departname: "dev", Alias: "lunny2", Created: time.Now()},
|
||||
&MyUserinfo2{Username: "1xlw22", Departname: "dev", Alias: "lunny3", Created: time.Now()},
|
||||
{Username: "1xlw", Departname: "dev", Alias: "lunny2", Created: time.Now()},
|
||||
{Username: "1xlw2", Departname: "dev", Alias: "lunny3", Created: time.Now()},
|
||||
{Username: "1xlw11", Departname: "dev", Alias: "lunny2", Created: time.Now()},
|
||||
{Username: "1xlw22", Departname: "dev", Alias: "lunny3", Created: time.Now()},
|
||||
}
|
||||
|
||||
cnt, err = testEngine.Insert(&users2)
|
||||
|
|
@ -720,7 +604,7 @@ func TestAnonymousStruct(t *testing.T) {
|
|||
} `json:"ext" xorm:"'EXT' json notnull"`
|
||||
}
|
||||
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(PlainFoo))
|
||||
|
||||
_, err := testEngine.Insert(&PlainFoo{
|
||||
|
|
@ -749,7 +633,7 @@ func TestInsertMap(t *testing.T) {
|
|||
Name string
|
||||
}
|
||||
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(InsertMap))
|
||||
|
||||
cnt, err := testEngine.Table(new(InsertMap)).Insert(map[string]interface{}{
|
||||
|
|
@ -834,7 +718,7 @@ func TestInsertWhere(t *testing.T) {
|
|||
IsTrue bool
|
||||
}
|
||||
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(InsertWhere))
|
||||
|
||||
var i = InsertWhere{
|
||||
|
|
@ -928,6 +812,64 @@ func TestInsertWhere(t *testing.T) {
|
|||
assert.EqualValues(t, 5, j5.Index)
|
||||
}
|
||||
|
||||
func TestInsertExpr2(t *testing.T) {
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type InsertExprsRelease struct {
|
||||
Id int64
|
||||
RepoId int
|
||||
IsTag bool
|
||||
IsDraft bool
|
||||
NumCommits int
|
||||
Sha1 string
|
||||
}
|
||||
|
||||
assertSync(t, new(InsertExprsRelease))
|
||||
|
||||
var ie = InsertExprsRelease{
|
||||
RepoId: 1,
|
||||
IsTag: true,
|
||||
}
|
||||
inserted, err := testEngine.
|
||||
SetExpr("is_draft", true).
|
||||
SetExpr("num_commits", 0).
|
||||
SetExpr("sha1", "").
|
||||
Insert(&ie)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, inserted)
|
||||
|
||||
var ie2 InsertExprsRelease
|
||||
has, err := testEngine.ID(ie.Id).Get(&ie2)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
assert.EqualValues(t, true, ie2.IsDraft)
|
||||
assert.EqualValues(t, "", ie2.Sha1)
|
||||
assert.EqualValues(t, 0, ie2.NumCommits)
|
||||
assert.EqualValues(t, 1, ie2.RepoId)
|
||||
assert.EqualValues(t, true, ie2.IsTag)
|
||||
|
||||
inserted, err = testEngine.Table(new(InsertExprsRelease)).
|
||||
SetExpr("is_draft", true).
|
||||
SetExpr("num_commits", 0).
|
||||
SetExpr("sha1", "").
|
||||
Insert(map[string]interface{}{
|
||||
"repo_id": 1,
|
||||
"is_tag": true,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, inserted)
|
||||
|
||||
var ie3 InsertExprsRelease
|
||||
has, err = testEngine.ID(ie.Id + 1).Get(&ie3)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
assert.EqualValues(t, true, ie3.IsDraft)
|
||||
assert.EqualValues(t, "", ie3.Sha1)
|
||||
assert.EqualValues(t, 0, ie3.NumCommits)
|
||||
assert.EqualValues(t, 1, ie3.RepoId)
|
||||
assert.EqualValues(t, true, ie3.IsTag)
|
||||
}
|
||||
|
||||
type NightlyRate struct {
|
||||
ID int64 `xorm:"'id' not null pk BIGINT(20)" json:"id"`
|
||||
}
|
||||
|
|
@ -937,7 +879,7 @@ func (NightlyRate) TableName() string {
|
|||
}
|
||||
|
||||
func TestMultipleInsertTableName(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
tableName := `prd_nightly_rate_16`
|
||||
assert.NoError(t, testEngine.Table(tableName).Sync2(new(NightlyRate)))
|
||||
|
|
@ -968,7 +910,7 @@ func TestMultipleInsertTableName(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestInsertMultiWithOmit(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type TestMultiOmit struct {
|
||||
Id int64 `xorm:"int(11) pk"`
|
||||
|
|
@ -1009,3 +951,38 @@ func TestInsertMultiWithOmit(t *testing.T) {
|
|||
assert.EqualValues(t, 3, num)
|
||||
check()
|
||||
}
|
||||
|
||||
func TestInsertTwice(t *testing.T) {
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type InsertStructA struct {
|
||||
FieldA int
|
||||
}
|
||||
|
||||
type InsertStructB struct {
|
||||
FieldB int
|
||||
}
|
||||
|
||||
assert.NoError(t, testEngine.Sync2(new(InsertStructA), new(InsertStructB)))
|
||||
|
||||
var sliceA []InsertStructA // sliceA is empty
|
||||
sliceB := []InsertStructB{
|
||||
{
|
||||
FieldB: 1,
|
||||
},
|
||||
}
|
||||
|
||||
ssn := testEngine.NewSession()
|
||||
defer ssn.Close()
|
||||
|
||||
err := ssn.Begin()
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = ssn.Insert(sliceA)
|
||||
assert.EqualValues(t, xorm.ErrNoElementsOnSlice, err)
|
||||
|
||||
_, err = ssn.Insert(sliceB)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.NoError(t, ssn.Commit())
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
|
@ -11,7 +11,7 @@ import (
|
|||
)
|
||||
|
||||
func TestIterate(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type UserIterate struct {
|
||||
Id int64
|
||||
|
|
@ -39,7 +39,7 @@ func TestIterate(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestBufferIterate(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type UserBufferIterate struct {
|
||||
Id int64
|
||||
|
|
@ -89,4 +89,15 @@ func TestBufferIterate(t *testing.T) {
|
|||
})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 7, cnt)
|
||||
|
||||
cnt = 0
|
||||
err = testEngine.Where("id <= 10").BufferSize(2).Iterate(new(UserBufferIterate), func(i int, bean interface{}) error {
|
||||
user := bean.(*UserBufferIterate)
|
||||
assert.EqualValues(t, cnt+1, user.Id)
|
||||
assert.EqualValues(t, true, user.IsMan)
|
||||
cnt++
|
||||
return nil
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 10, cnt)
|
||||
}
|
||||
|
|
@ -0,0 +1,673 @@
|
|||
// Copyright 2017 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"xorm.io/xorm/schemas"
|
||||
)
|
||||
|
||||
type IntId struct {
|
||||
Id int `xorm:"pk autoincr"`
|
||||
Name string
|
||||
}
|
||||
|
||||
type Int16Id struct {
|
||||
Id int16 `xorm:"pk autoincr"`
|
||||
Name string
|
||||
}
|
||||
|
||||
type Int32Id struct {
|
||||
Id int32 `xorm:"pk autoincr"`
|
||||
Name string
|
||||
}
|
||||
|
||||
type UintId struct {
|
||||
Id uint `xorm:"pk autoincr"`
|
||||
Name string
|
||||
}
|
||||
|
||||
type Uint16Id struct {
|
||||
Id uint16 `xorm:"pk autoincr"`
|
||||
Name string
|
||||
}
|
||||
|
||||
type Uint32Id struct {
|
||||
Id uint32 `xorm:"pk autoincr"`
|
||||
Name string
|
||||
}
|
||||
|
||||
type Uint64Id struct {
|
||||
Id uint64 `xorm:"pk autoincr"`
|
||||
Name string
|
||||
}
|
||||
|
||||
type StringPK struct {
|
||||
Id string `xorm:"pk notnull"`
|
||||
Name string
|
||||
}
|
||||
|
||||
type ID int64
|
||||
type MyIntPK struct {
|
||||
ID ID `xorm:"pk autoincr"`
|
||||
Name string
|
||||
}
|
||||
|
||||
type StrID string
|
||||
type MyStringPK struct {
|
||||
ID StrID `xorm:"pk notnull"`
|
||||
Name string
|
||||
}
|
||||
|
||||
func TestIntId(t *testing.T) {
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
err := testEngine.DropTables(&IntId{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = testEngine.CreateTables(&IntId{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
cnt, err := testEngine.Insert(&IntId{Name: "test"})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
bean := new(IntId)
|
||||
has, err := testEngine.Get(bean)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
|
||||
beans := make([]IntId, 0)
|
||||
err = testEngine.Find(&beans)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(beans))
|
||||
|
||||
beans2 := make(map[int]IntId)
|
||||
err = testEngine.Find(&beans2)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(beans2))
|
||||
|
||||
cnt, err = testEngine.ID(bean.Id).Delete(&IntId{})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
}
|
||||
|
||||
func TestInt16Id(t *testing.T) {
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
err := testEngine.DropTables(&Int16Id{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = testEngine.CreateTables(&Int16Id{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
cnt, err := testEngine.Insert(&Int16Id{Name: "test"})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
bean := new(Int16Id)
|
||||
has, err := testEngine.Get(bean)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
|
||||
beans := make([]Int16Id, 0)
|
||||
err = testEngine.Find(&beans)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(beans))
|
||||
|
||||
beans2 := make(map[int16]Int16Id, 0)
|
||||
err = testEngine.Find(&beans2)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(beans2))
|
||||
|
||||
cnt, err = testEngine.ID(bean.Id).Delete(&Int16Id{})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
}
|
||||
|
||||
func TestInt32Id(t *testing.T) {
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
err := testEngine.DropTables(&Int32Id{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = testEngine.CreateTables(&Int32Id{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
cnt, err := testEngine.Insert(&Int32Id{Name: "test"})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
bean := new(Int32Id)
|
||||
has, err := testEngine.Get(bean)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
|
||||
beans := make([]Int32Id, 0)
|
||||
err = testEngine.Find(&beans)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(beans))
|
||||
|
||||
beans2 := make(map[int32]Int32Id, 0)
|
||||
err = testEngine.Find(&beans2)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(beans2))
|
||||
|
||||
cnt, err = testEngine.ID(bean.Id).Delete(&Int32Id{})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
}
|
||||
|
||||
func TestUintId(t *testing.T) {
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
err := testEngine.DropTables(&UintId{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = testEngine.CreateTables(&UintId{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
cnt, err := testEngine.Insert(&UintId{Name: "test"})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
var inserts = []UintId{
|
||||
{Name: "test1"},
|
||||
{Name: "test2"},
|
||||
}
|
||||
cnt, err = testEngine.Insert(&inserts)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 2, cnt)
|
||||
|
||||
bean := new(UintId)
|
||||
has, err := testEngine.Get(bean)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
|
||||
beans := make([]UintId, 0)
|
||||
err = testEngine.Find(&beans)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 3, len(beans))
|
||||
|
||||
beans2 := make(map[uint]UintId, 0)
|
||||
err = testEngine.Find(&beans2)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 3, len(beans2))
|
||||
|
||||
cnt, err = testEngine.ID(bean.Id).Delete(&UintId{})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
}
|
||||
|
||||
func TestUint16Id(t *testing.T) {
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
err := testEngine.DropTables(&Uint16Id{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = testEngine.CreateTables(&Uint16Id{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
cnt, err := testEngine.Insert(&Uint16Id{Name: "test"})
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
bean := new(Uint16Id)
|
||||
has, err := testEngine.Get(bean)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
|
||||
beans := make([]Uint16Id, 0)
|
||||
err = testEngine.Find(&beans)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(beans))
|
||||
|
||||
beans2 := make(map[uint16]Uint16Id, 0)
|
||||
err = testEngine.Find(&beans2)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(beans2))
|
||||
|
||||
cnt, err = testEngine.ID(bean.Id).Delete(&Uint16Id{})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
}
|
||||
|
||||
func TestUint32Id(t *testing.T) {
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
err := testEngine.DropTables(&Uint32Id{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = testEngine.CreateTables(&Uint32Id{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
cnt, err := testEngine.Insert(&Uint32Id{Name: "test"})
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
bean := new(Uint32Id)
|
||||
has, err := testEngine.Get(bean)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
|
||||
beans := make([]Uint32Id, 0)
|
||||
err = testEngine.Find(&beans)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(beans))
|
||||
|
||||
beans2 := make(map[uint32]Uint32Id, 0)
|
||||
err = testEngine.Find(&beans2)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(beans2))
|
||||
|
||||
cnt, err = testEngine.ID(bean.Id).Delete(&Uint32Id{})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
}
|
||||
|
||||
func TestUint64Id(t *testing.T) {
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
err := testEngine.DropTables(&Uint64Id{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = testEngine.CreateTables(&Uint64Id{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
idbean := &Uint64Id{Name: "test"}
|
||||
cnt, err := testEngine.Insert(idbean)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
bean := new(Uint64Id)
|
||||
has, err := testEngine.Get(bean)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
assert.EqualValues(t, bean.Id, idbean.Id)
|
||||
|
||||
beans := make([]Uint64Id, 0)
|
||||
err = testEngine.Find(&beans)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(beans))
|
||||
assert.EqualValues(t, *bean, beans[0])
|
||||
|
||||
beans2 := make(map[uint64]Uint64Id, 0)
|
||||
err = testEngine.Find(&beans2)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(beans2))
|
||||
assert.EqualValues(t, *bean, beans2[bean.Id])
|
||||
|
||||
cnt, err = testEngine.ID(bean.Id).Delete(&Uint64Id{})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
}
|
||||
|
||||
func TestStringPK(t *testing.T) {
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
err := testEngine.DropTables(&StringPK{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = testEngine.CreateTables(&StringPK{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
cnt, err := testEngine.Insert(&StringPK{Id: "1-1-2", Name: "test"})
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
bean := new(StringPK)
|
||||
has, err := testEngine.Get(bean)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
|
||||
beans := make([]StringPK, 0)
|
||||
err = testEngine.Find(&beans)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(beans))
|
||||
|
||||
beans2 := make(map[string]StringPK)
|
||||
err = testEngine.Find(&beans2)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(beans2))
|
||||
|
||||
cnt, err = testEngine.ID(bean.Id).Delete(&StringPK{})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
}
|
||||
|
||||
type CompositeKey struct {
|
||||
Id1 int64 `xorm:"id1 pk"`
|
||||
Id2 int64 `xorm:"id2 pk"`
|
||||
UpdateStr string
|
||||
}
|
||||
|
||||
func TestCompositeKey(t *testing.T) {
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
err := testEngine.DropTables(&CompositeKey{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = testEngine.CreateTables(&CompositeKey{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
cnt, err := testEngine.Insert(&CompositeKey{11, 22, ""})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
cnt, err = testEngine.Insert(&CompositeKey{11, 22, ""})
|
||||
assert.Error(t, err)
|
||||
assert.NotEqual(t, int64(1), cnt)
|
||||
|
||||
var compositeKeyVal CompositeKey
|
||||
has, err := testEngine.ID(schemas.PK{11, 22}).Get(&compositeKeyVal)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
|
||||
var compositeKeyVal2 CompositeKey
|
||||
// test passing PK ptr, this test seem failed withCache
|
||||
has, err = testEngine.ID(&schemas.PK{11, 22}).Get(&compositeKeyVal2)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
assert.EqualValues(t, compositeKeyVal, compositeKeyVal2)
|
||||
|
||||
var cps = make([]CompositeKey, 0)
|
||||
err = testEngine.Find(&cps)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(cps))
|
||||
assert.EqualValues(t, cps[0], compositeKeyVal)
|
||||
|
||||
cnt, err = testEngine.Insert(&CompositeKey{22, 22, ""})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
cps = make([]CompositeKey, 0)
|
||||
err = testEngine.Find(&cps)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 2, len(cps), "should has two record")
|
||||
assert.EqualValues(t, compositeKeyVal, cps[0], "should be equeal")
|
||||
|
||||
compositeKeyVal = CompositeKey{UpdateStr: "test1"}
|
||||
cnt, err = testEngine.ID(schemas.PK{11, 22}).Update(&compositeKeyVal)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
cnt, err = testEngine.ID(schemas.PK{11, 22}).Delete(&CompositeKey{})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
}
|
||||
|
||||
func TestCompositeKey2(t *testing.T) {
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type User struct {
|
||||
UserId string `xorm:"varchar(19) not null pk"`
|
||||
NickName string `xorm:"varchar(19) not null"`
|
||||
GameId uint32 `xorm:"integer pk"`
|
||||
Score int32 `xorm:"integer"`
|
||||
}
|
||||
|
||||
err := testEngine.DropTables(&User{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = testEngine.CreateTables(&User{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
cnt, err := testEngine.Insert(&User{"11", "nick", 22, 5})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
cnt, err = testEngine.Insert(&User{"11", "nick", 22, 6})
|
||||
assert.Error(t, err)
|
||||
assert.NotEqual(t, 1, cnt)
|
||||
|
||||
var user User
|
||||
has, err := testEngine.ID(schemas.PK{"11", 22}).Get(&user)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
|
||||
// test passing PK ptr, this test seem failed withCache
|
||||
has, err = testEngine.ID(&schemas.PK{"11", 22}).Get(&user)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
|
||||
user = User{NickName: "test1"}
|
||||
cnt, err = testEngine.ID(schemas.PK{"11", 22}).Update(&user)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
cnt, err = testEngine.ID(schemas.PK{"11", 22}).Delete(&User{})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
}
|
||||
|
||||
type MyString string
|
||||
type UserPK2 struct {
|
||||
UserId MyString `xorm:"varchar(19) not null pk"`
|
||||
NickName string `xorm:"varchar(19) not null"`
|
||||
GameId uint32 `xorm:"integer pk"`
|
||||
Score int32 `xorm:"integer"`
|
||||
}
|
||||
|
||||
func TestCompositeKey3(t *testing.T) {
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
err := testEngine.DropTables(&UserPK2{})
|
||||
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = testEngine.CreateTables(&UserPK2{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
cnt, err := testEngine.Insert(&UserPK2{"11", "nick", 22, 5})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
cnt, err = testEngine.Insert(&UserPK2{"11", "nick", 22, 6})
|
||||
assert.Error(t, err)
|
||||
assert.NotEqual(t, 1, cnt)
|
||||
|
||||
var user UserPK2
|
||||
has, err := testEngine.ID(schemas.PK{"11", 22}).Get(&user)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
|
||||
// test passing PK ptr, this test seem failed withCache
|
||||
has, err = testEngine.ID(&schemas.PK{"11", 22}).Get(&user)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
|
||||
user = UserPK2{NickName: "test1"}
|
||||
cnt, err = testEngine.ID(schemas.PK{"11", 22}).Update(&user)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
cnt, err = testEngine.ID(schemas.PK{"11", 22}).Delete(&UserPK2{})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
}
|
||||
|
||||
func TestMyIntId(t *testing.T) {
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
err := testEngine.DropTables(&MyIntPK{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = testEngine.CreateTables(&MyIntPK{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
idbean := &MyIntPK{Name: "test"}
|
||||
cnt, err := testEngine.Insert(idbean)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
bean := new(MyIntPK)
|
||||
has, err := testEngine.Get(bean)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
assert.EqualValues(t, bean.ID, idbean.ID)
|
||||
|
||||
var beans []MyIntPK
|
||||
err = testEngine.Find(&beans)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(beans))
|
||||
assert.EqualValues(t, *bean, beans[0])
|
||||
|
||||
beans2 := make(map[ID]MyIntPK, 0)
|
||||
err = testEngine.Find(&beans2)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(beans2))
|
||||
assert.EqualValues(t, *bean, beans2[bean.ID])
|
||||
|
||||
cnt, err = testEngine.ID(bean.ID).Delete(&MyIntPK{})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
}
|
||||
|
||||
func TestMyStringId(t *testing.T) {
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
err := testEngine.DropTables(&MyStringPK{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = testEngine.CreateTables(&MyStringPK{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
idbean := &MyStringPK{ID: "1111", Name: "test"}
|
||||
cnt, err := testEngine.Insert(idbean)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
bean := new(MyStringPK)
|
||||
has, err := testEngine.Get(bean)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, has)
|
||||
assert.EqualValues(t, bean.ID, idbean.ID)
|
||||
|
||||
var beans []MyStringPK
|
||||
err = testEngine.Find(&beans)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(beans))
|
||||
assert.EqualValues(t, *bean, beans[0])
|
||||
|
||||
beans2 := make(map[StrID]MyStringPK, 0)
|
||||
err = testEngine.Find(&beans2)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(beans2))
|
||||
assert.EqualValues(t, *bean, beans2[bean.ID])
|
||||
|
||||
cnt, err = testEngine.ID(bean.ID).Delete(&MyStringPK{})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
}
|
||||
|
||||
func TestSingleAutoIncrColumn(t *testing.T) {
|
||||
type Account struct {
|
||||
Id int64 `xorm:"pk autoincr"`
|
||||
}
|
||||
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(Account))
|
||||
|
||||
_, err := testEngine.Insert(&Account{})
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestCompositePK(t *testing.T) {
|
||||
type TaskSolution struct {
|
||||
UID string `xorm:"notnull pk UUID 'uid'"`
|
||||
TID string `xorm:"notnull pk UUID 'tid'"`
|
||||
Created time.Time `xorm:"created"`
|
||||
Updated time.Time `xorm:"updated"`
|
||||
}
|
||||
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
tables1, err := testEngine.DBMetas()
|
||||
assert.NoError(t, err)
|
||||
|
||||
assertSync(t, new(TaskSolution))
|
||||
assert.NoError(t, testEngine.Sync2(new(TaskSolution)))
|
||||
|
||||
tables2, err := testEngine.DBMetas()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1+len(tables1), len(tables2))
|
||||
|
||||
var table *schemas.Table
|
||||
for _, t := range tables2 {
|
||||
if t.Name == testEngine.GetTableMapper().Obj2Table("TaskSolution") {
|
||||
table = t
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
assert.NotEqual(t, nil, table)
|
||||
|
||||
pkCols := table.PKColumns()
|
||||
assert.EqualValues(t, 2, len(pkCols))
|
||||
|
||||
names := []string{pkCols[0].Name, pkCols[1].Name}
|
||||
sort.Strings(names)
|
||||
assert.EqualValues(t, []string{"tid", "uid"}, names)
|
||||
}
|
||||
|
||||
func TestNoPKIdQueryUpdate(t *testing.T) {
|
||||
type NoPKTable struct {
|
||||
Username string
|
||||
}
|
||||
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(NoPKTable))
|
||||
|
||||
cnt, err := testEngine.Insert(&NoPKTable{
|
||||
Username: "test",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
var res NoPKTable
|
||||
has, err := testEngine.ID("test").Get(&res)
|
||||
assert.Error(t, err)
|
||||
assert.False(t, has)
|
||||
|
||||
cnt, err = testEngine.ID("test").Update(&NoPKTable{
|
||||
Username: "test1",
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.EqualValues(t, 0, cnt)
|
||||
|
||||
type UnvalidPKTable struct {
|
||||
ID int `xorm:"id"`
|
||||
Username string
|
||||
}
|
||||
|
||||
assertSync(t, new(UnvalidPKTable))
|
||||
|
||||
cnt, err = testEngine.Insert(&UnvalidPKTable{
|
||||
ID: 1,
|
||||
Username: "test",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
var res2 UnvalidPKTable
|
||||
has, err = testEngine.ID(1).Get(&res2)
|
||||
assert.Error(t, err)
|
||||
assert.False(t, has)
|
||||
|
||||
cnt, err = testEngine.ID(1).Update(&UnvalidPKTable{
|
||||
Username: "test1",
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.EqualValues(t, 0, cnt)
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
|
@ -11,13 +11,13 @@ import (
|
|||
"time"
|
||||
|
||||
"xorm.io/builder"
|
||||
"xorm.io/core"
|
||||
"xorm.io/xorm/schemas"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestQueryString(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type GetVar2 struct {
|
||||
Id int64 `xorm:"autoincr pk"`
|
||||
|
|
@ -48,7 +48,7 @@ func TestQueryString(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestQueryString2(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type GetVar3 struct {
|
||||
Id int64 `xorm:"autoincr pk"`
|
||||
|
|
@ -108,7 +108,7 @@ func toFloat64(i interface{}) float64 {
|
|||
}
|
||||
|
||||
func TestQueryInterface(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type GetVarInterface struct {
|
||||
Id int64 `xorm:"autoincr pk"`
|
||||
|
|
@ -139,7 +139,7 @@ func TestQueryInterface(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestQueryNoParams(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type QueryNoParams struct {
|
||||
Id int64 `xorm:"autoincr pk"`
|
||||
|
|
@ -188,7 +188,7 @@ func TestQueryNoParams(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestQueryStringNoParam(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type GetVar4 struct {
|
||||
Id int64 `xorm:"autoincr pk"`
|
||||
|
|
@ -207,7 +207,7 @@ func TestQueryStringNoParam(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(records))
|
||||
assert.EqualValues(t, "1", records[0]["id"])
|
||||
if testEngine.Dialect().DBType() == core.POSTGRES || testEngine.Dialect().DBType() == core.MSSQL {
|
||||
if testEngine.Dialect().URI().DBType == schemas.POSTGRES || testEngine.Dialect().URI().DBType == schemas.MSSQL {
|
||||
assert.EqualValues(t, "false", records[0]["msg"])
|
||||
} else {
|
||||
assert.EqualValues(t, "0", records[0]["msg"])
|
||||
|
|
@ -217,7 +217,7 @@ func TestQueryStringNoParam(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(records))
|
||||
assert.EqualValues(t, "1", records[0]["id"])
|
||||
if testEngine.Dialect().DBType() == core.POSTGRES || testEngine.Dialect().DBType() == core.MSSQL {
|
||||
if testEngine.Dialect().URI().DBType == schemas.POSTGRES || testEngine.Dialect().URI().DBType == schemas.MSSQL {
|
||||
assert.EqualValues(t, "false", records[0]["msg"])
|
||||
} else {
|
||||
assert.EqualValues(t, "0", records[0]["msg"])
|
||||
|
|
@ -225,7 +225,7 @@ func TestQueryStringNoParam(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestQuerySliceStringNoParam(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type GetVar6 struct {
|
||||
Id int64 `xorm:"autoincr pk"`
|
||||
|
|
@ -244,7 +244,7 @@ func TestQuerySliceStringNoParam(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(records))
|
||||
assert.EqualValues(t, "1", records[0][0])
|
||||
if testEngine.Dialect().DBType() == core.POSTGRES || testEngine.Dialect().DBType() == core.MSSQL {
|
||||
if testEngine.Dialect().URI().DBType == schemas.POSTGRES || testEngine.Dialect().URI().DBType == schemas.MSSQL {
|
||||
assert.EqualValues(t, "false", records[0][1])
|
||||
} else {
|
||||
assert.EqualValues(t, "0", records[0][1])
|
||||
|
|
@ -254,7 +254,7 @@ func TestQuerySliceStringNoParam(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(records))
|
||||
assert.EqualValues(t, "1", records[0][0])
|
||||
if testEngine.Dialect().DBType() == core.POSTGRES || testEngine.Dialect().DBType() == core.MSSQL {
|
||||
if testEngine.Dialect().URI().DBType == schemas.POSTGRES || testEngine.Dialect().URI().DBType == schemas.MSSQL {
|
||||
assert.EqualValues(t, "false", records[0][1])
|
||||
} else {
|
||||
assert.EqualValues(t, "0", records[0][1])
|
||||
|
|
@ -262,7 +262,7 @@ func TestQuerySliceStringNoParam(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestQueryInterfaceNoParam(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type GetVar5 struct {
|
||||
Id int64 `xorm:"autoincr pk"`
|
||||
|
|
@ -291,7 +291,7 @@ func TestQueryInterfaceNoParam(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestQueryWithBuilder(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type QueryWithBuilder struct {
|
||||
Id int64 `xorm:"autoincr pk"`
|
||||
|
|
@ -336,7 +336,7 @@ func TestQueryWithBuilder(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestJoinWithSubQuery(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type JoinWithSubQuery1 struct {
|
||||
Id int64 `xorm:"autoincr pk"`
|
||||
|
|
@ -371,10 +371,18 @@ func TestJoinWithSubQuery(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
|
||||
tbName := testEngine.Quote(testEngine.TableName("join_with_sub_query_depart", true))
|
||||
var querys []JoinWithSubQuery1
|
||||
err = testEngine.Join("INNER", builder.Select("id").From(testEngine.Quote(testEngine.TableName("join_with_sub_query_depart", true))),
|
||||
err = testEngine.Join("INNER", builder.Select("id").From(tbName),
|
||||
"join_with_sub_query_depart.id = join_with_sub_query1.depart_id").Find(&querys)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(querys))
|
||||
assert.EqualValues(t, q, querys[0])
|
||||
|
||||
querys = make([]JoinWithSubQuery1, 0, 1)
|
||||
err = testEngine.Join("INNER", "(SELECT id FROM "+tbName+") join_with_sub_query_depart", "join_with_sub_query_depart.id = join_with_sub_query1.depart_id").
|
||||
Find(&querys)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(querys))
|
||||
assert.EqualValues(t, q, querys[0])
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
|
@ -12,7 +12,7 @@ import (
|
|||
)
|
||||
|
||||
func TestExecAndQuery(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type UserinfoQuery struct {
|
||||
Uid int
|
||||
|
|
@ -2,11 +2,10 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
|
@ -14,7 +13,7 @@ import (
|
|||
)
|
||||
|
||||
func TestStoreEngine(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
assert.NoError(t, testEngine.DropTables("user_store_engine"))
|
||||
|
||||
|
|
@ -27,7 +26,7 @@ func TestStoreEngine(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestCreateTable(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
assert.NoError(t, testEngine.DropTables("user_user"))
|
||||
|
||||
|
|
@ -40,7 +39,7 @@ func TestCreateTable(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestCreateMultiTables(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
session := testEngine.NewSession()
|
||||
defer session.Close()
|
||||
|
|
@ -95,7 +94,7 @@ func (s *SyncTable3) TableName() string {
|
|||
}
|
||||
|
||||
func TestSyncTable(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
assert.NoError(t, testEngine.Sync2(new(SyncTable1)))
|
||||
|
||||
|
|
@ -120,7 +119,7 @@ func TestSyncTable(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSyncTable2(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
assert.NoError(t, testEngine.Table("sync_tablex").Sync2(new(SyncTable1)))
|
||||
|
||||
|
|
@ -145,7 +144,7 @@ func TestSyncTable2(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestIsTableExist(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
exist, err := testEngine.IsTableExist(new(CustomTableName))
|
||||
assert.NoError(t, err)
|
||||
|
|
@ -159,7 +158,7 @@ func TestIsTableExist(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestIsTableEmpty(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type NumericEmpty struct {
|
||||
Numeric float64 `xorm:"numeric(26,2)"`
|
||||
|
|
@ -202,7 +201,7 @@ func (c *CustomTableName) TableName() string {
|
|||
}
|
||||
|
||||
func TestCustomTableName(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
c := new(CustomTableName)
|
||||
assert.NoError(t, testEngine.DropTables(c))
|
||||
|
|
@ -210,14 +209,6 @@ func TestCustomTableName(t *testing.T) {
|
|||
assert.NoError(t, testEngine.CreateTables(c))
|
||||
}
|
||||
|
||||
func TestDump(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
|
||||
fp := testEngine.Dialect().URI().DbName + ".sql"
|
||||
os.Remove(fp)
|
||||
assert.NoError(t, testEngine.DumpAllToFile(fp))
|
||||
}
|
||||
|
||||
type IndexOrUnique struct {
|
||||
Id int64
|
||||
Index int `xorm:"index"`
|
||||
|
|
@ -229,7 +220,7 @@ type IndexOrUnique struct {
|
|||
}
|
||||
|
||||
func TestIndexAndUnique(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
assert.NoError(t, testEngine.CreateTables(&IndexOrUnique{}))
|
||||
|
||||
|
|
@ -245,7 +236,7 @@ func TestIndexAndUnique(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestMetaInfo(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assert.NoError(t, testEngine.Sync2(new(CustomTableName), new(IndexOrUnique)))
|
||||
|
||||
tables, err := testEngine.DBMetas()
|
||||
|
|
@ -257,19 +248,13 @@ func TestMetaInfo(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestCharst(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
err := testEngine.DropTables("user_charset")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
panic(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = testEngine.Charset("utf8").Table("user_charset").CreateTable(&Userinfo{})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
panic(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestSync2_1(t *testing.T) {
|
||||
|
|
@ -279,7 +264,7 @@ func TestSync2_1(t *testing.T) {
|
|||
Id_delete int8 `xorm:"null int default 1"`
|
||||
}
|
||||
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
assert.NoError(t, testEngine.DropTables("wx_test"))
|
||||
assert.NoError(t, testEngine.Sync2(new(WxTest)))
|
||||
|
|
@ -296,7 +281,7 @@ func TestUnique_1(t *testing.T) {
|
|||
UpdatedAt time.Time `xorm:"updated"`
|
||||
}
|
||||
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
assert.NoError(t, testEngine.DropTables("user_unique"))
|
||||
assert.NoError(t, testEngine.Sync2(new(UserUnique)))
|
||||
|
|
@ -312,7 +297,7 @@ func TestSync2_2(t *testing.T) {
|
|||
UserId int64 `xorm:"index"`
|
||||
}
|
||||
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
var tableNames = make(map[string]bool)
|
||||
for i := 0; i < 10; i++ {
|
||||
|
|
@ -341,7 +326,7 @@ func TestSync2_Default(t *testing.T) {
|
|||
Name string `xorm:"default('my_name')"`
|
||||
}
|
||||
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(TestSync2Default))
|
||||
assert.NoError(t, testEngine.Sync2(new(TestSync2Default)))
|
||||
}
|
||||
|
|
@ -2,15 +2,15 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"xorm.io/builder"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
func isFloatEq(i, j float64, precision int) bool {
|
||||
|
|
@ -23,7 +23,7 @@ func TestSum(t *testing.T) {
|
|||
Float float32
|
||||
}
|
||||
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assert.NoError(t, testEngine.Sync2(new(SumStruct)))
|
||||
|
||||
var (
|
||||
|
|
@ -82,7 +82,7 @@ func (s SumStructWithTableName) TableName() string {
|
|||
}
|
||||
|
||||
func TestSumWithTableName(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assert.NoError(t, testEngine.Sync2(new(SumStructWithTableName)))
|
||||
|
||||
var (
|
||||
|
|
@ -132,7 +132,7 @@ func TestSumWithTableName(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSumCustomColumn(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type SumStruct2 struct {
|
||||
Int int
|
||||
|
|
@ -160,7 +160,7 @@ func TestSumCustomColumn(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestCount(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type UserinfoCount struct {
|
||||
Departname string
|
||||
|
|
@ -196,7 +196,7 @@ func TestCount(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSQLCount(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type UserinfoCount2 struct {
|
||||
Id int64
|
||||
|
|
@ -218,7 +218,7 @@ func TestSQLCount(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestCountWithOthers(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type CountWithOthers struct {
|
||||
Id int64
|
||||
|
|
@ -252,7 +252,7 @@ func (CountWithTableName) TableName() string {
|
|||
}
|
||||
|
||||
func TestWithTableName(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
assertSync(t, new(CountWithTableName))
|
||||
|
||||
|
|
@ -274,3 +274,27 @@ func TestWithTableName(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 2, total)
|
||||
}
|
||||
|
||||
func TestCountWithSelectCols(t *testing.T) {
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
assertSync(t, new(CountWithTableName))
|
||||
|
||||
_, err := testEngine.Insert(&CountWithTableName{
|
||||
Name: "orderby",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = testEngine.Insert(CountWithTableName{
|
||||
Name: "limit",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
total, err := testEngine.Cols("id").Count(new(CountWithTableName))
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 2, total)
|
||||
|
||||
total, err = testEngine.Select("count(id)").Count(CountWithTableName{})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 2, total)
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
|
@ -12,7 +12,7 @@ import (
|
|||
)
|
||||
|
||||
func TestClose(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
sess1 := testEngine.NewSession()
|
||||
sess1.Close()
|
||||
|
|
@ -31,7 +31,7 @@ func TestNullFloatStruct(t *testing.T) {
|
|||
Amount MyNullFloat64
|
||||
}
|
||||
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assert.NoError(t, testEngine.Sync2(new(MyNullFloatStruct)))
|
||||
|
||||
_, err := testEngine.Insert(&MyNullFloatStruct{
|
||||
|
|
@ -43,3 +43,14 @@ func TestNullFloatStruct(t *testing.T) {
|
|||
})
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestMustLogSQL(t *testing.T) {
|
||||
assert.NoError(t, PrepareEngine())
|
||||
testEngine.ShowSQL(false)
|
||||
defer testEngine.ShowSQL(true)
|
||||
|
||||
assertSync(t, new(Userinfo))
|
||||
|
||||
_, err := testEngine.Table("userinfo").MustLogSQL(true).Get(new(Userinfo))
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
|
@ -2,30 +2,28 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"xorm.io/core"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"xorm.io/xorm/internal/utils"
|
||||
"xorm.io/xorm/names"
|
||||
)
|
||||
|
||||
func TestTransaction(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(Userinfo))
|
||||
|
||||
counter := func() {
|
||||
total, err := testEngine.Count(&Userinfo{})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
fmt.Printf("----now total %v records\n", total)
|
||||
counter := func(t *testing.T) {
|
||||
_, err := testEngine.Count(&Userinfo{})
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
counter()
|
||||
counter(t)
|
||||
//defer counter()
|
||||
|
||||
session := testEngine.NewSession()
|
||||
|
|
@ -39,7 +37,7 @@ func TestTransaction(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
|
||||
user2 := Userinfo{Username: "yyy"}
|
||||
_, err = session.Where("(id) = ?", 0).Update(&user2)
|
||||
_, err = session.Where("id = ?", 0).Update(&user2)
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = session.Delete(&user2)
|
||||
|
|
@ -50,14 +48,12 @@ func TestTransaction(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestCombineTransaction(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(Userinfo))
|
||||
|
||||
counter := func() {
|
||||
total, err := testEngine.Count(&Userinfo{})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
fmt.Printf("----now total %v records\n", total)
|
||||
}
|
||||
|
||||
|
|
@ -85,13 +81,13 @@ func TestCombineTransaction(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestCombineTransactionSameMapper(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
oldMapper := testEngine.GetColumnMapper()
|
||||
testEngine.UnMapType(rValue(new(Userinfo)).Type())
|
||||
testEngine.SetMapper(core.SameMapper{})
|
||||
testEngine.UnMapType(utils.ReflectValue(new(Userinfo)).Type())
|
||||
testEngine.SetMapper(names.SameMapper{})
|
||||
defer func() {
|
||||
testEngine.UnMapType(rValue(new(Userinfo)).Type())
|
||||
testEngine.UnMapType(utils.ReflectValue(new(Userinfo)).Type())
|
||||
testEngine.SetMapper(oldMapper)
|
||||
}()
|
||||
|
||||
|
|
@ -99,9 +95,7 @@ func TestCombineTransactionSameMapper(t *testing.T) {
|
|||
|
||||
counter := func() {
|
||||
total, err := testEngine.Count(&Userinfo{})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
fmt.Printf("----now total %v records\n", total)
|
||||
}
|
||||
|
||||
|
|
@ -119,7 +113,7 @@ func TestCombineTransactionSameMapper(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
|
||||
user2 := Userinfo{Username: "zzz"}
|
||||
_, err = session.Where("(id) = ?", 0).Update(&user2)
|
||||
_, err = session.Where("id = ?", 0).Update(&user2)
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = session.Exec("delete from "+testEngine.TableName("`Userinfo`", true)+" where `Username` = ?", user2.Username)
|
||||
|
|
@ -130,7 +124,7 @@ func TestCombineTransactionSameMapper(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestMultipleTransaction(t *testing.T) {
|
||||
assert.NoError(t, prepareEngine())
|
||||
assert.NoError(t, PrepareEngine())
|
||||
|
||||
type MultipleTransaction struct {
|
||||
Id int64
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue