contrib
contrib copied to clipboard
entproto: fix service.List pageToken for custom fields (UUID/string)
Motivation
The current List service template generates faulty code if a custom GoType field is used (currently only UUID and string types are supported by this fix).
I haven't tested this on a large set of inputs and probably I'm lacking context why the pageToken has been implemented this way (also why it is Base64-encoded), but using a call to the field_to_ent
template hopefully leads to a more sane behavior, as it is also used for Get()
and Update()
templates.
Example schema
Example 1: UUID type
field.UUID("id", PULID{}).
Default(func() PULID { return MustNewPULID(m.prefix) }).
Annotations(
entproto.Field(1)),
),
Example 2: String type
field.Bytes("id").
GoType(PULID{}).
DefaultFunc(func() PULID { return MustNewPULID(m.prefix) }).
Annotations(
entproto.Field(1, entproto.Type(descriptorpb.FieldDescriptorProto_TYPE_STRING)),
).
Diff of rendered code
IDLTE
only accepts custom type (in this case pulid.PULID). Therefore the green lines are working code:
if req.GetPageToken() != "" {
bytes, err := base64.StdEncoding.DecodeString(req.PageToken)
if err != nil {
return nil, status.Errorf(codes.InvalidArgument, "page token is invalid")
}
- pageToken, err := uuid.ParseBytes(bytes)
- if err != nil {
- return nil, status.Errorf(codes.InvalidArgument, "page token is invalid")
- }
+ pageToken := pulid.PULID{}
+ if err := (&pageToken).Scan(bytes); err != nil {
+ return nil, status.Errorf(codes.InvalidArgument, "invalid argument: %s", err)
+ }
listQuery = listQuery.
Where(evcharger.IDLTE(pageToken))
}
Alternatives
It would probably be cleaner to allow implementing UnmarshalProto
/MarshalProto
for custom types similar like we can implement a custom UnmarshalGQL
/MarshalGQL
. The reasoning is that the Valuer/Scanner interface used by the database driver is not necessarily what we want to represent in the protobuf types.