From 2fbe4125dd4715207bb0073b771cc76653f79412 Mon Sep 17 00:00:00 2001 From: Horizon <1820120473@qq.com> Date: Thu, 3 Aug 2023 19:58:16 +0800 Subject: [PATCH] feat: Using sqlite CGO is for building a 32-bit Windows operating system (#2743) --- .github/workflows/build_and_test.sh | 2 +- contrib/drivers/sqlitecgo/go.mod | 33 + contrib/drivers/sqlitecgo/go.sum | 84 + contrib/drivers/sqlitecgo/sqlite.go | 256 + contrib/drivers/sqlitecgo/sqlite_0_test.go | 163 + contrib/drivers/sqlitecgo/sqlite_core_test.go | 1609 ++++++ .../drivers/sqlitecgo/sqlite_model_test.go | 4344 +++++++++++++++++ 7 files changed, 6490 insertions(+), 1 deletion(-) create mode 100644 contrib/drivers/sqlitecgo/go.mod create mode 100644 contrib/drivers/sqlitecgo/go.sum create mode 100644 contrib/drivers/sqlitecgo/sqlite.go create mode 100644 contrib/drivers/sqlitecgo/sqlite_0_test.go create mode 100644 contrib/drivers/sqlitecgo/sqlite_core_test.go create mode 100644 contrib/drivers/sqlitecgo/sqlite_model_test.go diff --git a/.github/workflows/build_and_test.sh b/.github/workflows/build_and_test.sh index 8359862ec..a609df35a 100644 --- a/.github/workflows/build_and_test.sh +++ b/.github/workflows/build_and_test.sh @@ -54,4 +54,4 @@ for file in `find . -name go.mod`; do fi cd - -done \ No newline at end of file +done diff --git a/contrib/drivers/sqlitecgo/go.mod b/contrib/drivers/sqlitecgo/go.mod new file mode 100644 index 000000000..86a432d00 --- /dev/null +++ b/contrib/drivers/sqlitecgo/go.mod @@ -0,0 +1,33 @@ +module github.com/gogf/gf/contrib/drivers/sqlitecgo/v2 + +go 1.18 + +require ( + github.com/gogf/gf/v2 v2.4.4 + github.com/mattn/go-sqlite3 v1.14.17 +) + +require ( + github.com/BurntSushi/toml v1.1.0 // indirect + github.com/clbanning/mxj/v2 v2.5.5 // 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/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.1 // indirect +) + +replace github.com/gogf/gf/v2 => ../../../ diff --git a/contrib/drivers/sqlitecgo/go.sum b/contrib/drivers/sqlitecgo/go.sum new file mode 100644 index 000000000..fc5bee8b0 --- /dev/null +++ b/contrib/drivers/sqlitecgo/go.sum @@ -0,0 +1,84 @@ +github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I= +github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/clbanning/mxj/v2 v2.5.5 h1:oT81vUeEiQQ/DcHbzSytRngP6Ky9O+L+0Bw0zSJag9E= +github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= +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/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grokify/html-strip-tags-go v0.0.1 h1:0fThFwLbW7P/kOiTBs03FsJSV9RM2M/Q/MOnCQxKMo0= +github.com/grokify/html-strip-tags-go v0.0.1/go.mod h1:2Su6romC5/1VXOQMaWL2yb618ARB8iVo6/DR99A6d78= +github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= +github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +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-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/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM= +github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.opentelemetry.io/otel v1.7.0 h1:Z2lA3Tdch0iDcrhJXDIlC94XE+bxok1F9B+4Lz/lGsM= +go.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+nrD5xk= +go.opentelemetry.io/otel/sdk v1.7.0 h1:4OmStpcKVOfvDOgCt7UriAPtKolwIhxpnSNI/yK+1B0= +go.opentelemetry.io/otel/sdk v1.7.0/go.mod h1:uTEOTwaqIVuTGiJN7ii13Ibp75wJmYUDe374q6cZwUU= +go.opentelemetry.io/otel/trace v1.7.0 h1:O37Iogk1lEkMRXewVtZ1BBTVn5JEp8GrJvP92bJqC6o= +go.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48yyE4TNvoHqU= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2 h1:GLw7MR8AfAG2GmGcmVgObFOHXYypgGjnGno25RDwn3Y= +golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.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/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/contrib/drivers/sqlitecgo/sqlite.go b/contrib/drivers/sqlitecgo/sqlite.go new file mode 100644 index 000000000..b5698ebd0 --- /dev/null +++ b/contrib/drivers/sqlitecgo/sqlite.go @@ -0,0 +1,256 @@ +// Copyright GoFrame Author(https://goframe.org). 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 sqlitecgo implements gdb.Driver, which supports operations for database SQLite. +// +// Note: +// 1. Using sqlitecgo is for building a 32-bit Windows operating system +// 2. You need to set the environment variable CGO_ENABLED=1 and make sure that GCC is installed on your path. windows gcc: https://jmeubank.github.io/tdm-gcc/ +package sqlitecgo + +import ( + "context" + "database/sql" + "fmt" + "strings" + + _ "github.com/mattn/go-sqlite3" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/encoding/gurl" + "github.com/gogf/gf/v2/errors/gcode" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/os/gfile" + "github.com/gogf/gf/v2/text/gstr" + "github.com/gogf/gf/v2/util/gconv" + "github.com/gogf/gf/v2/util/gutil" +) + +// Driver is the driver for sqlite database. +type Driver struct { + *gdb.Core +} + +const ( + quoteChar = "`" +) + +func init() { + if err := gdb.Register(`sqlite`, New()); err != nil { + panic(err) + } +} + +// New create and returns a driver that implements gdb.Driver, which supports operations for SQLite. +func New() gdb.Driver { + return &Driver{} +} + +// New creates and returns a database object for sqlite. +// It implements the interface of gdb.Driver for extra database driver installation. +func (d *Driver) New(core *gdb.Core, node *gdb.ConfigNode) (gdb.DB, error) { + return &Driver{ + Core: core, + }, nil +} + +// Open creates and returns an underlying sql.DB object for sqlite. +// https://github.com/mattn/go-sglite3 +func (d *Driver) Open(config *gdb.ConfigNode) (db *sql.DB, err error) { + var ( + source string + underlyingDriverName = "sqlite3" + ) + if config.Link != "" { + // ============================================================================ + // Deprecated from v2.2.0. + // ============================================================================ + source = config.Link + } else { + source = config.Name + } + // It searches the source file to locate its absolute path.. + if absolutePath, _ := gfile.Search(source); absolutePath != "" { + source = absolutePath + } + + // Multiple PRAGMAs can be specified, e.g.: + // path/to/some.db?_pragma=busy_timeout(5000)&_pragma=journal_mode(WAL) + if config.Extra != "" { + var ( + options string + extraMap map[string]interface{} + ) + if extraMap, err = gstr.Parse(config.Extra); err != nil { + return nil, err + } + for k, v := range extraMap { + if options != "" { + options += "&" + } + options += fmt.Sprintf(`_pragma=%s(%s)`, k, gurl.Encode(gconv.String(v))) + } + if len(options) > 1 { + source += "?" + options + } + } + + if db, err = sql.Open(underlyingDriverName, source); err != nil { + err = gerror.WrapCodef( + gcode.CodeDbOperationError, err, + `sql.Open failed for driver "%s" by source "%s"`, underlyingDriverName, source, + ) + return nil, err + } + return +} + +// GetChars returns the security char for this type of database. +func (d *Driver) GetChars() (charLeft string, charRight string) { + return quoteChar, quoteChar +} + +// DoFilter deals with the sql string before commits it to underlying sql driver. +func (d *Driver) DoFilter(ctx context.Context, link gdb.Link, sql string, args []interface{}) (newSql string, newArgs []interface{}, err error) { + return d.Core.DoFilter(ctx, link, sql, args) +} + +// Tables retrieves and returns the tables of current schema. +// It's mainly used in cli tool chain for automatically generating the models. +func (d *Driver) Tables(ctx context.Context, schema ...string) (tables []string, err error) { + var result gdb.Result + link, err := d.SlaveLink(schema...) + if err != nil { + return nil, err + } + + result, err = d.DoSelect(ctx, link, `SELECT NAME FROM SQLITE_MASTER WHERE TYPE='table' ORDER BY NAME`) + if err != nil { + return + } + for _, m := range result { + for _, v := range m { + tables = append(tables, v.String()) + } + } + return +} + +// TableFields retrieves and returns the fields' information of specified table of current schema. +// +// Also see DriverMysql.TableFields. +func (d *Driver) TableFields( + ctx context.Context, table string, schema ...string, +) (fields map[string]*gdb.TableField, err error) { + var ( + result gdb.Result + link gdb.Link + usedSchema = gutil.GetOrDefaultStr(d.GetSchema(), schema...) + ) + if link, err = d.SlaveLink(usedSchema); err != nil { + return nil, err + } + result, err = d.DoSelect(ctx, link, fmt.Sprintf(`PRAGMA TABLE_INFO(%s)`, d.QuoteWord(table))) + if err != nil { + return nil, err + } + fields = make(map[string]*gdb.TableField) + for i, m := range result { + mKey := "" + if m["pk"].Bool() { + mKey = "pri" + } + fields[m["name"].String()] = &gdb.TableField{ + Index: i, + Name: m["name"].String(), + Type: m["type"].String(), + Key: mKey, + Default: m["dflt_value"].Val(), + Null: !m["notnull"].Bool(), + } + } + return fields, nil +} + +// DoInsert is not supported in sqlite. +func (d *Driver) DoInsert( + ctx context.Context, link gdb.Link, table string, list gdb.List, option gdb.DoInsertOption, +) (result sql.Result, err error) { + switch option.InsertOption { + case gdb.InsertOptionSave: + return nil, gerror.NewCode(gcode.CodeNotSupported, `Save operation is not supported by sqlite driver`) + + case gdb.InsertOptionIgnore, gdb.InsertOptionReplace: + var ( + keys []string // Field names. + values []string // Value holder string array, like: (?,?,?) + params []interface{} // Values that will be committed to underlying database driver. + onDuplicateStr string // onDuplicateStr is used in "ON DUPLICATE KEY UPDATE" statement. + ) + // Handle the field names and placeholders. + for k := range list[0] { + keys = append(keys, k) + } + // Prepare the batch result pointer. + var ( + charL, charR = d.GetChars() + batchResult = new(gdb.SqlResult) + keysStr = charL + strings.Join(keys, charR+","+charL) + charR + operation = "INSERT OR IGNORE" + ) + + if option.InsertOption == gdb.InsertOptionReplace { + operation = "INSERT OR REPLACE" + } + var ( + listLength = len(list) + valueHolder = make([]string, 0) + ) + for i := 0; i < listLength; i++ { + values = values[:0] + // Note that the map type is unordered, + // so it should use slice+key to retrieve the value. + for _, k := range keys { + if s, ok := list[i][k].(gdb.Raw); ok { + values = append(values, gconv.String(s)) + } else { + values = append(values, "?") + params = append(params, list[i][k]) + } + } + valueHolder = append(valueHolder, "("+gstr.Join(values, ",")+")") + // Batch package checks: It meets the batch number, or it is the last element. + if len(valueHolder) == option.BatchCount || (i == listLength-1 && len(valueHolder) > 0) { + var ( + stdSqlResult sql.Result + affectedRows int64 + ) + stdSqlResult, err = d.DoExec(ctx, link, fmt.Sprintf( + "%s INTO %s(%s) VALUES%s %s", + operation, d.QuotePrefixTableName(table), keysStr, + gstr.Join(valueHolder, ","), + onDuplicateStr, + ), params...) + if err != nil { + return stdSqlResult, err + } + if affectedRows, err = stdSqlResult.RowsAffected(); err != nil { + err = gerror.WrapCode(gcode.CodeDbOperationError, err, `sql.Result.RowsAffected failed`) + return stdSqlResult, err + } else { + batchResult.Result = stdSqlResult + batchResult.Affected += affectedRows + } + params = params[:0] + valueHolder = valueHolder[:0] + } + } + return batchResult, nil + + default: + return d.Core.DoInsert(ctx, link, table, list, option) + } +} diff --git a/contrib/drivers/sqlitecgo/sqlite_0_test.go b/contrib/drivers/sqlitecgo/sqlite_0_test.go new file mode 100644 index 000000000..fe778b93f --- /dev/null +++ b/contrib/drivers/sqlitecgo/sqlite_0_test.go @@ -0,0 +1,163 @@ +// Copyright GoFrame Author(https://goframe.org). 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 sqlitecgo_test + +import ( + "fmt" + + "github.com/gogf/gf/v2/container/garray" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/errors/gcode" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gctx" + "github.com/gogf/gf/v2/os/gfile" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/test/gtest" +) + +var ( + db gdb.DB + dbPrefix gdb.DB + dbInvalid gdb.DB + configNode gdb.ConfigNode + dbDir = gfile.Temp("sqlite") + ctx = gctx.New() + + // Error + ErrorSave = gerror.NewCode(gcode.CodeNotSupported, `Save operation is not supported by sqlite driver`) +) + +const ( + TableSize = 10 + TableName = "user" + TableNameWhichIsKeyword = "group" + TestSchema1 = "test1" + TestSchema2 = "test2" + TableNamePrefix = "gf_" + CreateTime = "2018-10-24 10:00:00" + DBGroupTest = "test" + DBGroupPrefix = "prefix" + DBGroupInvalid = "invalid" +) + +func init() { + fmt.Println("init sqlite db start") + + if err := gfile.Mkdir(dbDir); err != nil { + gtest.Error(err) + } + + fmt.Println("init sqlite db dir: ", dbDir) + + dbFilePath := gfile.Join(dbDir, "test.db") + configNode = gdb.ConfigNode{ + Type: "sqlite", + Link: fmt.Sprintf(`sqlite::@file(%s)`, dbFilePath), + Charset: "utf8", + } + nodePrefix := configNode + nodePrefix.Prefix = TableNamePrefix + + nodeInvalid := configNode + + gdb.AddConfigNode(DBGroupTest, configNode) + gdb.AddConfigNode(DBGroupPrefix, nodePrefix) + gdb.AddConfigNode(DBGroupInvalid, nodeInvalid) + gdb.AddConfigNode(gdb.DefaultGroupName, configNode) + + // Default db. + if r, err := gdb.NewByGroup(); err != nil { + gtest.Error(err) + } else { + db = r + } + + // Prefix db. + if r, err := gdb.NewByGroup(DBGroupPrefix); err != nil { + gtest.Error(err) + } else { + dbPrefix = r + } + + // Invalid db. + if r, err := gdb.NewByGroup(DBGroupInvalid); err != nil { + gtest.Error(err) + } else { + dbInvalid = r + } + + fmt.Println("init sqlite db finish") +} + +func createTable(table ...string) string { + return createTableWithDb(db, table...) +} + +func createInitTable(table ...string) string { + return createInitTableWithDb(db, table...) +} + +func dropTable(table string) { + dropTableWithDb(db, table) +} + +func createTableWithDb(db gdb.DB, table ...string) (name string) { + if len(table) > 0 { + name = table[0] + } else { + name = fmt.Sprintf(`%s_%d`, TableName, gtime.TimestampNano()) + } + dropTableWithDb(db, name) + + if _, err := db.Exec(ctx, fmt.Sprintf(` + CREATE TABLE %s ( + id INTEGER PRIMARY KEY AUTOINCREMENT + UNIQUE + NOT NULL, + passport VARCHAR(45) NOT NULL + DEFAULT passport, + password VARCHAR(128) NOT NULL + DEFAULT password, + nickname VARCHAR(45), + create_time DATETIME + ); + `, db.GetCore().QuoteWord(name), + )); err != nil { + gtest.Fatal(err) + } + + return +} + +func createInitTableWithDb(db gdb.DB, table ...string) (name string) { + name = createTableWithDb(db, 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.NewFromStr(CreateTime).String(), + }) + } + + result, err := db.Insert(ctx, name, array.Slice()) + gtest.AssertNil(err) + + n, e := result.RowsAffected() + gtest.Assert(e, nil) + gtest.Assert(n, TableSize) + return +} + +func dropTableWithDb(db gdb.DB, table string) { + if _, err := db.Exec(ctx, fmt.Sprintf("DROP TABLE IF EXISTS `%s`", table)); err != nil { + gtest.Error(err) + } +} diff --git a/contrib/drivers/sqlitecgo/sqlite_core_test.go b/contrib/drivers/sqlitecgo/sqlite_core_test.go new file mode 100644 index 000000000..f6f3a2af8 --- /dev/null +++ b/contrib/drivers/sqlitecgo/sqlite_core_test.go @@ -0,0 +1,1609 @@ +// Copyright GoFrame Author(https://goframe.org). 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 sqlitecgo_test + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/gogf/gf/v2/container/garray" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/encoding/gxml" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gfile" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/test/gtest" +) + +func Test_New(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + node := gdb.ConfigNode{ + Type: "sqlite", + Link: gfile.Join(dbDir, "test.db"), + Charset: "utf8", + } + newDb, err := gdb.New(node) + t.AssertNil(err) + value, err := newDb.GetValue(ctx, `select 1`) + t.AssertNil(err) + t.Assert(value, `1`) + t.AssertNil(newDb.Close(ctx)) + }) +} + +func Test_New_Path_With_Colon(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + + dbFilePathWithColon := gfile.Join(dbDir, "test:1") + if err := gfile.Mkdir(dbFilePathWithColon); err != nil { + gtest.Error(err) + } + node := gdb.ConfigNode{ + Type: "sqlite", + Link: fmt.Sprintf(`sqlite::@file(%s)`, gfile.Join(dbFilePathWithColon, "test.db")), + Charset: "utf8", + } + newDb, err := gdb.New(node) + t.AssertNil(err) + value, err := newDb.GetValue(ctx, `select 1`) + t.AssertNil(err) + t.Assert(value, `1`) + t.AssertNil(newDb.Close(ctx)) + }) +} + +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 ?", 1) + t.AssertNil(err) + + _, err = db.Query(ctx, "SELECT ?+?", 1, 2) + t.AssertNil(err) + + _, err = db.Query(ctx, "SELECT ?+?", g.Slice{1, 2}) + t.AssertNil(err) + }) +} + +func Test_DB_Exec(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + _, err := db.Exec(ctx, "SELECT ?", 1) + t.AssertNil(err) + }) +} + +func Test_DB_Prepare(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + st, err := db.Prepare(ctx, "SELECT 100") + t.AssertNil(err) + + rows, err := st.Query() + t.AssertNil(err) + + array, err := rows.Columns() + t.AssertNil(err) + t.Assert(array[0], "100") + + err = rows.Close() + t.AssertNil(err) + }) +} + +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) + + 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) + }) +} + +// Fix issue: https://github.com/gogf/gf/issues/819 +func Test_DB_Insert_WithStructAndSliceAttribute(t *testing.T) { + table := createTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + type Password struct { + Salt string `json:"salt"` + Pass string `json:"pass"` + } + data := g.Map{ + "id": 1, + "passport": "t1", + "password": &Password{"123", "456"}, + "nickname": []string{"A", "B", "C"}, + "create_time": gtime.Now().String(), + } + _, err := db.Insert(ctx, table, data) + t.AssertNil(err) + + one, err := db.GetOne(ctx, fmt.Sprintf("SELECT * FROM %s WHERE id=?", table), 1) + t.AssertNil(err) + t.Assert(one["passport"], data["passport"]) + t.Assert(one["create_time"], data["create_time"]) + t.Assert(one["nickname"], gjson.New(data["nickname"]).MustToJson()) + }) +} + +func Test_DB_Insert_KeyFieldNameMapping(t *testing.T) { + table := createTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + Nickname string + CreateTime string + } + data := User{ + Id: 1, + Passport: "user_1", + Password: "pass_1", + Nickname: "name_1", + CreateTime: "2020-10-10 12:00:01", + } + _, err := db.Insert(ctx, table, data) + t.AssertNil(err) + + one, err := db.GetOne(ctx, fmt.Sprintf("SELECT * FROM %s WHERE id=?", table), 1) + t.AssertNil(err) + t.Assert(one["passport"], data.Passport) + t.Assert(one["create_time"], data.CreateTime) + t.Assert(one["nickname"], data.Nickname) + }) +} + +func Test_DB_Upadte_KeyFieldNameMapping(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 string + } + data := User{ + Id: 1, + Passport: "user_10", + Password: "pass_10", + Nickname: "name_10", + CreateTime: "2020-10-10 12:00:01", + } + _, err := db.Update(ctx, table, data, "id=1") + t.AssertNil(err) + + one, err := db.GetOne(ctx, fmt.Sprintf("SELECT * FROM %s WHERE id=?", table), 1) + t.AssertNil(err) + t.Assert(one["passport"], data.Passport) + t.Assert(one["create_time"], data.CreateTime) + t.Assert(one["nickname"], data.Nickname) + }) +} + +func Test_DB_InsertIgnore(t *testing.T) { + table := createInitTable() + 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": CreateTime, + }) + t.AssertNE(err, nil) + }) + gtest.C(t, func(t *gtest.T) { + _, err := db.InsertIgnore(ctx, table, g.Map{ + "id": 1, + "passport": "t1", + "password": "25d55ad283aa400af464c76d713c07ad", + "nickname": "T1", + "create_time": CreateTime, + }) + t.AssertNil(err) + }) +} + +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) + + n, _ = r.LastInsertId() + t.Assert(n, 3) + }) + + 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_Save(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + timeStr := gtime.Now().String() + _, err := db.Save(ctx, table, g.Map{ + "id": 1, + "passport": "t1", + "password": "25d55ad283aa400af464c76d713c07ad", + "nickname": "T11", + "create_time": timeStr, + }) + t.Assert(err, ErrorSave) + }) +} + +func Test_DB_Replace(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + timeStr := gtime.Now().String() + _, err := db.Replace(ctx, table, g.Map{ + "id": 1, + "passport": "t1", + "password": "25d55ad283aa400af464c76d713c07ad", + "nickname": "T11", + "create_time": timeStr, + }) + t.AssertNil(err) + + one, err := db.Model(table).Where("id", 1).One() + t.AssertNil(err) + t.Assert(one["id"].Int(), 1) + t.Assert(one["passport"].String(), "t1") + t.Assert(one["password"].String(), "25d55ad283aa400af464c76d713c07ad") + t.Assert(one["nickname"].String(), "T11") + t.Assert(one["create_time"].GTime().String(), timeStr) + }) +} + +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(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_GetArray(t *testing.T) { + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + array, err := db.GetArray(ctx, fmt.Sprintf("SELECT id FROM %s WHERE id>?", table), 1) + t.AssertNil(err) + t.Assert(len(array), TableSize-1) + for i, v := range array { + t.Assert(v.Int(), i+2) + } + }) +} + +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) + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, TableSize) + }) +} + +func Test_DB_Time(t *testing.T) { + table := createTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + result, err := db.Insert(ctx, table, g.Map{ + "id": 200, + "passport": "t200", + "password": "123456", + "nickname": "T200", + "create_time": time.Now(), + }) + if err != nil { + gtest.Error(err) + } + n, _ := result.RowsAffected() + t.Assert(n, 1) + value, err := db.GetValue(ctx, fmt.Sprintf("select `passport` from `%s` where id=?", table), 200) + t.AssertNil(err) + t.Assert(value.String(), "t200") + }) + + gtest.C(t, func(t *gtest.T) { + t1 := time.Now() + result, err := db.Insert(ctx, table, g.Map{ + "id": 300, + "passport": "t300", + "password": "123456", + "nickname": "T300", + "create_time": &t1, + }) + if err != nil { + gtest.Error(err) + } + n, _ := result.RowsAffected() + t.Assert(n, 1) + value, err := db.GetValue(ctx, fmt.Sprintf("select `passport` from `%s` where id=?", table), 300) + t.AssertNil(err) + t.Assert(value.String(), "t300") + }) + + gtest.C(t, func(t *gtest.T) { + result, err := db.Delete(ctx, table, 1) + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 2) + }) +} + +func Test_DB_ToJson(t *testing.T) { + table := createInitTable() + defer dropTable(table) + _, err := db.Update(ctx, table, "create_time='2010-10-10 00:00:01'", "id=?", 1) + gtest.AssertNil(err) + + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Fields("*").Where("id =? ", 1).All() + if err != nil { + gtest.Fatal(err) + } + + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime string + } + + users := make([]User, 0) + + err = result.Structs(users) + t.AssertNE(err, nil) + + err = result.Structs(&users) + if err != nil { + gtest.Fatal(err) + } + + // ToJson + resultJson, err := gjson.LoadContent(result.Json()) + if err != nil { + gtest.Fatal(err) + } + + t.Assert(users[0].Id, resultJson.Get("0.id").Int()) + t.Assert(users[0].Passport, resultJson.Get("0.passport").String()) + t.Assert(users[0].Password, resultJson.Get("0.password").String()) + t.Assert(users[0].NickName, resultJson.Get("0.nickname").String()) + t.Assert(users[0].CreateTime, resultJson.Get("0.create_time").String()) + + result = nil + err = result.Structs(&users) + t.AssertNil(err) + }) + + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Fields("*").Where("id =? ", 1).One() + if err != nil { + gtest.Fatal(err) + } + + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime string + } + + users := User{} + + err = result.Struct(&users) + if err != nil { + gtest.Fatal(err) + } + + result = nil + err = result.Struct(&users) + t.AssertNE(err, nil) + }) +} + +func Test_DB_ToXml(t *testing.T) { + table := createInitTable() + defer dropTable(table) + _, err := db.Update(ctx, table, "create_time='2010-10-10 00:00:01'", "id=?", 1) + gtest.AssertNil(err) + + gtest.C(t, func(t *gtest.T) { + record, err := db.Model(table).Fields("*").Where("id = ?", 1).One() + if err != nil { + gtest.Fatal(err) + } + + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime string + } + + user := User{} + err = record.Struct(&user) + if err != nil { + gtest.Fatal(err) + } + + result, err := gxml.Decode([]byte(record.Xml("doc"))) + if err != nil { + gtest.Fatal(err) + } + + resultXml := result["doc"].(map[string]interface{}) + if v, ok := resultXml["id"]; ok { + t.Assert(user.Id, v) + } else { + gtest.Fatal("FAIL") + } + + if v, ok := resultXml["passport"]; ok { + t.Assert(user.Passport, v) + } else { + gtest.Fatal("FAIL") + } + + if v, ok := resultXml["password"]; ok { + t.Assert(user.Password, v) + } else { + gtest.Fatal("FAIL") + } + + if v, ok := resultXml["nickname"]; ok { + t.Assert(user.NickName, v) + } else { + gtest.Fatal("FAIL") + } + + if v, ok := resultXml["create_time"]; ok { + t.Assert(user.CreateTime, v) + } else { + gtest.Fatal("FAIL") + } + }) +} + +func Test_DB_ToStringMap(t *testing.T) { + table := createInitTable() + defer dropTable(table) + _, err := db.Update(ctx, table, "create_time='2010-10-10 00:00:01'", "id=?", 1) + gtest.AssertNil(err) + gtest.C(t, func(t *gtest.T) { + id := "1" + result, err := db.Model(table).Fields("*").Where("id = ?", 1).All() + if err != nil { + gtest.Fatal(err) + } + + type t_user struct { + Id int + Passport string + Password string + NickName string + CreateTime string + } + + t_users := make([]t_user, 0) + err = result.Structs(&t_users) + if err != nil { + gtest.Fatal(err) + } + + resultStringMap := result.MapKeyStr("id") + t.Assert(t_users[0].Id, resultStringMap[id]["id"]) + t.Assert(t_users[0].Passport, resultStringMap[id]["passport"]) + t.Assert(t_users[0].Password, resultStringMap[id]["password"]) + t.Assert(t_users[0].NickName, resultStringMap[id]["nickname"]) + t.Assert(t_users[0].CreateTime, resultStringMap[id]["create_time"]) + }) +} + +func Test_DB_ToIntMap(t *testing.T) { + table := createInitTable() + defer dropTable(table) + _, err := db.Update(ctx, table, "create_time='2010-10-10 00:00:01'", "id=?", 1) + gtest.AssertNil(err) + + gtest.C(t, func(t *gtest.T) { + id := 1 + result, err := db.Model(table).Fields("*").Where("id = ?", id).All() + if err != nil { + gtest.Fatal(err) + } + + type t_user struct { + Id int + Passport string + Password string + NickName string + CreateTime string + } + + t_users := make([]t_user, 0) + err = result.Structs(&t_users) + if err != nil { + gtest.Fatal(err) + } + + resultIntMap := result.MapKeyInt("id") + t.Assert(t_users[0].Id, resultIntMap[id]["id"]) + t.Assert(t_users[0].Passport, resultIntMap[id]["passport"]) + t.Assert(t_users[0].Password, resultIntMap[id]["password"]) + t.Assert(t_users[0].NickName, resultIntMap[id]["nickname"]) + t.Assert(t_users[0].CreateTime, resultIntMap[id]["create_time"]) + }) +} + +func Test_DB_ToUintMap(t *testing.T) { + table := createInitTable() + defer dropTable(table) + _, err := db.Update(ctx, table, "create_time='2010-10-10 00:00:01'", "id=?", 1) + gtest.AssertNil(err) + + gtest.C(t, func(t *gtest.T) { + id := 1 + result, err := db.Model(table).Fields("*").Where("id = ?", id).All() + if err != nil { + gtest.Fatal(err) + } + + type t_user struct { + Id int + Passport string + Password string + NickName string + CreateTime string + } + + t_users := make([]t_user, 0) + err = result.Structs(&t_users) + if err != nil { + gtest.Fatal(err) + } + + resultUintMap := result.MapKeyUint("id") + t.Assert(t_users[0].Id, resultUintMap[uint(id)]["id"]) + t.Assert(t_users[0].Passport, resultUintMap[uint(id)]["passport"]) + t.Assert(t_users[0].Password, resultUintMap[uint(id)]["password"]) + t.Assert(t_users[0].NickName, resultUintMap[uint(id)]["nickname"]) + t.Assert(t_users[0].CreateTime, resultUintMap[uint(id)]["create_time"]) + }) +} + +func Test_DB_ToStringRecord(t *testing.T) { + table := createInitTable() + defer dropTable(table) + _, err := db.Update(ctx, table, "create_time='2010-10-10 00:00:01'", "id=?", 1) + gtest.AssertNil(err) + + gtest.C(t, func(t *gtest.T) { + id := 1 + ids := "1" + result, err := db.Model(table).Fields("*").Where("id = ?", id).All() + if err != nil { + gtest.Fatal(err) + } + + type t_user struct { + Id int + Passport string + Password string + NickName string + CreateTime string + } + + t_users := make([]t_user, 0) + err = result.Structs(&t_users) + if err != nil { + gtest.Fatal(err) + } + + resultStringRecord := result.RecordKeyStr("id") + t.Assert(t_users[0].Id, resultStringRecord[ids]["id"].Int()) + t.Assert(t_users[0].Passport, resultStringRecord[ids]["passport"].String()) + t.Assert(t_users[0].Password, resultStringRecord[ids]["password"].String()) + t.Assert(t_users[0].NickName, resultStringRecord[ids]["nickname"].String()) + t.Assert(t_users[0].CreateTime, resultStringRecord[ids]["create_time"].String()) + }) +} + +func Test_DB_ToIntRecord(t *testing.T) { + table := createInitTable() + defer dropTable(table) + _, err := db.Update(ctx, table, "create_time='2010-10-10 00:00:01'", "id=?", 1) + gtest.AssertNil(err) + + gtest.C(t, func(t *gtest.T) { + id := 1 + result, err := db.Model(table).Fields("*").Where("id = ?", id).All() + if err != nil { + gtest.Fatal(err) + } + + type t_user struct { + Id int + Passport string + Password string + NickName string + CreateTime string + } + + t_users := make([]t_user, 0) + err = result.Structs(&t_users) + if err != nil { + gtest.Fatal(err) + } + + resultIntRecord := result.RecordKeyInt("id") + t.Assert(t_users[0].Id, resultIntRecord[id]["id"].Int()) + t.Assert(t_users[0].Passport, resultIntRecord[id]["passport"].String()) + t.Assert(t_users[0].Password, resultIntRecord[id]["password"].String()) + t.Assert(t_users[0].NickName, resultIntRecord[id]["nickname"].String()) + t.Assert(t_users[0].CreateTime, resultIntRecord[id]["create_time"].String()) + }) +} + +func Test_DB_ToUintRecord(t *testing.T) { + table := createInitTable() + defer dropTable(table) + _, err := db.Update(ctx, table, "create_time='2010-10-10 00:00:01'", "id=?", 1) + gtest.AssertNil(err) + + gtest.C(t, func(t *gtest.T) { + id := 1 + result, err := db.Model(table).Fields("*").Where("id = ?", id).All() + if err != nil { + gtest.Fatal(err) + } + + type t_user struct { + Id int + Passport string + Password string + NickName string + CreateTime string + } + + t_users := make([]t_user, 0) + err = result.Structs(&t_users) + if err != nil { + gtest.Fatal(err) + } + + resultUintRecord := result.RecordKeyUint("id") + t.Assert(t_users[0].Id, resultUintRecord[uint(id)]["id"].Int()) + t.Assert(t_users[0].Passport, resultUintRecord[uint(id)]["passport"].String()) + t.Assert(t_users[0].Password, resultUintRecord[uint(id)]["password"].String()) + t.Assert(t_users[0].NickName, resultUintRecord[uint(id)]["nickname"].String()) + t.Assert(t_users[0].CreateTime, resultUintRecord[uint(id)]["create_time"].String()) + }) +} + +func Test_DB_TableField(t *testing.T) { + name := "field_test" + dropTable(name) + defer dropTable(name) + _, err := db.Exec(ctx, fmt.Sprintf(` + CREATE TABLE %s ( + field_tinyint tinyint(8) NULL , + field_int int(8) NULL , + field_integer integer(8) NULL , + field_bigint bigint(8) NULL , + field_real real(8,0) NULL , + field_double double(12,2) NULL , + field_varchar varchar(10) NULL , + field_varbinary varbinary(255) NULL + ); + `, name)) + if err != nil { + gtest.Fatal(err) + } + + data := gdb.Map{ + "field_tinyint": 1, + "field_int": 2, + "field_integer": 3, + "field_bigint": 4, + "field_real": 123, + "field_double": 123.25, + "field_varchar": "abc", + "field_varbinary": "aaa", + } + res, err := db.Model(name).Data(data).Insert() + if err != nil { + gtest.Fatal(err) + } + + n, err := res.RowsAffected() + if err != nil { + gtest.Fatal(err) + } else { + gtest.Assert(n, 1) + } + + result, err := db.Model(name).Fields("*").Where("field_int = ?", 2).All() + if err != nil { + gtest.Fatal(err) + } + + gtest.Assert(result[0], data) +} + +func Test_DB_Prefix(t *testing.T) { + db := dbPrefix + noPrefixName := fmt.Sprintf(`%s_%d`, TableName, gtime.TimestampNano()) + table := TableNamePrefix + noPrefixName + createTableWithDb(db, table) + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + id := 10000 + result, err := db.Insert(ctx, noPrefixName, g.Map{ + "id": id, + "passport": fmt.Sprintf(`user_%d`, id), + "password": fmt.Sprintf(`pass_%d`, id), + "nickname": fmt.Sprintf(`name_%d`, id), + "create_time": gtime.NewFromStr(CreateTime).String(), + }) + t.AssertNil(err) + + n, e := result.RowsAffected() + t.Assert(e, nil) + t.Assert(n, 1) + }) + + gtest.C(t, func(t *gtest.T) { + id := 10000 + result, err := db.Replace(ctx, noPrefixName, g.Map{ + "id": id, + "passport": fmt.Sprintf(`user_%d`, id), + "password": fmt.Sprintf(`pass_%d`, id), + "nickname": fmt.Sprintf(`name_%d`, id), + "create_time": gtime.Now().String(), + }) + t.AssertNil(err) + + n, e := result.RowsAffected() + t.Assert(e, nil) + t.Assert(n, 1) + }) + + gtest.C(t, func(t *gtest.T) { + id := 10000 + result, err := db.Update(ctx, noPrefixName, g.Map{ + "id": id, + "passport": fmt.Sprintf(`user_%d`, id), + "password": fmt.Sprintf(`pass_%d`, id), + "nickname": fmt.Sprintf(`name_%d`, id), + "create_time": gtime.NewFromStr("2018-10-24 10:00:03").String(), + }, "id=?", id) + t.AssertNil(err) + + n, e := result.RowsAffected() + t.Assert(e, nil) + t.Assert(n, 1) + }) + + gtest.C(t, func(t *gtest.T) { + id := 10000 + result, err := db.Delete(ctx, noPrefixName, "id=?", id) + t.AssertNil(err) + + n, e := result.RowsAffected() + t.Assert(e, nil) + t.Assert(n, 1) + }) + + gtest.C(t, func(t *gtest.T) { + 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.NewFromStr(CreateTime).String(), + }) + } + + result, err := db.Insert(ctx, noPrefixName, array.Slice()) + t.AssertNil(err) + + n, e := result.RowsAffected() + t.Assert(e, nil) + t.Assert(n, TableSize) + }) +} + +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_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) + }) +} + +// update counter test. +func Test_DB_UpdateCounter(t *testing.T) { + tableName := "gf_update_counter_test_" + gtime.TimestampNanoStr() + _, err := db.Exec(ctx, fmt.Sprintf(` + CREATE TABLE IF NOT EXISTS %s ( + id INTEGER PRIMARY KEY AUTOINCREMENT + UNIQUE + NOT NULL, + views int(8) DEFAULT '0' NOT NULL , + updated_time int(10) DEFAULT '0' NOT NULL + ); + `, tableName)) + if err != nil { + gtest.Fatal(err) + } + defer dropTable(tableName) + + gtest.C(t, func(t *gtest.T) { + insertData := g.Map{ + "id": 1, + "views": 0, + "updated_time": 0, + } + _, err = db.Insert(ctx, tableName, insertData) + t.AssertNil(err) + }) + + gtest.C(t, func(t *gtest.T) { + gdbCounter := &gdb.Counter{ + Field: "id", + Value: 1, + } + updateData := g.Map{ + "views": gdbCounter, + } + result, err := db.Update(ctx, tableName, updateData, "id", 1) + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + one, err := db.Model(tableName).Where("id", 1).One() + t.AssertNil(err) + t.Assert(one["id"].Int(), 1) + t.Assert(one["views"].Int(), 2) + }) + + gtest.C(t, func(t *gtest.T) { + gdbCounter := &gdb.Counter{ + Field: "views", + Value: -1, + } + updateData := g.Map{ + "views": gdbCounter, + "updated_time": gtime.Now().Unix(), + } + result, err := db.Update(ctx, tableName, updateData, "id", 1) + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + one, err := db.Model(tableName).Where("id", 1).One() + t.AssertNil(err) + t.Assert(one["id"].Int(), 1) + t.Assert(one["views"].Int(), 1) + }) +} + +func Test_DB_Ctx_Logger(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + type TraceId string + defer db.SetDebug(db.GetDebug()) + db.SetDebug(true) + ctx := context.WithValue(context.Background(), TraceId("Trace-Id"), "123456789") + _, err := db.Query(ctx, "SELECT 1") + t.AssertNil(err) + }) +} + +// All types testing. +// https://www.sqlite.org/datatype3.html +func Test_Types(t *testing.T) { + tableName := "types_" + gtime.TimestampNanoStr() + gtest.C(t, func(t *gtest.T) { + if _, err := db.Exec(ctx, fmt.Sprintf(` + CREATE TABLE IF NOT EXISTS %s ( + id INTEGER PRIMARY KEY AUTOINCREMENT + UNIQUE + NOT NULL, + %s blob NOT NULL, + %s binary(8) NOT NULL, + %s date NOT NULL, + %s time NOT NULL, + %s timestamp(6) NOT NULL, + %s decimal(5,2) NOT NULL, + %s double NOT NULL, + %s tinyint(1) NOT NULL, + %s bool NOT NULL + ); + `, + tableName, + "`blob`", + "`binary`", + "`date`", + "`time`", + "`timestamp`", + "`decimal`", + "`double`", + "`tinyint`", + "`bool`")); err != nil { + gtest.Error(err) + } + defer dropTable(tableName) + data := g.Map{ + "id": 1, + "blob": "i love gf", + "binary": []byte("abcdefgh"), + "date": "1880-10-24", + "time": "10:00:01", + "timestamp": "2022-02-14 12:00:01.123456", + "decimal": -123.456, + "double": -123.456, + "tinyint": true, + "bool": false, + } + r, err := db.Model(tableName).Data(data).Insert() + t.AssertNil(err) + n, _ := r.RowsAffected() + t.Assert(n, 1) + + one, err := db.Model(tableName).One() + t.AssertNil(err) + t.Assert(one["id"].Int(), 1) + t.Assert(one["blob"].String(), data["blob"]) + t.Assert(one["binary"].String(), data["binary"]) + t.Assert(one["date"].String(), data["date"]) + t.Assert(one["time"].String(), `10:00:01`) + t.Assert(one["timestamp"].GTime().Format(`Y-m-d H:i:s.u`), `2022-02-14 12:00:01.123`) + t.Assert(one["decimal"].String(), data["decimal"]) // In SQLite, the datatype of a value is associated with the value itself, not with its container. + t.Assert(one["double"].String(), data["double"]) + t.Assert(one["tinyint"].Bool(), data["tinyint"]) + + type T struct { + Id int + Blob []byte + Binary []byte + Date *gtime.Time + Time *gtime.Time + Timestamp *gtime.Time + Decimal float64 + Double float64 + Bit int8 + TinyInt bool + } + var obj *T + err = db.Model(tableName).Scan(&obj) + t.AssertNil(err) + t.Assert(obj.Id, 1) + t.Assert(obj.Blob, data["blob"]) + t.Assert(obj.Binary, data["binary"]) + t.Assert(obj.Date.Format("Y-m-d"), data["date"]) + t.Assert(obj.Time.String(), `10:00:01`) + t.Assert(obj.Timestamp.Format(`Y-m-d H:i:s.u`), `2022-02-14 12:00:01.123`) + t.Assert(obj.Decimal, data["decimal"]) + t.Assert(obj.Double, data["double"]) + t.Assert(obj.TinyInt, data["tinyint"]) + }) +} + +func Test_TableFields(t *testing.T) { + + gtest.C(t, func(t *gtest.T) { + tableName := "fields_" + gtime.TimestampNanoStr() + createTable(tableName) + defer dropTable(tableName) + var expect = map[string][]interface{}{ + // fields type null key default extra comment + "id": {"INTEGER", false, "pri", nil, "", ""}, + "passport": {"VARCHAR(45)", false, "", "passport", "", ""}, + "password": {"VARCHAR(128)", false, "", "password", "", ""}, + "nickname": {"VARCHAR(45)", true, "", nil, "", ""}, + "create_time": {"DATETIME", true, "", nil, "", ""}, + } + + res, err := db.TableFields(context.Background(), tableName) + gtest.Assert(err, nil) + + 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]) + } + + }) + + gtest.C(t, func(t *gtest.T) { + _, err := db.TableFields(context.Background(), "t1 t2") + gtest.AssertNE(err, nil) + }) +} + +func Test_TableNameIsKeyword(t *testing.T) { + table := createInitTable(TableNameWhichIsKeyword) + defer dropTable(table) + _, err := db.Update(ctx, table, "create_time='2010-10-10 00:00:01'", "id=?", 1) + gtest.AssertNil(err) + + gtest.C(t, func(t *gtest.T) { + id := 1 + result, err := db.Model(table).Fields("*").Where("id = ?", id).All() + if err != nil { + gtest.Fatal(err) + } + + type t_user struct { + Id int + Passport string + Password string + NickName string + CreateTime string + } + + t_users := make([]t_user, 0) + err = result.Structs(&t_users) + if err != nil { + gtest.Fatal(err) + } + + resultIntMap := result.MapKeyInt("id") + t.Assert(t_users[0].Id, resultIntMap[id]["id"]) + t.Assert(t_users[0].Passport, resultIntMap[id]["passport"]) + t.Assert(t_users[0].Password, resultIntMap[id]["password"]) + t.Assert(t_users[0].NickName, resultIntMap[id]["nickname"]) + t.Assert(t_users[0].CreateTime, resultIntMap[id]["create_time"]) + }) +} diff --git a/contrib/drivers/sqlitecgo/sqlite_model_test.go b/contrib/drivers/sqlitecgo/sqlite_model_test.go new file mode 100644 index 000000000..c47bccd12 --- /dev/null +++ b/contrib/drivers/sqlitecgo/sqlite_model_test.go @@ -0,0 +1,4344 @@ +// Copyright GoFrame Author(https://goframe.org). 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 sqlitecgo_test + +import ( + "bytes" + "context" + "database/sql" + "fmt" + "os" + "testing" + "time" + + "github.com/gogf/gf/v2/container/garray" + "github.com/gogf/gf/v2/container/gmap" + "github.com/gogf/gf/v2/container/gvar" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/errors/gcode" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/glog" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/test/gtest" + "github.com/gogf/gf/v2/text/gstr" + "github.com/gogf/gf/v2/util/guid" + "github.com/gogf/gf/v2/util/gutil" +) + +func Test_Model_Insert(t *testing.T) { + table := createTable() + defer dropTable(table) + + 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) + n, _ := result.LastInsertId() + t.Assert(n, 1) + + 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) + n, _ = result.RowsAffected() + t.Assert(n, 1) + + 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) + n, _ = result.RowsAffected() + t.Assert(n, 1) + 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) + n, _ = result.RowsAffected() + t.Assert(n, 1) + 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) + n, _ = result.RowsAffected() + t.Assert(n, 3) + }) +} + +// Fix issue: https://github.com/gogf/gf/issues/819 +func Test_Model_Insert_WithStructAndSliceAttribute(t *testing.T) { + table := createTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + type Password struct { + Salt string `json:"salt"` + Pass string `json:"pass"` + } + data := g.Map{ + "id": 1, + "passport": "t1", + "password": &Password{"123", "456"}, + "nickname": []string{"A", "B", "C"}, + "create_time": gtime.Now().String(), + } + _, 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"], data["passport"]) + t.Assert(one["create_time"], data["create_time"]) + t.Assert(one["nickname"], gjson.New(data["nickname"]).MustToJson()) + }) +} + +func Test_Model_Insert_KeyFieldNameMapping(t *testing.T) { + table := createTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + Nickname string + CreateTime string + } + data := User{ + Id: 1, + Passport: "user_1", + Password: "pass_1", + Nickname: "name_1", + CreateTime: "2020-10-10 12:00:01", + } + _, err := db.Model(table).Data(data).Insert() + t.AssertNil(err) + + one, err := db.Model(table).WherePri(1).One() + t.AssertNil(err) + t.Assert(one["passport"], data.Passport) + t.Assert(one["create_time"], data.CreateTime) + t.Assert(one["nickname"], data.Nickname) + }) +} + +func Test_Model_Update_KeyFieldNameMapping(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 string + } + data := User{ + Id: 999999, + Passport: "user_10", + Password: "pass_10", + Nickname: "name_10", + CreateTime: "2020-10-10 12:00:01", + } + _, err := db.Model(table).Data(data).Where("id", 1).Update() + t.AssertNil(err) + + one, err := db.Model(table).Where("id", data.Id).One() + t.AssertNil(err) + t.Assert(one["passport"], data.Passport) + t.Assert(one["create_time"], data.CreateTime) + t.Assert(one["nickname"], data.Nickname) + }) +} + +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.334", + } + _, 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"], data["passport"]) + t.Assert(one["create_time"], "2020-10-10 20:09:18") + t.Assert(one["nickname"], data["nickname"]) + }) +} + +func Test_Model_BatchInsertWithArrayStruct(t *testing.T) { + table := createTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + user := db.Model(table) + array := garray.New() + for i := 1; i <= TableSize; i++ { + array.Append(g.Map{ + "id": i, + "uid": i, + "passport": fmt.Sprintf("t%d", i), + "password": "25d55ad283aa400af464c76d713c07ad", + "nickname": fmt.Sprintf("name_%d", i), + "create_time": gtime.Now().String(), + }) + } + + result, err := user.Data(array).Insert() + t.AssertNil(err) + n, _ := result.LastInsertId() + t.Assert(n, TableSize) + }) +} + +func Test_Model_InsertIgnore(t *testing.T) { + table := createTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + _, err := db.Model(table).Data(g.Map{ + "id": 1, + "uid": 1, + "passport": "t1", + "password": "25d55ad283aa400af464c76d713c07ad", + "nickname": "name_1", + "create_time": CreateTime, + }).Insert() + t.AssertNil(err) + }) + gtest.C(t, func(t *gtest.T) { + _, err := db.Model(table).Data(g.Map{ + "id": 1, + "uid": 1, + "passport": "t1", + "password": "25d55ad283aa400af464c76d713c07ad", + "nickname": "name_1", + "create_time": CreateTime, + }).InsertIgnore() + t.AssertNil(err) + }) +} + +func Test_Model_Batch(t *testing.T) { + // batch insert + gtest.C(t, func(t *gtest.T) { + table := createTable() + defer dropTable(table) + result, 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) + } + n, _ := result.RowsAffected() + t.Assert(n, 2) + }) + + // batch insert, retrieving last insert auto-increment id. + gtest.C(t, func(t *gtest.T) { + table := createTable() + defer dropTable(table) + result, err := db.Model(table).Data(g.List{ + {"passport": "t1", "password": "25d55ad283aa400af464c76d713c07ad", "nickname": "name", "create_time": gtime.Now().String()}, + {"passport": "t2", "password": "25d55ad283aa400af464c76d713c07ad", "nickname": "name", "create_time": gtime.Now().String()}, + {"passport": "t3", "password": "25d55ad283aa400af464c76d713c07ad", "nickname": "name", "create_time": gtime.Now().String()}, + {"passport": "t4", "password": "25d55ad283aa400af464c76d713c07ad", "nickname": "name", "create_time": gtime.Now().String()}, + {"passport": "t5", "password": "25d55ad283aa400af464c76d713c07ad", "nickname": "name", "create_time": gtime.Now().String()}, + }).Batch(2).Insert() + if err != nil { + gtest.Error(err) + } + n, _ := result.RowsAffected() + t.Assert(n, 5) + }) + + // batch replace + gtest.C(t, func(t *gtest.T) { + table := createInitTable() + defer dropTable(table) + result, err := db.Model(table).All() + t.AssertNil(err) + t.Assert(len(result), TableSize) + for _, v := range result { + v["nickname"].Set(v["nickname"].String() + v["id"].String()) + v["id"].Set(v["id"].Int() + 100) + } + r, e := db.Model(table).Data(result).Replace() + t.Assert(e, nil) + n, e := r.RowsAffected() + t.Assert(e, nil) + t.Assert(n, TableSize) + }) +} + +func Test_Model_Replace(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Data(g.Map{ + "id": 1, + "passport": "t11", + "password": "25d55ad283aa400af464c76d713c07ad", + "nickname": "T11", + "create_time": CreateTime, + }).Replace() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + + one, err := db.Model(table).Where("id", 1).One() + t.AssertNil(err) + t.Assert(one["id"].Int(), 1) + t.Assert(one["passport"].String(), "t11") + t.Assert(one["password"].String(), "25d55ad283aa400af464c76d713c07ad") + t.Assert(one["nickname"].String(), "T11") + t.Assert(one["create_time"].GTime().String(), CreateTime) + }) +} + +func Test_Model_Save(t *testing.T) { + table := createTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + _, err := db.Model(table).Data(g.Map{ + "id": 1, + "passport": "t111", + "password": "25d55ad283aa400af464c76d713c07ad", + "nickname": "T111", + "create_time": CreateTime, + }).Save() + t.Assert(err, ErrorSave) + }) +} + +func Test_Model_Update(t *testing.T) { + table := createInitTable() + defer dropTable(table) + // UPDATE...LIMIT + // gtest.C(t, func(t *gtest.T) { + // result, err := db.Model(table).Data("nickname", "T100").Where(1).Limit(2).Update() + // t.AssertNil(err) + // n, _ := result.RowsAffected() + // t.Assert(n, 2) + + // v1, err := db.Model(table).Fields("nickname").Where("id", 10).Value() + // t.AssertNil(err) + // t.Assert(v1.String(), "T100") + + // v2, err := db.Model(table).Fields("nickname").Where("id", 8).Value() + // t.AssertNil(err) + // t.Assert(v2.String(), "name_8") + // }) + + 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_UpdateAndGetAffected(t *testing.T) { + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + n, err := db.Model(table).Data("nickname", "T100"). + Where(1). + UpdateAndGetAffected() + t.AssertNil(err) + t.Assert(n, TableSize) + }) +} + +func Test_Model_Clone(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + md := db.Model(table).Safe(true).Where("id IN(?)", g.Slice{1, 3}) + count, err := md.Count() + t.AssertNil(err) + + record, err := md.Safe(true).Order("id DESC").One() + t.AssertNil(err) + + result, err := md.Safe(true).Order("id ASC").All() + t.AssertNil(err) + + t.Assert(count, int64(2)) + t.Assert(record["id"].Int(), 3) + t.Assert(len(result), 2) + t.Assert(result[0]["id"].Int(), 1) + t.Assert(result[1]["id"].Int(), 3) + }) +} + +func Test_Model_Safe(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + md := db.Model(table).Safe(false).Where("id IN(?)", g.Slice{1, 3}) + count, err := md.Count() + t.AssertNil(err) + t.Assert(count, int64(2)) + + md.Where("id = ?", 1) + count, err = md.Count() + t.AssertNil(err) + t.Assert(count, int64(1)) + }) + gtest.C(t, func(t *gtest.T) { + md := db.Model(table).Safe(true).Where("id IN(?)", g.Slice{1, 3}) + count, err := md.Count() + t.AssertNil(err) + t.Assert(count, int64(2)) + + md.Where("id = ?", 1) + count, err = md.Count() + t.AssertNil(err) + t.Assert(count, int64(2)) + }) + + gtest.C(t, func(t *gtest.T) { + md := db.Model(table).Safe().Where("id IN(?)", g.Slice{1, 3}) + count, err := md.Count() + t.AssertNil(err) + t.Assert(count, int64(2)) + + md.Where("id = ?", 1) + count, err = md.Count() + t.AssertNil(err) + t.Assert(count, int64(2)) + }) + gtest.C(t, func(t *gtest.T) { + md1 := db.Model(table).Safe() + md2 := md1.Where("id in (?)", g.Slice{1, 3}) + count, err := md2.Count() + t.AssertNil(err) + t.Assert(count, int64(2)) + + all, err := md2.All() + t.AssertNil(err) + t.Assert(len(all), 2) + + all, err = md2.Page(1, 10).All() + t.AssertNil(err) + t.Assert(len(all), 2) + }) + + gtest.C(t, func(t *gtest.T) { + table := createInitTable() + defer dropTable(table) + + md1 := db.Model(table).Where("id>", 0).Safe() + md2 := md1.Where("id in (?)", g.Slice{1, 3}) + md3 := md1.Where("id in (?)", g.Slice{4, 5, 6}) + + // 1,3 + count, err := md2.Count() + t.AssertNil(err) + t.Assert(count, int64(2)) + + all, err := md2.Order("id asc").All() + t.AssertNil(err) + t.Assert(len(all), 2) + t.Assert(all[0]["id"].Int(), 1) + t.Assert(all[1]["id"].Int(), 3) + + all, err = md2.Page(1, 10).All() + t.AssertNil(err) + t.Assert(len(all), 2) + + // 4,5,6 + count, err = md3.Count() + t.AssertNil(err) + t.Assert(count, int64(3)) + + all, err = md3.Order("id asc").All() + t.AssertNil(err) + t.Assert(len(all), 3) + t.Assert(all[0]["id"].Int(), 4) + t.Assert(all[1]["id"].Int(), 5) + t.Assert(all[2]["id"].Int(), 6) + + all, err = md3.Page(1, 10).All() + t.AssertNil(err) + t.Assert(len(all), 3) + }) +} + +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_AllAndCount(t *testing.T) { + table := createInitTable() + defer dropTable(table) + tableName2 := "user_" + gtime.Now().TimestampNanoStr() + if _, err := db.Exec(ctx, fmt.Sprintf(` + CREATE TABLE %s ( + id INTEGER PRIMARY KEY AUTOINCREMENT + UNIQUE + NOT NULL, + name varchar(45) NULL, + age int(10) + ); + `, tableName2, + )); err != nil { + gtest.AssertNil(err) + } + defer dropTable(tableName2) + r, err := db.Insert(ctx, tableName2, g.Map{ + "id": 1, + "name": "table2_1", + "age": 18, + }) + gtest.AssertNil(err) + n, _ := r.RowsAffected() + gtest.Assert(n, 1) + + // AllAndCount with all data + gtest.C(t, func(t *gtest.T) { + result, count, err := db.Model(table).AllAndCount(false) + t.AssertNil(err) + t.Assert(len(result), TableSize) + t.Assert(count, TableSize) + }) + // AllAndCount with no data + gtest.C(t, func(t *gtest.T) { + result, count, err := db.Model(table).Where("id<0").AllAndCount(false) + t.Assert(result, nil) + t.AssertNil(err) + t.Assert(count, 0) + }) + // AllAndCount with page + gtest.C(t, func(t *gtest.T) { + result, count, err := db.Model(table).Page(1, 5).AllAndCount(false) + t.AssertNil(err) + t.Assert(len(result), 5) + t.Assert(count, TableSize) + }) + // AllAndCount with normal result + gtest.C(t, func(t *gtest.T) { + result, count, err := db.Model(table).Where("id=?", 1).AllAndCount(false) + t.AssertNil(err) + t.Assert(count, 1) + t.Assert(result[0]["id"], 1) + t.Assert(result[0]["nickname"], "name_1") + t.Assert(result[0]["passport"], "user_1") + }) + // AllAndCount with distinct + gtest.C(t, func(t *gtest.T) { + result, count, err := db.Model(table).Fields("DISTINCT nickname").AllAndCount(true) + t.AssertNil(err) + t.Assert(count, TableSize) + t.Assert(result[0]["nickname"], "name_1") + t.AssertNil(result[0]["id"]) + }) + // AllAndCount with Join + gtest.C(t, func(t *gtest.T) { + all, count, err := db.Model(table).As("u1"). + LeftJoin(tableName2, "u2", "u2.id=u1.id"). + Fields("u1.passport,u1.id,u2.name,u2.age"). + Where("u1.id<2"). + AllAndCount(false) + t.AssertNil(err) + t.Assert(len(all), 1) + t.Assert(len(all[0]), 4) + t.Assert(all[0]["id"], 1) + t.Assert(all[0]["age"], 18) + t.Assert(all[0]["name"], "table2_1") + t.Assert(all[0]["passport"], "user_1") + t.Assert(count, 1) + }) + // AllAndCount with Join return CodeDbOperationError + gtest.C(t, func(t *gtest.T) { + all, count, err := db.Model(table).As("u1"). + LeftJoin(tableName2, "u2", "u2.id=u1.id"). + Fields("u1.passport,u1.id,u2.name,u2.age"). + Where("u1.id<2"). + AllAndCount(true) + t.AssertNE(err, nil) + t.AssertEQ(gerror.Code(err), gcode.CodeDbOperationError) + t.Assert(count, 0) + t.Assert(all, nil) + }) +} + +func Test_Model_Fields(t *testing.T) { + tableName1 := createInitTable() + defer dropTable(tableName1) + + tableName2 := "user_" + gtime.Now().TimestampNanoStr() + if _, err := db.Exec(ctx, fmt.Sprintf(` + CREATE TABLE %s ( + id INTEGER PRIMARY KEY AUTOINCREMENT + UNIQUE + NOT NULL, + name varchar(45) NULL, + age int(10) + ); + `, tableName2, + )); err != nil { + gtest.AssertNil(err) + } + defer dropTable(tableName2) + + r, err := db.Insert(ctx, tableName2, g.Map{ + "id": 1, + "name": "table2_1", + "age": 18, + }) + gtest.AssertNil(err) + n, _ := r.RowsAffected() + gtest.Assert(n, 1) + + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(tableName1).As("u").Fields("u.passport,u.id").Where("u.id<2").All() + t.AssertNil(err) + t.Assert(len(all), 1) + t.Assert(len(all[0]), 2) + }) + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(tableName1).As("u1"). + LeftJoin(tableName1, "u2", "u2.id=u1.id"). + Fields("u1.passport,u1.id,u2.id AS u2id"). + Where("u1.id<2"). + All() + t.AssertNil(err) + t.Assert(len(all), 1) + t.Assert(len(all[0]), 3) + }) + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(tableName1).As("u1"). + LeftJoin(tableName2, "u2", "u2.id=u1.id"). + Fields("u1.passport,u1.id,u2.name,u2.age"). + Where("u1.id<2"). + All() + t.AssertNil(err) + t.Assert(len(all), 1) + t.Assert(len(all[0]), 4) + t.Assert(all[0]["id"], 1) + t.Assert(all[0]["age"], 18) + t.Assert(all[0]["name"], "table2_1") + t.Assert(all[0]["passport"], "user_1") + }) +} + +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) + t.Assert(all.Array("id"), g.Slice{1, 2, 3}) + 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, int64(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, int64(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, int64(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, int64(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, int64(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") + t.Assert(user.CreateTime.String(), CreateTime) + }) + 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") + t.Assert(user.CreateTime.String(), CreateTime) + }) + // 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") + t.Assert(user.CreateTime.String(), CreateTime) + }) + // 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") + t.Assert(user.CreateTime.String(), CreateTime) + }) + // 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_Struct_CustomType(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + type MyInt int + + gtest.C(t, func(t *gtest.T) { + type User struct { + Id MyInt + 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") + t.Assert(user.CreateTime.String(), CreateTime) + }) +} + +func Test_Model_Structs(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.Model(table).Order("id asc").Scan(&users) + if err != nil { + gtest.Error(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") + t.Assert(users[0].CreateTime.String(), CreateTime) + }) + // Auto create struct slice. + 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) + if err != nil { + gtest.Error(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") + t.Assert(users[0].CreateTime.String(), CreateTime) + }) + // Just using Scan. + 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) + if err != nil { + gtest.Error(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") + t.Assert(users[0].CreateTime.String(), CreateTime) + }) + // sql.ErrNoRows + 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).Where("id<0").Scan(&users) + t.AssertNil(err) + }) +} + +func Test_Model_StructsWithOrmTag(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + db.SetDebug(true) + defer db.SetDebug(false) + type User struct { + Uid int `orm:"id"` + Passport string + Password string `orm:"password"` + Name string `orm:"nickname"` + Time gtime.Time `orm:"create_time"` + } + var ( + users []User + buffer = bytes.NewBuffer(nil) + ) + db.GetLogger().(*glog.Logger).SetWriter(buffer) + defer db.GetLogger().(*glog.Logger).SetWriter(os.Stdout) + db.Model(table).Order("id asc").Scan(&users) + // fmt.Println(buffer.String()) + t.Assert( + gstr.Contains(buffer.String(), "SELECT `id`,`passport`,`password`,`nickname`,`create_time` FROM `user"), + true, + ) + }) + + gtest.C(t, func(t *gtest.T) { + type A struct { + Passport string + Password string + } + type B struct { + A + NickName string + } + one, err := db.Model(table).Fields(&B{}).Where("id", 2).One() + t.AssertNil(err) + t.Assert(len(one), 3) + t.Assert(one["nickname"], "name_2") + t.Assert(one["passport"], "user_2") + t.Assert(one["password"], "pass_2") + }) +} + +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") + t.Assert(user.CreateTime.String(), CreateTime) + }) + 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") + t.Assert(user.CreateTime.String(), CreateTime) + }) + 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") + t.Assert(users[0].CreateTime.String(), CreateTime) + }) + 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") + t.Assert(users[0].CreateTime.String(), CreateTime) + }) + // 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_ScanAndCount(t *testing.T) { + table := createInitTable() + defer dropTable(table) + tableName2 := "user_" + gtime.Now().TimestampNanoStr() + if _, err := db.Exec(ctx, fmt.Sprintf(` + CREATE TABLE %s ( + id INTEGER PRIMARY KEY AUTOINCREMENT + UNIQUE + NOT NULL, + name varchar(45) NULL, + age int(10) + ); + `, tableName2, + )); err != nil { + gtest.AssertNil(err) + } + defer dropTable(tableName2) + r, err := db.Insert(ctx, tableName2, g.Map{ + "id": 1, + "name": "table2_1", + "age": 18, + }) + gtest.AssertNil(err) + n, _ := r.RowsAffected() + gtest.Assert(n, 1) + + // ScanAndCount with normal struct result + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime *gtime.Time + } + user := new(User) + var count int + err := db.Model(table).Where("id=1").ScanAndCount(user, &count, true) + t.AssertNil(err) + t.Assert(user.NickName, "name_1") + t.Assert(user.CreateTime.String(), CreateTime) + t.Assert(count, 1) + }) + // ScanAndCount with normal array result + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime gtime.Time + } + var users []User + var count int + err := db.Model(table).Order("id asc").ScanAndCount(&users, &count, true) + 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") + t.Assert(users[0].CreateTime.String(), CreateTime) + t.Assert(count, len(users)) + }) + // 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) + ) + var count1 int + var count2 int + err1 := db.Model(table).Where("id < 0").ScanAndCount(user, &count1, true) + err2 := db.Model(table).Where("id < 0").ScanAndCount(users, &count2, true) + t.Assert(count1, 0) + t.Assert(count2, 0) + t.Assert(err1, nil) + t.Assert(err2, nil) + }) + // ScanAndCount with page + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime gtime.Time + } + var users []User + var count int + err := db.Model(table).Order("id asc").Page(1, 3).ScanAndCount(&users, &count, true) + t.AssertNil(err) + t.Assert(len(users), 3) + t.Assert(count, TableSize) + }) + // ScanAndCount with distinct + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime gtime.Time + } + var users []User + var count int + err = db.Model(table).Fields("distinct id").ScanAndCount(&users, &count, true) + t.AssertNil(err) + t.Assert(len(users), 10) + t.Assert(count, TableSize) + t.Assert(users[0].Id, 1) + }) + // ScanAndCount with join + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Name string + Age int + } + var users []User + var count int + err = db.Model(table).As("u1"). + LeftJoin(tableName2, "u2", "u2.id=u1.id"). + Fields("u1.passport,u1.id,u2.name,u2.age"). + Where("u1.id<2"). + ScanAndCount(&users, &count, false) + t.AssertNil(err) + t.Assert(len(users), 1) + t.Assert(count, 1) + t.AssertEQ(users[0].Name, "table2_1") + }) + // ScanAndCount with join return CodeDbOperationError + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Name string + Age int + } + var users []User + var count int + err = db.Model(table).As("u1"). + LeftJoin(tableName2, "u2", "u2.id=u1.id"). + Fields("u1.passport,u1.id,u2.name,u2.age"). + Where("u1.id<2"). + ScanAndCount(&users, &count, true) + t.AssertNE(err, nil) + t.Assert(gerror.Code(err), gcode.CodeDbOperationError) + t.Assert(count, 0) + t.AssertEQ(users, nil) + }) +} + +func Test_Model_Scan_NilSliceAttrWhenNoRecordsFound(t *testing.T) { + table := createTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime gtime.Time + } + type Response struct { + Users []User `json:"users"` + } + var res Response + err := db.Model(table).Scan(&res.Users) + t.AssertNil(err) + t.Assert(res.Users, nil) + }) +} + +func Test_Model_OrderBy(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Order("id DESC").All() + t.AssertNil(err) + t.Assert(len(result), TableSize) + t.Assert(result[0]["nickname"].String(), fmt.Sprintf("name_%d", TableSize)) + }) + + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Order("NULL").All() + t.AssertNil(err) + t.Assert(len(result), TableSize) + t.Assert(result[0]["nickname"].String(), "name_1") + }) + +} + +func Test_Model_GroupBy(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Group("id").All() + t.AssertNil(err) + t.Assert(len(result), TableSize) + t.Assert(result[0]["nickname"].String(), "name_1") + }) +} + +func Test_Model_Data(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + table := createInitTable() + defer dropTable(table) + result, err := db.Model(table).Data("nickname=?", "test").Where("id=?", 3).Update() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + }) + gtest.C(t, func(t *gtest.T) { + table := createTable() + defer dropTable(table) + users := make([]g.MapStrAny, 0) + for i := 1; i <= 10; i++ { + users = append(users, g.MapStrAny{ + "id": i, + "passport": fmt.Sprintf(`passport_%d`, i), + "password": fmt.Sprintf(`password_%d`, i), + "nickname": fmt.Sprintf(`nickname_%d`, i), + "create_time": gtime.Now().String(), + }) + } + result, err := db.Model(table).Data(users).Batch(2).Insert() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 10) + }) + gtest.C(t, func(t *gtest.T) { + table := createTable() + defer dropTable(table) + users := garray.New() + for i := 1; i <= 10; i++ { + users.Append(g.MapStrAny{ + "id": i, + "passport": fmt.Sprintf(`passport_%d`, i), + "password": fmt.Sprintf(`password_%d`, i), + "nickname": fmt.Sprintf(`nickname_%d`, i), + "create_time": gtime.Now().String(), + }) + } + result, err := db.Model(table).Data(users).Batch(2).Insert() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 10) + }) +} + +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, + "create_time > 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, + "create_time > ?": 0, + "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_Where_ISNULL_1(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + // db.SetDebug(true) + result, err := db.Model(table).Data("nickname", nil).Where("id", 2).Update() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + + one, err := db.Model(table).Where("nickname", nil).One() + t.AssertNil(err) + t.Assert(one.IsEmpty(), false) + t.Assert(one["id"], 2) + }) +} + +func Test_Model_Where_ISNULL_2(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + // complicated one. + 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, + "create_time > 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) + }) +} + +func Test_Model_Where_OmitEmpty(t *testing.T) { + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + conditions := g.Map{ + "id < 4": "", + } + result, err := db.Model(table).Where(conditions).Order("id desc").All() + t.AssertNil(err) + t.Assert(len(result), 3) + t.Assert(result[0]["id"].Int(), 3) + }) + gtest.C(t, func(t *gtest.T) { + conditions := g.Map{ + "id < 4": "", + } + result, err := db.Model(table).Where(conditions).OmitEmpty().Order("id desc").All() + t.AssertNil(err) + t.Assert(len(result), 10) + t.Assert(result[0]["id"].Int(), 10) + }) +} + +func Test_Model_Where_GTime(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where("create_time>?", gtime.NewFromStr("2010-09-01")).All() + t.AssertNil(err) + t.Assert(len(result), 10) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where("create_time>?", *gtime.NewFromStr("2010-09-01")).All() + t.AssertNil(err) + t.Assert(len(result), 10) + }) +} + +func Test_Model_WherePri(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + // primary key + gtest.C(t, func(t *gtest.T) { + one, err := db.Model(table).WherePri(3).One() + t.AssertNil(err) + t.AssertNE(one, nil) + t.Assert(one["id"].Int(), 3) + }) + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).WherePri(g.Slice{3, 9}).Order("id asc").All() + t.AssertNil(err) + t.Assert(len(all), 2) + t.Assert(all[0]["id"].Int(), 3) + t.Assert(all[1]["id"].Int(), 9) + }) + + // string + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).WherePri("id=? and nickname=?", 3, "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).WherePri("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).WherePri(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).WherePri(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).WherePri(g.Map{ + "id": g.Slice{1, 2, 3}, + "passport": g.Slice{"user_2", "user_3"}, + }).WhereOr("nickname=?", g.Slice{"name_4"}).Where("id", 3).One() + t.AssertNil(err) + t.AssertGT(len(result), 0) + t.Assert(result["id"].Int(), 2) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).WherePri("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).WherePri("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).WherePri("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).WherePri("id", 3).WherePri("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).WherePri("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).WherePri("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).WherePri("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).WherePri("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).WherePri("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).WherePri("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).WherePri("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).WherePri(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).WherePri(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).WherePri(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).WherePri(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).WherePri(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).WherePri(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).WherePri(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).WherePri(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, + "create_time > 0": nil, + "id": g.Slice{1, 2, 3}, + } + result, err := db.Model(table).WherePri(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, + "create_time > ?": 0, + "id in(?)": g.Slice{1, 2, 3}, + } + result, err := db.Model(table).WherePri(conditions).Order("id asc").All() + t.AssertNil(err) + t.Assert(len(result), 3) + t.Assert(result[0]["id"].Int(), 1) + }) + // struct + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int `json:"id"` + Nickname string `gconv:"nickname"` + } + result, err := db.Model(table).WherePri(User{3, "name_3"}).One() + t.AssertNil(err) + t.Assert(result["id"].Int(), 3) + + result, err = db.Model(table).WherePri(&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).WherePri("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).WherePri("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).WherePri(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).WherePri(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) + + // DELETE...LIMIT + // https://github.com/mattn/go-sqlite3/pull/802 + // gtest.C(t, func(t *gtest.T) { + // result, err := db.Model(table).Where(1).Limit(2).Delete() + // t.AssertNil(err) + // n, _ := result.RowsAffected() + // t.Assert(n, 2) + // }) + + gtest.C(t, func(t *gtest.T) { + table := createInitTable() + defer dropTable(table) + result, err := db.Model(table).Where(1).Delete() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, TableSize) + }) +} + +func Test_Model_Offset(t *testing.T) { + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Limit(2).Offset(5).Order("id").All() + t.AssertNil(err) + t.Assert(len(result), 2) + t.Assert(result[0]["id"], 6) + t.Assert(result[1]["id"], 7) + }) +} + +func Test_Model_Page(t *testing.T) { + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Page(3, 3).Order("id").All() + t.AssertNil(err) + t.Assert(len(result), 3) + t.Assert(result[0]["id"], 7) + t.Assert(result[1]["id"], 8) + }) + gtest.C(t, func(t *gtest.T) { + model := db.Model(table).Safe().Order("id") + all, err := model.Page(3, 3).All() + t.AssertNil(err) + count, err := model.Count() + t.AssertNil(err) + t.Assert(len(all), 3) + t.Assert(all[0]["id"], "7") + t.Assert(count, int64(TableSize)) + }) +} + +func Test_Model_Option_Map(t *testing.T) { + // Insert + gtest.C(t, func(t *gtest.T) { + table := createTable() + defer dropTable(table) + r, err := db.Model(table).Fields("id, passport", "password", "create_time").Data(g.Map{ + "id": 1, + "passport": "1", + "password": "1", + "nickname": "1", + "create_time": gtime.Now().String(), + }).Insert() + t.AssertNil(err) + n, _ := r.RowsAffected() + t.Assert(n, 1) + one, err := db.Model(table).Where("id", 1).One() + t.AssertNil(err) + t.AssertNE(one["password"].String(), "2") + t.AssertNE(one["nickname"].String(), "2") + t.Assert(one["passport"].String(), "1") + }) + gtest.C(t, func(t *gtest.T) { + table := createTable() + defer dropTable(table) + r, err := db.Model(table).OmitEmptyData().Data(g.Map{ + "id": 1, + "passport": "1", + "password": "1", + "nickname": "", + "create_time": gtime.Now().String(), + }).Insert() + t.AssertNil(err) + n, _ := r.RowsAffected() + t.Assert(n, 1) + one, err := db.Model(table).Where("id", 1).One() + t.AssertNil(err) + t.AssertNE(one["passport"].String(), "0") + t.AssertNE(one["password"].String(), "0") + t.Assert(one["nickname"].String(), "") + }) + + // Replace + gtest.C(t, func(t *gtest.T) { + table := createInitTable() + defer dropTable(table) + _, err := db.Model(table).OmitEmptyData().Data(g.Map{ + "id": 1, + "passport": 0, + "password": 0, + "nickname": "1", + }).Replace() + t.AssertNil(err) + one, err := db.Model(table).Where("id", 1).One() + t.AssertNil(err) + t.AssertNE(one["passport"].String(), "0") + t.AssertNE(one["password"].String(), "0") + t.Assert(one["nickname"].String(), "1") + }) + + // Update + gtest.C(t, func(t *gtest.T) { + table := createInitTable() + defer dropTable(table) + + r, err := db.Model(table).Data(g.Map{"nickname": ""}).Where("id", 1).Update() + t.AssertNil(err) + n, _ := r.RowsAffected() + t.Assert(n, 1) + + _, err = db.Model(table).OmitEmptyData().Data(g.Map{"nickname": ""}).Where("id", 2).Update() + t.AssertNE(err, nil) + + r, err = db.Model(table).OmitEmpty().Data(g.Map{"nickname": "", "password": "123"}).Where("id", 3).Update() + t.AssertNil(err) + n, _ = r.RowsAffected() + t.Assert(n, 1) + + _, err = db.Model(table).OmitEmpty().Fields("nickname").Data(g.Map{"nickname": "", "password": "123"}).Where("id", 4).Update() + t.AssertNE(err, nil) + + r, err = db.Model(table).OmitEmpty(). + Fields("password").Data(g.Map{ + "nickname": "", + "passport": "123", + "password": "456", + }).Where("id", 5).Update() + t.AssertNil(err) + n, _ = r.RowsAffected() + t.Assert(n, 1) + + one, err := db.Model(table).Where("id", 5).One() + t.AssertNil(err) + t.Assert(one["password"], "456") + t.AssertNE(one["passport"].String(), "") + t.AssertNE(one["passport"].String(), "123") + }) +} + +func Test_Model_Option_Where(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + table := createInitTable() + defer dropTable(table) + r, err := db.Model(table).OmitEmpty().Data("nickname", 1).Where(g.Map{"id": 0, "passport": ""}).Where(1).Update() + t.AssertNil(err) + n, _ := r.RowsAffected() + t.Assert(n, TableSize) + }) +} + +func Test_Model_Where_MultiSliceArguments(t *testing.T) { + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + r, err := db.Model(table).Where(g.Map{ + "id": g.Slice{1, 2, 3, 4}, + "passport": g.Slice{"user_2", "user_3", "user_4"}, + "nickname": g.Slice{"name_2", "name_4"}, + "id >= 4": nil, + }).All() + t.AssertNil(err) + t.Assert(len(r), 1) + t.Assert(r[0]["id"], 4) + }) + + 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"}, + }).WhereOr("nickname=?", g.Slice{"name_4"}).Where("id", 3).One() + t.AssertNil(err) + t.AssertGT(len(result), 0) + t.Assert(result["id"].Int(), 2) + }) +} + +func Test_Model_FieldsEx(t *testing.T) { + table := createInitTable() + defer dropTable(table) + // Select. + gtest.C(t, func(t *gtest.T) { + r, err := db.Model(table).FieldsEx("create_time, id").Where("id in (?)", g.Slice{1, 2}).Order("id asc").All() + t.AssertNil(err) + t.Assert(len(r), 2) + t.Assert(len(r[0]), 3) + t.Assert(r[0]["id"], "") + t.Assert(r[0]["passport"], "user_1") + t.Assert(r[0]["password"], "pass_1") + t.Assert(r[0]["nickname"], "name_1") + t.Assert(r[0]["create_time"], "") + t.Assert(r[1]["id"], "") + t.Assert(r[1]["passport"], "user_2") + t.Assert(r[1]["password"], "pass_2") + t.Assert(r[1]["nickname"], "name_2") + t.Assert(r[1]["create_time"], "") + }) + // Update. + gtest.C(t, func(t *gtest.T) { + r, err := db.Model(table).FieldsEx("password").Data(g.Map{"nickname": "123", "password": "456"}).Where("id", 3).Update() + t.AssertNil(err) + n, _ := r.RowsAffected() + t.Assert(n, 1) + + one, err := db.Model(table).Where("id", 3).One() + t.AssertNil(err) + t.Assert(one["nickname"], "123") + t.AssertNE(one["password"], "456") + }) +} + +func Test_Model_Prefix(t *testing.T) { + db := dbPrefix + noPrefixName := fmt.Sprintf(`%s_%d`, TableName, gtime.TimestampNano()) + table := TableNamePrefix + noPrefixName + createInitTableWithDb(db, table) + defer dropTable(table) + // Select. + gtest.C(t, func(t *gtest.T) { + r, err := db.Model(noPrefixName).Where("id in (?)", g.Slice{1, 2}).Order("id asc").All() + t.AssertNil(err) + t.Assert(len(r), 2) + t.Assert(r[0]["id"], "1") + t.Assert(r[1]["id"], "2") + }) + // Select with alias. + gtest.C(t, func(t *gtest.T) { + r, err := db.Model(noPrefixName+" as u").Where("u.id in (?)", g.Slice{1, 2}).Order("u.id asc").All() + t.AssertNil(err) + t.Assert(len(r), 2) + t.Assert(r[0]["id"], "1") + t.Assert(r[1]["id"], "2") + }) + // Select with alias to struct. + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + } + var users []User + err := db.Model(noPrefixName+" u").Where("u.id in (?)", g.Slice{1, 5}).Order("u.id asc").Scan(&users) + t.AssertNil(err) + t.Assert(len(users), 2) + t.Assert(users[0].Id, 1) + t.Assert(users[1].Id, 5) + }) + // Select with alias and join statement. + gtest.C(t, func(t *gtest.T) { + r, err := db.Model(noPrefixName+" as u1").LeftJoin(noPrefixName+" as u2", "u2.id=u1.id").Where("u1.id in (?)", g.Slice{1, 2}).Order("u1.id asc").All() + t.AssertNil(err) + t.Assert(len(r), 2) + t.Assert(r[0]["id"], "1") + t.Assert(r[1]["id"], "2") + }) + gtest.C(t, func(t *gtest.T) { + r, err := db.Model(noPrefixName).As("u1").LeftJoin(noPrefixName+" as u2", "u2.id=u1.id").Where("u1.id in (?)", g.Slice{1, 2}).Order("u1.id asc").All() + t.AssertNil(err) + t.Assert(len(r), 2) + t.Assert(r[0]["id"], "1") + t.Assert(r[1]["id"], "2") + }) +} + +func Test_Model_FieldsExStruct(t *testing.T) { + table := createTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int `orm:"id" json:"id"` + Passport string `orm:"passport" json:"pass_port"` + Password string `orm:"password" json:"password"` + NickName string `orm:"nickname" json:"nick__name"` + Time time.Time `orm:"create_time" ` + } + user := &User{ + Id: 1, + Passport: "111", + Password: "222", + NickName: "333", + Time: time.Now(), + } + r, err := db.Model(table).FieldsEx("nickname").OmitEmpty().Data(user).Insert() + t.AssertNil(err) + n, err := r.RowsAffected() + t.AssertNil(err) + t.Assert(n, 1) + }) + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int `orm:"id" json:"id"` + Passport string `orm:"passport" json:"pass_port"` + Password string `orm:"password" json:"password"` + NickName string `orm:"nickname" json:"nick__name"` + Time time.Time `orm:"create_time" ` + } + users := make([]*User, 0) + for i := 100; i < 110; i++ { + users = append(users, &User{ + Id: i, + Passport: fmt.Sprintf(`passport_%d`, i), + Password: fmt.Sprintf(`password_%d`, i), + NickName: fmt.Sprintf(`nickname_%d`, i), + Time: time.Now(), + }) + } + r, err := db.Model(table).FieldsEx("nickname"). + OmitEmpty(). + Batch(2). + Data(users). + Insert() + t.AssertNil(err) + n, err := r.RowsAffected() + t.AssertNil(err) + t.Assert(n, 10) + }) +} + +func Test_Model_OmitEmpty_Time(t *testing.T) { + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int `orm:"id" json:"id"` + Passport string `orm:"password" json:"pass_port"` + Password string `orm:"password" json:"password"` + Time time.Time `orm:"create_time" ` + } + user := &User{ + Id: 1, + Passport: "111", + Password: "222", + Time: time.Time{}, + } + r, err := db.Model(table).OmitEmpty().Data(user).Where("id", 1).Update() + t.AssertNil(err) + n, err := r.RowsAffected() + t.AssertNil(err) + t.Assert(n, 1) + }) +} + +func Test_Result_Chunk(t *testing.T) { + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + r, err := db.Model(table).Order("id asc").All() + t.AssertNil(err) + chunks := r.Chunk(3) + t.Assert(len(chunks), 4) + t.Assert(chunks[0][0]["id"].Int(), 1) + t.Assert(chunks[1][0]["id"].Int(), 4) + t.Assert(chunks[2][0]["id"].Int(), 7) + t.Assert(chunks[3][0]["id"].Int(), 10) + }) +} + +func Test_Model_DryRun(t *testing.T) { + table := createInitTable() + defer dropTable(table) + db.SetDryRun(true) + defer db.SetDryRun(false) + + gtest.C(t, func(t *gtest.T) { + one, err := db.Model(table).WherePri(1).One() + t.AssertNil(err) + t.Assert(one["id"], 1) + }) + gtest.C(t, func(t *gtest.T) { + r, err := db.Model(table).Data("passport", "port_1").WherePri(1).Update() + t.AssertNil(err) + n, err := r.RowsAffected() + t.AssertNil(err) + t.Assert(n, 0) + }) +} + +func Test_Model_Join_SubQuery(t *testing.T) { + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + subQuery := fmt.Sprintf("select * from `%s`", table) + r, err := db.Model(table, "t1").Fields("t2.id").LeftJoin(subQuery, "t2", "t2.id=t1.id").Array() + t.AssertNil(err) + t.Assert(len(r), TableSize) + t.Assert(r[0], "1") + t.Assert(r[TableSize-1], TableSize) + }) +} + +func Test_Model_Cache(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + one, err := db.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test1", + Force: false, + }).WherePri(1).One() + t.AssertNil(err) + t.Assert(one["passport"], "user_1") + + r, err := db.Model(table).Data("passport", "user_100").WherePri(1).Update() + t.AssertNil(err) + n, err := r.RowsAffected() + t.AssertNil(err) + t.Assert(n, 1) + + one, err = db.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test1", + Force: false, + }).WherePri(1).One() + t.AssertNil(err) + t.Assert(one["passport"], "user_1") + + time.Sleep(time.Second * 2) + + one, err = db.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test1", + Force: false, + }).WherePri(1).One() + t.AssertNil(err) + t.Assert(one["passport"], "user_100") + }) + gtest.C(t, func(t *gtest.T) { + one, err := db.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test2", + Force: false, + }).WherePri(2).One() + t.AssertNil(err) + t.Assert(one["passport"], "user_2") + + r, err := db.Model(table).Data("passport", "user_200").Cache(gdb.CacheOption{ + Duration: -1, + Name: "test2", + Force: false, + }).WherePri(2).Update() + t.AssertNil(err) + n, err := r.RowsAffected() + t.AssertNil(err) + t.Assert(n, 1) + + one, err = db.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test2", + Force: false, + }).WherePri(2).One() + t.AssertNil(err) + t.Assert(one["passport"], "user_200") + }) + // transaction. + gtest.C(t, func(t *gtest.T) { + // make cache for id 3 + one, err := db.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test3", + Force: false, + }).WherePri(3).One() + t.AssertNil(err) + t.Assert(one["passport"], "user_3") + + r, err := db.Model(table).Data("passport", "user_300").Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test3", + Force: false, + }).WherePri(3).Update() + t.AssertNil(err) + n, err := r.RowsAffected() + t.AssertNil(err) + t.Assert(n, 1) + + err = db.Transaction(context.TODO(), func(ctx context.Context, tx gdb.TX) error { + one, err := tx.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test3", + Force: false, + }).WherePri(3).One() + t.AssertNil(err) + t.Assert(one["passport"], "user_300") + return nil + }) + t.AssertNil(err) + + one, err = db.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test3", + Force: false, + }).WherePri(3).One() + t.AssertNil(err) + t.Assert(one["passport"], "user_3") + }) + gtest.C(t, func(t *gtest.T) { + // make cache for id 4 + one, err := db.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test4", + Force: false, + }).WherePri(4).One() + t.AssertNil(err) + t.Assert(one["passport"], "user_4") + + r, err := db.Model(table).Data("passport", "user_400").Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test3", + Force: false, + }).WherePri(4).Update() + t.AssertNil(err) + n, err := r.RowsAffected() + t.AssertNil(err) + t.Assert(n, 1) + + err = db.Transaction(context.TODO(), func(ctx context.Context, tx gdb.TX) error { + // Cache feature disabled. + one, err := tx.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test4", + Force: false, + }).WherePri(4).One() + t.AssertNil(err) + t.Assert(one["passport"], "user_400") + // Update the cache. + r, err := tx.Model(table).Data("passport", "user_4000"). + Cache(gdb.CacheOption{ + Duration: -1, + Name: "test4", + Force: false, + }).WherePri(4).Update() + t.AssertNil(err) + n, err := r.RowsAffected() + t.AssertNil(err) + t.Assert(n, 1) + return nil + }) + t.AssertNil(err) + // Read from db. + one, err = db.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test4", + Force: false, + }).WherePri(4).One() + t.AssertNil(err) + t.Assert(one["passport"], "user_4000") + }) +} + +func Test_Model_Having(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).Where("id > 1").Group("id").Having("id > 8").All() + t.AssertNil(err) + t.Assert(len(all), 2) + }) + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).Where("id > 1").Group("id").Having("id > ?", 8).All() + t.AssertNil(err) + t.Assert(len(all), 2) + }) + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).Where("id > ?", 1).Group("id").Having("id > ?", 8).All() + t.AssertNil(err) + t.Assert(len(all), 2) + }) + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).Where("id > ?", 1).Group("id").Having("id", 8).All() + t.AssertNil(err) + t.Assert(len(all), 1) + }) +} + +func Test_Model_Distinct(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table, "t").Fields("distinct t.id").Where("id > 1").Group("id").Having("id > 8").All() + t.AssertNil(err) + t.Assert(len(all), 2) + }) + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Where("id > 1").Distinct().Count() + t.AssertNil(err) + t.Assert(count, int64(9)) + }) +} + +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_Fields_AutoMapping(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + value, err := db.Model(table).Fields("ID").Where("id", 2).Value() + t.AssertNil(err) + t.Assert(value.Int(), 2) + }) + + gtest.C(t, func(t *gtest.T) { + value, err := db.Model(table).Fields("NICK_NAME").Where("id", 2).Value() + t.AssertNil(err) + t.Assert(value.String(), "name_2") + }) + // Map + gtest.C(t, func(t *gtest.T) { + one, err := db.Model(table).Fields(g.Map{ + "ID": 1, + "NICK_NAME": 1, + }).Where("id", 2).One() + t.AssertNil(err) + t.Assert(len(one), 2) + t.Assert(one["id"], 2) + t.Assert(one["nickname"], "name_2") + }) + // Struct + gtest.C(t, func(t *gtest.T) { + type T struct { + ID int + NICKNAME int + } + one, err := db.Model(table).Fields(&T{ + ID: 0, + NICKNAME: 0, + }).Where("id", 2).One() + t.AssertNil(err) + t.Assert(len(one), 2) + t.Assert(one["id"], 2) + t.Assert(one["nickname"], "name_2") + }) +} + +func Test_Model_FieldsEx_AutoMapping(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + // "id": i, + // "passport": fmt.Sprintf(`user_%d`, i), + // "password": fmt.Sprintf(`pass_%d`, i), + // "nickname": fmt.Sprintf(`name_%d`, i), + // "create_time": gtime.NewFromStr(CreateTime).String(), + + gtest.C(t, func(t *gtest.T) { + value, err := db.Model(table).FieldsEx("Passport, Password, NickName, CreateTime").Where("id", 2).Value() + t.AssertNil(err) + t.Assert(value.Int(), 2) + }) + + gtest.C(t, func(t *gtest.T) { + value, err := db.Model(table).FieldsEx("ID, Passport, Password, CreateTime").Where("id", 2).Value() + t.AssertNil(err) + t.Assert(value.String(), "name_2") + }) + // Map + gtest.C(t, func(t *gtest.T) { + one, err := db.Model(table).FieldsEx(g.Map{ + "Passport": 1, + "Password": 1, + "CreateTime": 1, + }).Where("id", 2).One() + t.AssertNil(err) + t.Assert(len(one), 2) + t.Assert(one["id"], 2) + t.Assert(one["nickname"], "name_2") + }) + // Struct + gtest.C(t, func(t *gtest.T) { + type T struct { + Passport int + Password int + CreateTime int + } + one, err := db.Model(table).FieldsEx(&T{ + Passport: 0, + Password: 0, + CreateTime: 0, + }).Where("id", 2).One() + t.AssertNil(err) + t.Assert(len(one), 2) + t.Assert(one["id"], 2) + t.Assert(one["nickname"], "name_2") + }) +} + +func Test_Model_Fields_Struct(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + type A struct { + Passport string + Password string + } + type B struct { + A + NickName string + } + gtest.C(t, func(t *gtest.T) { + one, err := db.Model(table).Fields(A{}).Where("id", 2).One() + t.AssertNil(err) + t.Assert(len(one), 2) + t.Assert(one["passport"], "user_2") + t.Assert(one["password"], "pass_2") + }) + gtest.C(t, func(t *gtest.T) { + one, err := db.Model(table).Fields(&A{}).Where("id", 2).One() + t.AssertNil(err) + t.Assert(len(one), 2) + t.Assert(one["passport"], "user_2") + t.Assert(one["password"], "pass_2") + }) + gtest.C(t, func(t *gtest.T) { + one, err := db.Model(table).Fields(B{}).Where("id", 2).One() + t.AssertNil(err) + t.Assert(len(one), 3) + t.Assert(one["passport"], "user_2") + t.Assert(one["password"], "pass_2") + t.Assert(one["nickname"], "name_2") + }) + gtest.C(t, func(t *gtest.T) { + one, err := db.Model(table).Fields(&B{}).Where("id", 2).One() + t.AssertNil(err) + t.Assert(len(one), 3) + t.Assert(one["passport"], "user_2") + t.Assert(one["password"], "pass_2") + t.Assert(one["nickname"], "name_2") + }) +} + +// func Test_Model_NullField(t *testing.T) { +// table := createTable() +// defer dropTable(table) + +// gtest.C(t, func(t *gtest.T) { +// type User struct { +// Id int +// Passport *string +// } +// data := g.Map{ +// "id": 1, +// "passport": nil, +// } +// result, err := db.Model(table).Data(data).Insert() +// t.AssertNil(err) +// n, _ := result.RowsAffected() +// t.Assert(n, 1) +// one, err := db.Model(table).WherePri(1).One() +// t.AssertNil(err) + +// var user *User +// err = one.Struct(&user) +// t.AssertNil(err) +// t.Assert(user.Id, data["id"]) +// t.Assert(user.Passport, data["passport"]) +// }) +// } + +func Test_Model_Empty_Slice_Argument(t *testing.T) { + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where(`id`, g.Slice{}).All() + t.AssertNil(err) + t.Assert(len(result), 0) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where(`id in(?)`, g.Slice{}).All() + t.AssertNil(err) + t.Assert(len(result), 0) + }) +} + +func Test_Model_HasTable(t *testing.T) { + table := createTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + result, err := db.GetCore().HasTable(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) + }) +} + +// Issue: https://github.com/gogf/gf/issues/1002 +func Test_Model_Issue1002(t *testing.T) { + table := createTable() + defer dropTable(table) + + result, err := db.Model(table).Data(g.Map{ + "id": 1, + "passport": "port_1", + "password": "pass_1", + "nickname": "name_2", + "create_time": "2020-10-27 19:03:33", + }).Insert() + gtest.AssertNil(err) + n, _ := result.RowsAffected() + gtest.Assert(n, 1) + + // where + string. + gtest.C(t, func(t *gtest.T) { + v, err := db.Model(table).Fields("id").Where("create_time>'2020-10-27 19:03:32' and create_time<'2020-10-27 19:03:34'").Value() + t.AssertNil(err) + t.Assert(v.Int(), 1) + }) + gtest.C(t, func(t *gtest.T) { + v, err := db.Model(table).Fields("id").Where("create_time>'2020-10-27 19:03:32' and create_time<'2020-10-27 19:03:34'").Value() + t.AssertNil(err) + t.Assert(v.Int(), 1) + }) + // where + string arguments. + gtest.C(t, func(t *gtest.T) { + v, err := db.Model(table).Fields("id").Where("create_time>? and create_time? and create_time? and create_time