mirror of
https://gitee.com/johng/gf
synced 2026-06-28 10:16:09 +08:00
Merge branch 'master' into copilot/fix-3931
This commit is contained in:
@ -181,7 +181,7 @@ type DB interface {
|
||||
|
||||
// GetArray executes a query and returns the first column of all rows.
|
||||
// It's useful for queries like SELECT id FROM table.
|
||||
GetArray(ctx context.Context, sql string, args ...any) ([]Value, error)
|
||||
GetArray(ctx context.Context, sql string, args ...any) (Array, error)
|
||||
|
||||
// GetCount executes a COUNT query and returns the result as an integer.
|
||||
// It's a convenience method for counting rows.
|
||||
@ -673,6 +673,9 @@ type (
|
||||
// Value is the field value type.
|
||||
Value = *gvar.Var
|
||||
|
||||
// Array is the field value array type.
|
||||
Array = gvar.Vars
|
||||
|
||||
// Record is the row record of the table.
|
||||
Record map[string]Value
|
||||
|
||||
|
||||
@ -12,6 +12,7 @@ import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/v2/container/gmap"
|
||||
@ -174,7 +175,7 @@ func (c *Core) GetOne(ctx context.Context, sql string, args ...any) (Record, err
|
||||
|
||||
// GetArray queries and returns data values as slice from database.
|
||||
// Note that if there are multiple columns in the result, it returns just one column values randomly.
|
||||
func (c *Core) GetArray(ctx context.Context, sql string, args ...any) ([]Value, error) {
|
||||
func (c *Core) GetArray(ctx context.Context, sql string, args ...any) (Array, error) {
|
||||
all, err := c.db.DoSelect(ctx, nil, sql, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -446,25 +447,30 @@ func (c *Core) DoInsert(ctx context.Context, link Link, table string, list List,
|
||||
// It here uses ListMap to keep sequence for data inserting.
|
||||
// ============================================================================================
|
||||
var keyListMap = gmap.NewListMap()
|
||||
var tmpkeyListMap = make(map[string]List)
|
||||
for _, item := range list {
|
||||
var (
|
||||
tmpKeys = make([]string, 0)
|
||||
tmpKeysInSequenceStr string
|
||||
)
|
||||
mapLen := len(item)
|
||||
if mapLen == 0 {
|
||||
continue
|
||||
}
|
||||
tmpKeys := make([]string, 0, mapLen)
|
||||
for k := range item {
|
||||
tmpKeys = append(tmpKeys, k)
|
||||
}
|
||||
keys, err = c.fieldsToSequence(ctx, table, tmpKeys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if mapLen > 1 {
|
||||
sort.Strings(tmpKeys)
|
||||
}
|
||||
tmpKeysInSequenceStr = gstr.Join(keys, ",")
|
||||
if !keyListMap.Contains(tmpKeysInSequenceStr) {
|
||||
keyListMap.Set(tmpKeysInSequenceStr, make(List, 0))
|
||||
keys = tmpKeys // for fieldsToSequence
|
||||
|
||||
tmpKeysInSequenceStr := gstr.Join(tmpKeys, ",")
|
||||
if tmpkeyListMapItem, ok := tmpkeyListMap[tmpKeysInSequenceStr]; ok {
|
||||
tmpkeyListMap[tmpKeysInSequenceStr] = append(tmpkeyListMapItem, item)
|
||||
} else {
|
||||
tmpkeyListMap[tmpKeysInSequenceStr] = List{item}
|
||||
}
|
||||
tmpKeysInSequenceList := keyListMap.Get(tmpKeysInSequenceStr).(List)
|
||||
tmpKeysInSequenceList = append(tmpKeysInSequenceList, item)
|
||||
keyListMap.Set(tmpKeysInSequenceStr, tmpKeysInSequenceList)
|
||||
}
|
||||
for tmpKeysInSequenceStr, itemList := range tmpkeyListMap {
|
||||
keyListMap.Set(tmpKeysInSequenceStr, itemList)
|
||||
}
|
||||
if keyListMap.Size() > 1 {
|
||||
var (
|
||||
@ -488,6 +494,15 @@ func (c *Core) DoInsert(ctx context.Context, link Link, table string, list List,
|
||||
return &sqlResult, err
|
||||
}
|
||||
|
||||
keys, err = c.fieldsToSequence(ctx, table, keys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(keys) == 0 {
|
||||
return nil, gerror.NewCode(gcode.CodeInvalidParameter, "no valid data fields found in table")
|
||||
}
|
||||
|
||||
// Prepare the batch result pointer.
|
||||
var (
|
||||
charL, charR = c.db.GetChars()
|
||||
|
||||
@ -251,15 +251,47 @@ func AddDefaultConfigNode(node ConfigNode) error {
|
||||
}
|
||||
|
||||
// AddDefaultConfigGroup adds multiple node configurations to configuration of default group.
|
||||
//
|
||||
// Deprecated: Use SetDefaultConfigGroup instead.
|
||||
func AddDefaultConfigGroup(nodes ConfigGroup) error {
|
||||
return SetConfigGroup(DefaultGroupName, nodes)
|
||||
}
|
||||
|
||||
// SetDefaultConfigGroup sets multiple node configurations to configuration of default group.
|
||||
func SetDefaultConfigGroup(nodes ConfigGroup) error {
|
||||
return SetConfigGroup(DefaultGroupName, nodes)
|
||||
}
|
||||
|
||||
// GetConfig retrieves and returns the configuration of given group.
|
||||
//
|
||||
// Deprecated: Use GetConfigGroup instead.
|
||||
func GetConfig(group string) ConfigGroup {
|
||||
configGroup, _ := GetConfigGroup(group)
|
||||
return configGroup
|
||||
}
|
||||
|
||||
// GetConfigGroup retrieves and returns the configuration of given group.
|
||||
// It returns an error if the group does not exist, or an empty slice if the group exists but has no nodes.
|
||||
func GetConfigGroup(group string) (ConfigGroup, error) {
|
||||
configs.RLock()
|
||||
defer configs.RUnlock()
|
||||
return configs.config[group]
|
||||
|
||||
configGroup, exists := configs.config[group]
|
||||
if !exists {
|
||||
return nil, gerror.NewCodef(
|
||||
gcode.CodeInvalidParameter,
|
||||
`configuration group "%s" not found`,
|
||||
group,
|
||||
)
|
||||
}
|
||||
return configGroup, nil
|
||||
}
|
||||
|
||||
// GetAllConfig retrieves and returns all configurations.
|
||||
func GetAllConfig() Config {
|
||||
configs.RLock()
|
||||
defer configs.RUnlock()
|
||||
return configs.config
|
||||
}
|
||||
|
||||
// SetDefaultGroup sets the group name for default configuration.
|
||||
|
||||
@ -159,6 +159,10 @@ func (h *HookSelectInput) Next(ctx context.Context) (result Result, err error) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
h.Model.db.GetCore().schema = h.Schema
|
||||
defer func() {
|
||||
h.Model.db.GetCore().schema = h.originalSchemaName.String()
|
||||
}()
|
||||
}
|
||||
return h.Model.db.DoSelect(ctx, h.link, toBeCommittedSql, h.Args...)
|
||||
}
|
||||
@ -195,6 +199,10 @@ func (h *HookInsertInput) Next(ctx context.Context) (result sql.Result, err erro
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
h.Model.db.GetCore().schema = h.Schema
|
||||
defer func() {
|
||||
h.Model.db.GetCore().schema = h.originalSchemaName.String()
|
||||
}()
|
||||
}
|
||||
return h.Model.db.DoInsert(ctx, h.link, h.Table, h.Data, h.Option)
|
||||
}
|
||||
@ -238,6 +246,10 @@ func (h *HookUpdateInput) Next(ctx context.Context) (result sql.Result, err erro
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
h.Model.db.GetCore().schema = h.Schema
|
||||
defer func() {
|
||||
h.Model.db.GetCore().schema = h.originalSchemaName.String()
|
||||
}()
|
||||
}
|
||||
return h.Model.db.DoUpdate(ctx, h.link, h.Table, h.Data, h.Condition, h.Args...)
|
||||
}
|
||||
@ -281,6 +293,10 @@ func (h *HookDeleteInput) Next(ctx context.Context) (result sql.Result, err erro
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
h.Model.db.GetCore().schema = h.Schema
|
||||
defer func() {
|
||||
h.Model.db.GetCore().schema = h.originalSchemaName.String()
|
||||
}()
|
||||
}
|
||||
return h.Model.db.DoDelete(ctx, h.link, h.Table, h.Condition, h.Args...)
|
||||
}
|
||||
|
||||
@ -126,7 +126,7 @@ func (m *Model) One(where ...any) (Record, error) {
|
||||
// If the optional parameter `fieldsAndWhere` is given, the fieldsAndWhere[0] is the selected fields
|
||||
// and fieldsAndWhere[1:] is treated as where condition fields.
|
||||
// Also see Model.Fields and Model.Where functions.
|
||||
func (m *Model) Array(fieldsAndWhere ...any) ([]Value, error) {
|
||||
func (m *Model) Array(fieldsAndWhere ...any) (Array, error) {
|
||||
if len(fieldsAndWhere) > 0 {
|
||||
if len(fieldsAndWhere) > 2 {
|
||||
return m.Fields(gconv.String(fieldsAndWhere[0])).Where(fieldsAndWhere[1], fieldsAndWhere[2:]...).Array()
|
||||
|
||||
@ -76,8 +76,8 @@ func (r Result) List() List {
|
||||
// Array retrieves and returns specified column values as slice.
|
||||
// The parameter `field` is optional is the column field is only one.
|
||||
// The default `field` is the first field name of the first item in `Result` if parameter `field` is not given.
|
||||
func (r Result) Array(field ...string) []Value {
|
||||
array := make([]Value, len(r))
|
||||
func (r Result) Array(field ...string) Array {
|
||||
array := make(Array, len(r))
|
||||
if len(r) == 0 {
|
||||
return array
|
||||
}
|
||||
|
||||
1191
database/gdb/gdb_z_core_config_external_test.go
Normal file
1191
database/gdb/gdb_z_core_config_external_test.go
Normal file
File diff suppressed because it is too large
Load Diff
204
database/gdb/gdb_z_core_config_test.go
Normal file
204
database/gdb/gdb_z_core_config_test.go
Normal file
@ -0,0 +1,204 @@
|
||||
// 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 gdb
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/container/gtype"
|
||||
"github.com/gogf/gf/v2/os/glog"
|
||||
"github.com/gogf/gf/v2/test/gtest"
|
||||
)
|
||||
|
||||
func Test_Core_SetDebug_GetDebug(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
// Save original config and restore after test
|
||||
originalConfig := configs.config
|
||||
defer func() {
|
||||
configs.config = originalConfig
|
||||
}()
|
||||
|
||||
// Create a test configuration
|
||||
configs.config = make(Config)
|
||||
testNode := ConfigNode{
|
||||
Host: "127.0.0.1",
|
||||
Port: "3306",
|
||||
User: "root",
|
||||
Pass: "123456",
|
||||
Name: "test_db",
|
||||
Type: "mysql",
|
||||
}
|
||||
err := AddConfigNode("test_group", testNode)
|
||||
t.AssertNil(err)
|
||||
|
||||
// Create Core instance
|
||||
node, err := GetConfigGroup("test_group")
|
||||
t.AssertNil(err)
|
||||
core := &Core{
|
||||
group: "test_group",
|
||||
config: &node[0],
|
||||
debug: gtype.NewBool(false),
|
||||
}
|
||||
|
||||
// Test default value
|
||||
result := core.GetDebug()
|
||||
t.Assert(result, false)
|
||||
|
||||
// Test setting debug to true
|
||||
core.SetDebug(true)
|
||||
result = core.GetDebug()
|
||||
t.Assert(result, true)
|
||||
|
||||
// Test setting debug to false
|
||||
core.SetDebug(false)
|
||||
result = core.GetDebug()
|
||||
t.Assert(result, false)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Core_SetDryRun_GetDryRun(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
// Save original config and restore after test
|
||||
originalConfig := configs.config
|
||||
defer func() {
|
||||
configs.config = originalConfig
|
||||
}()
|
||||
|
||||
// Create a test configuration
|
||||
configs.config = make(Config)
|
||||
testNode := ConfigNode{
|
||||
Host: "127.0.0.1",
|
||||
Port: "3306",
|
||||
User: "root",
|
||||
Pass: "123456",
|
||||
Name: "test_db",
|
||||
Type: "mysql",
|
||||
DryRun: false,
|
||||
}
|
||||
err := AddConfigNode("test_group", testNode)
|
||||
t.AssertNil(err)
|
||||
|
||||
// Create Core instance
|
||||
node, err := GetConfigGroup("test_group")
|
||||
t.AssertNil(err)
|
||||
core := &Core{
|
||||
group: "test_group",
|
||||
config: &node[0],
|
||||
}
|
||||
|
||||
// Test default value
|
||||
result := core.GetDryRun()
|
||||
t.Assert(result, false)
|
||||
|
||||
// Test setting dry run to true
|
||||
core.SetDryRun(true)
|
||||
result = core.GetDryRun()
|
||||
t.Assert(result, true)
|
||||
|
||||
// Test setting dry run to false
|
||||
core.SetDryRun(false)
|
||||
result = core.GetDryRun()
|
||||
t.Assert(result, false)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Core_SetLogger_GetLogger(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
// Create Core instance
|
||||
core := &Core{}
|
||||
|
||||
// Test setting custom logger
|
||||
customLogger := glog.New()
|
||||
core.SetLogger(customLogger)
|
||||
result := core.GetLogger()
|
||||
t.Assert(result, customLogger)
|
||||
|
||||
// Test setting nil logger
|
||||
core.SetLogger(nil)
|
||||
result = core.GetLogger()
|
||||
t.Assert(result, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Core_SetMaxConnections(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
// Create Core instance
|
||||
core := &Core{}
|
||||
|
||||
// Test SetMaxIdleConnCount
|
||||
core.SetMaxIdleConnCount(10)
|
||||
t.Assert(core.dynamicConfig.MaxIdleConnCount, 10)
|
||||
|
||||
// Test SetMaxOpenConnCount
|
||||
core.SetMaxOpenConnCount(20)
|
||||
t.Assert(core.dynamicConfig.MaxOpenConnCount, 20)
|
||||
|
||||
// Test SetMaxConnLifeTime
|
||||
testDuration := time.Hour
|
||||
core.SetMaxConnLifeTime(testDuration)
|
||||
t.Assert(core.dynamicConfig.MaxConnLifeTime, testDuration)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Core_GetCache(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
// Create Core instance
|
||||
core := &Core{}
|
||||
|
||||
cache := core.GetCache()
|
||||
// Cache might be nil if not initialized, so we just test that the call doesn't panic
|
||||
_ = cache
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Core_GetGroup(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
// Create Core instance
|
||||
core := &Core{
|
||||
group: "test_group",
|
||||
}
|
||||
|
||||
group := core.GetGroup()
|
||||
t.Assert(group, "test_group")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Core_GetPrefix(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
// Save original config and restore after test
|
||||
originalConfig := configs.config
|
||||
defer func() {
|
||||
configs.config = originalConfig
|
||||
}()
|
||||
|
||||
// Create a test configuration
|
||||
configs.config = make(Config)
|
||||
testNode := ConfigNode{
|
||||
Host: "127.0.0.1",
|
||||
Port: "3306",
|
||||
User: "root",
|
||||
Pass: "123456",
|
||||
Name: "test_db",
|
||||
Type: "mysql",
|
||||
Prefix: "gf_",
|
||||
}
|
||||
err := AddConfigNode("test_group", testNode)
|
||||
t.AssertNil(err)
|
||||
|
||||
// Create Core instance
|
||||
node, err := GetConfigGroup("test_group")
|
||||
t.AssertNil(err)
|
||||
core := &Core{
|
||||
group: "test_group",
|
||||
config: &node[0],
|
||||
}
|
||||
|
||||
prefix := core.GetPrefix()
|
||||
t.Assert(prefix, "gf_")
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user