reform icon indicating copy to clipboard operation
reform copied to clipboard

Allow `[]byte` to be used as PK

Open AlekSi opened this issue 7 years ago • 2 comments

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 avatar Sep 02 '16 13:09 AlekSi

@AlekSi do you have a vision of what exactly should be done to fix the problem?

rumyantseva avatar Apr 23 '19 12:04 rumyantseva

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.

AlekSi avatar Apr 28 '19 16:04 AlekSi