Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

能否支持下字段属性的枚举生成 #262

Closed
waltcow opened this issue Dec 1, 2021 · 16 comments
Closed

能否支持下字段属性的枚举生成 #262

waltcow opened this issue Dec 1, 2021 · 16 comments
Assignees

Comments

@waltcow
Copy link

waltcow commented Dec 1, 2021

在编码过程中,经常会遇到用某个数值来表示某种状态、类型或者阶段的情况,比如有这样一个枚举:

public enum ComputerState {
    OPEN(10),         //开启
    CLOSE(11),         //关闭
    OFF_LINE(12),     //离线
    FAULT(200),     //故障
    UNKNOWN(255);     //未知

    private int code;
    ComputerState(int code) { this.code = code; }
}

通常我们希望将表示状态的数值存入数据库,即ComputerState.OPEN存入数据库取值为10。

能否通过field comment的中备注,来生成对应枚举值

比如可以约定注释检查规则的正则表达式如下

REMARKS_PATTERN = ".*\\s*\\[\\s*(\\w+\\s*\\(\\s*[\\u4e00-\\u9fa5_\\-a-zA-Z0-9]+\\s*\\)\\s*:\\s*[\\u4e00-\\u9fa5_\\-a-zA-Z0-9]+\\s*\\,?\\s*)+\\s*\\]\\s*.*";
CREATE TABLE `tb` (
  `type` smallint(3) COMMENT '注释[success(0):成功, fail(1):失败]',                       
);

提取出字段属性相应的枚举

type Type int

const (
        Success  Type = 0 //成功
        Fail Type = 1 //失败
)
@tr1v3r
Copy link
Member

tr1v3r commented Dec 1, 2021

如果只是对数字类型的枚举可以通过在生成的时候加入gen.FieldType("type", "basic.Type")方式直接将对应字段指定为相应类型就可以了 https://github.com/go-gorm/gen#generate-model

@tr1v3r
Copy link
Member

tr1v3r commented Dec 1, 2021

如果是字符串或者其他的枚举类型就实现ScanValuer接口就可以了

@waltcow
Copy link
Author

waltcow commented Dec 1, 2021

如果只是对数字类型的枚举可以通过在生成的时候加入gen.FieldType("type", "basic.Type")方式直接将对应字段指定为相应类型就可以了 https://github.com/go-gorm/gen#generate-model

如果这样的话,“basic.Type" 的 import 路径如何适配,这类constant文件不在一个package里

@tr1v3r
Copy link
Member

tr1v3r commented Dec 1, 2021

可以直接用constant.Type这种形势,生成代码的过程中有一步是使用goimports修正格式和引用路径,可以试一下

@waltcow
Copy link
Author

waltcow commented Dec 2, 2021

可以直接用constant.Type这种形势,生成代码的过程中有一步是使用goimports修正格式和引用路径,可以试一下

err = render(tmpl.Model, &buf, data.BaseStruct)

这里model的模版都是写死了的

import "time"

在经过process后遗留的package会被导入

result, err := imports.Process(fileName, content, nil)

生成出来的model 头是这样的,

import (
	"time"

	"gorm.io/gorm"
)

如果改的话是直接在model template的import 里面加变量控制吗😅

@tr1v3r
Copy link
Member

tr1v3r commented Dec 2, 2021

gen.FieldType("type", "constant.Type")就可以了, goimports会自动补全constan包的完整引用路径

@waltcow waltcow closed this as completed Dec 2, 2021
@waltcow waltcow reopened this Dec 23, 2021
@waltcow waltcow closed this as completed Dec 23, 2021
@waltcow waltcow reopened this Dec 23, 2021
@waltcow
Copy link
Author

waltcow commented Dec 23, 2021

在使用枚举类时, 这个ScanValuer接口,无法兼容 database/sql scanner 接口

https://husobee.github.io/golang/database/2015/06/12/scanner-valuer.html

image

image

@tr1v3r
Copy link
Member

tr1v3r commented Dec 23, 2021

是因为没有用指针吧? ScanValuer接口的Scan用的就是database/sql的Scanner方法

@waltcow
Copy link
Author

waltcow commented Dec 23, 2021

是因为没有用指针吧? ScanValuer接口的Scan用的就是database/sql的Scanner方法

可以给多一点提示吗😭

@waltcow
Copy link
Author

waltcow commented Dec 23, 2021

我发现数据库读出来的record里面的值无法映射成枚举类

@tr1v3r
Copy link
Member

tr1v3r commented Dec 23, 2021

是因为没有用指针吧? ScanValuer接口的Scan用的就是database/sql的Scanner方法

可以给多一点提示吗😭

😂就是说 Type这个字段,类型可以用 *const.ArtworkSnapshotType 而不是单纯的类型const.ArtworkSnapshotType

@tr1v3r
Copy link
Member

tr1v3r commented Dec 23, 2021

我发现数据库读出来的record里面的值无法映射成枚举类

因为scan方法没有生效吧

@waltcow
Copy link
Author

waltcow commented Dec 23, 2021

原来我是这样写的

func (a ArtworkSnapshotType) Scan(value interface{}) error {
	return nil
}

后面写成这样

func (a *ArtworkSnapshotType) Scan(value interface{}) error {
	if v, ok := value.(int64); ok {
	
		*a = ArtworkSnapshotType(v)
		return nil
	}
	return errors.New("failed to scan ArtworkSnapshotType")
}

编译不过

cannot use constant.ArtworkSnapshotWeixinChatBackground (type constant.ArtworkSnapshotType) as type field.ScanValuer in argument to Template.Type.In:
constant.ArtworkSnapshotType does not implement field.ScanValuer (Scan method has pointer receiver)

@tr1v3r
Copy link
Member

tr1v3r commented Dec 23, 2021

原来我是这样写的

func (a ArtworkSnapshotType) Scan(value interface{}) error {
	return nil
}

后面写成这样

func (a *ArtworkSnapshotType) Scan(value interface{}) error {
	if v, ok := value.(int64); ok {
	
		*a = ArtworkSnapshotType(v)
		return nil
	}
	return errors.New("failed to scan ArtworkSnapshotType")
}

编译不过

cannot use constant.ArtworkSnapshotWeixinChatBackground (type constant.ArtworkSnapshotType) as type field.ScanValuer in argument to Template.Type.In:
constant.ArtworkSnapshotType does not implement field.ScanValuer (Scan method has pointer receiver)

用指针做接收器就是*constant.ArtworkSnapshotType实现了field.ScanValuer,而不是constant.ArtworkSnapshotType实现了field.ScanValuer

另外,只能用指针作为接收器,不然不能修改自身的值

@waltcow
Copy link
Author

waltcow commented Dec 24, 2021

字段如果用了*const.ArtworkSnapshotType,业务编码时将带来更多的复杂性,思虑再三还是不想用枚举了

还有就是scan 出来的value竟然是uint8[],

image

查了下也有类似的 go-sql-driver/mysql#441

@tr1v3r
Copy link
Member

tr1v3r commented Dec 24, 2021

嗯嗯,自定义类型的方法如果不用指针是不能修改自身值的,这是go本身的特性。这个value类型是[]uint8应该是受数据库里的类型影响吧,确实比较奇怪

@waltcow waltcow closed this as completed Dec 24, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants