diff --git a/.github/workflows/gf.yml b/.github/workflows/gf.yml index fe60fa464..72f0f174d 100644 --- a/.github/workflows/gf.yml +++ b/.github/workflows/gf.yml @@ -97,10 +97,23 @@ jobs: - 8090:8090 - 8091:8091 + #oracle 11g server + oracle-server: + image: loads/oracle-xe-11g-r2:latest + env: + ORACLE_ALLOW_REMOTE: true + ORACLE_SID: XE + ORACLE_DB_USER_NAME: system + ORACLE_DB_PASSWORD: oracle + ports: + - 1521:1521 + + + strategy: matrix: - go: ["1.15", "1.16", "1.17"] - goarch: ["386", "amd64"] + go: [ "1.15", "1.16", "1.17" ] + goarch: [ "386", "amd64" ] steps: @@ -131,7 +144,9 @@ jobs: dirpath=$(dirname $file) if [ "oracle" = $(basename $dirpath) ]; then - continue 1 + if ! go version|grep -q "1.17"; then + continue 1 + fi fi cd $dirpath diff --git a/contrib/drivers/mssql/mssql.go b/contrib/drivers/mssql/mssql.go index 73982c4a9..4b97d39a4 100644 --- a/contrib/drivers/mssql/mssql.go +++ b/contrib/drivers/mssql/mssql.go @@ -299,6 +299,7 @@ ORDER BY a.id,a.colorder`, } fields = make(map[string]*gdb.TableField) for i, m := range result { + fields[m["Field"].String()] = &gdb.TableField{ Index: i, Name: m["Field"].String(), diff --git a/contrib/drivers/mssql/mssql_z_basic_test.go b/contrib/drivers/mssql/mssql_z_basic_test.go index 2345453be..5d6dd410e 100644 --- a/contrib/drivers/mssql/mssql_z_basic_test.go +++ b/contrib/drivers/mssql/mssql_z_basic_test.go @@ -63,32 +63,42 @@ func TestTableFields(t *testing.T) { gtest.C(t, func(t *gtest.T) { createTable("t_user") defer dropTable("t_user") - var expect map[string]string = map[string]string{ - "ID": "numeric(10,0)", - "PASSPORT": "VARCHAR(45)", - "PASSWORD": "CHAR(32)", - "NICKNAME": "VARCHAR(45)", - "CREATE_TIME": "time", + var expect = map[string][]interface{}{ + "ID": {"numeric(10,0)", false, "PRI", "", "", ""}, + "PASSPORT": {"varchar(45)", true, "", "", "", ""}, + "PASSWORD": {"varchar(32)", true, "", "", "", ""}, + "NICKNAME": {"varchar(45)", true, "", "", "", ""}, + "CREATE_TIME": {"datetime", true, "", "", "", ""}, } res, err := db.TableFields(context.Background(), "t_user") gtest.Assert(err, nil) - for k, _ := range expect { + for k, v := range expect { _, ok := res[k] gtest.AssertEQ(ok, true) - gtest.AssertEQ(res[k].Name, k) + gtest.AssertEQ(res[k].Type, v[0]) + gtest.AssertEQ(res[k].Null, v[1]) + gtest.AssertEQ(res[k].Key, v[2]) + gtest.AssertEQ(res[k].Default, v[3]) + gtest.AssertEQ(res[k].Extra, v[4]) + gtest.AssertEQ(res[k].Comment, v[5]) } res, err = db.TableFields(context.Background(), "t_user", "test") gtest.Assert(err, nil) - for k, _ := range expect { + for k, v := range expect { _, ok := res[k] gtest.AssertEQ(ok, true) - gtest.AssertEQ(res[k].Name, k) + gtest.AssertEQ(res[k].Type, v[0]) + gtest.AssertEQ(res[k].Null, v[1]) + gtest.AssertEQ(res[k].Key, v[2]) + gtest.AssertEQ(res[k].Default, v[3]) + gtest.AssertEQ(res[k].Extra, v[4]) + gtest.AssertEQ(res[k].Comment, v[5]) } }) diff --git a/contrib/drivers/oracle/go.mod b/contrib/drivers/oracle/go.mod index 85ea4f5a3..fd1468a62 100644 --- a/contrib/drivers/oracle/go.mod +++ b/contrib/drivers/oracle/go.mod @@ -1,10 +1,36 @@ module github.com/gogf/gf/contrib/drivers/oracle/v2 -go 1.15 +go 1.17 require ( github.com/gogf/gf/v2 v2.0.0 - github.com/mattn/go-oci8 v0.1.1 + github.com/sijms/go-ora/v2 v2.4.20 +) + +require ( + github.com/BurntSushi/toml v1.1.0 // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/clbanning/mxj/v2 v2.5.5 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/fsnotify/fsnotify v1.5.4 // indirect + github.com/go-logr/logr v1.2.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-redis/redis/v8 v8.11.5 // indirect + github.com/gorilla/websocket v1.5.0 // indirect + github.com/grokify/html-strip-tags-go v0.0.1 // indirect + github.com/magiconair/properties v1.8.6 // indirect + github.com/mattn/go-colorable v0.1.9 // indirect + github.com/mattn/go-isatty v0.0.14 // indirect + github.com/mattn/go-runewidth v0.0.9 // indirect + github.com/olekukonko/tablewriter v0.0.5 // indirect + go.opentelemetry.io/otel v1.7.0 // indirect + go.opentelemetry.io/otel/sdk v1.7.0 // indirect + go.opentelemetry.io/otel/trace v1.7.0 // indirect + golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect + golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect + golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2 // indirect + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect ) replace github.com/gogf/gf/v2 => ../../../ diff --git a/contrib/drivers/oracle/go.sum b/contrib/drivers/oracle/go.sum index 3dc280183..7dc3230fa 100644 --- a/contrib/drivers/oracle/go.sum +++ b/contrib/drivers/oracle/go.sum @@ -34,7 +34,6 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -56,8 +55,6 @@ github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-oci8 v0.1.1 h1:aEUDxNAyDG0tv8CA3TArnDQNyc4EhnWlsfxRgDHABHM= -github.com/mattn/go-oci8 v0.1.1/go.mod h1:wjDx6Xm9q7dFtHJvIlrI99JytznLw5wQ4R+9mNXJwGI= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= @@ -70,7 +67,6 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108 github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.0.0 h1:CcuG/HvWNkkaqCUpJifQY8z7qEMBJya6aLPx6ftGyjQ= github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= @@ -79,6 +75,8 @@ github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= 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/sijms/go-ora/v2 v2.4.20 h1:9e3z7VLBQXRAHGiIda1GEFtRhfxata0LghyMZqvLKew= +github.com/sijms/go-ora/v2 v2.4.20/go.mod h1:EHxlY6x7y9HAsdfumurRfTd+v8NrEOTR3Xl4FWlH6xk= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= @@ -142,7 +140,6 @@ golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -151,7 +148,6 @@ google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miE google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 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= diff --git a/contrib/drivers/oracle/oracle.go b/contrib/drivers/oracle/oracle.go index f20145900..6065a0193 100644 --- a/contrib/drivers/oracle/oracle.go +++ b/contrib/drivers/oracle/oracle.go @@ -5,7 +5,7 @@ // You can obtain one at https://github.com/gogf/gf. // // Note: -// 1. It needs manually import: _ "github.com/mattn/go-oci8" +// 1. It needs manually import: _ "github.com/sijms/go-ora/v2" // 2. It does not support Save/Replace features. // 3. It does not support LastInsertId. @@ -16,12 +16,7 @@ import ( "context" "database/sql" "fmt" - "reflect" - "strconv" - "strings" - "time" - - _ "github.com/mattn/go-oci8" + gora "github.com/sijms/go-ora/v2" "github.com/gogf/gf/v2/container/gmap" "github.com/gogf/gf/v2/database/gdb" @@ -30,6 +25,8 @@ import ( "github.com/gogf/gf/v2/text/gregex" "github.com/gogf/gf/v2/text/gstr" "github.com/gogf/gf/v2/util/gconv" + "strconv" + "strings" ) // Driver is the driver for oracle database. @@ -65,9 +62,18 @@ func (d *Driver) New(core *gdb.Core, node *gdb.ConfigNode) (gdb.DB, error) { func (d *Driver) Open(config *gdb.ConfigNode) (db *sql.DB, err error) { var ( source string - underlyingDriverName = "oci8" + underlyingDriverName = "oracle" ) - // [username/[password]@]host[:port][/service_name][?param1=value1&...¶mN=valueN] + + options := map[string]string{ + "CONNECTION TIMEOUT": "60", + "PREFETCH_ROWS": "25", + } + + if config.Debug { + options["TRACE FILE"] = "oracle_trace.log" + } + // [username:[password]@]host[:port][/service_name][?param1=value1&...¶mN=valueN] if config.Link != "" { source = config.Link // Custom changing the schema in runtime. @@ -75,10 +81,7 @@ func (d *Driver) Open(config *gdb.ConfigNode) (db *sql.DB, err error) { source, _ = gregex.ReplaceString(`@(.+?)/([\w\.\-]+)+`, "@$1/"+config.Name, source) } } else { - source = fmt.Sprintf( - "%s/%s@%s:%s/%s", - config.User, config.Pass, config.Host, config.Port, config.Name, - ) + source = gora.BuildUrl(config.Host, gconv.Int(config.Port), config.Name, config.User, config.Pass, options) } if db, err = sql.Open(underlyingDriverName, source); err != nil { @@ -99,8 +102,8 @@ func (d *Driver) FilteredLink() string { return "" } s, _ := gregex.ReplaceString( - `(.+?)\s*/\s*(.+)\s*@\s*(.+)\s*:\s*(\d+)\s*/\s*(.+)`, - `$1/xxx@$3:$4/$5`, + `(.+?)\s*:\s*(.+)\s*@\s*(.+)\s*:\s*(\d+)\s*/\s*(.+)`, + `$1:xxx@$3:$4/$5`, linkInfo, ) return s @@ -124,16 +127,7 @@ func (d *Driver) DoFilter(ctx context.Context, link gdb.Link, sql string, args [ return fmt.Sprintf(":v%d", index) }) newSql, _ = gregex.ReplaceString("\"", "", newSql) - // Handle string datetime argument. - for i, v := range args { - if reflect.TypeOf(v).Kind() == reflect.String { - valueStr := gconv.String(v) - if gregex.IsMatchString(`^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$`, valueStr) { - // args[i] = fmt.Sprintf(`TO_DATE('%s','yyyy-MM-dd HH:MI:SS')`, valueStr) - args[i], _ = time.ParseInLocation("2006-01-02 15:04:05", valueStr, time.Local) - } - } - } + newSql = d.parseSql(newSql) newArgs = args return @@ -168,7 +162,7 @@ func (d *Driver) parseSql(sql string) string { strings.EqualFold(queryExpr[3], "LIMIT") == false { break } - first, limit := 0, 0 + page, limit := 0, 0 for i := 1; i < len(allMatch[index]); i++ { if len(strings.TrimSpace(allMatch[index][i])) == 0 { continue @@ -176,8 +170,16 @@ func (d *Driver) parseSql(sql string) string { if strings.HasPrefix(allMatch[index][i], "LIMIT") { if allMatch[index][i+2] != "" { - first, _ = strconv.Atoi(allMatch[index][i+1]) + page, _ = strconv.Atoi(allMatch[index][i+1]) limit, _ = strconv.Atoi(allMatch[index][i+2]) + + if page <= 0 { + page = 1 + } + + limit = (page/limit + 1) * limit + + page, _ = strconv.Atoi(allMatch[index][i+1]) } else { limit, _ = strconv.Atoi(allMatch[index][i+1]) } @@ -187,8 +189,8 @@ func (d *Driver) parseSql(sql string) string { sql = fmt.Sprintf( "SELECT * FROM "+ "(SELECT GFORM.*, ROWNUM ROWNUM_ FROM (%s %s) GFORM WHERE ROWNUM <= %d)"+ - " WHERE ROWNUM_ >= %d", - queryExpr[1], queryExpr[2], limit, first, + " WHERE ROWNUM_ > %d", + queryExpr[1], queryExpr[2], limit, page, ) } return sql @@ -241,7 +243,7 @@ SELECT CASE DATA_TYPE WHEN 'NUMBER' THEN DATA_TYPE||'('||DATA_PRECISION||','||DATA_SCALE||')' WHEN 'FLOAT' THEN DATA_TYPE||'('||DATA_PRECISION||','||DATA_SCALE||')' - ELSE DATA_TYPE||'('||DATA_LENGTH||')' END AS TYPE + ELSE DATA_TYPE||'('||DATA_LENGTH||')' END AS TYPE,NULLABLE FROM USER_TAB_COLUMNS WHERE TABLE_NAME = '%s' ORDER BY COLUMN_ID`, strings.ToUpper(table), ) @@ -256,10 +258,16 @@ FROM USER_TAB_COLUMNS WHERE TABLE_NAME = '%s' ORDER BY COLUMN_ID`, } fields = make(map[string]*gdb.TableField) for i, m := range result { - fields[strings.ToLower(m["FIELD"].String())] = &gdb.TableField{ + isNull := false + if m["NULLABLE"].String() == "Y" { + isNull = true + } + + fields[m["FIELD"].String()] = &gdb.TableField{ Index: i, - Name: strings.ToLower(m["FIELD"].String()), - Type: strings.ToLower(m["TYPE"].String()), + Name: m["FIELD"].String(), + Type: m["TYPE"].String(), + Null: isNull, } } return fields @@ -288,10 +296,10 @@ func (d *Driver) DoInsert( ) (result sql.Result, err error) { switch option.InsertOption { case gdb.InsertOptionSave: - return nil, gerror.NewCode(gcode.CodeNotSupported, `Save operation is not supported by mssql driver`) + return nil, gerror.NewCode(gcode.CodeNotSupported, `Save operation is not supported by oracle driver`) case gdb.InsertOptionReplace: - return nil, gerror.NewCode(gcode.CodeNotSupported, `Replace operation is not supported by mssql driver`) + return nil, gerror.NewCode(gcode.CodeNotSupported, `Replace operation is not supported by oracle driver`) } var ( diff --git a/contrib/drivers/oracle/oracle_init_test.go b/contrib/drivers/oracle/oracle_init_test.go new file mode 100644 index 000000000..b16c8cb9e --- /dev/null +++ b/contrib/drivers/oracle/oracle_init_test.go @@ -0,0 +1,162 @@ +// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package oracle_test + +import ( + "context" + "fmt" + "github.com/gogf/gf/v2/container/garray" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/test/gtest" + _ "github.com/sijms/go-ora/v2" + "strings" +) + +var ( + db gdb.DB + dblink gdb.DB + dbErr gdb.DB + ctx context.Context +) + +const ( + TableSize = 10 + TableName = "t_user" + TestSchema1 = "test1" + TestSchema2 = "test2" + TableNamePrefix1 = "gf_" + TestSchema = "XE" +) + +const ( + TestDbIP = "127.0.0.1" + TestDbPort = "1521" + TestDbUser = "system" + TestDbPass = "oracle" + TestDbName = "XE" + TestDbType = "oracle" +) + +func init() { + node := gdb.ConfigNode{ + Host: TestDbIP, + Port: TestDbPort, + User: TestDbUser, + Pass: TestDbPass, + Name: TestDbName, + Type: TestDbType, + Role: "master", + Charset: "utf8", + Weight: 1, + MaxIdleConnCount: 10, + MaxOpenConnCount: 10, + } + + nodeLink := gdb.ConfigNode{ + Type: TestDbType, + Name: TestDbName, + Link: fmt.Sprintf("%s://%s:%s@%s:%s/%s", + TestDbType, TestDbUser, TestDbPass, TestDbIP, TestDbPort, TestDbName), + } + + nodeErr := gdb.ConfigNode{ + Host: TestDbIP, + Port: TestDbPort, + User: TestDbUser, + Pass: "1234", + Name: TestDbName, + Type: TestDbType, + Role: "master", + Charset: "utf8", + Weight: 1, + } + + gdb.AddConfigNode(gdb.DefaultGroupName, node) + if r, err := gdb.New(node); err != nil { + gtest.Fatal(err) + } else { + db = r + } + + gdb.AddConfigNode("dblink", nodeLink) + if r, err := gdb.New(nodeLink); err != nil { + gtest.Fatal(err) + } else { + dblink = r + } + + gdb.AddConfigNode("dbErr", nodeErr) + if r, err := gdb.New(nodeErr); err != nil { + gtest.Fatal(err) + } else { + dbErr = r + } + + ctx = context.Background() +} + +func createTable(table ...string) (name string) { + if len(table) > 0 { + name = table[0] + } else { + name = fmt.Sprintf("user_%d", gtime.Timestamp()) + } + + dropTable(name) + + if _, err := db.Exec(ctx, fmt.Sprintf(` + CREATE TABLE %s ( + ID NUMBER(10) NOT NULL, + PASSPORT VARCHAR(45) NOT NULL, + PASSWORD CHAR(32) NOT NULL, + NICKNAME VARCHAR(45) NOT NULL, + CREATE_TIME varchar(45), + PRIMARY KEY (ID)) + `, name)); err != nil { + gtest.Fatal(err) + } + + //db.Schema("test") + return +} + +func createInitTable(table ...string) (name string) { + name = createTable(table...) + array := garray.New(true) + for i := 1; i <= TableSize; i++ { + array.Append(g.Map{ + "id": i, + "passport": fmt.Sprintf(`user_%d`, i), + "password": fmt.Sprintf(`pass_%d`, i), + "nickname": fmt.Sprintf(`name_%d`, i), + "create_time": gtime.Now().String(), + }) + } + result, err := db.Insert(context.Background(), name, array.Slice()) + gtest.Assert(err, nil) + + n, e := result.RowsAffected() + gtest.Assert(e, nil) + gtest.Assert(n, TableSize) + return +} + +func dropTable(table string) { + count, err := db.GetCount(ctx, "SELECT COUNT(*) FROM USER_TABLES WHERE TABLE_NAME = ?", strings.ToUpper(table)) + if err != nil { + gtest.Fatal(err) + } + + if count == 0 { + return + } + if _, err := db.Exec(ctx, fmt.Sprintf("DROP TABLE %s", table)); err != nil { + gtest.Fatal(err) + } +} diff --git a/contrib/drivers/oracle/oracle_z_basic_test.go b/contrib/drivers/oracle/oracle_z_basic_test.go new file mode 100644 index 000000000..bc3d61bb5 --- /dev/null +++ b/contrib/drivers/oracle/oracle_z_basic_test.go @@ -0,0 +1,665 @@ +// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package oracle_test + +import ( + "fmt" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/test/gtest" + "strings" + "testing" +) + +func TestTables(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + tables := []string{"t_user1", "pop", "haha"} + + for _, v := range tables { + createTable(v) + } + + result, err := db.Tables(ctx) + gtest.Assert(err, nil) + + for i := 0; i < len(tables); i++ { + find := false + for j := 0; j < len(result); j++ { + if strings.ToUpper(tables[i]) == result[j] { + find = true + break + } + } + gtest.AssertEQ(find, true) + } + + result, err = db.Tables(ctx, TestSchema) + gtest.Assert(err, nil) + for i := 0; i < len(tables); i++ { + find := false + for j := 0; j < len(result); j++ { + if strings.ToUpper(tables[i]) == result[j] { + find = true + break + } + } + gtest.AssertEQ(find, true) + } + + for _, v := range tables { + dropTable(v) + } + }) +} + +func TestTableFields(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + createTable("t_user") + defer dropTable("t_user") + var expect = map[string][]interface{}{ + "ID": {"NUMBER(10,0)", false}, + "PASSPORT": {"VARCHAR2(45)", false}, + "PASSWORD": {"CHAR(32)", false}, + "NICKNAME": {"VARCHAR2(45)", false}, + "CREATE_TIME": {"VARCHAR2(45)", true}, + } + + _, err := dbErr.TableFields(ctx, "t_user") + gtest.AssertNE(err, nil) + + res, err := db.TableFields(ctx, "t_user") + gtest.Assert(err, nil) + + for k, v := range expect { + _, ok := res[k] + gtest.AssertEQ(ok, true) + + gtest.AssertEQ(res[k].Name, k) + gtest.Assert(res[k].Type, v[0]) + gtest.Assert(res[k].Null, v[1]) + } + + res, err = db.TableFields(ctx, "t_user", TestSchema) + gtest.Assert(err, nil) + + for k, v := range expect { + _, ok := res[k] + gtest.AssertEQ(ok, true) + + gtest.AssertEQ(res[k].Name, k) + gtest.Assert(res[k].Type, v[0]) + gtest.Assert(res[k].Null, v[1]) + } + }) + + gtest.C(t, func(t *gtest.T) { + _, err := db.TableFields(ctx, "t_user t_user2") + gtest.AssertNE(err, nil) + }) +} + +func TestFilteredLink(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + s := dblink.FilteredLink() + gtest.AssertEQ(s, "oracle:xxx@127.0.0.1:1521/XE") + }) + +} +func TestDoInsert(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + createTable("t_user") + defer dropTable("t_user") + + i := 10 + data := g.Map{ + "ID": i, + "PASSPORT": fmt.Sprintf(`t%d`, i), + "PASSWORD": fmt.Sprintf(`p%d`, i), + "NICKNAME": fmt.Sprintf(`T%d`, i), + "CREATE_TIME": gtime.Now().String(), + } + _, err := db.Insert(ctx, "t_user", data) + gtest.Assert(err, nil) + + }) + + gtest.C(t, func(t *gtest.T) { + createTable("t_user") + defer dropTable("t_user") + + i := 10 + data := g.Map{ + "ID": i, + "PASSPORT": fmt.Sprintf(`t%d`, i), + "PASSWORD": fmt.Sprintf(`p%d`, i), + "NICKNAME": fmt.Sprintf(`T%d`, i), + "CREATE_TIME": gtime.Now().String(), + } + _, err := db.Save(ctx, "t_user", data, 10) + gtest.AssertNE(err, nil) + + _, err = db.Replace(ctx, "t_user", data, 10) + gtest.AssertNE(err, nil) + }) +} + +func Test_DB_Ping(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + err1 := db.PingMaster() + err2 := db.PingSlave() + t.Assert(err1, nil) + t.Assert(err2, nil) + }) +} + +func Test_DB_Query(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + _, err := db.Query(ctx, "SELECT ? from dual", 1) + t.AssertNil(err) + + _, err = db.Query(ctx, "SELECT ?+? from dual", 1, 2) + t.AssertNil(err) + + _, err = db.Query(ctx, "SELECT ?+? from dual", g.Slice{1, 2}) + t.AssertNil(err) + + _, err = db.Query(ctx, "ERROR") + t.AssertNE(err, nil) + }) +} + +func Test_DB_Exec(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + _, err := db.Exec(ctx, "SELECT ? from dual", 1) + t.AssertNil(err) + + _, err = db.Exec(ctx, "ERROR") + t.AssertNE(err, nil) + }) +} + +func Test_DB_Insert(t *testing.T) { + table := createTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + _, err := db.Insert(ctx, table, g.Map{ + "ID": 1, + "PASSPORT": "t1", + "PASSWORD": "25d55ad283aa400af464c76d713c07ad", + "NICKNAME": "T1", + "CREATE_TIME": gtime.Now().String(), + }) + t.AssertNil(err) + + // normal map + result, err := db.Insert(ctx, table, g.Map{ + "ID": "2", + "PASSPORT": "t2", + "PASSWORD": "25d55ad283aa400af464c76d713c07ad", + "NICKNAME": "name_2", + "CREATE_TIME": gtime.Now().String(), + }) + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + + // struct + type User struct { + Id int `gconv:"ID"` + Passport string `json:"PASSPORT"` + Password string `gconv:"PASSWORD"` + Nickname string `gconv:"NICKNAME"` + CreateTime string `json:"CREATE_TIME"` + } + timeStr := gtime.Now().String() + result, err = db.Insert(ctx, table, User{ + Id: 3, + Passport: "user_3", + Password: "25d55ad283aa400af464c76d713c07ad", + Nickname: "name_3", + CreateTime: timeStr, + }) + t.AssertNil(err) + n, _ = result.RowsAffected() + t.Assert(n, 1) + + one, err := db.Model(table).Where("ID", 3).One() + t.AssertNil(err) + fmt.Println(one) + t.Assert(one["ID"].Int(), 3) + t.Assert(one["PASSPORT"].String(), "user_3") + t.Assert(one["PASSWORD"].String(), "25d55ad283aa400af464c76d713c07ad") + t.Assert(one["NICKNAME"].String(), "name_3") + t.Assert(one["CREATE_TIME"].GTime().String(), timeStr) + + // *struct + timeStr = gtime.Now().String() + result, err = db.Insert(ctx, table, &User{ + Id: 4, + Passport: "t4", + Password: "25d55ad283aa400af464c76d713c07ad", + Nickname: "name_4", + CreateTime: timeStr, + }) + t.AssertNil(err) + n, _ = result.RowsAffected() + t.Assert(n, 1) + + one, err = db.Model(table).Where("ID", 4).One() + t.AssertNil(err) + t.Assert(one["ID"].Int(), 4) + t.Assert(one["PASSPORT"].String(), "t4") + t.Assert(one["PASSWORD"].String(), "25d55ad283aa400af464c76d713c07ad") + t.Assert(one["NICKNAME"].String(), "name_4") + t.Assert(one["CREATE_TIME"].GTime().String(), timeStr) + + // batch with Insert + timeStr = gtime.Now().String() + r, err := db.Insert(ctx, table, g.Slice{ + g.Map{ + "ID": 200, + "PASSPORT": "t200", + "PASSWORD": "25d55ad283aa400af464c76d71qw07ad", + "NICKNAME": "T200", + "CREATE_TIME": timeStr, + }, + g.Map{ + "ID": 300, + "PASSPORT": "t300", + "PASSWORD": "25d55ad283aa400af464c76d713c07ad", + "NICKNAME": "T300", + "CREATE_TIME": timeStr, + }, + }) + t.AssertNil(err) + n, _ = r.RowsAffected() + t.Assert(n, 2) + + one, err = db.Model(table).Where("ID", 200).One() + t.AssertNil(err) + t.Assert(one["ID"].Int(), 200) + t.Assert(one["PASSPORT"].String(), "t200") + t.Assert(one["PASSWORD"].String(), "25d55ad283aa400af464c76d71qw07ad") + t.Assert(one["NICKNAME"].String(), "T200") + t.Assert(one["CREATE_TIME"].GTime().String(), timeStr) + }) +} + +func Test_DB_BatchInsert(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + table := createTable() + defer dropTable(table) + r, err := db.Insert(ctx, table, g.List{ + { + "ID": 2, + "PASSPORT": "t2", + "PASSWORD": "25d55ad283aa400af464c76d713c07ad", + "NICKNAME": "name_2", + "CREATE_TIME": gtime.Now().String(), + }, + { + "ID": 3, + "PASSPORT": "user_3", + "PASSWORD": "25d55ad283aa400af464c76d713c07ad", + "NICKNAME": "name_3", + "CREATE_TIME": gtime.Now().String(), + }, + }, 1) + t.AssertNil(err) + n, _ := r.RowsAffected() + t.Assert(n, 2) + + }) + + gtest.C(t, func(t *gtest.T) { + table := createTable() + defer dropTable(table) + // []interface{} + r, err := db.Insert(ctx, table, g.Slice{ + g.Map{ + "ID": 2, + "PASSPORT": "t2", + "PASSWORD": "25d55ad283aa400af464c76d713c07ad", + "NICKNAME": "name_2", + "CREATE_TIME": gtime.Now().String(), + }, + g.Map{ + "ID": 3, + "PASSPORT": "user_3", + "PASSWORD": "25d55ad283aa400af464c76d713c07ad", + "NICKNAME": "name_3", + "CREATE_TIME": gtime.Now().String(), + }, + }, 1) + t.AssertNil(err) + n, _ := r.RowsAffected() + t.Assert(n, 2) + }) + + // batch insert map + gtest.C(t, func(t *gtest.T) { + table := createTable() + defer dropTable(table) + result, err := db.Insert(ctx, table, g.Map{ + "ID": 1, + "PASSPORT": "t1", + "PASSWORD": "p1", + "NICKNAME": "T1", + "CREATE_TIME": gtime.Now().String(), + }) + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + }) +} + +func Test_DB_BatchInsert_Struct(t *testing.T) { + // batch insert struct + gtest.C(t, func(t *gtest.T) { + table := createTable() + defer dropTable(table) + + type User struct { + Id int `c:"ID"` + Passport string `c:"PASSPORT"` + Password string `c:"PASSWORD"` + NickName string `c:"NICKNAME"` + CreateTime *gtime.Time `c:"CREATE_TIME"` + } + user := &User{ + Id: 1, + Passport: "t1", + Password: "p1", + NickName: "T1", + CreateTime: gtime.Now(), + } + result, err := db.Insert(ctx, table, user) + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + }) +} + +func Test_DB_Update(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + result, err := db.Update(ctx, table, "password='987654321'", "id=3") + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + + one, err := db.Model(table).Where("ID", 3).One() + t.AssertNil(err) + t.Assert(one["ID"].Int(), 3) + t.Assert(one["PASSPORT"].String(), "user_3") + t.Assert(strings.TrimSpace(one["PASSWORD"].String()), "987654321") + t.Assert(one["NICKNAME"].String(), "name_3") + }) +} + +func Test_DB_GetAll(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + result, err := db.GetAll(ctx, fmt.Sprintf("SELECT * FROM %s WHERE id=?", table), 1) + t.AssertNil(err) + t.Assert(len(result), 1) + t.Assert(result[0]["ID"].Int(), 1) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.GetAll(ctx, fmt.Sprintf("SELECT * FROM %s WHERE id=?", table), g.Slice{1}) + t.AssertNil(err) + t.Assert(len(result), 1) + t.Assert(result[0]["ID"].Int(), 1) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.GetAll(ctx, fmt.Sprintf("SELECT * FROM %s WHERE id in(?)", table), g.Slice{1, 2, 3}) + t.AssertNil(err) + t.Assert(len(result), 3) + t.Assert(result[0]["ID"].Int(), 1) + t.Assert(result[1]["ID"].Int(), 2) + t.Assert(result[2]["ID"].Int(), 3) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.GetAll(ctx, fmt.Sprintf("SELECT * FROM %s WHERE id in(?,?,?)", table), g.Slice{1, 2, 3}) + t.AssertNil(err) + t.Assert(len(result), 3) + t.Assert(result[0]["ID"].Int(), 1) + t.Assert(result[1]["ID"].Int(), 2) + t.Assert(result[2]["ID"].Int(), 3) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.GetAll(ctx, fmt.Sprintf("SELECT * FROM %s WHERE id in(?,?,?)", table), g.Slice{1, 2, 3}...) + t.AssertNil(err) + t.Assert(len(result), 3) + t.Assert(result[0]["ID"].Int(), 1) + t.Assert(result[1]["ID"].Int(), 2) + t.Assert(result[2]["ID"].Int(), 3) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.GetAll(ctx, fmt.Sprintf("SELECT * FROM %s WHERE id>=? AND id <=?", table), g.Slice{1, 3}) + t.AssertNil(err) + t.Assert(len(result), 3) + t.Assert(result[0]["ID"].Int(), 1) + t.Assert(result[1]["ID"].Int(), 2) + t.Assert(result[2]["ID"].Int(), 3) + }) +} + +func Test_DB_GetOne(t *testing.T) { + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + record, err := db.GetOne(ctx, fmt.Sprintf("SELECT * FROM %s WHERE passport=?", table), "user_1") + t.AssertNil(err) + t.Assert(record["NICKNAME"].String(), "name_1") + }) +} + +func Test_DB_GetValue(t *testing.T) { + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + value, err := db.GetValue(ctx, fmt.Sprintf("SELECT id FROM %s WHERE passport=?", table), "user_3") + t.AssertNil(err) + t.Assert(value.Int(), 3) + }) +} + +func Test_DB_GetCount(t *testing.T) { + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + count, err := db.GetCount(ctx, fmt.Sprintf("SELECT * FROM %s", table)) + t.AssertNil(err) + t.Assert(count, TableSize) + }) +} + +func Test_DB_GetStruct(t *testing.T) { + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime gtime.Time + } + user := new(User) + err := db.GetScan(ctx, user, fmt.Sprintf("SELECT * FROM %s WHERE id=?", table), 3) + t.AssertNil(err) + t.Assert(user.NickName, "name_3") + }) + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime *gtime.Time + } + user := new(User) + err := db.GetScan(ctx, user, fmt.Sprintf("SELECT * FROM %s WHERE id=?", table), 3) + t.AssertNil(err) + t.Assert(user.NickName, "name_3") + }) +} + +func Test_DB_GetStructs(t *testing.T) { + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime gtime.Time + } + var users []User + err := db.GetScan(ctx, &users, fmt.Sprintf("SELECT * FROM %s WHERE id>?", table), 1) + t.AssertNil(err) + t.Assert(len(users), TableSize-1) + t.Assert(users[0].Id, 2) + t.Assert(users[1].Id, 3) + t.Assert(users[2].Id, 4) + t.Assert(users[0].NickName, "name_2") + t.Assert(users[1].NickName, "name_3") + t.Assert(users[2].NickName, "name_4") + }) + + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime *gtime.Time + } + var users []User + err := db.GetScan(ctx, &users, fmt.Sprintf("SELECT * FROM %s WHERE id>?", table), 1) + t.AssertNil(err) + t.Assert(len(users), TableSize-1) + t.Assert(users[0].Id, 2) + t.Assert(users[1].Id, 3) + t.Assert(users[2].Id, 4) + t.Assert(users[0].NickName, "name_2") + t.Assert(users[1].NickName, "name_3") + t.Assert(users[2].NickName, "name_4") + }) +} + +func Test_DB_GetScan(t *testing.T) { + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime gtime.Time + } + user := new(User) + err := db.GetScan(ctx, user, fmt.Sprintf("SELECT * FROM %s WHERE id=?", table), 3) + t.AssertNil(err) + t.Assert(user.NickName, "name_3") + }) + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime gtime.Time + } + var user *User + err := db.GetScan(ctx, &user, fmt.Sprintf("SELECT * FROM %s WHERE id=?", table), 3) + t.AssertNil(err) + t.Assert(user.NickName, "name_3") + }) + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime *gtime.Time + } + user := new(User) + err := db.GetScan(ctx, user, fmt.Sprintf("SELECT * FROM %s WHERE id=?", table), 3) + t.AssertNil(err) + t.Assert(user.NickName, "name_3") + }) + + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime gtime.Time + } + var users []User + err := db.GetScan(ctx, &users, fmt.Sprintf("SELECT * FROM %s WHERE id>?", table), 1) + t.AssertNil(err) + t.Assert(len(users), TableSize-1) + t.Assert(users[0].Id, 2) + t.Assert(users[1].Id, 3) + t.Assert(users[2].Id, 4) + t.Assert(users[0].NickName, "name_2") + t.Assert(users[1].NickName, "name_3") + t.Assert(users[2].NickName, "name_4") + }) + + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime *gtime.Time + } + var users []User + err := db.GetScan(ctx, &users, fmt.Sprintf("SELECT * FROM %s WHERE id>?", table), 1) + t.AssertNil(err) + t.Assert(len(users), TableSize-1) + t.Assert(users[0].Id, 2) + t.Assert(users[1].Id, 3) + t.Assert(users[2].Id, 4) + t.Assert(users[0].NickName, "name_2") + t.Assert(users[1].NickName, "name_3") + t.Assert(users[2].NickName, "name_4") + }) +} + +func Test_DB_Delete(t *testing.T) { + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + result, err := db.Delete(ctx, table, "1=1") + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, TableSize) + }) +} + +func Test_Empty_Slice_Argument(t *testing.T) { + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + result, err := db.GetAll(ctx, fmt.Sprintf(`select * from %s where id in(?)`, table), g.Slice{}) + t.AssertNil(err) + t.Assert(len(result), 0) + }) +} diff --git a/contrib/drivers/oracle/oracle_z_model_test.go b/contrib/drivers/oracle/oracle_z_model_test.go new file mode 100644 index 000000000..2f2d731ec --- /dev/null +++ b/contrib/drivers/oracle/oracle_z_model_test.go @@ -0,0 +1,1113 @@ +// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package oracle_test + +import ( + "database/sql" + "fmt" + "github.com/gogf/gf/v2/container/gmap" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/test/gtest" + "github.com/gogf/gf/v2/util/guid" + "github.com/gogf/gf/v2/util/gutil" + "strings" + "testing" + "time" +) + +func Test_Model_InnerJoin(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + table1 := createInitTable("user1") + table2 := createInitTable("user2") + + defer dropTable(table1) + defer dropTable(table2) + + res, err := db.Model(table1).Where("id > ?", 5).Delete() + if err != nil { + t.Fatal(err) + } + + n, err := res.RowsAffected() + if err != nil { + t.Fatal(err) + } + + t.Assert(n, 5) + + result, err := db.Model(table1+" u1").InnerJoin(table2+" u2", "u1.id = u2.id").Order("u1.id").All() + if err != nil { + t.Fatal(err) + } + + t.Assert(len(result), 5) + + result, err = db.Model(table1+" u1").InnerJoin(table2+" u2", "u1.id = u2.id").Where("u1.id > ?", 1).Order("u1.id").All() + if err != nil { + t.Fatal(err) + } + + t.Assert(len(result), 4) + }) +} + +func Test_Model_LeftJoin(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + table1 := createInitTable("user1") + table2 := createInitTable("user2") + + defer dropTable(table1) + defer dropTable(table2) + + res, err := db.Model(table2).Where("id > ?", 3).Delete() + if err != nil { + t.Fatal(err) + } + + n, err := res.RowsAffected() + if err != nil { + t.Fatal(err) + } else { + t.Assert(n, 7) + } + + result, err := db.Model(table1+" u1").LeftJoin(table2+" u2", "u1.id = u2.id").All() + if err != nil { + t.Fatal(err) + } + + t.Assert(len(result), 10) + + result, err = db.Model(table1+" u1").LeftJoin(table2+" u2", "u1.id = u2.id").Where("u1.id > ? ", 2).All() + if err != nil { + t.Fatal(err) + } + + t.Assert(len(result), 8) + }) +} + +func Test_Model_RightJoin(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + table1 := createInitTable("user1") + table2 := createInitTable("user2") + + defer dropTable(table1) + defer dropTable(table2) + + res, err := db.Model(table1).Where("id > ?", 3).Delete() + if err != nil { + t.Fatal(err) + } + + n, err := res.RowsAffected() + if err != nil { + t.Fatal(err) + } + + t.Assert(n, 7) + + result, err := db.Model(table1+" u1").RightJoin(table2+" u2", "u1.id = u2.id").All() + if err != nil { + t.Fatal(err) + } + t.Assert(len(result), 10) + + result, err = db.Model(table1+" u1").RightJoin(table2+" u2", "u1.id = u2.id").Where("u1.id > 2").All() + if err != nil { + t.Fatal(err) + } + t.Assert(len(result), 1) + }) +} + +func TestPage(t *testing.T) { + table := createInitTable() + defer dropTable(table) + db.SetDebug(true) + result, err := db.Model(table).Page(1, 2).Order("ID").All() + gtest.Assert(err, nil) + fmt.Println("page:1--------", result) + gtest.Assert(len(result), 2) + gtest.Assert(result[0]["ID"], 1) + gtest.Assert(result[1]["ID"], 2) + + result, err = db.Model(table).Page(2, 2).Order("ID").All() + gtest.Assert(err, nil) + fmt.Println("page: 2--------", result) + gtest.Assert(len(result), 2) + gtest.Assert(result[0]["ID"], 3) + gtest.Assert(result[1]["ID"], 4) + + result, err = db.Model(table).Page(3, 2).Order("ID").All() + gtest.Assert(err, nil) + fmt.Println("page:3 --------", result) + gtest.Assert(len(result), 2) + gtest.Assert(result[0]["ID"], 5) + + result, err = db.Model(table).Page(2, 3).All() + gtest.Assert(err, nil) + gtest.Assert(len(result), 3) + gtest.Assert(result[0]["ID"], 4) + gtest.Assert(result[1]["ID"], 5) + gtest.Assert(result[2]["ID"], 6) +} + +func Test_Model_Insert(t *testing.T) { + table := createTable() + defer dropTable(table) + //db.SetDebug(true) + gtest.C(t, func(t *gtest.T) { + user := db.Model(table) + result, err := user.Data(g.Map{ + "ID": 1, + "UID": 1, + "PASSPORT": "t1", + "PASSWORD": "25d55ad283aa400af464c76d713c07ad", + "NICKNAME": "name_1", + "CREATE_TIME": gtime.Now().String(), + }).Insert() + t.AssertNil(err) + + result, err = db.Model(table).Data(g.Map{ + "ID": "2", + "UID": "2", + "PASSPORT": "t2", + "PASSWORD": "25d55ad283aa400af464c76d713c07ad", + "NICKNAME": "name_2", + "CREATE_TIME": gtime.Now().String(), + }).Insert() + t.AssertNil(err) + + type User struct { + Id int `gconv:"ID"` + Uid int `gconv:"uid"` + Passport string `json:"PASSPORT"` + Password string `gconv:"PASSWORD"` + Nickname string `gconv:"NICKNAME"` + CreateTime *gtime.Time `json:"CREATE_TIME"` + } + // Model inserting. + result, err = db.Model(table).Data(User{ + Id: 3, + Uid: 3, + Passport: "t3", + Password: "25d55ad283aa400af464c76d713c07ad", + Nickname: "name_3", + CreateTime: gtime.Now(), + }).Insert() + t.AssertNil(err) + + value, err := db.Model(table).Fields("PASSPORT").Where("id=3").Value() + t.AssertNil(err) + t.Assert(value.String(), "t3") + + result, err = db.Model(table).Data(&User{ + Id: 4, + Uid: 4, + Passport: "t4", + Password: "25d55ad283aa400af464c76d713c07ad", + Nickname: "T4", + CreateTime: gtime.Now(), + }).Insert() + t.AssertNil(err) + + value, err = db.Model(table).Fields("PASSPORT").Where("id=4").Value() + t.AssertNil(err) + t.Assert(value.String(), "t4") + + result, err = db.Model(table).Where("id>?", 1).Delete() + t.AssertNil(err) + _, _ = result.RowsAffected() + + }) +} + +func Test_Model_Insert_Time(t *testing.T) { + table := createTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + data := g.Map{ + "ID": 1, + "PASSPORT": "t1", + "PASSWORD": "p1", + "NICKNAME": "n1", + "CREATE_TIME": "2020-10-10 20:09:18", + } + _, err := db.Model(table).Data(data).Insert() + t.AssertNil(err) + + one, err := db.Model(table).One("ID", 1) + t.AssertNil(err) + t.Assert(one["PASSPORT"].String(), data["PASSPORT"]) + t.Assert(one["CREATE_TIME"].String(), "2020-10-10 20:09:18") + t.Assert(one["NICKNAME"].String(), data["NICKNAME"]) + }) +} + +func Test_Model_Batch(t *testing.T) { + // batch insert + gtest.C(t, func(t *gtest.T) { + table := createTable() + defer dropTable(table) + _, err := db.Model(table).Data(g.List{ + { + "ID": 2, + "uid": 2, + "PASSPORT": "t2", + "PASSWORD": "25d55ad283aa400af464c76d713c07ad", + "NICKNAME": "name_2", + "CREATE_TIME": gtime.Now().String(), + }, + { + "ID": 3, + "uid": 3, + "PASSPORT": "t3", + "PASSWORD": "25d55ad283aa400af464c76d713c07ad", + "NICKNAME": "name_3", + "CREATE_TIME": gtime.Now().String(), + }, + }).Batch(1).Insert() + if err != nil { + gtest.Error(err) + } + }) + +} + +func Test_Model_Update(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Data("PASSPORT", "user_22").Where("passport=?", "user_2").Update() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + }) + + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Data("PASSPORT", "user_2").Where("passport='user_22'").Update() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + }) + + // Update + Data(string) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Data("passport='user_33'").Where("passport='user_3'").Update() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + }) + // Update + Fields(string) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Fields("PASSPORT").Data(g.Map{ + "PASSPORT": "user_44", + "none": "none", + }).Where("passport='user_4'").Update() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + }) +} + +func Test_Model_All(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).All() + t.AssertNil(err) + t.Assert(len(result), TableSize) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where("id<0").All() + t.Assert(result, nil) + t.AssertNil(err) + }) +} + +func Test_Model_One(t *testing.T) { + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + record, err := db.Model(table).Where("ID", 1).One() + t.AssertNil(err) + t.Assert(record["NICKNAME"].String(), "name_1") + }) + + gtest.C(t, func(t *gtest.T) { + record, err := db.Model(table).Where("ID", 0).One() + t.AssertNil(err) + t.Assert(record, nil) + }) +} + +func Test_Model_Value(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + value, err := db.Model(table).Fields("NICKNAME").Where("ID", 1).Value() + t.AssertNil(err) + t.Assert(value.String(), "name_1") + }) + + gtest.C(t, func(t *gtest.T) { + value, err := db.Model(table).Fields("NICKNAME").Where("ID", 0).Value() + t.AssertNil(err) + t.Assert(value, nil) + }) +} + +func Test_Model_Array(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).Where("ID", g.Slice{1, 2, 3}).All() + t.AssertNil(err) + for k, v := range all.Array("ID") { + t.Assert(v.Int(), k+1) + } + t.Assert(all.Array("NICKNAME"), g.Slice{"name_1", "name_2", "name_3"}) + }) + gtest.C(t, func(t *gtest.T) { + array, err := db.Model(table).Fields("NICKNAME").Where("ID", g.Slice{1, 2, 3}).Array() + t.AssertNil(err) + t.Assert(array, g.Slice{"name_1", "name_2", "name_3"}) + }) + gtest.C(t, func(t *gtest.T) { + array, err := db.Model(table).Array("NICKNAME", "ID", g.Slice{1, 2, 3}) + t.AssertNil(err) + t.Assert(array, g.Slice{"name_1", "name_2", "name_3"}) + }) +} + +func Test_Model_Count(t *testing.T) { + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Count() + t.AssertNil(err) + t.Assert(count, TableSize) + }) + // Count with cache, check internal ctx data feature. + gtest.C(t, func(t *gtest.T) { + for i := 0; i < 10; i++ { + count, err := db.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second * 10, + Name: guid.S(), + Force: false, + }).Count() + t.AssertNil(err) + t.Assert(count, TableSize) + } + }) + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).FieldsEx("ID").Where("id>8").Count() + t.AssertNil(err) + t.Assert(count, 2) + }) + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Fields("distinct id").Where("id>8").Count() + t.AssertNil(err) + t.Assert(count, 2) + }) + // COUNT...LIMIT... + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Page(1, 2).Count() + t.AssertNil(err) + t.Assert(count, TableSize) + }) + +} + +func Test_Model_Select(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime gtime.Time + } + gtest.C(t, func(t *gtest.T) { + var users []User + err := db.Model(table).Scan(&users) + t.AssertNil(err) + t.Assert(len(users), TableSize) + }) +} + +func Test_Model_Struct(t *testing.T) { + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime gtime.Time + } + user := new(User) + err := db.Model(table).Where("id=1").Scan(user) + t.AssertNil(err) + t.Assert(user.NickName, "name_1") + }) + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime *gtime.Time + } + user := new(User) + err := db.Model(table).Where("id=1").Scan(user) + t.AssertNil(err) + t.Assert(user.NickName, "name_1") + }) + // Auto creating struct object. + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime *gtime.Time + } + user := (*User)(nil) + err := db.Model(table).Where("id=1").Scan(&user) + t.AssertNil(err) + t.Assert(user.NickName, "name_1") + }) + // Just using Scan. + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime *gtime.Time + } + user := (*User)(nil) + err := db.Model(table).Where("id=1").Scan(&user) + if err != nil { + gtest.Error(err) + } + t.Assert(user.NickName, "name_1") + }) + // sql.ErrNoRows + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime *gtime.Time + } + user := new(User) + err := db.Model(table).Where("id=-1").Scan(user) + t.Assert(err, sql.ErrNoRows) + }) + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime *gtime.Time + } + var user *User + err := db.Model(table).Where("id=-1").Scan(&user) + t.AssertNil(err) + }) +} + +func Test_Model_Scan(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime gtime.Time + } + user := new(User) + err := db.Model(table).Where("id=1").Scan(user) + t.AssertNil(err) + t.Assert(user.NickName, "name_1") + }) + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime *gtime.Time + } + user := new(User) + err := db.Model(table).Where("id=1").Scan(user) + t.AssertNil(err) + t.Assert(user.NickName, "name_1") + }) + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime gtime.Time + } + var users []User + err := db.Model(table).Order("id asc").Scan(&users) + t.AssertNil(err) + t.Assert(len(users), TableSize) + t.Assert(users[0].Id, 1) + t.Assert(users[1].Id, 2) + t.Assert(users[2].Id, 3) + t.Assert(users[0].NickName, "name_1") + t.Assert(users[1].NickName, "name_2") + t.Assert(users[2].NickName, "name_3") + }) + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime *gtime.Time + } + var users []*User + err := db.Model(table).Order("id asc").Scan(&users) + t.AssertNil(err) + t.Assert(len(users), TableSize) + t.Assert(users[0].Id, 1) + t.Assert(users[1].Id, 2) + t.Assert(users[2].Id, 3) + t.Assert(users[0].NickName, "name_1") + t.Assert(users[1].NickName, "name_2") + t.Assert(users[2].NickName, "name_3") + }) + // sql.ErrNoRows + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime *gtime.Time + } + var ( + user = new(User) + users = new([]*User) + ) + err1 := db.Model(table).Where("id < 0").Scan(user) + err2 := db.Model(table).Where("id < 0").Scan(users) + t.Assert(err1, sql.ErrNoRows) + t.Assert(err2, nil) + }) +} + +func Test_Model_Where(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + // string + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where("id=? and nickname=?", 3, "name_3").One() + t.AssertNil(err) + t.AssertGT(len(result), 0) + t.Assert(result["ID"].Int(), 3) + }) + + // slice + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where(g.Slice{"ID", 3}).One() + t.AssertNil(err) + t.AssertGT(len(result), 0) + t.Assert(result["ID"].Int(), 3) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where(g.Slice{"ID", 3, "NICKNAME", "name_3"}).One() + t.AssertNil(err) + t.AssertGT(len(result), 0) + t.Assert(result["ID"].Int(), 3) + }) + + // slice parameter + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where("id=? and nickname=?", g.Slice{3, "name_3"}).One() + t.AssertNil(err) + t.AssertGT(len(result), 0) + t.Assert(result["ID"].Int(), 3) + }) + // map like + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where(g.Map{ + "passport like": "user_1%", + }).Order("id asc").All() + t.AssertNil(err) + t.Assert(len(result), 2) + t.Assert(result[0].GMap().Get("ID"), 1) + t.Assert(result[1].GMap().Get("ID"), 10) + }) + // map + slice parameter + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where(g.Map{ + "ID": g.Slice{1, 2, 3}, + "PASSPORT": g.Slice{"user_2", "user_3"}, + }).Where("id=? and nickname=?", g.Slice{3, "name_3"}).One() + t.AssertNil(err) + t.AssertGT(len(result), 0) + t.Assert(result["ID"].Int(), 3) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where("id=3", g.Slice{}).One() + t.AssertNil(err) + t.AssertGT(len(result), 0) + t.Assert(result["ID"].Int(), 3) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where("id=?", g.Slice{3}).One() + t.AssertNil(err) + t.AssertGT(len(result), 0) + t.Assert(result["ID"].Int(), 3) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where("ID", 3).One() + t.AssertNil(err) + t.AssertGT(len(result), 0) + t.Assert(result["ID"].Int(), 3) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where("ID", 3).Where("NICKNAME", "name_3").One() + t.AssertNil(err) + t.Assert(result["ID"].Int(), 3) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where("ID", 3).Where("NICKNAME", "name_3").One() + t.AssertNil(err) + t.Assert(result["ID"].Int(), 3) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where("ID", 30).WhereOr("NICKNAME", "name_3").One() + t.AssertNil(err) + t.Assert(result["ID"].Int(), 3) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where("ID", 30).WhereOr("NICKNAME", "name_3").Where("id>?", 1).One() + t.AssertNil(err) + t.Assert(result["ID"].Int(), 3) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where("ID", 30).WhereOr("NICKNAME", "name_3").Where("id>", 1).One() + t.AssertNil(err) + t.Assert(result["ID"].Int(), 3) + }) + // slice + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where("id=? AND nickname=?", g.Slice{3, "name_3"}...).One() + t.AssertNil(err) + t.Assert(result["ID"].Int(), 3) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where("id=? AND nickname=?", g.Slice{3, "name_3"}).One() + t.AssertNil(err) + t.Assert(result["ID"].Int(), 3) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where("passport like ? and nickname like ?", g.Slice{"user_3", "name_3"}).One() + t.AssertNil(err) + t.Assert(result["ID"].Int(), 3) + }) + // map + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where(g.Map{"ID": 3, "NICKNAME": "name_3"}).One() + t.AssertNil(err) + t.Assert(result["ID"].Int(), 3) + }) + // map key operator + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where(g.Map{"id>": 1, "id<": 3}).One() + t.AssertNil(err) + t.Assert(result["ID"].Int(), 2) + }) + + // gmap.Map + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where(gmap.NewFrom(g.MapAnyAny{"ID": 3, "NICKNAME": "name_3"})).One() + t.AssertNil(err) + t.Assert(result["ID"].Int(), 3) + }) + // gmap.Map key operator + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where(gmap.NewFrom(g.MapAnyAny{"id>": 1, "id<": 3})).One() + t.AssertNil(err) + t.Assert(result["ID"].Int(), 2) + }) + + // list map + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where(gmap.NewListMapFrom(g.MapAnyAny{"ID": 3, "NICKNAME": "name_3"})).One() + t.AssertNil(err) + t.Assert(result["ID"].Int(), 3) + }) + // list map key operator + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where(gmap.NewListMapFrom(g.MapAnyAny{"id>": 1, "id<": 3})).One() + t.AssertNil(err) + t.Assert(result["ID"].Int(), 2) + }) + + // tree map + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where(gmap.NewTreeMapFrom(gutil.ComparatorString, g.MapAnyAny{"ID": 3, "NICKNAME": "name_3"})).One() + t.AssertNil(err) + t.Assert(result["ID"].Int(), 3) + }) + // tree map key operator + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where(gmap.NewTreeMapFrom(gutil.ComparatorString, g.MapAnyAny{"id>": 1, "id<": 3})).One() + t.AssertNil(err) + t.Assert(result["ID"].Int(), 2) + }) + + // complicated where 1 + gtest.C(t, func(t *gtest.T) { + // db.SetDebug(true) + conditions := g.Map{ + "nickname like ?": "%name%", + "id between ? and ?": g.Slice{1, 3}, + "id > 0": nil, + "ID": g.Slice{1, 2, 3}, + } + result, err := db.Model(table).Where(conditions).Order("id asc").All() + t.AssertNil(err) + t.Assert(len(result), 3) + t.Assert(result[0]["ID"].Int(), 1) + }) + // complicated where 2 + gtest.C(t, func(t *gtest.T) { + // db.SetDebug(true) + conditions := g.Map{ + "nickname like ?": "%name%", + "id between ? and ?": g.Slice{1, 3}, + "id >= ?": 1, + "id in(?)": g.Slice{1, 2, 3}, + } + result, err := db.Model(table).Where(conditions).Order("id asc").All() + t.AssertNil(err) + t.Assert(len(result), 3) + t.Assert(result[0]["ID"].Int(), 1) + }) + // struct, automatic mapping and filtering. + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Nickname string + } + result, err := db.Model(table).Where(User{3, "name_3"}).One() + t.AssertNil(err) + t.Assert(result["ID"].Int(), 3) + + result, err = db.Model(table).Where(&User{3, "name_3"}).One() + t.AssertNil(err) + t.Assert(result["ID"].Int(), 3) + }) + // slice single + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where("id IN(?)", g.Slice{1, 3}).Order("id ASC").All() + t.AssertNil(err) + t.Assert(len(result), 2) + t.Assert(result[0]["ID"].Int(), 1) + t.Assert(result[1]["ID"].Int(), 3) + }) + // slice + string + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where("nickname=? AND id IN(?)", "name_3", g.Slice{1, 3}).Order("id ASC").All() + t.AssertNil(err) + t.Assert(len(result), 1) + t.Assert(result[0]["ID"].Int(), 3) + }) + // slice + map + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where(g.Map{ + "ID": g.Slice{1, 3}, + "NICKNAME": "name_3", + }).Order("id ASC").All() + t.AssertNil(err) + t.Assert(len(result), 1) + t.Assert(result[0]["ID"].Int(), 3) + }) + // slice + struct + gtest.C(t, func(t *gtest.T) { + type User struct { + Ids []int `json:"ID"` + Nickname string `gconv:"NICKNAME"` + } + result, err := db.Model(table).Where(User{ + Ids: []int{1, 3}, + Nickname: "name_3", + }).Order("id ASC").All() + t.AssertNil(err) + t.Assert(len(result), 1) + t.Assert(result[0]["ID"].Int(), 3) + }) +} + +func Test_Model_Delete(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where("1=1").Delete() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, TableSize) + }) +} + +func Test_Model_Having(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).Fields("id, count(*)").Where("id > 1").Group("ID").Having("id > 8").All() + t.AssertNil(err) + t.Assert(len(all), 2) + }) + +} + +func Test_Model_Distinct(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Where("id > 1").Distinct().Count() + t.AssertNil(err) + t.Assert(count, 9) + }) +} + +//not support +/* +func Test_Model_Min_Max(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + value, err := db.Model(table, "t").Fields("min(t.id)").Where("id > 1").Value() + t.AssertNil(err) + t.Assert(value.Int(), 2) + }) + gtest.C(t, func(t *gtest.T) { + value, err := db.Model(table, "t").Fields("max(t.id)").Where("id > 1").Value() + t.AssertNil(err) + t.Assert(value.Int(), 10) + }) +} +*/ +func Test_Model_HasTable(t *testing.T) { + table := createTable() + defer dropTable(table) + //db.SetDebug(true) + gtest.C(t, func(t *gtest.T) { + result, err := db.GetCore().HasTable(strings.ToUpper(table)) + t.Assert(result, true) + t.AssertNil(err) + }) + + gtest.C(t, func(t *gtest.T) { + result, err := db.GetCore().HasTable("table12321") + t.Assert(result, false) + t.AssertNil(err) + }) +} + +func Test_Model_HasField(t *testing.T) { + table := createTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).HasField("ID") + t.Assert(result, true) + t.AssertNil(err) + }) + + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).HasField("id123") + t.Assert(result, false) + t.AssertNil(err) + }) +} + +func Test_Model_WhereIn(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).WhereIn("ID", g.Slice{1, 2, 3, 4}).WhereIn("ID", g.Slice{3, 4, 5}).OrderAsc("ID").All() + t.AssertNil(err) + t.Assert(len(result), 2) + t.Assert(result[0]["ID"], 3) + t.Assert(result[1]["ID"], 4) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).WhereIn("ID", g.Slice{}).OrderAsc("ID").All() + t.AssertNil(err) + t.Assert(len(result), 0) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).OmitEmptyWhere().WhereIn("ID", g.Slice{}).OrderAsc("ID").All() + t.AssertNil(err) + t.Assert(len(result), TableSize) + }) +} + +func Test_Model_WhereNotIn(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).WhereNotIn("ID", g.Slice{1, 2, 3, 4}).WhereNotIn("ID", g.Slice{3, 4, 5}).OrderAsc("ID").All() + t.AssertNil(err) + t.Assert(len(result), 5) + t.Assert(result[0]["ID"], 6) + t.Assert(result[1]["ID"], 7) + }) +} + +func Test_Model_WhereOrIn(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).WhereOrIn("ID", g.Slice{1, 2, 3, 4}).WhereOrIn("ID", g.Slice{3, 4, 5}).OrderAsc("ID").All() + t.AssertNil(err) + t.Assert(len(result), 5) + t.Assert(result[0]["ID"], 1) + t.Assert(result[4]["ID"], 5) + }) +} + +func Test_Model_WhereLike(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).WhereLike("NICKNAME", "name%").OrderAsc("ID").All() + t.AssertNil(err) + t.Assert(len(result), TableSize) + t.Assert(result[0]["ID"], 1) + t.Assert(result[TableSize-1]["ID"], TableSize) + }) +} + +func Test_Model_WhereNotLike(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).WhereNotLike("NICKNAME", "name%").OrderAsc("ID").All() + t.AssertNil(err) + t.Assert(len(result), 0) + }) +} + +func Test_Model_WhereOrLike(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).WhereOrLike("NICKNAME", "namexxx%").WhereOrLike("NICKNAME", "name%").OrderAsc("ID").All() + t.AssertNil(err) + t.Assert(len(result), TableSize) + t.Assert(result[0]["ID"], 1) + t.Assert(result[TableSize-1]["ID"], TableSize) + }) +} + +func Test_Model_WhereOrNotLike(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).WhereOrNotLike("NICKNAME", "namexxx%").WhereOrNotLike("NICKNAME", "name%").OrderAsc("ID").All() + t.AssertNil(err) + t.Assert(len(result), TableSize) + t.Assert(result[0]["ID"], 1) + t.Assert(result[TableSize-1]["ID"], TableSize) + }) +} + +/* not support the "AS" +func Test_Model_Raw(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + all, err := db. + Raw(fmt.Sprintf("select * from %s where id in (?)", table), g.Slice{1, 5, 7, 8, 9, 10}). + WhereLT("ID", 8). + WhereIn("ID", g.Slice{1, 2, 3, 4, 5, 6, 7}). + OrderDesc("ID"). + All() + t.AssertNil(err) + t.Assert(len(all), 3) + t.Assert(all[0]["ID"], 7) + t.Assert(all[1]["ID"], 5) + }) + + gtest.C(t, func(t *gtest.T) { + count, err := db. + Raw(fmt.Sprintf("select * from %s where id in (?)", table), g.Slice{1, 5, 7, 8, 9, 10}). + WhereLT("ID", 8). + WhereIn("ID", g.Slice{1, 2, 3, 4, 5, 6, 7}). + OrderDesc("ID"). + Count() + t.AssertNil(err) + t.Assert(count, 6) + }) +} + +func Test_Model_FieldCount(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).Fields("ID").FieldCount("ID", "total").Group("ID").OrderAsc("ID").All() + t.AssertNil(err) + t.Assert(len(all), TableSize) + t.Assert(all[0]["ID"], 1) + t.Assert(all[0]["total"], 1) + }) +} + +func Test_Model_FieldMax(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).Fields("ID").FieldMax("ID", "total").Group("ID").OrderAsc("ID").All() + t.AssertNil(err) + t.Assert(len(all), TableSize) + t.Assert(all[0]["ID"], 1) + t.Assert(all[0]["total"], 1) + }) +}*/