From d82c1b6a05cedd6de80ed77aadb0af257238c301 Mon Sep 17 00:00:00 2001 From: Simon Wenmouth Date: Mon, 15 Jul 2024 22:57:02 -0500 Subject: [PATCH] protoc-gen-ent: support `entgql.Annotation` Added support for `entgql.Annotation` to the `protoc-gen-ent` plugin. It should now be possible to generate an Ent schema and its GraphQL configuration from a Protocol Buffer file. The `opts.proto` was updated adding `GQL` child MessageTypes to the existing MessageTypes (`Schema`, `Field`, `Edge`). The associated generated code (`opts.pb.go`) was regenerated using `protoc-gen-go`. The AST generation code in `schemaast/annotation.go` was updated to know about the `entgql` annotations. The new method attempts to generate code similar to that in the documentation. The main package was updated to map the configuration settings in the updated `opts.proto` to the corresponding annotations for the schema, fields, and edges. --- entproto/cmd/protoc-gen-ent/main.go | 119 +++- .../cmd/protoc-gen-ent/options/ent/opts.pb.go | 567 +++++++++++++++--- .../cmd/protoc-gen-ent/options/ent/opts.proto | 32 + schemast/annotation.go | 65 ++ 4 files changed, 698 insertions(+), 85 deletions(-) diff --git a/entproto/cmd/protoc-gen-ent/main.go b/entproto/cmd/protoc-gen-ent/main.go index 0a0f7c9e0..3c4112fe4 100644 --- a/entproto/cmd/protoc-gen-ent/main.go +++ b/entproto/cmd/protoc-gen-ent/main.go @@ -17,10 +17,13 @@ package main import ( "flag" "fmt" + "strings" + "entgo.io/contrib/entgql" entopts "entgo.io/contrib/entproto/cmd/protoc-gen-ent/options/ent" "entgo.io/contrib/schemast" "entgo.io/ent" + "entgo.io/ent/schema" "entgo.io/ent/schema/edge" "entgo.io/ent/schema/field" "google.golang.org/protobuf/compiler/protogen" @@ -108,8 +111,37 @@ func toSchema(m *protogen.Message, opts *entopts.Schema) (*schemast.UpsertSchema if opts.Name != nil { name = opts.GetName() } + var annotations []schema.Annotation + gql := opts.GetGql() + if gql != nil { + if gql.GetQueryField() { + if gql.GetQueryFieldName() != "" { + annotations = append(annotations, entgql.QueryField(gql.GetQueryFieldName()).Annotation) + } else { + annotations = append(annotations, entgql.QueryField().Annotation) + } + } + if gql.GetType() != "" { + annotations = append(annotations, entgql.Type(gql.GetType())) + } + if gql.GetRelayConnection() { + annotations = append(annotations, entgql.RelayConnection()) + } + var create, update = gql.GetMutationCreate(), gql.GetMutationUpdate() + if create || update { + var options []entgql.MutationOption + if create { + options = append(options, entgql.MutationCreate()) + } + if update { + options = append(options, entgql.MutationUpdate()) + } + annotations = append(annotations, entgql.Mutations(options...)) + } + } out := &schemast.UpsertSchema{ - Name: name, + Name: name, + Annotations: annotations, } for _, f := range m.Fields { if isEdge(f) { @@ -130,7 +162,16 @@ func toSchema(m *protogen.Message, opts *entopts.Schema) (*schemast.UpsertSchema } func isEdge(f *protogen.Field) bool { - return f.Desc.Kind() == protoreflect.MessageKind + isMessageKind := f.Desc.Kind() == protoreflect.MessageKind + if isMessageKind { + switch f.Desc.Message().FullName() { + case "google.protobuf.Timestamp": + return false + case "google.type.Date": + return false + } + } + return isMessageKind } func toEdge(f *protogen.Field) (ent.Edge, error) { @@ -194,6 +235,15 @@ func toField(f *protogen.Field) (ent.Field, error) { values = append(values, string(pbEnum.Get(i).Name())) } fld = field.Enum(name).Values(values...) + case protoreflect.MessageKind: + switch f.Desc.Message().FullName() { + case "google.protobuf.Timestamp": + fld = field.Time(name) + case "google.type.Date": + fld = field.Time(name) + default: + return nil, fmt.Errorf("protoc-gen-ent: unsupported kind %q", f.Desc.Kind()) + } default: return nil, fmt.Errorf("protoc-gen-ent: unsupported kind %q", f.Desc.Kind()) } @@ -214,6 +264,43 @@ func applyFieldOpts(fld ent.Field, opts *entopts.Field) { d.Tag = opts.GetStructTag() d.StorageKey = opts.GetStorageKey() d.SchemaType = opts.GetSchemaType() + + gql := opts.GetGql() + if gql != nil { + var annotations []schema.Annotation + if gql.GetOrderField() { + if gql.GetOrderFieldName() != "" { + annotations = append(annotations, entgql.OrderField(gql.GetOrderFieldName())) + } else { + annotations = append(annotations, entgql.OrderField(strings.ToUpper(fld.Descriptor().Name))) + } + } + if gql.GetType() != "" { + annotations = append(annotations, entgql.Type(gql.GetType())) + } + skipType, skipEnum, skipOrder, skipWhere, skipCreate, skipUpdate := gql.GetSkipType(), gql.GetSkipEnumField(), gql.GetSkipOrderField(), gql.GetSkipWhereInput(), gql.GetSkipMutationCreateInput(), gql.GetSkipMutationUpdateInput() + if skipType || skipEnum || skipOrder || skipWhere || skipCreate || skipUpdate { + var skipModeVals = []bool{ + skipType, skipEnum, skipOrder, skipWhere, skipCreate, skipUpdate, + } + var skipModeList = []entgql.SkipMode{ + entgql.SkipType, + entgql.SkipEnumField, + entgql.SkipOrderField, + entgql.SkipWhereInput, + entgql.SkipMutationCreateInput, + entgql.SkipMutationUpdateInput, + } + var skipMode entgql.SkipMode + for i, mode := range skipModeList { + if skipModeVals[i] { + skipMode |= mode + } + } + annotations = append(annotations, entgql.Skip(skipMode)) + } + d.Annotations = annotations + } } func applyEdgeOpts(edg ent.Edge, opts *entopts.Edge) { @@ -229,6 +316,34 @@ func applyEdgeOpts(edg ent.Edge, opts *entopts.Edge) { Columns: sk.GetColumns(), } } + + gql := opts.GetGql() + if gql != nil { + var annotations []schema.Annotation + skipType, skipWhere, skipCreate, skipUpdate := gql.GetSkipType(), gql.GetSkipWhereInput(), gql.GetSkipMutationCreateInput(), gql.GetSkipMutationUpdateInput() + if skipType || skipWhere || skipCreate || skipUpdate { + var skipModeVals = []bool{ + skipType, skipWhere, skipCreate, skipUpdate, + } + var skipModeList = []entgql.SkipMode{ + entgql.SkipType, + entgql.SkipWhereInput, + entgql.SkipMutationCreateInput, + entgql.SkipMutationUpdateInput, + } + var skipMode entgql.SkipMode + for i, mode := range skipModeList { + if skipModeVals[i] { + skipMode |= mode + } + } + annotations = append(annotations, entgql.Skip(skipMode)) + } + if gql.GetRelayConnection() { + annotations = append(annotations, entgql.RelayConnection()) + } + d.Annotations = annotations + } } type placeholder struct { diff --git a/entproto/cmd/protoc-gen-ent/options/ent/opts.pb.go b/entproto/cmd/protoc-gen-ent/options/ent/opts.pb.go index 04c73c316..753baedf9 100644 --- a/entproto/cmd/protoc-gen-ent/options/ent/opts.pb.go +++ b/entproto/cmd/protoc-gen-ent/options/ent/opts.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.28.0 +// protoc-gen-go v1.28.1 // protoc v3.19.4 // source: opts.proto @@ -26,8 +26,9 @@ type Schema struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Gen *bool `protobuf:"varint,1,opt,name=gen" json:"gen,omitempty"` - Name *string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"` + Gen *bool `protobuf:"varint,1,opt,name=gen" json:"gen,omitempty"` + Name *string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"` + Gql *Schema_GQL `protobuf:"bytes,3,opt,name=gql" json:"gql,omitempty"` } func (x *Schema) Reset() { @@ -76,6 +77,13 @@ func (x *Schema) GetName() string { return "" } +func (x *Schema) GetGql() *Schema_GQL { + if x != nil { + return x.Gql + } + return nil +} + type Field struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -90,6 +98,7 @@ type Field struct { StructTag *string `protobuf:"bytes,7,opt,name=struct_tag,json=structTag" json:"struct_tag,omitempty"` StorageKey *string `protobuf:"bytes,8,opt,name=storage_key,json=storageKey" json:"storage_key,omitempty"` SchemaType map[string]string `protobuf:"bytes,9,rep,name=schema_type,json=schemaType" json:"schema_type,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + Gql *Field_GQL `protobuf:"bytes,10,opt,name=gql" json:"gql,omitempty"` } func (x *Field) Reset() { @@ -187,6 +196,13 @@ func (x *Field) GetSchemaType() map[string]string { return nil } +func (x *Field) GetGql() *Field_GQL { + if x != nil { + return x.Gql + } + return nil +} + type Edge struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -198,6 +214,7 @@ type Edge struct { Field *string `protobuf:"bytes,4,opt,name=field" json:"field,omitempty"` StorageKey *Edge_StorageKey `protobuf:"bytes,5,opt,name=storage_key,json=storageKey" json:"storage_key,omitempty"` StructTag *string `protobuf:"bytes,6,opt,name=struct_tag,json=structTag" json:"struct_tag,omitempty"` + Gql *Edge_GQL `protobuf:"bytes,7,opt,name=gql" json:"gql,omitempty"` } func (x *Edge) Reset() { @@ -274,6 +291,211 @@ func (x *Edge) GetStructTag() string { return "" } +func (x *Edge) GetGql() *Edge_GQL { + if x != nil { + return x.Gql + } + return nil +} + +type Schema_GQL struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Type *string `protobuf:"bytes,1,opt,name=type" json:"type,omitempty"` + MutationCreate *bool `protobuf:"varint,2,opt,name=mutationCreate" json:"mutationCreate,omitempty"` + MutationUpdate *bool `protobuf:"varint,3,opt,name=mutationUpdate" json:"mutationUpdate,omitempty"` + QueryField *bool `protobuf:"varint,4,opt,name=queryField" json:"queryField,omitempty"` + QueryFieldName *string `protobuf:"bytes,5,opt,name=queryFieldName" json:"queryFieldName,omitempty"` + RelayConnection *bool `protobuf:"varint,6,opt,name=relayConnection" json:"relayConnection,omitempty"` +} + +func (x *Schema_GQL) Reset() { + *x = Schema_GQL{} + if protoimpl.UnsafeEnabled { + mi := &file_opts_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Schema_GQL) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Schema_GQL) ProtoMessage() {} + +func (x *Schema_GQL) ProtoReflect() protoreflect.Message { + mi := &file_opts_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Schema_GQL.ProtoReflect.Descriptor instead. +func (*Schema_GQL) Descriptor() ([]byte, []int) { + return file_opts_proto_rawDescGZIP(), []int{0, 0} +} + +func (x *Schema_GQL) GetType() string { + if x != nil && x.Type != nil { + return *x.Type + } + return "" +} + +func (x *Schema_GQL) GetMutationCreate() bool { + if x != nil && x.MutationCreate != nil { + return *x.MutationCreate + } + return false +} + +func (x *Schema_GQL) GetMutationUpdate() bool { + if x != nil && x.MutationUpdate != nil { + return *x.MutationUpdate + } + return false +} + +func (x *Schema_GQL) GetQueryField() bool { + if x != nil && x.QueryField != nil { + return *x.QueryField + } + return false +} + +func (x *Schema_GQL) GetQueryFieldName() string { + if x != nil && x.QueryFieldName != nil { + return *x.QueryFieldName + } + return "" +} + +func (x *Schema_GQL) GetRelayConnection() bool { + if x != nil && x.RelayConnection != nil { + return *x.RelayConnection + } + return false +} + +type Field_GQL struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + OrderField *bool `protobuf:"varint,1,opt,name=orderField" json:"orderField,omitempty"` + OrderFieldName *string `protobuf:"bytes,2,opt,name=orderFieldName" json:"orderFieldName,omitempty"` + Type *string `protobuf:"bytes,3,opt,name=type" json:"type,omitempty"` + SkipType *bool `protobuf:"varint,4,opt,name=skipType" json:"skipType,omitempty"` + SkipEnumField *bool `protobuf:"varint,5,opt,name=skipEnumField" json:"skipEnumField,omitempty"` + SkipOrderField *bool `protobuf:"varint,6,opt,name=skipOrderField" json:"skipOrderField,omitempty"` + SkipWhereInput *bool `protobuf:"varint,7,opt,name=skipWhereInput" json:"skipWhereInput,omitempty"` + SkipMutationCreateInput *bool `protobuf:"varint,8,opt,name=skipMutationCreateInput" json:"skipMutationCreateInput,omitempty"` + SkipMutationUpdateInput *bool `protobuf:"varint,9,opt,name=skipMutationUpdateInput" json:"skipMutationUpdateInput,omitempty"` +} + +func (x *Field_GQL) Reset() { + *x = Field_GQL{} + if protoimpl.UnsafeEnabled { + mi := &file_opts_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Field_GQL) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Field_GQL) ProtoMessage() {} + +func (x *Field_GQL) ProtoReflect() protoreflect.Message { + mi := &file_opts_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Field_GQL.ProtoReflect.Descriptor instead. +func (*Field_GQL) Descriptor() ([]byte, []int) { + return file_opts_proto_rawDescGZIP(), []int{1, 1} +} + +func (x *Field_GQL) GetOrderField() bool { + if x != nil && x.OrderField != nil { + return *x.OrderField + } + return false +} + +func (x *Field_GQL) GetOrderFieldName() string { + if x != nil && x.OrderFieldName != nil { + return *x.OrderFieldName + } + return "" +} + +func (x *Field_GQL) GetType() string { + if x != nil && x.Type != nil { + return *x.Type + } + return "" +} + +func (x *Field_GQL) GetSkipType() bool { + if x != nil && x.SkipType != nil { + return *x.SkipType + } + return false +} + +func (x *Field_GQL) GetSkipEnumField() bool { + if x != nil && x.SkipEnumField != nil { + return *x.SkipEnumField + } + return false +} + +func (x *Field_GQL) GetSkipOrderField() bool { + if x != nil && x.SkipOrderField != nil { + return *x.SkipOrderField + } + return false +} + +func (x *Field_GQL) GetSkipWhereInput() bool { + if x != nil && x.SkipWhereInput != nil { + return *x.SkipWhereInput + } + return false +} + +func (x *Field_GQL) GetSkipMutationCreateInput() bool { + if x != nil && x.SkipMutationCreateInput != nil { + return *x.SkipMutationCreateInput + } + return false +} + +func (x *Field_GQL) GetSkipMutationUpdateInput() bool { + if x != nil && x.SkipMutationUpdateInput != nil { + return *x.SkipMutationUpdateInput + } + return false +} + type Edge_StorageKey struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -286,7 +508,7 @@ type Edge_StorageKey struct { func (x *Edge_StorageKey) Reset() { *x = Edge_StorageKey{} if protoimpl.UnsafeEnabled { - mi := &file_opts_proto_msgTypes[4] + mi := &file_opts_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -299,7 +521,7 @@ func (x *Edge_StorageKey) String() string { func (*Edge_StorageKey) ProtoMessage() {} func (x *Edge_StorageKey) ProtoReflect() protoreflect.Message { - mi := &file_opts_proto_msgTypes[4] + mi := &file_opts_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -329,6 +551,85 @@ func (x *Edge_StorageKey) GetColumns() []string { return nil } +type Edge_GQL struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RelayConnection *bool `protobuf:"varint,1,opt,name=relayConnection" json:"relayConnection,omitempty"` + SkipType *bool `protobuf:"varint,2,opt,name=skipType" json:"skipType,omitempty"` + SkipWhereInput *bool `protobuf:"varint,3,opt,name=skipWhereInput" json:"skipWhereInput,omitempty"` + SkipMutationCreateInput *bool `protobuf:"varint,4,opt,name=skipMutationCreateInput" json:"skipMutationCreateInput,omitempty"` + SkipMutationUpdateInput *bool `protobuf:"varint,5,opt,name=skipMutationUpdateInput" json:"skipMutationUpdateInput,omitempty"` +} + +func (x *Edge_GQL) Reset() { + *x = Edge_GQL{} + if protoimpl.UnsafeEnabled { + mi := &file_opts_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Edge_GQL) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Edge_GQL) ProtoMessage() {} + +func (x *Edge_GQL) ProtoReflect() protoreflect.Message { + mi := &file_opts_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Edge_GQL.ProtoReflect.Descriptor instead. +func (*Edge_GQL) Descriptor() ([]byte, []int) { + return file_opts_proto_rawDescGZIP(), []int{2, 1} +} + +func (x *Edge_GQL) GetRelayConnection() bool { + if x != nil && x.RelayConnection != nil { + return *x.RelayConnection + } + return false +} + +func (x *Edge_GQL) GetSkipType() bool { + if x != nil && x.SkipType != nil { + return *x.SkipType + } + return false +} + +func (x *Edge_GQL) GetSkipWhereInput() bool { + if x != nil && x.SkipWhereInput != nil { + return *x.SkipWhereInput + } + return false +} + +func (x *Edge_GQL) GetSkipMutationCreateInput() bool { + if x != nil && x.SkipMutationCreateInput != nil { + return *x.SkipMutationCreateInput + } + return false +} + +func (x *Edge_GQL) GetSkipMutationUpdateInput() bool { + if x != nil && x.SkipMutationUpdateInput != nil { + return *x.SkipMutationUpdateInput + } + return false +} + var file_opts_proto_extTypes = []protoimpl.ExtensionInfo{ { ExtendedType: (*descriptorpb.MessageOptions)(nil), @@ -376,64 +677,122 @@ var file_opts_proto_rawDesc = []byte{ 0x0a, 0x0a, 0x6f, 0x70, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x03, 0x65, 0x6e, 0x74, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x22, 0x2e, 0x0a, 0x06, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x10, 0x0a, - 0x03, 0x67, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x67, 0x65, 0x6e, 0x12, - 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x22, 0xe9, 0x02, 0x0a, 0x05, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x1a, 0x0a, - 0x08, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x08, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x69, 0x6c, - 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x6e, 0x69, 0x6c, - 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x12, 0x1c, 0x0a, - 0x09, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x09, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x69, - 0x6d, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, - 0x69, 0x6d, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, - 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, - 0x65, 0x6e, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x5f, 0x74, 0x61, - 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x54, - 0x61, 0x67, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x6b, 0x65, - 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, - 0x4b, 0x65, 0x79, 0x12, 0x3b, 0x0a, 0x0b, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x5f, 0x74, 0x79, - 0x70, 0x65, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x65, 0x6e, 0x74, 0x2e, 0x46, - 0x69, 0x65, 0x6c, 0x64, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x54, 0x79, 0x70, 0x65, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x54, 0x79, 0x70, 0x65, - 0x1a, 0x3d, 0x0a, 0x0f, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x54, 0x79, 0x70, 0x65, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, - 0xf6, 0x01, 0x0a, 0x04, 0x45, 0x64, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x6e, 0x69, 0x71, - 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, - 0x12, 0x10, 0x0a, 0x03, 0x72, 0x65, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x72, - 0x65, 0x66, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x14, - 0x0a, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x66, - 0x69, 0x65, 0x6c, 0x64, 0x12, 0x35, 0x0a, 0x0b, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, - 0x6b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x65, 0x6e, 0x74, 0x2e, - 0x45, 0x64, 0x67, 0x65, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4b, 0x65, 0x79, 0x52, - 0x0a, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x73, - 0x74, 0x72, 0x75, 0x63, 0x74, 0x5f, 0x74, 0x61, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x09, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x54, 0x61, 0x67, 0x1a, 0x3c, 0x0a, 0x0a, 0x53, 0x74, - 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x61, 0x62, 0x6c, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x18, - 0x0a, 0x07, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x07, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x3a, 0x46, 0x0a, 0x06, 0x73, 0x63, 0x68, 0x65, - 0x6d, 0x61, 0x12, 0x1f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4f, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x18, 0xe7, 0x94, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x65, 0x6e, - 0x74, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, - 0x3a, 0x41, 0x0a, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x1d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, - 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xe7, 0x94, 0x09, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x0a, 0x2e, 0x65, 0x6e, 0x74, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x52, 0x05, 0x66, 0x69, - 0x65, 0x6c, 0x64, 0x3a, 0x3e, 0x0a, 0x04, 0x65, 0x64, 0x67, 0x65, 0x12, 0x1d, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, - 0x65, 0x6c, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xe8, 0x94, 0x09, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x65, 0x6e, 0x74, 0x2e, 0x45, 0x64, 0x67, 0x65, 0x52, 0x04, 0x65, - 0x64, 0x67, 0x65, 0x42, 0x3a, 0x5a, 0x38, 0x65, 0x6e, 0x74, 0x67, 0x6f, 0x2e, 0x69, 0x6f, 0x2f, - 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x69, 0x62, 0x2f, 0x65, 0x6e, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2f, 0x63, 0x6d, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, - 0x65, 0x6e, 0x74, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x65, 0x6e, 0x74, + 0x6f, 0x74, 0x6f, 0x22, 0xaf, 0x02, 0x0a, 0x06, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x10, + 0x0a, 0x03, 0x67, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x67, 0x65, 0x6e, + 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x03, 0x67, 0x71, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x0f, 0x2e, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x47, + 0x51, 0x4c, 0x52, 0x03, 0x67, 0x71, 0x6c, 0x1a, 0xdb, 0x01, 0x0a, 0x03, 0x47, 0x51, 0x4c, 0x12, + 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, + 0x79, 0x70, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x6d, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x6d, 0x75, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x6d, + 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x0e, 0x6d, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x71, 0x75, 0x65, 0x72, 0x79, 0x46, 0x69, 0x65, 0x6c, + 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x71, 0x75, 0x65, 0x72, 0x79, 0x46, 0x69, + 0x65, 0x6c, 0x64, 0x12, 0x26, 0x0a, 0x0e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x46, 0x69, 0x65, 0x6c, + 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x71, 0x75, 0x65, + 0x72, 0x79, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x72, + 0x65, 0x6c, 0x61, 0x79, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x43, 0x6f, 0x6e, 0x6e, 0x65, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xf5, 0x05, 0x0a, 0x05, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x12, + 0x1a, 0x0a, 0x08, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x08, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x6e, + 0x69, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x6e, + 0x69, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x6e, 0x69, 0x71, 0x75, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x12, + 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x09, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x12, 0x1c, 0x0a, + 0x09, 0x69, 0x6d, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x09, 0x69, 0x6d, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, + 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, + 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x5f, + 0x74, 0x61, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x72, 0x75, 0x63, + 0x74, 0x54, 0x61, 0x67, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, + 0x6b, 0x65, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x74, 0x6f, 0x72, 0x61, + 0x67, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x3b, 0x0a, 0x0b, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x5f, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x65, 0x6e, 0x74, + 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x54, 0x79, 0x70, + 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x54, 0x79, + 0x70, 0x65, 0x12, 0x20, 0x0a, 0x03, 0x67, 0x71, 0x6c, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x0e, 0x2e, 0x65, 0x6e, 0x74, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x2e, 0x47, 0x51, 0x4c, 0x52, + 0x03, 0x67, 0x71, 0x6c, 0x1a, 0x3d, 0x0a, 0x0f, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x54, 0x79, + 0x70, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, + 0x02, 0x38, 0x01, 0x1a, 0xe7, 0x02, 0x0a, 0x03, 0x47, 0x51, 0x4c, 0x12, 0x1e, 0x0a, 0x0a, 0x6f, + 0x72, 0x64, 0x65, 0x72, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0a, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x26, 0x0a, 0x0e, 0x6f, + 0x72, 0x64, 0x65, 0x72, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4e, + 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x6b, 0x69, 0x70, 0x54, + 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x73, 0x6b, 0x69, 0x70, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x73, 0x6b, 0x69, 0x70, 0x45, 0x6e, 0x75, 0x6d, 0x46, + 0x69, 0x65, 0x6c, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x73, 0x6b, 0x69, 0x70, + 0x45, 0x6e, 0x75, 0x6d, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x26, 0x0a, 0x0e, 0x73, 0x6b, 0x69, + 0x70, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x0e, 0x73, 0x6b, 0x69, 0x70, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x46, 0x69, 0x65, 0x6c, + 0x64, 0x12, 0x26, 0x0a, 0x0e, 0x73, 0x6b, 0x69, 0x70, 0x57, 0x68, 0x65, 0x72, 0x65, 0x49, 0x6e, + 0x70, 0x75, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x73, 0x6b, 0x69, 0x70, 0x57, + 0x68, 0x65, 0x72, 0x65, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x38, 0x0a, 0x17, 0x73, 0x6b, 0x69, + 0x70, 0x4d, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, + 0x6e, 0x70, 0x75, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x17, 0x73, 0x6b, 0x69, 0x70, + 0x4d, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, 0x6e, + 0x70, 0x75, 0x74, 0x12, 0x38, 0x0a, 0x17, 0x73, 0x6b, 0x69, 0x70, 0x4d, 0x75, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x17, 0x73, 0x6b, 0x69, 0x70, 0x4d, 0x75, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x22, 0x81, 0x04, + 0x0a, 0x04, 0x45, 0x64, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x12, 0x10, + 0x0a, 0x03, 0x72, 0x65, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x72, 0x65, 0x66, + 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, + 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x66, 0x69, 0x65, + 0x6c, 0x64, 0x12, 0x35, 0x0a, 0x0b, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x6b, 0x65, + 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x65, 0x6e, 0x74, 0x2e, 0x45, 0x64, + 0x67, 0x65, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x0a, 0x73, + 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x72, + 0x75, 0x63, 0x74, 0x5f, 0x74, 0x61, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, + 0x74, 0x72, 0x75, 0x63, 0x74, 0x54, 0x61, 0x67, 0x12, 0x1f, 0x0a, 0x03, 0x67, 0x71, 0x6c, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x65, 0x6e, 0x74, 0x2e, 0x45, 0x64, 0x67, 0x65, + 0x2e, 0x47, 0x51, 0x4c, 0x52, 0x03, 0x67, 0x71, 0x6c, 0x1a, 0x3c, 0x0a, 0x0a, 0x53, 0x74, 0x6f, + 0x72, 0x61, 0x67, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x61, 0x62, 0x6c, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x18, 0x0a, + 0x07, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, + 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x1a, 0xe7, 0x01, 0x0a, 0x03, 0x47, 0x51, 0x4c, 0x12, + 0x28, 0x0a, 0x0f, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x43, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x6b, 0x69, + 0x70, 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x73, 0x6b, 0x69, + 0x70, 0x54, 0x79, 0x70, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x73, 0x6b, 0x69, 0x70, 0x57, 0x68, 0x65, + 0x72, 0x65, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x73, + 0x6b, 0x69, 0x70, 0x57, 0x68, 0x65, 0x72, 0x65, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x38, 0x0a, + 0x17, 0x73, 0x6b, 0x69, 0x70, 0x4d, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x17, + 0x73, 0x6b, 0x69, 0x70, 0x4d, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x38, 0x0a, 0x17, 0x73, 0x6b, 0x69, 0x70, 0x4d, + 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x70, + 0x75, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x17, 0x73, 0x6b, 0x69, 0x70, 0x4d, 0x75, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x70, 0x75, + 0x74, 0x3a, 0x46, 0x0a, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x1f, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xe7, 0x94, 0x09, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, + 0x61, 0x52, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x3a, 0x41, 0x0a, 0x05, 0x66, 0x69, 0x65, + 0x6c, 0x64, 0x12, 0x1d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x18, 0xe7, 0x94, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x65, 0x6e, 0x74, 0x2e, + 0x46, 0x69, 0x65, 0x6c, 0x64, 0x52, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x3a, 0x3e, 0x0a, 0x04, + 0x65, 0x64, 0x67, 0x65, 0x12, 0x1d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x18, 0xe8, 0x94, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x65, 0x6e, + 0x74, 0x2e, 0x45, 0x64, 0x67, 0x65, 0x52, 0x04, 0x65, 0x64, 0x67, 0x65, 0x42, 0x3a, 0x5a, 0x38, + 0x65, 0x6e, 0x74, 0x67, 0x6f, 0x2e, 0x69, 0x6f, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x69, 0x62, + 0x2f, 0x65, 0x6e, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6d, 0x64, 0x2f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x65, 0x6e, 0x74, 0x2f, 0x6f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x65, 0x6e, 0x74, } var ( @@ -448,30 +807,36 @@ func file_opts_proto_rawDescGZIP() []byte { return file_opts_proto_rawDescData } -var file_opts_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_opts_proto_msgTypes = make([]protoimpl.MessageInfo, 8) var file_opts_proto_goTypes = []interface{}{ (*Schema)(nil), // 0: ent.Schema (*Field)(nil), // 1: ent.Field (*Edge)(nil), // 2: ent.Edge - nil, // 3: ent.Field.SchemaTypeEntry - (*Edge_StorageKey)(nil), // 4: ent.Edge.StorageKey - (*descriptorpb.MessageOptions)(nil), // 5: google.protobuf.MessageOptions - (*descriptorpb.FieldOptions)(nil), // 6: google.protobuf.FieldOptions + (*Schema_GQL)(nil), // 3: ent.Schema.GQL + nil, // 4: ent.Field.SchemaTypeEntry + (*Field_GQL)(nil), // 5: ent.Field.GQL + (*Edge_StorageKey)(nil), // 6: ent.Edge.StorageKey + (*Edge_GQL)(nil), // 7: ent.Edge.GQL + (*descriptorpb.MessageOptions)(nil), // 8: google.protobuf.MessageOptions + (*descriptorpb.FieldOptions)(nil), // 9: google.protobuf.FieldOptions } var file_opts_proto_depIdxs = []int32{ - 3, // 0: ent.Field.schema_type:type_name -> ent.Field.SchemaTypeEntry - 4, // 1: ent.Edge.storage_key:type_name -> ent.Edge.StorageKey - 5, // 2: ent.schema:extendee -> google.protobuf.MessageOptions - 6, // 3: ent.field:extendee -> google.protobuf.FieldOptions - 6, // 4: ent.edge:extendee -> google.protobuf.FieldOptions - 0, // 5: ent.schema:type_name -> ent.Schema - 1, // 6: ent.field:type_name -> ent.Field - 2, // 7: ent.edge:type_name -> ent.Edge - 8, // [8:8] is the sub-list for method output_type - 8, // [8:8] is the sub-list for method input_type - 5, // [5:8] is the sub-list for extension type_name - 2, // [2:5] is the sub-list for extension extendee - 0, // [0:2] is the sub-list for field type_name + 3, // 0: ent.Schema.gql:type_name -> ent.Schema.GQL + 4, // 1: ent.Field.schema_type:type_name -> ent.Field.SchemaTypeEntry + 5, // 2: ent.Field.gql:type_name -> ent.Field.GQL + 6, // 3: ent.Edge.storage_key:type_name -> ent.Edge.StorageKey + 7, // 4: ent.Edge.gql:type_name -> ent.Edge.GQL + 8, // 5: ent.schema:extendee -> google.protobuf.MessageOptions + 9, // 6: ent.field:extendee -> google.protobuf.FieldOptions + 9, // 7: ent.edge:extendee -> google.protobuf.FieldOptions + 0, // 8: ent.schema:type_name -> ent.Schema + 1, // 9: ent.field:type_name -> ent.Field + 2, // 10: ent.edge:type_name -> ent.Edge + 11, // [11:11] is the sub-list for method output_type + 11, // [11:11] is the sub-list for method input_type + 8, // [8:11] is the sub-list for extension type_name + 5, // [5:8] is the sub-list for extension extendee + 0, // [0:5] is the sub-list for field type_name } func init() { file_opts_proto_init() } @@ -516,7 +881,31 @@ func file_opts_proto_init() { return nil } } - file_opts_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_opts_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Schema_GQL); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_opts_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Field_GQL); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_opts_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Edge_StorageKey); i { case 0: return &v.state @@ -528,6 +917,18 @@ func file_opts_proto_init() { return nil } } + file_opts_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Edge_GQL); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -535,7 +936,7 @@ func file_opts_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_opts_proto_rawDesc, NumEnums: 0, - NumMessages: 5, + NumMessages: 8, NumExtensions: 3, NumServices: 0, }, diff --git a/entproto/cmd/protoc-gen-ent/options/ent/opts.proto b/entproto/cmd/protoc-gen-ent/options/ent/opts.proto index 9b0bc53a1..478beb71e 100644 --- a/entproto/cmd/protoc-gen-ent/options/ent/opts.proto +++ b/entproto/cmd/protoc-gen-ent/options/ent/opts.proto @@ -7,6 +7,16 @@ option go_package = "entgo.io/contrib/entproto/cmd/protoc-gen-ent/options/ent"; message Schema { optional bool gen = 1; optional string name = 2; + optional GQL gql = 3; + + message GQL { + optional string type = 1; + optional bool mutationCreate = 2; + optional bool mutationUpdate = 3; + optional bool queryField = 4; + optional string queryFieldName = 5; + optional bool relayConnection = 6; + } } extend google.protobuf.MessageOptions { @@ -23,6 +33,19 @@ message Field { optional string struct_tag = 7; optional string storage_key = 8; map schema_type = 9; + optional GQL gql = 10; + + message GQL { + optional bool orderField = 1; + optional string orderFieldName = 2; + optional string type = 3; + optional bool skipType = 4; + optional bool skipEnumField = 5; + optional bool skipOrderField = 6; + optional bool skipWhereInput = 7; + optional bool skipMutationCreateInput = 8; + optional bool skipMutationUpdateInput = 9; + } } message Edge { @@ -32,11 +55,20 @@ message Edge { optional string field = 4; optional StorageKey storage_key = 5; optional string struct_tag = 6; + optional GQL gql = 7; message StorageKey { optional string table = 1; repeated string columns = 2; } + + message GQL { + optional bool relayConnection = 1; + optional bool skipType = 2; + optional bool skipWhereInput = 3; + optional bool skipMutationCreateInput = 4; + optional bool skipMutationUpdateInput = 5; + } } extend google.protobuf.FieldOptions { diff --git a/schemast/annotation.go b/schemast/annotation.go index efecc6250..ebf77ae25 100644 --- a/schemast/annotation.go +++ b/schemast/annotation.go @@ -17,8 +17,10 @@ package schemast import ( "fmt" "go/ast" + "go/token" "sort" + "entgo.io/contrib/entgql" "entgo.io/contrib/entproto" "entgo.io/ent/dialect/entsql" "entgo.io/ent/schema" @@ -48,6 +50,7 @@ func Annotation(annot schema.Annotation) (ast.Expr, bool, error) { entproto.FieldAnnotation: protoField, entproto.EnumAnnotation: protoEnum, "EntSQL": entSQL, + "EntGQL": entGQL, } fn, ok := annotators[annot.Name()] if !ok { @@ -186,6 +189,68 @@ func entSQL(annot schema.Annotation) (ast.Expr, bool, error) { return c, true, nil } +func entGQL(annot schema.Annotation) (ast.Expr, bool, error) { + m := &entgql.Annotation{} + if err := mapstructure.Decode(annot, m); err != nil { + return nil, false, err + } + if m.OrderField != "" { + return fnCall(selectorLit("entgql", "OrderField"), strLit(m.OrderField)), true, nil + } + if m.MultiOrder { + return fnCall(selectorLit("entgql", "MultiOrder")), true, nil + } + if m.Type != "" { + return fnCall(selectorLit("entgql", "Type"), strLit(m.Type)), true, nil + } + if m.Skip != 0 { + var skipModeList = []*ast.SelectorExpr{ + selectorLit("entgql", "SkipType"), + selectorLit("entgql", "SkipEnumField"), + selectorLit("entgql", "SkipOrderField"), + selectorLit("entgql", "SkipWhereInput"), + selectorLit("entgql", "SkipMutationCreateInput"), + selectorLit("entgql", "SkipMutationUpdateInput")} + var skip []*ast.SelectorExpr + for i, expr := range skipModeList { + if m.Skip&(1< 0 { + var options []ast.Expr + for _, mutation := range m.MutationInputs { + if mutation.IsCreate { + options = append(options, fnCall(selectorLit("entgql", "MutationCreate"))) + } else { + options = append(options, fnCall(selectorLit("entgql", "MutationUpdate"))) + } + } + return fnCall(selectorLit("entgql", "Mutations"), options...), true, nil + } + return &ast.CompositeLit{Type: selectorLit("entgql", "Annotation")}, true, nil +} + func toAnnotASTs(annots []schema.Annotation) ([]ast.Expr, error) { out := make([]ast.Expr, 0, len(annots)) for _, annot := range annots {