6382 Commits

Author SHA1 Message Date
8c8c7c8c71 feat: new version v2.10.0 (#4657)
This pull request upgrades the GoFrame framework and all related
dependencies from version `v2.9.8` (and similar) to `v2.10.0` across the
codebase. It also refactors the `.make_version.sh` script to improve
cross-platform compatibility when editing files, and ensures
documentation reflects the new version. These changes help keep the
project up-to-date and simplify version management.

**Dependency upgrades:**

* Updated all `go.mod` files in the main repo and contrib modules to
require `github.com/gogf/gf/v2 v2.10.0` (replacing `v2.9.8` and similar)
for consistency and latest features/bugfixes.
[[1]](diffhunk://#diff-ee0abb9c50b9f91f424349123e31b7b1ba1e1e4f7497250422696c5bda2e74ceL6-R12)
[[2]](diffhunk://#diff-cef597d401b6dad225f9e2e431bdde7e53cb60bdf287624cef38a6a7bb9ae7a3L7-R7)
[[3]](diffhunk://#diff-970f7eacff9cd97a0d8a00d59ea8041eedaa21c7544c6669aaa58ca692c6b274L6-R6)
[[4]](diffhunk://#diff-c23d0ca80cd6588b7df84de8ef84713f0ce0555ba05d2d9e7f5d1e0324b1ed3aL6-R6)
[[5]](diffhunk://#diff-aa230a2b1198e6ef8afeb7f48335eb2e2f51d87d918d63c4d891fea612d18ff0L6-R6)
[[6]](diffhunk://#diff-86c2390edbede20803cd862908fe95e7207f7dbabd5089ddd4838e1f26e7fecaL6-R6)
[[7]](diffhunk://#diff-5e1af33d38ced461fc0e13981d7051e125876d1692efc3aa9cb4b7faa4c18addL7-R7)
[[8]](diffhunk://#diff-8c6247829130f219981483ccf25af699a63de99afedeb0dd5c1b7bd8ff0919bdL9-R9)
[[9]](diffhunk://#diff-accbd2d37d45e51db3fcb0468043b1e1fd53eeac9e3d3558467ef24444188d2fL7-R7)
[[10]](diffhunk://#diff-15fac9b8e76d2782594c91da72f6a6f42fc18e359c3be35bf6564ac3ca09f700L6-R7)
[[11]](diffhunk://#diff-8e1a76afd564b6073aac7b02ca59f296ae45a24da3dc4d5c40f18169f48ceba1L6-R6)
[[12]](diffhunk://#diff-00a9db26966c21305c72e8f659628dffaff0d6e9dc98a751406d2141d51a5d90L7-R7)
[[13]](diffhunk://#diff-2cbf2f66d5cb77d9f4d00e4c0ce45055620fff50c941a588da31729f09a81f1bL6-R7)
[[14]](diffhunk://#diff-20a21d07addeea398c4adb76d077875894a73b4b5b181b9df1fafe497d3fc843L6-R6)
[[15]](diffhunk://#diff-909670f1c29b0bba24faf1420504b9eacdff124c4cbbec1ddec5de60653ad007L6-R6)
[[16]](diffhunk://#diff-8eef5f0c081743f8002e0faba686e838b323cb53b749706ea42e0440aaa793f1L7-R7)
[[17]](diffhunk://#diff-82345842a29e8eaffa4f51aab96fa2aa78597e6639fe4b0ece797bc60edacea8L6-R6)

**Script improvements:**

* Refactored `.make_version.sh` to use a new `sed_inplace` function for
in-place file editing, improving cross-platform support (Linux/macOS)
and removing reliance on a global variable for the sed command.
* Updated `.make_version.sh` to use `sed_inplace` consistently for
version replacement and dependency cleanup steps, ensuring robust file
modification regardless of OS.
[[1]](diffhunk://#diff-546db9206ba1b7973e6187a1025b3904a0b08681d40d0ee4767082040fd0f661L46-R47)
[[2]](diffhunk://#diff-546db9206ba1b7973e6187a1025b3904a0b08681d40d0ee4767082040fd0f661L84-R97)
* Added a step in `.make_version.sh` to insert local development replace
directives for Go modules, streamlining local testing and development.

**Documentation updates:**

* Updated contributor badge version in `README.MD` and `README.zh_CN.MD`
to reflect the new GoFrame version (`v2.10.0`).
[[1]](diffhunk://#diff-01e6d9ffed056a02cae8d8a0ec5d476a64d017bf85c0d5a94bb23ca21f33f5aaL48-R48)
[[2]](diffhunk://#diff-c93759cb9a9500f20e551c741eb167fc72825fd638d36121357feb8253ce6ac1L48-R48)
contrib/drivers/oceanbase/v2.10.0 contrib/drivers/clickhouse/v2.10.0 contrib/registry/file/v2.10.0 v2.10.0 contrib/drivers/sqlitecgo/v2.10.0 contrib/drivers/mysql/v2.10.0 contrib/drivers/sqlite/v2.10.0 contrib/drivers/mssql/v2.10.0 contrib/registry/consul/v2.10.0 contrib/drivers/mariadb/v2.10.0 contrib/drivers/gaussdb/v2.10.0 contrib/registry/nacos/v2.10.0 contrib/trace/otlphttp/v2.10.0 contrib/drivers/tidb/v2.10.0 contrib/config/kubecm/v2.10.0 contrib/config/nacos/v2.10.0 contrib/trace/otlpgrpc/v2.10.0 contrib/config/polaris/v2.10.0 contrib/sdk/httpclient/v2.10.0 contrib/drivers/pgsql/v2.10.0 contrib/registry/zookeeper/v2.10.0 contrib/rpc/grpcx/v2.10.0 contrib/metric/otelmetric/v2.10.0 contrib/registry/etcd/v2.10.0 contrib/config/consul/v2.10.0 contrib/config/apollo/v2.10.0 contrib/nosql/redis/v2.10.0 contrib/drivers/dm/v2.10.0 contrib/registry/polaris/v2.10.0 contrib/drivers/oracle/v2.10.0
2026-01-26 20:37:48 +08:00
73211707fb refactor(container): add default nil checker, rename RegisterNilChecker to SetNilChecker, migrate instance containers to type-safe generics (#4630)
## 变更说明

本 PR 主要对代码库进行了重构,以提升类型安全性和优化连接管理实现。

### 详细变更

#### 1. 数据库连接管理优化
- 修改 `RegisterNilChecker`方法返回实例以支持链式调用,涉及
`KVMap`、`ListKVMap`、`TSet`、`AVLKVTree`、`BKVTree`、`RedBlackKVTree`
等多个容器类型
- 更新 `Core`结构体中 `links`字段类型为类型安全的 `KVMap[ConfigNode, *sql.DB]`
- 添加专门的链接检查器函数用于连接池管理
- 使用泛型 `KVMap`替代原始 map 类型提升类型安全性
- 简化连接关闭逻辑并移除不必要的类型断言
- 优化统计功能中的迭代器实现提高性能

#### 2. 数据库驱动类型安全增强
- 将 dm、gaussdb、mssql、oracle 驱动中的 `conflictKeySet` 从 `gset.New`修改为
`gset.NewStrSet`
- 统一使用字符串集合类型以提高类型安全性

#### 3. 配置文件适配器类型安全改进
- 将 `jsonMap`从 `StrAnyMap` 类型更改为泛型 `KVMap[string, *gjson.Json]` 类型
- 添加 `jsonMapChecker` 函数用于 JSON 对象验证
- 使用 `NewKVMapWithChecker` 替代 `NewStrAnyMap` 提高类型安全性
- 简化数据库链接关闭日志中的键值转换逻辑

## 影响范围

- 数据库连接管理模块
- 多个数据库驱动实现
- 配置文件管理系统

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: John Guo <john@johng.cn>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-23 16:37:38 +08:00
609f44c5fe fix(cmd/gf): fix genservice losing versioned import paths (#4242) (#4638)
## Summary
- Fix `gf gen service` incorrectly handling versioned imports (e.g.,
`github.com/minio/minio-go/v7` → `github.com/minio/minio-go`)
- The root cause was faulty package name inference from import paths -
Go allows package names to differ from directory names
- Solution: Keep all non-anonymous imports and let gofmt clean up unused
ones

## Changes
- Simplified `calculateImportedItems` function in
`genservice_calculate.go`
- Added test case for versioned imports and aliased imports

## Test plan
- [x] All existing genservice tests pass (`Test_Gen_Service_Default`,
`Test_Issue3328`, `Test_Issue3835`)
- [x] New test `Test_Issue4242` verifies both versioned imports and
aliased imports are preserved
- [x] Verified generated files match expected output exactly

Closes #4242

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-22 20:45:19 +08:00
0a82036da5 feat(contrib/registry): update nacos sdk to 2.3.5 (#4628)
- Update nacos go sdk to 2.3.5;
- ctx params not use, skip it;
- adjust docs style

---------

Signed-off-by: yuluo-yx <yuluo08290126@gmail.com>
Co-authored-by: hailaz <739476267@qq.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-22 19:09:06 +08:00
b4053ed32e feat(os/gcfg): add Loader with automatic struct binding and config watching (like Spring Boot @ConfigurationProperties) (#4575)
# Loader 配置加载器

Loader 是一个通用的配置管理器,提供了类似于 Spring Boot
的`@ConfigurationProperties`的配置加载、监控、更新和管理功能。

## 功能特性

- **泛型支持**:使用 Go 泛型,类型安全的配置绑定
- **配置加载**:从配置源加载数据并绑定到结构体
- **配置监控**:自动监控配置变化并更新
- **自定义转换器**:支持自定义数据转换函数
- **回调处理**:配置变更时的回调函数
- **错误处理**:灵活的错误处理机制

## 安装

```bash
go get github.com/gogf/gf/v2
```

## 使用示例

### 1. 基本用法

#### 用法一

```go
package main

import (
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/gcfg"
	"github.com/gogf/gf/v2/os/gctx"
)

type AppConfig struct {
	Name     string       `json:"name"`
	Age      int          `json:"age"`
	Enabled  bool         `json:"enabled"`
	Features []string     `json:"features"`
	Server   ServerConfig `json:"server"`
}

type ServerConfig struct {
	Host string `json:"host"`
	Port int    `json:"port"`
}

func main() {
	ctx := gctx.New()
	// 创建配置器实例
	loader := gcfg.NewLoader[AppConfig](g.Cfg("test"), "")

	// 加载和监听配置
	loader.MustLoadAndWatch(ctx, "test-watcher")

	// 获取配置
	config := loader.Get()
	fmt.Println(config.Name)
}
```

#### 用法二

```go
package main

import (
	"fmt"
	"github.com/gogf/gf/v2/os/gcfg"
	"github.com/gogf/gf/v2/os/gctx"
)

type AppConfig struct {
	Name     string       `json:"name"`
	Age      int          `json:"age"`
	Enabled  bool         `json:"enabled"`
	Features []string     `json:"features"`
	Server   ServerConfig `json:"server"`
}

type ServerConfig struct {
	Host string `json:"host"`
	Port int    `json:"port"`
}

func main() {
	ctx := gctx.New()

	// 使用单独的适配器创建
	// 创建配置管理器
	cfg, _ := gcfg.NewAdapterFile("test.yaml")
	// 创建配置器实例
	loader := gcfg.NewLoaderWithAdapter[AppConfig](cfg, "")

	// 加载和监听配置
	loader.MustLoadAndWatch(ctx, "test-watcher")

	// 获取配置
	config := loader.Get()
	fmt.Println(config.Name)
}
```

### 2. 配置监控

```go


// 仅加载App配置
loader := gcfg.NewLoaderWithAdapter[AppConfig](cfg, "app")

// 设置配置变更回调
loader.OnChange(func (updated AppConfig) error {
// 配置变更时的处理逻辑
println("配置已更新:", updated.Name)
return nil
})

// 加载数据
err := loader.Load(ctx)
if err != nil {
panic(err)
}

// 开始监控配置变化
err := loader.Watch(context.Background(), "my-watcher")
if err != nil {
panic(err)
}

```

### 3. 自定义转换器

```go
// 设置自定义转换器
loader.SetConverter(func (data any, target *AppConfig) error {
// 自定义数据转换逻辑
return nil
})
```

### 4. 便捷方法

```go
// 一步完成加载和监控
loader.MustLoadAndWatch(context.Background(), "my-app")
```

## API 参考

### `NewLoader`

创建一个新的 Loader 实例。

```go
func NewLoader[T any](config *Config, propertyKey string, targetStruct ...*T) *Loader[T]
```

参数:

- `config`: 配置实例,用于监控变化
- `propertyKey`: 监控的属性键模式(使用 "" 或 "." 监控所有配置)
- `targetStruct`: 接收配置值的结构体指针(可选)

### `NewLoaderWithAdapter`

使用适配器创建一个新的 Loader 实例。

```go
func NewLoaderWithAdapter[T any](adapter Adapter, propertyKey string, targetStruct ...*T) *Loader[T]
```

### `Load`

从配置实例加载数据并绑定到目标结构体。

```go
func (l *Loader[T]) Load(ctx context.Context) error
```

### `MustLoad`

与 Load 类似,但出错时会 panic。

```go
func (l *Loader[T]) MustLoad(ctx context.Context)
```

### `Watch`

开始监控配置变化并自动更新目标结构体。

```go
func (l *Loader[T]) Watch(ctx context.Context, name string) error
```

### `MustWatch`

与 Watch 类似,但出错时会 panic。

```go
func (l *Loader[T]) MustWatch(ctx context.Context, name string)
```

### `MustLoadAndWatch`

便捷方法,调用 MustLoad 和 MustWatch。

```go
func (l *Loader[T]) MustLoadAndWatch(ctx context.Context, name string)
```

### `Get`

返回当前配置结构体。

```go
func (l *Loader[T]) Get() T
```

### `GetPointer() *T`

返回指向当前配置结构体的指针。

```go
func (l *Loader[T]) GetPointer() *T
```

### `OnChange`

设置配置变化时调用的回调函数。

```go
func (l *Loader[T]) OnChange(fn func (updated T) error)
```

### `SetConverter`

设置在 Load 操作期间使用的自定义转换函数。

```go
func (l *Loader[T]) SetConverter(converter func (data any, target *T) error)
```

### `SetWatchErrorHandler`

设置在 Watch 过程中 Load 操作失败时调用的错误处理函数。

```go
func (l *Loader[T]) SetWatchErrorHandler(errorFunc func(ctx context.Context, err error))
```

### `SetReuseTargetStruct`

设置是否在更新时重用相同的目标结构体或创建新结构体。

```go
func (l *Loader[T]) SetReuseTargetStruct(reuse bool)
```

### `StopWatch`

停止监控配置变化并移除关联的监控器。

```go
func (l *Loader[T]) StopWatch(ctx context.Context) (bool, error)
```

### `IsWatching`

返回 Loader 是否正在监控配置变化。

```go
func (l *Loader[T]) IsWatching() bool
```

## 高级用法

### 监控特定配置键

```go
// 只监控特定配置键
loader := gcfg.NewLoaderWithAdapter[ServerConfig](cfg, "server")
```

### 使用默认值

```go
// 创建带默认值的目标结构体
var targetConfig AppConfig
targetConfig.Name = "default-app" // 设置默认值

loader := gcfg.NewLoaderWithAdapter(cfg, "", &targetConfig)
```

## 错误处理

Loader 提供了灵活的错误处理机制:

```go
loader.SetWatchErrorHandler(func(ctx context.Context, err error) {
    // 处理加载错误
    log.Printf("配置加载失败: %v", err)
})
```

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: houseme <housemecn@gmail.com>
2026-01-22 19:04:52 +08:00
110e3fbf16 feat(cmd/gendao): add wildcard pattern support for tables configuration (#4632)
## Summary
- Add wildcard pattern support (`*` and `?`) for `tables` configuration
- Fix `tablesEx` wildcard to use exact match (`^$`) for consistency
- Add warning when exact table name does not exist
- Add unit tests and integration tests for MySQL and PostgreSQL

## Changes
| Configuration | Before | After |
|---------------|--------|-------|
| `tables: "user_*"` | Not supported | Matches tables starting with
"user_" |
| `tables: "*"` | Not supported | Matches all tables |
| `tablesEx: "user_*"` | Partial match | Exact match (consistent with
tables) |

## Features
- `*` matches any characters (e.g., `user_*` matches `user_info`,
`user_log`)
- `?` matches single character (e.g., `user_???` matches `user_log` but
not `user_info`)
- Mixed patterns and exact names supported (e.g., `tables:
"user_*,config"`)
- Non-existent exact table names are skipped with warning message

## Test plan
- [x] Unit tests for `containsWildcard`, `patternToRegex`,
`filterTablesByPatterns` (11 cases)
- [x] Integration tests for MySQL (5 cases)
- [x] Integration tests for PostgreSQL (1 case with tables + tablesEx)
- [x] Standard SQL syntax for cross-database compatibility

Closes #4629

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-21 19:16:12 +08:00
095c69c424 fix(cmd/gf): fix gf env and gf build --dumpEnv command error (#4635)
## Summary
- Fix `gf env` and `gf build --dumpEnv` command failing when `go env`
outputs warning messages
- When `go env` outputs warnings (e.g., invalid characters in
environment variables), it returns non-zero exit code but still provides
valid output
- The original code would fail in this case

## Changes
- Only fail when `go env` returns empty output, allow non-zero exit code
with valid output
- Skip lines that don't match `key=value` format instead of failing with
Fatal error
- Add debug log for skipped lines to help troubleshooting
- Add unit tests for env command

## Related Issue
Fixes #4469

## Test plan
- [x] `gf env` command works correctly even when `go env` outputs
warnings
- [x] `gf build --dumpEnv` works correctly
- [x] Added unit tests pass
2026-01-21 19:15:57 +08:00
cee6f499fc fix(cmd/gf): fix gf gen enums output path error when using relative path (#4636)
## Summary
- Fix `gf gen enums` output file created at wrong location when using
relative path
- Output was incorrectly relative to source directory instead of current
working directory
- Add `defer gfile.Chdir(originPwd)` to restore original working
directory

## Root Cause
The code calls `gfile.Chdir(realPath)` to change to source directory
before `gfile.PutContents(in.Path, ...)`, causing relative output path
to be resolved relative to source directory.

## Solution
- Convert output path to absolute using `gfile.Abs()` before `Chdir`
- Restore original working directory with `defer` (following `genpb.go`
pattern)

## Test Cases
- `Test_Gen_Enums_Issue4387_RelativePath` - standard project with
relative path
- `Test_Gen_Enums_AbsolutePath` - absolute path (should work as before)
- `Test_Gen_Enums_Issue4387_Monorepo` - monorepo mode (`cd app/xxx && gf
gen enums`)

Closes #4387
2026-01-21 19:15:42 +08:00
73560cfe31 fix(cmd/gendao): fix overlapping shardingPattern matching issue (#4631)
## Summary
- Fix overlapping shardingPattern matching issue where shorter patterns
incorrectly match tables meant for longer patterns
- Sort shardingPattern by length descending so longer (more specific)
patterns are matched first
- Add break after successful pattern match to prevent tables from
matching multiple patterns

## Problem
When `shardingPattern` contains overlapping prefixes like `["a_?",
"a_b_?", "a_c_?"]`:
- Tables `a_b_1`, `a_b_2` should match `a_b_?` and generate `a_b.go`
- Tables `a_c_1`, `a_c_2` should match `a_c_?` and generate `a_c.go`
- Tables `a_1`, `a_2` should match `a_?` and generate `a.go`

But without this fix, `a_?` (converted to regex `a_(.+)`) would match
`a_b_1` first, causing `a_b_?` and `a_c_?` patterns to fail to generate
their respective dao files.

## Solution
1. Sort `shardingPattern` by length descending before matching
2. Add `break` after a table matches a pattern to prevent multiple
matches

## Test plan
- [x] Added integration test `Test_Gen_Dao_Sharding_Overlapping` with
overlapping patterns
- [x] Added SQL test data file `sharding_overlapping.sql`
- [x] Verified 3 separate dao files are generated: `a.go`, `a_b.go`,
`a_c.go`

Fixes #4603
2026-01-21 19:15:06 +08:00
9a7df9944c revert(os/gcfg): restore config file priority over env/cmd in GetWithEnv and GetWithCmd (#4647)
## Summary
- Reverts the behavior change introduced in PR #4587 (commit caea7ea4b)
- Restores v2.9.7 priority behavior:
  - `GetWithEnv`: config file > environment variable > default value
  - `GetWithCmd`: config file > command line option > default value

## Related Issue
Closes #4074

## Changes
- `os/gcfg/gcfg.go`: Restore original logic that checks config file
first, then falls back to env/cmd
- `os/gcfg/gcfg_z_example_test.go`: Restore original example test
expectations
2026-01-21 19:14:03 +08:00
dd02af1b2f test(cmd/gf): enhance integration tests for gen service command (#4645)
## Summary
- Add 2 new integration test cases for `gf gen service` command
- `Test_Gen_Service_CamelCase`: tests `DstFileNameCase: "Camel"` option
to generate service files with CamelCase naming
- `Test_Gen_Service_PackagesFilter`: tests `Packages` filter option to
generate service files only for specified packages

## Test Plan
- [x] Run `go test -v -run "Test_Gen_Service" ./...` - all 5 tests pass
(3 existing + 2 new)
2026-01-21 19:12:37 +08:00
626fc629ef test(cmd/gf): enhance integration tests for gen pb command (#4644)
## Summary
- Add 2 new integration test cases for `gf gen pb` command
- `TestGenPb_MultipleTags`: tests multiple validation tags (v:required,
v:#Id > 0, v:email) and dc tags
- `TestGenPb_NestedMessage`: tests nested message structures with
various tag types

## Test Data
- Add `testdata/genpb/multiple_tags.proto` - proto file with multiple
tag annotations
- Add `testdata/genpb/nested_message.proto` - proto file with nested
message structures

## Test Plan
- [x] Run `go test -v -run "TestGenPb" ./...` - all 4 tests pass (2
existing + 2 new)
2026-01-21 19:11:45 +08:00
2d05fb426f test(cmd/gf): enhance unit tests for fix command (#4643)
## Summary
- Enhance unit tests for the `fix` command's `doFixV25Content` function
- 5 new test cases added (total: 6)

## New Test Cases

| Test | Description |
|------|-------------|
| Test_Fix_doFixV25Content_WithReplacement | Verify actual replacement
is made |
| Test_Fix_doFixV25Content_NoMatch | Handle content without patterns |
| Test_Fix_doFixV25Content_MultipleMatches | Handle multiple occurrences
|
| Test_Fix_doFixV25Content_EmptyContent | Handle empty content |
| Test_Fix_doFixV25Content_ComplexPath | Handle complex URL paths |

## Test plan
- [x] All 6 tests pass locally
- [x] Only added new test cases to existing test file
- [x] No modifications to non-test code
2026-01-21 19:10:56 +08:00
bf2997e9cc test(cmd/gf): add unit tests for pack command (#4642)
## Summary
- Add comprehensive unit tests for the `pack` command which handles
resource file packing
- 8 new test cases covering core functionality

## Test Coverage

| Test | Description |
|------|-------------|
| Test_Pack_ToGoFile | Pack files to .go file |
| Test_Pack_ToBinaryFile | Pack files to binary file |
| Test_Pack_MultipleSources | Pack multiple source directories |
| Test_Pack_WithPrefix | Pack with prefix option |
| Test_Pack_WithKeepPath | Pack with keepPath option |
| Test_Pack_AutoPackageName | Auto-detect package name from directory |
| Test_Pack_EmptySource | Handle empty source directory |
| Test_Pack_NestedDirectories | Handle deeply nested directory structure
|

## Test plan
- [x] All 8 tests pass locally
- [x] No modifications to existing code
- [x] New test file only: `cmd_z_unit_pack_test.go`
2026-01-21 19:10:20 +08:00
82d4d77e56 test(cmd/gf): add unit tests for genenums package (#4641)
## Summary
- Add comprehensive unit tests for the `genenums` package which handles
enum parsing and JSON export
- 13 new test cases covering core functionality

## Test Coverage

| Function | Tests | Description |
|----------|-------|-------------|
| `NewEnumsParser` | 2 | Parser initialization |
| `Export` | 7 | JSON export with various types |
| `ParsePackages` | 2 | Integration with Go packages |
| `EnumItem` | 1 | Data structure |
| `getStandardPackages` | 1 | Standard library detection |

## Test plan
- [x] All 13 tests pass locally
- [x] No modifications to existing code
- [x] New test file only: `genenums_z_unit_test.go`
2026-01-21 19:09:38 +08:00
4f43b40a18 test(cmd/gf): add unit tests for geninit package (#4640)
## Summary
- Add comprehensive unit tests for the `geninit` package which handles
project initialization from templates
- 17 new test cases covering core functionality

## Test Coverage

| Function | Tests | Description |
|----------|-------|-------------|
| `ParseGitURL` | 7 | Git URL parsing with various formats |
| `IsSubdirRepo` | 3 | Subdirectory detection |
| `GetModuleNameFromGoMod` | 3 | Module name extraction |
| `ASTReplacer` | 2 | Import path replacement |
| `findGoFiles` | 2 | Go file discovery |

## Test plan
- [x] All 17 tests pass locally
- [x] No modifications to existing code
- [x] New test file only: `geninit_z_unit_test.go`
2026-01-21 19:07:52 +08:00
f3f2cb3c57 refactor(encoding/gjson): enhance auto type checks when loading data without type specified (#4637)
This pull request improves YAML support for i18n translation files and
refactors content type detection and loading logic in the `gjson`
package. The main changes include more robust detection of YAML, TOML,
INI, and Properties formats, refactoring of content type handling, and
the addition of new tests to ensure correct parsing of YAML-based i18n
resources.

### Improved content type detection and loading

* Refactored content type detection logic in `gjson` to use dedicated
functions for XML, YAML, TOML, INI, and Properties formats, making the
detection more reliable and maintainable.
* Changed the content loading mechanism in `gjson` to use specific
decode functions (`gxml.Decode`, `gyaml.Decode`, etc.) for each format
instead of converting everything to JSON first, improving accuracy and
extensibility.
* Updated type definitions and struct field comments in `gjson.go` for
clarity and consistency, including changing `ContentType` to a type
alias and improving documentation.
[[1]](diffhunk://#diff-0e4432d7e4cf171c0339e01b1842530432b986948d7f839a155543623236a03fL24-R24)
[[2]](diffhunk://#diff-0e4432d7e4cf171c0339e01b1842530432b986948d7f839a155543623236a03fL38-R71)

### i18n YAML support

* Modified i18n manager to use the new `gjson.LoadPath` method for
loading translation files, ensuring correct parsing of YAML files for
i18n.
* Added new test cases and test data for loading and verifying YAML i18n
files, including edge cases and real-world translation strings.
[[1]](diffhunk://#diff-e6eacc5abab33c149f9b39d8ebe300cf4d0abe907434605991984a5969e8707dR262-R283)
[[2]](diffhunk://#diff-1bfd438797c1f9ef18ab3cb00d23ae95202e85e2362c39c3df4f1a29c55733feR421-R430)
[[3]](diffhunk://#diff-a3ee37ff2a67c9e1ba2e1617e0f5fd63eb261ad7760a07423f703538138c2decR1-R16)

### Minor improvements

* Simplified file loading logic in `gjson.LoadPath` by removing caching
and directly reading file bytes, which streamlines the code and avoids
potential cache issues.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-20 19:25:23 +08:00
102c3b6cb0 fix(util/gconv): fix incompatable converting to nil pointer target from older version implement (#4224)
fixed: https://github.com/gogf/gf/issues/4218
2026-01-20 10:57:32 +08:00
5e677a1e05 fix(net/gclient): fix form field value truncation when uploading files (#4627)
## What does this PR do?

Fixes #4156

When posting form data with file upload, if a field value contains `=`
or `&`, the value was being truncated.

### Example

```go
data := g.Map{
    "file":      "@file:/path/to/file.txt",
    "fieldName": "aaa=1&b=2",
}
client.Post(ctx, "/upload", data)
```

**Expected**: Server receives `fieldName = "aaa=1&b=2"`
**Actual (before fix)**: Server receives `fieldName = "aaa"` (truncated)

## Root Cause Analysis

The issue was caused by three problems in the original code:

### Problem 1: Global URL encoding disable (httputils.go)

```go
// Original code - PROBLEMATIC
if urlEncode {
    for k, v := range m {
        if gstr.Contains(k, fileUploadingKey) || gstr.Contains(gconv.String(v), fileUploadingKey) {
            urlEncode = false  // Disables URL encoding for ALL values!
            break
        }
    }
}
```

When any value contained `@file:`, URL encoding was disabled for ALL
values, causing `"aaa=1&b=2"` to remain unencoded. The `&` character was
then treated as a parameter separator.

### Problem 2: Split on all `=` characters (gclient_request.go)

```go
// Original code - PROBLEMATIC
array := strings.Split(item, "=")  // Splits on ALL '=' characters
```

This caused `"fieldName=aaa=1"` to be split into `["fieldName", "aaa",
"1"]`.

### Problem 3: No URL decoding for field values

URL-encoded values were written directly to the multipart form without
decoding.

## Solution

### Fix 1: Remove global URL encoding disable

Only `@file:` prefixed values are kept unencoded for file upload
detection. Other values are properly URL-encoded.

### Fix 2: Use SplitN to limit split count

```go
array := strings.SplitN(item, "=", 2)  // Only split on first '='
```

### Fix 3: Add URL decoding for field values

```go
if v, err := gurl.Decode(fieldValue); err == nil {
    fieldValue = v
}
```

## Compatibility Analysis

| Scenario | Before | After | Compatible |
|----------|--------|-------|------------|
| Normal form POST (no file upload) |  Works |  Works |  Yes |
| File upload + normal field values |  Works |  Works |  Yes |
| File upload + field values containing `=` or `&` |  Truncated | 
Works |  Fixed |
| Field value is `@file:` (no path) |  Works |  Works |  Yes |
| Field value starts with `@file:` but file doesn't exist |  Error | 
Error |  Yes |
| User sends pre-encoded value like `"aaa%3D1"` |  Works |  Works | 
Yes |
| Content-Type: application/json |  Works |  Works |  Yes |
| Content-Type: application/xml |  Works |  Works |  Yes |

### Breaking Change Assessment

**No breaking changes.** The fix only affects the file upload scenario
where field values contain special characters (`=`, `&`). Previously
this scenario was broken, now it works correctly.

### Edge Cases

1. **Literal `@file:` value**: GoFrame treats `@file:` as a special
marker for file upload. This is a framework design decision and remains
unchanged.

2. **URL decode failure**: If URL decoding fails (e.g., invalid `%XX`
sequence), the original value is preserved.

## Test Coverage

Added comprehensive tests covering:

- `Test_Issue4156` - Basic fix verification
- `Test_Issue4156_MultipleSpecialChars` - Multiple `=`, `&`, `%`, `+`,
spaces
- `Test_Issue4156_MultipleFields` - Multiple fields with special
characters
- `Test_Issue4156_NoFileUpload` - Normal POST without file upload
- `Test_Issue4156_PreEncodedValue` - Pre-encoded values like `%3D`
- `Test_Issue4156_EmptyAndSpecialValues` - Edge cases (`=` at start/end,
only special chars)
- `TestBuildParams_*` - httputil.BuildParams comprehensive tests

All tests pass, including existing `Test_Issue3748` which tests the
`@file:` marker handling.

## Files Changed

- `internal/httputil/httputils.go` - Remove global URL encoding disable,
adjust `@file:` condition
- `internal/httputil/httputils_test.go` - Add comprehensive BuildParams
tests
- `net/gclient/gclient_request.go` - Use SplitN, add URL decoding
- `net/gclient/gclient_z_unit_issue_test.go` - Add Issue 4156 test cases
2026-01-19 13:05:44 +08:00
75f89f19ba feat(database/gdb): add MaxIdleConnTime configuration for SetConnMaxIdleTime support (#4625)
## Summary
- Add `MaxIdleConnTime` configuration field to support Go 1.15+
`sql.DB.SetConnMaxIdleTime()` method
- Add `SetMaxIdleConnTime()` method to DB interface and Core
implementation
- Apply configuration during connection pool initialization
- Add unit tests for the new configuration option

## Related Issue
Closes #4596

## Changes
| File | Change |
|------|--------|
| `database/gdb/gdb_core_config.go` | Add `MaxIdleConnTime` field to
`ConfigNode`, add `SetMaxIdleConnTime()` method |
| `database/gdb/gdb.go` | Add interface method, `dynamicConfig` field,
initialization logic |
| `database/gdb/gdb_z_core_config_test.go` | Add unit test for
`SetMaxIdleConnTime` |
| `database/gdb/gdb_z_core_config_external_test.go` | Add `ConfigNode`
connection pool settings test |

## Usage
**Configuration file:**
```yaml
database:
  default:
    maxIdleTime: "10s"  # Close idle connections after 10 seconds
```

**Code:**
```go
db.SetMaxIdleConnTime(10 * time.Second)
```

## Test Plan
- [x] Unit tests pass (`go test -run
"Test_Core_SetMaxConnections|Test_ConfigNode_ConnectionPoolSettings"`)
- [x] All database drivers compile successfully (mysql, pgsql, sqlite,
clickhouse, dm, mssql, oracle, etc.)
- [x] No breaking changes - follows Go's default behavior (0 = no idle
time limit)
2026-01-19 13:04:03 +08:00
afe6bebde7 fix(util/gutil): fix false positive cycle detection in Dump (#2902) (#4626)
## Summary
- Fix false positive cycle detection in `gutil.Dump`
- Change from global pointer tracking to path-based cycle detection
- Shared references (multiple fields pointing to same object) no longer
incorrectly marked as cycles

## Problem
When using `gutil.Dump` with structs containing fields that share the
same `reflect.Type` (e.g., multiple `int` fields), the second field's
type was incorrectly displayed as `<cycle dump 0x...>`.

Example from issue:
```go
type User struct {
    Id   int `params:"id"`
    Name int `params:"name"`
}
fields, _ := gstructs.TagFields(&user, []string{"p", "params"})
gutil.Dump(fields)  // Second field's Type shows "<cycle dump>" instead of "int"
```

## Solution
Change cycle detection from global to path-based:
- Add `defer delete()` to remove pointer from tracking set when function
returns
- Only detect true cycles (A→B→A), not shared references (A,B both point
to C)

## Benchmark Comparison

Run benchmark with:
```bash
cd util/gutil && go test -bench=Benchmark_Dump -benchmem -run=^$
```

**Before fix (master branch):**
| Benchmark | ns/op | B/op | allocs/op |
|-----------|-------|------|-----------|
| Shallow | 4071 | 5989 | 85 |
| Nested20 | 105700 | 173993 | 1952 |
| Deep50 | 422515 | 692298 | 4869 |

**After fix (this PR):**
| Benchmark | ns/op | B/op | allocs/op |
|-----------|-------|------|-----------|
| Shallow | 4049 | 5989 | 85 |
| Nested20 | 103065 | 173990 | 1952 |
| Deep50 | 469502 | 692291 | 4869 |

**Performance impact**: 
- Memory allocation (B/op and allocs/op) is **identical**
- Execution time is within normal variance (±5-10%)
- The `defer delete()` operation is O(1), negligible compared to
reflection overhead

## Test plan
- [x] All existing `gutil` tests pass (68 tests)
- [x] Added `Test_Dump_Issue2902_SharedPointer` - shared pointer not
marked as cycle
- [x] Added `Test_Dump_Issue2902_SameTypeFields` - original issue
scenario
- [x] Added benchmark tests for performance tracking
- [x] Verified real cycles still detected correctly

Fixes #2902
2026-01-19 10:56:25 +08:00
2af2342d67 fix: update gf cli to v2.9.8 (#4619)
Automated changes by
[create-pull-request](https://github.com/peter-evans/create-pull-request)
GitHub action

Co-authored-by: hailaz <hailaz@users.noreply.github.com>
2026-01-16 16:21:44 +08:00
c9641ea115 fix: v2.9.8 (#4616)
Co-authored-by: houseme <housemecn@gmail.com>
v2.9.8 contrib/config/apollo/v2.9.8 contrib/registry/polaris/v2.9.8 contrib/rpc/grpcx/v2.9.8 contrib/registry/etcd/v2.9.8 contrib/trace/otlphttp/v2.9.8 contrib/drivers/mssql/v2.9.8 contrib/config/consul/v2.9.8 contrib/sdk/httpclient/v2.9.8 contrib/drivers/mysql/v2.9.8 contrib/drivers/dm/v2.9.8 contrib/drivers/oceanbase/v2.9.8 contrib/drivers/gaussdb/v2.9.8 contrib/registry/zookeeper/v2.9.8 contrib/drivers/clickhouse/v2.9.8 contrib/drivers/mariadb/v2.9.8 contrib/metric/otelmetric/v2.9.8 contrib/registry/file/v2.9.8 contrib/drivers/pgsql/v2.9.8 contrib/drivers/oracle/v2.9.8 contrib/registry/consul/v2.9.8 contrib/registry/nacos/v2.9.8 contrib/config/kubecm/v2.9.8 contrib/config/nacos/v2.9.8 contrib/config/polaris/v2.9.8 contrib/drivers/sqlite/v2.9.8 contrib/trace/otlpgrpc/v2.9.8 contrib/drivers/sqlitecgo/v2.9.8 contrib/drivers/tidb/v2.9.8 contrib/nosql/redis/v2.9.8
2026-01-16 16:05:07 +08:00
d8a173d9f0 feat(instance): migrate instance containers to type-safe generics (#4617)
### 变更说明

本次重构将项目中用于**实例管理的容器**从 `StrAnyMap`/`IntAnyMap` 迁移到类型安全的泛型实现
`KVMapWithChecker`,同时将相关的 `glist.List` 和 `gqueue.Queue`
替换为对应的泛型版本,以提高实例管理的类型安全性。并且减少原先代码中的大量类型断言,提高性能。

### 前因

目前`goframe`中大量使用了包含`any`的容器,然后通过断言去转换类型,麻烦且影响性能,尤其是对`gdb/gredis/glog`等需要高频获取`instance`实例的组件影响较大。最近几个版本中gf完成了数据结构容器的泛型化改造,以及我最近解决了其中几个泛型容器对于`typed
nil`过滤的问题,所以可以逐步迁移这些实例容器到泛型容器,减少断言优化性能

### 主要改进

#### 1. 实例容器泛型化

以下模块的实例管理容器已迁移到泛型实现:

**核心实例管理**:
- `database/gdb`: 数据库实例容器 → `KVMap[string, DB]`
- `database/gredis`: Redis 实例容器 → `KVMap[string, *Redis]`
- `database/gredis`: Redis 配置容器 → `KVMap[string, *Config]`
- `os/gcfg`: 配置实例容器 → `KVMap[string, *Config]`
- `os/glog`: 日志实例容器 → `KVMap[string, *Logger]`
- `os/gview`: 视图实例容器 → `KVMap[string, *View]`
- `i18n/gi18n`: 国际化实例容器 → `KVMap[string, *Manager]`

**网络服务实例**:
- `net/ghttp`: HTTP 服务器容器 → `KVMap[string, *Server]`
- `net/gtcp`: TCP 服务器容器 → `KVMap[any, *Server]`
- `net/gudp`: UDP 服务器容器 → `KVMap[string, *Server]`

**其他实例容器**:
- `os/gres`: 资源实例容器 → `KVMap[string, *Resource]`
- `os/gfpool`: 文件池容器 → `KVMap[string, *Pool]`
- `os/gspath`: 路径搜索容器 → `KVMap[string, *SPath]`
- `net/gtcp`: 连接池容器 → `KVMap[string, *gpool.Pool]`

#### 2. 相关数据结构泛型化

- `os/gfsnotify`: 回调列表 → `TList[*Callback]`,事件队列 → `TQueue[*Event]`
- `os/grpool`: 任务队列 → `TList[*localPoolItem]`
- `os/gcache`: 事件队列 → `TList[*adapterMemoryEvent]`
- `net/ghttp`: 解析项列表 → `TList[*HandlerItemParsed]`
- `os/gproc`: 消息队列 → `TQueue[*MsgRequest]`
- `os/gmlock`: 锁映射 → `KVMap[string, *sync.RWMutex]`

### 技术实现

1. **引入检查器函数**: 为每个实例容器添加 `checker` 函数用于空值检测
2. **消除类型断言**: 实例获取时无需 `v.(*Type)` 转换
3. **明确函数签名**: `GetOrSetFuncLock` 的回调从 `func() any` 改为 `func() T`

### 使用示例

#### 实例容器的变更

**变更前**:
```go
// 旧的实例管理方式
var instances = gmap.NewStrAnyMap(true)

func Instance(name string) *Logger {
    v := instances.GetOrSetFuncLock(name, func() any {
        return New()
    })
    return v.(*Logger)  // 需要类型断言
}
```


**变更后**:
```go
// 新的泛型实例容器
var (
    checker   = func(v *Logger) bool { return v == nil }
    instances = gmap.NewKVMapWithChecker[string, *Logger](checker, true)
)

func Instance(name string) *Logger {
    return instances.GetOrSetFuncLock(name, New)  // 直接返回,无需断言
}
```


#### 队列容器的变更

**变更前**:
```go
// 旧的队列方式
events := gqueue.New()
events.Push(&Event{Path: "/tmp/file"})

if v := events.Pop(); v != nil {
    event := v.(*Event)  // 需要类型断言
    handleEvent(event)
}
```


**变更后**:
```go
// 新的泛型队列
events := gqueue.NewTQueue[*Event]()
events.Push(&Event{Path: "/tmp/file"})

if event := events.Pop(); event != nil {
    handleEvent(event)  // event 已是 *Event 类型
}
```


### 收益

-  **编译时类型安全**: 实例容器的类型错误在编译期捕获
-  **消除运行时断言**: 避免类型断言带来的 panic 风险
-  **提升代码可读性**: 实例管理逻辑更清晰
-  **改善开发体验**: IDE 类型提示和代码补全更准确

### 性能权衡

**编译时**:
- 泛型实例化会增加编译时间和二进制体积
- 预估编译时间增加 5-15%,二进制体积增加约 1-2MB

**运行时**:
- 减少类型断言的反射开销
- 提升实例获取等热点路径的性能
2026-01-16 15:23:13 +08:00
5d1712b4ab fix(database/gdb): Raw SQL Count ignores Where condition (#4611)
## Summary
- Fixed a bug where `Raw()` with `Where()` and
`Count()`/`ScanAndCount()` was ignoring the Where conditions in Count
queries
- The issue was in `getFormattedSqlAndArgs()` which returned `nil` for
`conditionArgs` without calling `formatCondition()` for Raw SQL in
`SelectTypeCount` case

## Changes
- Modified `database/gdb/gdb_model_select.go` to call
`formatCondition()` for Raw SQL Count queries
- Added comprehensive test cases for MySQL and PostgreSQL drivers
- Fixed incorrect test expectation in `Test_Model_Raw`

## Test plan
- [x] Added `Test_Issue4500` with 6 edge cases covering:
  - Raw SQL with WHERE + external Where condition
  - Raw SQL without WHERE + external Where condition  
  - Raw + Where + ScanAndCount
  - Raw + multiple Where conditions
  - Raw SQL with no external Where (baseline)
  - Verify All() still works correctly
- [x] All tests pass on PostgreSQL

Closes #4500
2026-01-16 13:05:33 +08:00
a4f98c2490 fix(‎database/gdb):Fix panic handling in DoCommit to prevent blocking on database driver panics (#4423)
When underlying database drivers panic during SQL operations, the
`DoCommit` function would propagate the panic unhandled, causing Insert
operations to block indefinitely instead of returning proper errors.
This was particularly problematic with ClickHouse when using `*big.Int`
values that exceed column type limits (e.g., int128).

## Problem

The issue manifested in the following scenario:
1. User inserts data with `*big.Int` value larger than ClickHouse int128
capacity
2. ClickHouse driver panics with `"math/big: buffer too small to fit
value"`
3. Panic propagates through the call stack: `big.nat.bytes` → ClickHouse
driver → `gdb.(*Core).DoCommit`
4. Insert operation blocks indefinitely, returning neither success nor
error

## Solution

Added comprehensive panic recovery to the `DoCommit` function in
`database/gdb/gdb_core_underlying.go`:

```go
// Panic recovery to handle panics from underlying database drivers
defer func() {
    if exception := recover(); exception != nil {
        if err == nil {
            if v, ok := exception.(error); ok && gerror.HasStack(v) {
                err = v
            } else {
                err = gerror.WrapCodef(gcode.CodeDbOperationError, 
                    gerror.NewCodef(gcode.CodeInternalPanic, "%+v", exception), 
                    FormatSqlWithArgs(in.Sql, in.Args))
            }
        }
    }
}()
```

## Benefits

- **Prevents blocking**: Insert operations now return errors instead of
hanging
- **Proper error context**: Errors include full SQL statement and
arguments for debugging
- **Graceful degradation**: Applications can handle driver panics
appropriately
- **Backward compatibility**: No breaking changes to existing
functionality
- **Universal coverage**: Protects against panics from any database
driver

## Testing

Added comprehensive tests covering:
- String panic values (e.g., "math/big: buffer too small")
- Error panic values with stack traces
- Various SQL operation types (Insert, Query, Prepare, etc.)
- Error message formatting and context preservation

All existing tests continue to pass, ensuring no regressions.

Fixes #4372.

<!-- START COPILOT CODING AGENT TIPS -->
---

💡 You can make Copilot smarter by setting up custom instructions,
customizing its development environment and configuring Model Context
Protocol (MCP) servers. Learn more [Copilot coding agent
tips](https://gh.io/copilot-coding-agent-tips) in the docs.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: houseme <4829346+houseme@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: hailaz <739476267@qq.com>
2026-01-16 12:43:52 +08:00
d1cd30c9b4 fix(contrib/drivers/gaussdb): remove github.com/lib/pq dependence (#4615)
Co-authored-by: John Guo <claymore1986@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-16 11:36:01 +08:00
5979261584 fix: the use of the deprecated variable {format} in the file util/gval… (#4258)
Fix the use of the deprecated variable {format} in the file
util/gvalid/testdata/i18n/cn/validation.toml.
2026-01-16 10:42:55 +08:00
df463d75bc fix(database/gdb): Resolve the cache error overwriting caused by the use of fixed cache keys in pagination queries. (#4339)
```golang
func main() {
	adapter := gcache.NewAdapterRedis(g.Redis())
	g.DB().GetCache().SetAdapter(adapter)
	result, count, err := g.Model("TBL_USER").Cache(gdb.CacheOption{
		Duration: 100 * time.Minute,
		Name:     "VIP",
	}).AllAndCount(false)
	g.DumpJson(result)
	fmt.Println(count, err)
}
```
执行这段查询后`g.DumpJson(result)`的结果是`[
    {
        "COUNT(1)": 5
    }

]`,但是正确结果应该是五条用户信息,查看源代码后发现先执行的count查询和后来select查询都是直接使用了`VIP`这个缓存key,在redis中实际缓存key是`SelectCache:VIP`,第二步查询select获得的是count查询的缓存,所以查询结果是错的。
因此为`Model`增加一个`PageCache`方法允许用户分别设置`count query`和`data query`的缓存参数
```golang
// PageCache sets the cache feature for pagination queries. It allows to configure
// separate cache options for count query and data query in pagination.
//
// Note that, the cache feature is disabled if the model is performing select statement
// on a transaction.
func (m *Model) PageCache(countOption CacheOption, dataOption CacheOption) *Model {
	model := m.getModel()
	model.pageCacheOption = []CacheOption{countOption, dataOption}
	model.cacheEnabled = true
	return model
}
```
然后`AllAndCount`在查询时分别给两个查询设置对应的缓存参数`ScanAndCount`同理
```golang

// AllAndCount retrieves all records and the total count of records from the model.
// If useFieldForCount is true, it will use the fields specified in the model for counting;
// otherwise, it will use a constant value of 1 for counting.
// It returns the result as a slice of records, the total count of records, and an error if any.
// The where parameter is an optional list of conditions to use when retrieving records.
//
// Example:
//
//	var model Model
//	var result Result
//	var count int
//	where := []any{"name = ?", "John"}
//	result, count, err := model.AllAndCount(true)
//	if err != nil {
//	    // Handle error.
//	}
//	fmt.Println(result, count)
func (m *Model) AllAndCount(useFieldForCount bool) (result Result, totalCount int, err error) {
	// Clone the model for counting
	countModel := m.Clone()

	// If useFieldForCount is false, set the fields to a constant value of 1 for counting
	if !useFieldForCount {
		countModel.fields = []any{Raw("1")}
	}
	if len(m.pageCacheOption) > 0 {
		countModel = countModel.Cache(m.pageCacheOption[0])
	}

	// Get the total count of records
	totalCount, err = countModel.Count()
	if err != nil {
		return
	}

	// If the total count is 0, there are no records to retrieve, so return early
	if totalCount == 0 {
		return
	}

	resultModel := m.Clone()
	if len(m.pageCacheOption) > 1 {
		resultModel = resultModel.Cache(m.pageCacheOption[1])
	}

	// Retrieve all records
	result, err = resultModel.doGetAll(m.GetCtx(), SelectTypeDefault, false)
	return
}
```

---------

Co-authored-by: houseme <housemecn@gmail.com>
2026-01-16 10:33:05 +08:00
de9d3c2b3c feat(util/gconv): Add OmitEmpty and OmitNil options to Scan function (#4584)
## 改进内容
- 扩展 `ScanOption`/`StructOption` 结构体,添加 `OmitEmpty bool` 字段:当设置为 true
时,跳过空值(如空字符串、零值等)的赋值;添加 `OmitNil bool` 字段:当设置为 true 时,跳过 nil 值的赋值;
- 添加 `ScanWithOptions` 函数,支持通过 `ScanOption` 参数使用新选项
- 原有的 `Scan` 函数行为完全不变
- 通过 `NewConverter` 创建的转换器也支持新功能

## 使用示例

### 基本用法
```go
type User struct {
    Name  *string
    Age   int
    Email string
}

type Person struct {
    Name  string
    Age   int
    Email string
}

user := User{Name: nil, Age: 25, Email: ""}
person := Person{Name: "zhangsan", Age: 0, Email: "old@example.com"}

err := gconv.ScanWithOptions(user, &person, gconv.ScanOption{
    OmitEmpty: true,
    OmitNil: true,
})
// 结果: person.Name 保持 "zhangsan",person.Age 变为 25,person.Email 保持 "old@example.com"
```

后续可以将`func Scan(srcValue any, dstPointer any, paramKeyToAttrMap
...map[string]string) (err error)`和`func ScanWithOptions(srcValue any,
dstPointer any, option ...ScanOption) (err error)`直接用`func Scan(srcValue
any, dstPointer any, option ...ScanOption) (err
error)`代替,`ScanOption`里已经包含了`paramKeyToAttrMap map[string]string`

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-16 10:19:02 +08:00
ce3599a672 fix(util/gconv): fix nested map conversion data loss in MapToMap (#4612)
## Summary
- Fix nested map conversion data loss when using `gconv.Scan()` or
`MapToMap()`
- When converting `map[string]any` to `map[string]map[string]float64`,
the nested data was lost
- Root cause: `MapToMap` incorrectly called `Struct()` for map value
types
- Solution: Separate `reflect.Map` handling from `reflect.Struct`, use
recursive `MapToMap()` for nested maps

## Test plan
- [x] Added test case reproducing original bug (nested map conversion)
- [x] Added test cases for deep nesting (3-5 levels)
- [x] Added test case for different key types
- [x] Added test case for empty nested map
- [x] Verified struct conversion still works (no regression)
- [x] Verified no infinite recursion with timeout tests
- [x] All gconv tests pass

Closes #4542

---------

Co-authored-by: hailaz <739476267@qq.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-15 21:24:35 +08:00
cd6fd247e2 fix(‎database/gdb): fix iTableName interface detection when using WithAll with .Scan on reflect.Value objects (#4606)
fix(gdb/getTableNameFromOrmTag): 修复在使用WithAll, 并且使用.Scan传入对象的情况下,
无法识别该对象字段是否实现了iTableName的接口. 因为该情况下, 传入的object是reflect.Value.

示例如下: 

type MaterialDetail struct {
*entity.Material
SourceFile MaterialSourceFileDetail json:"source_file"
orm:"with:id=source_file_id"
}

type MaterialSourceFileDetail struct {
*entity.MaterialSourceFile
}

func (MaterialSourceFileDetail) TableName() string {
return dao.MaterialSourceFile.Table()
}

func foo(ctx context.Context) {

err = dao.Material.Ctx(ctx).WithAll().
	Where(dao.Material.Columns().MaterialId, materialId).
	Scan(&material)
}

这种情况下, 传入getTableNameFromOrmTag的object是reflect.Value, 而不是对象本身.
这会导致识别出MaterialSourceFileDetail已经实现了iTableName接口, 无法获取到正确的表名.

---------

Co-authored-by: hailaz <739476267@qq.com>
2026-01-15 21:23:07 +08:00
be91c4889e feat(util/gvalid): add more rules: alpha,alpha-dash,alpha-num,lowercase,numeric,uppercase (#4601)
Add more check rules

---------

Signed-off-by: yuluo-yx <yuluo08290126@gmail.com>
Co-authored-by: hailaz <739476267@qq.com>
2026-01-15 17:51:55 +08:00
6219da7a76 feat(‎contrib/registry/nacos): add SetDefaultEndpoint and SetDefaultMetadata methods (#4608)
Add configurable default endpoint and metadata support to nacos
Registry,
providing a more flexible alternative to hardcoded environment variable
reads.

- Add defaultEndpoint and defaultMetadata fields to Registry struct
- Add SetDefaultEndpoint method to override service endpoints
- Add SetDefaultMetadata method to merge extra metadata
- Update Register method to use configured defaults

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: houseme <housemecn@gmail.com>
2026-01-15 14:36:27 +08:00
c600f3aae8 feat(container): Add NewXXXWithChecker function for gmap/gset/gtree (#4610)
为了解决开发者需要通过`var`在代码顶部创建`gmap/gset/gtree`时需要同时设置`nilchecker`的需求,为这几个容易增加带有`checker`入参的构造函数`NewxxxxWithChecker`和`NewxxxWithCheckerFrom`

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-15 14:26:42 +08:00
9dd43cd331 feat(gdb/gdb_model_lock.go): gdb support lock update skip locked (#4607)
feat(gdb/gdb_model_lock.go): GDB 支持 FOR UPDATE SKIP LOCKED 语法

---------

Co-authored-by: hailaz <739476267@qq.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-15 13:27:25 +08:00
3e73e2d2cc fix(database/gdb): skip field filtering when table/alias is unknown in FieldsPrefix (#4602)
## Summary
- Fix FieldsPrefix silently dropping fields when called before LeftJoin
- When table/alias is unknown, skip filtering and return fields directly

## Test plan
- [x] Added unit test Test_Issue4595 in pgsql driver
- [x] Test covers: FieldsPrefix before LeftJoin, Fields with prefix,
FieldsPrefix after LeftJoin

Closes #4595
2026-01-15 10:25:40 +08:00
1ed4e0267a fix(util/gconv): gconv unsafe str to bytes (#4600)
The gconv.UnsafeStrToBytes function has been updated to use the Go 1.20+
safe approach, as the previous implementation could cause a panic in
certain scenarios.

For example, when an HTTP request header specifies Content-Type:
application/x-www-form-urlencoded, but the actual request body contains
JSON data, the following code attempts to detect and handle this case:
```go
if !gregex.IsMatchString(`^[\w\-\[\]]+$`, name) && len(r.PostForm) == 1 {
    // It might be JSON/XML content.
    if s := gstr.Trim(name + strings.Join(values, " ")); len(s) > 0 {
        if s[0] == '{' && s[len(s)-1] == '}' || s[0] == '<' && s[len(s)-1] == '>' {
            r.bodyContent = gconv.UnsafeStrToBytes(s)
            params = ""
            break
        }
    }
}
```
However, after this assignment, bodyContent ends up with a capacity
(cap) of 0. slice operations like [:] perform stricter validation and
will panic if the capacity is 0. This causes a panic in functions such
as:

```go
body = bytes.TrimSpace(body)

func TrimSpace(s []byte) []byte {
    ...
    return s[start:stop] // panic here due to cap == 0
}
```
The capacity (cap) of the slice returned by directly calling this
function is unpredictable, as it depends on the adjacent memory layout.
However, within the framework, this causes issues—likely because,
starting from Go 1.22, the standard library's parseForm implementation
consistently appends a trailing zero byte after the string data in
memory.
This PR fix the problem.

------------------------------------
gconv unsafe str to bytes 改用 go1.20 后的写法,之前的写法在某些场景下会 panic
例如 http 请求头为`application/x-www-form-urlencoded`,实际的 body 为 json,
经过解析后
```go
	if !gregex.IsMatchString(`^[\w\-\[\]]+$`, name) && len(r.PostForm) == 1 {
					// It might be JSON/XML content.
					if s := gstr.Trim(name + strings.Join(values, " ")); len(s) > 0 {
						if s[0] == '{' && s[len(s)-1] == '}' || s[0] == '<' && s[len(s)-1] == '>' {
							r.bodyContent = gconv.UnsafeStrToBytes(s)
							params = ""
							break
						}
					}
				}
```
bodyContent的 cap 为 0,由于切片操作[:]会校验 cap 为 0,会直接 panic
```go
body = bytes.TrimSpace(body)

---
func TrimSpace(s []byte) []byte {
...
return s[start:stop] // panic
}
```
直接使用这个函数得到的 cap 会是随机的, 因为跟的内存不确定,但是在框架中有问题,估计是1.22 后标准库parseForm
的时候后面内存固定跟了个 0
该 PR 修复这个问题

Co-authored-by: liov-ola <liov@olaparty.sg>
2026-01-15 10:21:45 +08:00
3120a8bc22 fix(net/goai): add openapi uuid.UUID type support (#4604)
This pull request updates the logic in `golangTypeToOAIType` to improve
how Go types are mapped to OpenAPI types. The most important changes are
focused on handling specific struct and slice types more accurately,
ensuring better compatibility with OpenAPI specifications.

Type mapping improvements:

* Added explicit handling for `[]uint8` and `uuid.UUID` types, mapping
both to `TypeString`. This ensures these commonly used types are
correctly represented in OpenAPI schemas.
* Refactored the switch statement to check for specific struct types
(`time.Time`, `gtime.Time`, `ghttp.UploadFile`, `[]uint8`, and
`uuid.UUID`) before falling back to the kind-based mapping. This
improves accuracy for special-case types.
2026-01-15 10:20:19 +08:00
13524a36bc fix(container): Add NilChecker Support to gmap, gset, and gtree for Typed Nil Issue Resolution (#4605)
## 描述
本PR为`gmap`、`gset`和`gtree`容器引入了`NilChecker`机制,以解决Go语言中的`typed
nil`问题。该实现允许用户注册自定义的nil检查函数来确定值是否应被视为nil,这对于处理那些会被存储到容器中的`typed
nil`值特别有用。
## 情况描述
当前`gmap`等容器的泛型容器存在对`value`的`nil`值无法正确过滤的问题,例如以下例子中如果使用默认的`if any(value)
!=
nil`去判断就会得到错误的结果,原因是会出现带有类型的`(*Student)(nil)`直接和`nil`比较或者使用`any`强转都是不对的,使用反射可以解决但是性能太差了,所以换个思虑我们让用户自己决定如何判断`nil`就能解决这个问题
```golang
func main() {
	type Student struct {
		Name string
		Age  int
	}
	m1 := gmap.NewKVMap[int, *Student](true)
	for i := 0; i < 10; i++ {
		m1.GetOrSetFuncLock(i, func() *Student {
			if i%2 == 0 {
				return &Student{}
			}
			return nil
		})
	}
	fmt.Println(m1.Size()) //  10
	m2 := gmap.NewKVMap[int, *Student](true)
	m2.RegisterNilChecker(func(student *Student) bool {
		return student == nil
	})
	for i := 0; i < 10; i++ {
		m2.GetOrSetFuncLock(i, func() *Student {
			if i%2 == 0 {
				return &Student{}
			}
			return nil
		})
	}
	fmt.Println(m2.Size())  // 5

}

```

## 变更内容
- 在gmap、gset和gtree包中添加了`NilChecker`类型定义
- 扩展容器结构体,增加`nilChecker`字段来存储自定义nil检查函数
- 实现了`RegisterNilChecker`方法,允许用户注册自定义nil检查逻辑
- 添加了`isNil`内部方法,优先使用自定义nil检查函数或回退到默认的`any(v) == nil`检查
- 更新关键操作(AddIfNotExist、Set等)以利用nil检查机制
- 为所有三个容器类型添加了全面的测试用例以验证nilchecker功能

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-15 10:18:05 +08:00
cb26931378 ci(docker-services): change chinese printing message to english (#4599)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-09 16:04:41 +08:00
40f4d9f8ec chore: translte zh comment to en (#4591)
AS TITLE

---------

Signed-off-by: yuluo-yx <yuluo08290126@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-09 14:27:28 +08:00
caea7ea4b8 fix(os/gcfg): adjust priority of env|cmd higer than config file (#4074) (#4587)
Co-authored-by: 杨延庆 <yangyq@bosyun.cn>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-09 11:04:00 +08:00
a6485d53af fix(cmd/gf): Fixed an issue where formatting caused import errors in gf init (#4598)
This pull request refactors the way Go files are formatted after project
generation in the `geninit` package. The main change is replacing the
previous formatting utility with a new function that uses the standard
library's `go/format` package, ensuring that only code formatting is
applied and import paths are not inadvertently modified.

**Formatting improvements:**

* Replaced the use of `utils.GoFmt` with a new `formatGoFiles` function
that utilizes `go/format` for formatting Go files, avoiding unwanted
changes to local import paths.
(`cmd/gf/internal/cmd/geninit/geninit_generator.go`)
* Added the `formatGoFiles` function, which recursively formats all Go
files in a directory using `go/format` and logs any formatting errors.
(`cmd/gf/internal/cmd/geninit/geninit_generator.go`)
* Updated comments and references in the code to clarify that formatting
is now handled by `formatGoFiles` instead of `utils.GoFmt`.
(`cmd/gf/internal/cmd/geninit/geninit_ast.go`)

**Dependency changes:**

* Removed the import of the custom `utils` package and added the
standard `go/format` package to support the new formatting approach.
(`cmd/gf/internal/cmd/geninit/geninit_generator.go`)
2026-01-09 11:00:35 +08:00
db9f47d942 refract(gerror): add ITextArgs interface and its implements, mainly for i18n that needs text and args separately (#4597)
This pull request refactors the error handling code to improve support
for error text formatting with arguments, making it easier to retrieve
both the error message template and its arguments (useful for i18n and
structured error handling). It introduces the new `ITextArgs` interface,
updates error constructors to store format strings and arguments
separately, and adds methods to retrieve them. Several usages and tests
are updated to reflect these changes.

### Error formatting and argument support

* Introduced the `ITextArgs` interface to allow errors to expose their
text template and arguments separately, supporting advanced use cases
like internationalization (`errors/gerror/gerror.go`).
* Updated the `Error` struct to include an `args` field for error
arguments, and added methods `TextWithArgs()`, `Text()`, and `Args()` to
retrieve formatted error text, the template, and arguments respectively
(`errors/gerror/gerror_error.go`).
[[1]](diffhunk://#diff-b56b52e546735b8196ec3e8bd25c0b007ac134e2f13b116ee3abcb2f92c3bdd9R23)
[[2]](diffhunk://#diff-b56b52e546735b8196ec3e8bd25c0b007ac134e2f13b116ee3abcb2f92c3bdd9L121-R145)
* Changed all error creation and wrapping functions (e.g., `Newf`,
`Wrapf`, `NewCodef`, etc.) to store the format string and arguments
separately, rather than pre-formatting the error text
(`errors/gerror/gerror_api.go`, `errors/gerror/gerror_api_code.go`).
[[1]](diffhunk://#diff-847475c1de42114004c50163aa2f34a4095e05122b4c2993aa3df4e5923e83cbL24-R27)
[[2]](diffhunk://#diff-847475c1de42114004c50163aa2f34a4095e05122b4c2993aa3df4e5923e83cbL43-R48)
[[3]](diffhunk://#diff-847475c1de42114004c50163aa2f34a4095e05122b4c2993aa3df4e5923e83cbL77-R78)
[[4]](diffhunk://#diff-31ee6b1493f4b206c060a98818226b1b78102c91b5ae22e34ed4d1bb4a38c185L25-R29)
[[5]](diffhunk://#diff-31ee6b1493f4b206c060a98818226b1b78102c91b5ae22e34ed4d1bb4a38c185L44-R50)
[[6]](diffhunk://#diff-31ee6b1493f4b206c060a98818226b1b78102c91b5ae22e34ed4d1bb4a38c185L77-R79)
[[7]](diffhunk://#diff-31ee6b1493f4b206c060a98818226b1b78102c91b5ae22e34ed4d1bb4a38c185L107-R110)
* Updated the `Option` struct and related constructor to handle error
arguments (`errors/gerror/gerror_api_option.go`).
[[1]](diffhunk://#diff-4b458af6df9a0d8289303cf408b082ed472360b286cdc5a556c8fe7541973caaR16)
[[2]](diffhunk://#diff-4b458af6df9a0d8289303cf408b082ed472360b286cdc5a556c8fe7541973caaR26)

### Code and test improvements

* Updated formatting and equality checks to use the new methods for
retrieving formatted error text and arguments, ensuring consistent
behavior (`errors/gerror/gerror_error.go`,
`errors/gerror/gerror_error_format.go`).
[[1]](diffhunk://#diff-b56b52e546735b8196ec3e8bd25c0b007ac134e2f13b116ee3abcb2f92c3bdd9L45-R46)
[[2]](diffhunk://#diff-fa801ef307f6c6fdda49fe9853593de29eda5b4d3712ea5bf9ed39de6e6859ebL26-R26)
* Improved unit tests to verify the new interface and argument handling,
including tests for the `ITextArgs` interface
(`errors/gerror/gerror_z_unit_test.go`).
* Minor code cleanup, such as removing unused imports and updating
comments for clarity (`errors/gerror/gerror_api.go`,
`errors/gerror/gerror_api_code.go`,
`errors/gerror/gerror_error_json.go`).
[[1]](diffhunk://#diff-847475c1de42114004c50163aa2f34a4095e05122b4c2993aa3df4e5923e83cbL10-L11)
[[2]](diffhunk://#diff-31ee6b1493f4b206c060a98818226b1b78102c91b5ae22e34ed4d1bb4a38c185L10)
[[3]](diffhunk://#diff-3e4ba207e242eb338f31f1091466374e8e72754a8969d92724bfb5c6b88f25edL15-R15)

These changes make error handling more flexible and maintainable,
especially for scenarios where error messages need to be localized or
programmatically inspected.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-09 10:48:43 +08:00
c5778127b1 fix(contrib/drivers): resolve field duplication issue when same table/column names exist across different MySQL/MariaDB databases (#4577)
当不同数据库存在相同表名和相同字段名, 并且该字段存在约束时, 例如字段类型是JSON, 会出现字段叠加. 导致访问数据库时, 出现数组越界.

---------

Co-authored-by: hailaz <739476267@qq.com>
2026-01-07 17:32:16 +08:00
8f826edc43 fix(cmd/gf): improve init command with version retry and gofmt support (#4592)
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: hailaz <29968474+hailaz@users.noreply.github.com>
2026-01-07 16:20:29 +08:00
d148e0ea62 test(errors/gcode,gerror): add unit tests for error handling interfaces and methods (#4586)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-05 13:26:02 +08:00
d091547212 fix(gf/gen): Fixed a problem that could cause duplication when generating wit… (#4268)
Fixed #4217

---------

Co-authored-by: hailaz <739476267@qq.com>
2025-12-27 20:48:15 +08:00
6334ee1958 feat(cmd/gf): improve and enhance gen ctrl (#4325)
## 介绍
有时候某些项目没有达到要使用大仓模式的程度,使用单仓便可以完成业务。
但是`gf gen ctrl` 只能支持 `module/version` 这种目录,譬如
`user/v1`,像`api/app/user/v1`,`api/admin/admin/v1` 这种接口便无能为力。

**本`PR`改进了生成模式,现在使其可以更灵活的生成控制器,包括多级目录生成。**

## 例子
在 `api` 下定义了 `app` 和 `admin` 两个模块,其中 `app` 下又定义了 `/user/v1` 和
`/user/user_ext/v1`,最后生成如红框所示:


![image](https://github.com/user-attachments/assets/67db2f1c-8873-44c8-83ee-8620cfeb07e8)

这是一个复杂的例子,用来检测代码的健壮性。
在真实的项目中,应该类似 `api/app/user/v1`,`api/app/user_ext/v1`。

## 其他
- 规范了一些测试用例,譬如本来的测试文件放在 `/testdata/genctrl` 和 `/testdata/genctrl-merge`
中,现在更改为 `/testdata/genctrl/default` 和 `/testdata/genctrl/merge`;
- 替换掉废弃的方法 `gfile.Remove`。

增进来源:Issue和官网评论

---------

Co-authored-by: hailaz <739476267@qq.com>
2025-12-27 19:50:21 +08:00