feat: replace mapping generation with checked copy utilities
This commit is contained in:
23
examples/copying/README.md
Normal file
23
examples/copying/README.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# 结构复制示例
|
||||
|
||||
在框架仓库根目录运行 `go run ./examples/copying`;不需要数据库、网络服务或 JSON 映射配置。
|
||||
|
||||
示例包含:可复用构造器、Go 字段改名、时间自定义转换、保留 false、深拷贝切片、同类型 Clone,以及拒绝自定义转换器返回输入的原切片。
|
||||
|
||||
预期输出:
|
||||
|
||||
```text
|
||||
name=sample enabled=false time=2026-01-01T00:00:00Z sourceTag=original
|
||||
clone detached: true
|
||||
shared converter rejected: true
|
||||
```
|
||||
|
||||
测试:`go test -race ./examples/copying`。完整策略、限制与旧生成映射迁移见 [COPY.md](../../COPY.md)。
|
||||
|
||||
独立工资三端的实际生成、HTTP 与金额用例见 [集成测试](../../cmd/go-omni/apigen/copyConsumer_test.go) 和 [公共契约](../../cmd/go-omni/apigen/testdata/composition/service.api)。框架根目录运行:
|
||||
|
||||
```sh
|
||||
GO_OMNI_SCAFFOLD_INTEGRATION=1 go test ./cmd/go-omni/apigen -run TestCopyxThreeEndpointConsumer -count=1
|
||||
```
|
||||
|
||||
该测试在临时独立项目中执行,三个入口共用一个普通 Go copyx helper。公共字段新增时,只修改公共契约和独立业务结构,三个入口的转换规则不增加。
|
||||
61
examples/copying/main.go
Normal file
61
examples/copying/main.go
Normal file
@@ -0,0 +1,61 @@
|
||||
// copying demonstrates optional Go-to-Go conversion and checked deep copying.
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"git.yuntuo.hk/k2safe/go-omni/copyx"
|
||||
)
|
||||
|
||||
type Input struct {
|
||||
Name string
|
||||
Enabled bool
|
||||
Tags []string
|
||||
CreatedAt time.Time
|
||||
}
|
||||
type View struct {
|
||||
DisplayName string
|
||||
Enabled bool
|
||||
Tags []string
|
||||
CreatedAt string
|
||||
}
|
||||
|
||||
func run() error {
|
||||
converter, err := copyx.New(
|
||||
copyx.WithDeepCopy(),
|
||||
copyx.WithFieldNames[Input, View](map[string]string{"Name": "DisplayName"}),
|
||||
copyx.WithConverter(func(v time.Time) (string, error) { return v.UTC().Format(time.RFC3339), nil }),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
source := Input{Name: "sample", Enabled: false, Tags: []string{"original"}, CreatedAt: time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC)}
|
||||
var target View
|
||||
if err = converter.Copy(&target, source); err != nil {
|
||||
return err
|
||||
}
|
||||
target.Tags[0] = "changed"
|
||||
fmt.Printf("name=%s enabled=%t time=%s sourceTag=%s\n", target.DisplayName, target.Enabled, target.CreatedAt, source.Tags[0])
|
||||
|
||||
cloned, err := copyx.Clone(source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cloned.Tags[0] = "separate"
|
||||
fmt.Println("clone detached:", source.Tags[0] == "original")
|
||||
|
||||
_, err = copyx.Clone(source.Tags, copyx.WithConverter(func(v []string) ([]string, error) { return v, nil }))
|
||||
fmt.Println("shared converter rejected:", errors.Is(err, copyx.ErrSharedReference))
|
||||
if !errors.Is(err, copyx.ErrSharedReference) {
|
||||
return errors.New("expected alias rejection")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func main() {
|
||||
if err := run(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
9
examples/copying/main_test.go
Normal file
9
examples/copying/main_test.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package main
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestExample(t *testing.T) {
|
||||
if err := run(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"generatorConfig": true,
|
||||
"templateVersion": "v0.18.0-preview",
|
||||
"templateVersion": "v0.19.0-preview",
|
||||
"profile": {
|
||||
"database": "none",
|
||||
"storage": "none",
|
||||
|
||||
@@ -2,7 +2,7 @@ module example.com/managed
|
||||
|
||||
go 1.22.0
|
||||
|
||||
require git.yuntuo.hk/k2safe/go-omni v0.18.0-preview
|
||||
require git.yuntuo.hk/k2safe/go-omni v0.19.0-preview
|
||||
|
||||
require (
|
||||
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
||||
|
||||
Reference in New Issue
Block a user