reform
reform copied to clipboard
Allow `[]byte` to be used as PK
WIP branch: https://github.com/go-reform/reform/tree/slice-pk
Valid use-case: UUID in binary form, probably should be used as []byte
or [16]byte, not as string
.
Remaining problems:
-
HasPK
implementation (operator != not defined on slice
) -
SetPK
implementation (cannot convert i64 (type int64) to type []uint8
)
Related to #43.
@AlekSi do you have a vision of what exactly should be done to fix the problem?
We need more information about PK type.
HasPK
is currently generated with this template:
// HasPK returns true if record has non-zero primary key set, false otherwise.
func (s *{{ .Type }}) HasPK() bool {
return s.{{ .PKField.Name }} != {{ .TableVar }}.z[{{ .TableVar }}.s.PKFieldIndex]
}
It compiles only for types that has !=
operators defined, and slices do not define it. We could use !reflect.DeepEqual(s.{{ .PKField.Name }}, {{ .TableVar }}.z[{{ .TableVar }}.s.PKFieldIndex])
, but that might be not so good. With knowledge about PK type, we could use code with !=
for simple types, s.{{ .PKField.Name }}.Equal({{ .TableVar }}.z[{{ .TableVar }}.s.PKFieldIndex])
for types defining Equal(x X) bool
, and reflect.DeepEqual
as fallback.
SetPK
is currently generated with this template:
// SetPK sets record primary key.
func (s *{{ .Type }}) SetPK(pk interface{}) {
if i64, ok := pk.(int64); ok {
s.{{ .PKField.Name }} = {{ .PKField.Type }}(i64)
} else {
s.{{ .PKField.Name }} = pk.({{ .PKField.Type }})
}
}
It is only used by when Record
with zero PK is inserted, PK is autogenerated, and RDBMS support LastInsertId
: https://github.com/go-reform/reform/blob/c8eea006559b6f50a00404d9f81b191da8fd02cc/querier_commands.go#L97 In that case, SetPK
argument is always int64
, but PK field can have another type, for example, int32
or even type MyPKType int32
. That's why we handle int64
differently and try a conversion. With knowledge about the PK type, we can use the type-specific code.
There are two ways to get more information about PK type. The first one is to parse files with go/types
: https://github.com/go-reform/reform/issues/57 The second is to use some reflection in init()
function to switch implementations. You are welcome to work on any of them.