Campos Opcionales
Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →
Un problema común con Protobufs es cómo se representan los valores nulos: un campo primitivo con valor cero no se codifica en la representación binaria. Esto significa que las aplicaciones no pueden distinguir entre cero y no-definido para campos primitivos.
Para solucionarlo, el proyecto Protobuf incluye unos tipos bien conocidos llamados "tipos wrapper".
Por ejemplo, el tipo wrapper para un bool se llama google.protobuf.BoolValue y está definido así:
// Wrapper message for `bool`.
//
// The JSON representation for `BoolValue` is JSON `true` and `false`.
message BoolValue {
// The bool value.
bool value = 1;
}
Cuando entproto genera una definición de mensaje Protobuf, utiliza estos tipos wrapper para representar campos "Opcionales" de ent.
Veámoslo en acción modificando nuestro esquema ent para incluir un campo opcional:
// Fields of the User.
func (User) Fields() []ent.Field {
return []ent.Field{
field.String("name").
Unique().
Annotations(
entproto.Field(2),
),
field.String("email_address").
Unique().
Annotations(
entproto.Field(3),
),
field.String("alias").
Optional().
Annotations(entproto.Field(4)),
}
}
Si volvemos a ejecutar go generate ./..., observa que nuestra definición Protobuf para User ahora luce así:
message User {
int32 id = 1;
string name = 2;
string email_address = 3;
google.protobuf.StringValue alias = 4; // <-- this is new
repeated Category administered = 5;
}
La implementación del servicio generado también utiliza este campo. Observa en entpb_user_service.go:
func (svc *UserService) createBuilder(user *User) (*ent.UserCreate, error) {
m := svc.client.User.Create()
if user.GetAlias() != nil {
userAlias := user.GetAlias().GetValue()
m.SetAlias(userAlias)
}
userEmailAddress := user.GetEmailAddress()
m.SetEmailAddress(userEmailAddress)
userName := user.GetName()
m.SetName(userName)
for _, item := range user.GetAdministered() {
administered := int(item.GetId())
m.AddAdministeredIDs(administered)
}
return m, nil
}
Para usar los tipos wrapper en nuestro código cliente, podemos emplear métodos auxiliares del paquete wrapperspb
que facilitan la creación de instancias de estos tipos. Por ejemplo en cmd/client/main.go:
func randomUser() *entpb.User {
return &entpb.User{
Name: fmt.Sprintf("user_%d", rand.Int()),
EmailAddress: fmt.Sprintf("user_%d@example.com", rand.Int()),
Alias: wrapperspb.String("John Doe"),
}
}