diff --git a/cqproto/grpc.go b/cqproto/grpc.go index 839de096..b6b0f382 100644 --- a/cqproto/grpc.go +++ b/cqproto/grpc.go @@ -2,6 +2,7 @@ package cqproto import ( "context" + "encoding/json" "github.com/cloudquery/cq-provider-sdk/cqproto/internal" "github.com/cloudquery/cq-provider-sdk/provider/schema" @@ -38,13 +39,19 @@ func (g GRPCClient) GetProviderConfig(ctx context.Context, _ *GetProviderConfigR } func (g GRPCClient) ConfigureProvider(ctx context.Context, request *ConfigureProviderRequest) (*ConfigureProviderResponse, error) { + fieldsData, err := json.Marshal(request.ExtraFields) + if err != nil { + return nil, err + } res, err := g.client.ConfigureProvider(ctx, &internal.ConfigureProvider_Request{ CloudqueryVersion: request.CloudQueryVersion, Connection: &internal.ConnectionDetails{ Type: internal.ConnectionType_POSTGRES, Dsn: request.Connection.DSN, }, - Config: request.Config, + Config: request.Config, + DisableDelete: request.DisableDelete, + ExtraFields: fieldsData, }) if err != nil { return nil, err @@ -102,13 +109,22 @@ func (g *GRPCServer) GetProviderConfig(ctx context.Context, _ *internal.GetProvi } func (g *GRPCServer) ConfigureProvider(ctx context.Context, request *internal.ConfigureProvider_Request) (*internal.ConfigureProvider_Response, error) { + + var eFields = make(map[string]interface{}) + if request.GetExtraFields() != nil { + if err := json.Unmarshal(request.GetExtraFields(), &eFields); err != nil { + return nil, err + } + } resp, err := g.Impl.ConfigureProvider(ctx, &ConfigureProviderRequest{ CloudQueryVersion: request.GetCloudqueryVersion(), Connection: ConnectionDetails{ Type: string(request.Connection.GetType()), DSN: request.Connection.GetDsn(), }, - Config: request.Config, + Config: request.Config, + DisableDelete: request.DisableDelete, + ExtraFields: eFields, }) if err != nil { return nil, err @@ -161,11 +177,18 @@ func tableFromProto(v *internal.Table) *schema.Table { for i, r := range v.GetRelations() { rels[i] = tableFromProto(r) } + + var opts schema.TableCreationOptions + if o := v.GetOptions(); o != nil { + opts.PrimaryKeys = o.GetPrimaryKeys() + } + return &schema.Table{ Name: v.GetName(), Description: v.GetDescription(), Columns: cols, Relations: rels, + Options: opts, } } @@ -198,5 +221,8 @@ func tableToProto(in *schema.Table) *internal.Table { Description: in.Description, Columns: cols, Relations: rels, + Options: &internal.TableCreationOptions{ + PrimaryKeys: in.Options.PrimaryKeys, + }, } } diff --git a/cqproto/internal/plugin.pb.go b/cqproto/internal/plugin.pb.go index d27d5ec0..c19cb5a1 100644 --- a/cqproto/internal/plugin.pb.go +++ b/cqproto/internal/plugin.pb.go @@ -326,10 +326,11 @@ type Table struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` - Columns []*Column `protobuf:"bytes,3,rep,name=columns,proto3" json:"columns,omitempty"` - Relations []*Table `protobuf:"bytes,4,rep,name=relations,proto3" json:"relations,omitempty"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + Columns []*Column `protobuf:"bytes,3,rep,name=columns,proto3" json:"columns,omitempty"` + Relations []*Table `protobuf:"bytes,4,rep,name=relations,proto3" json:"relations,omitempty"` + Options *TableCreationOptions `protobuf:"bytes,5,opt,name=options,proto3,oneof" json:"options,omitempty"` } func (x *Table) Reset() { @@ -392,6 +393,60 @@ func (x *Table) GetRelations() []*Table { return nil } +func (x *Table) GetOptions() *TableCreationOptions { + if x != nil { + return x.Options + } + return nil +} + +type TableCreationOptions struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + PrimaryKeys []string `protobuf:"bytes,1,rep,name=PrimaryKeys,proto3" json:"PrimaryKeys,omitempty"` +} + +func (x *TableCreationOptions) Reset() { + *x = TableCreationOptions{} + if protoimpl.UnsafeEnabled { + mi := &file_internal_plugin_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TableCreationOptions) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TableCreationOptions) ProtoMessage() {} + +func (x *TableCreationOptions) ProtoReflect() protoreflect.Message { + mi := &file_internal_plugin_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 TableCreationOptions.ProtoReflect.Descriptor instead. +func (*TableCreationOptions) Descriptor() ([]byte, []int) { + return file_internal_plugin_proto_rawDescGZIP(), []int{5} +} + +func (x *TableCreationOptions) GetPrimaryKeys() []string { + if x != nil { + return x.PrimaryKeys + } + return nil +} + type Column struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -405,7 +460,7 @@ type Column struct { func (x *Column) Reset() { *x = Column{} if protoimpl.UnsafeEnabled { - mi := &file_internal_plugin_proto_msgTypes[5] + mi := &file_internal_plugin_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -418,7 +473,7 @@ func (x *Column) String() string { func (*Column) ProtoMessage() {} func (x *Column) ProtoReflect() protoreflect.Message { - mi := &file_internal_plugin_proto_msgTypes[5] + mi := &file_internal_plugin_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -431,7 +486,7 @@ func (x *Column) ProtoReflect() protoreflect.Message { // Deprecated: Use Column.ProtoReflect.Descriptor instead. func (*Column) Descriptor() ([]byte, []int) { - return file_internal_plugin_proto_rawDescGZIP(), []int{5} + return file_internal_plugin_proto_rawDescGZIP(), []int{6} } func (x *Column) GetName() string { @@ -467,7 +522,7 @@ type ConnectionDetails struct { func (x *ConnectionDetails) Reset() { *x = ConnectionDetails{} if protoimpl.UnsafeEnabled { - mi := &file_internal_plugin_proto_msgTypes[6] + mi := &file_internal_plugin_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -480,7 +535,7 @@ func (x *ConnectionDetails) String() string { func (*ConnectionDetails) ProtoMessage() {} func (x *ConnectionDetails) ProtoReflect() protoreflect.Message { - mi := &file_internal_plugin_proto_msgTypes[6] + mi := &file_internal_plugin_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -493,7 +548,7 @@ func (x *ConnectionDetails) ProtoReflect() protoreflect.Message { // Deprecated: Use ConnectionDetails.ProtoReflect.Descriptor instead. func (*ConnectionDetails) Descriptor() ([]byte, []int) { - return file_internal_plugin_proto_rawDescGZIP(), []int{6} + return file_internal_plugin_proto_rawDescGZIP(), []int{7} } func (x *ConnectionDetails) GetType() ConnectionType { @@ -521,12 +576,16 @@ type ConfigureProvider_Request struct { Connection *ConnectionDetails `protobuf:"bytes,2,opt,name=connection,proto3" json:"connection,omitempty"` // Holds information such as credentials, regions, accounts, etc' Config []byte `protobuf:"bytes,3,opt,name=config,proto3" json:"config,omitempty"` + // Disables auto delete of table data before fetch of resources + DisableDelete bool `protobuf:"varint,4,opt,name=disableDelete,proto3" json:"disableDelete,omitempty"` + // Allows to inject & override fields into resource tables, use this carefully to override fields + ExtraFields []byte `protobuf:"bytes,5,opt,name=extraFields,proto3" json:"extraFields,omitempty"` } func (x *ConfigureProvider_Request) Reset() { *x = ConfigureProvider_Request{} if protoimpl.UnsafeEnabled { - mi := &file_internal_plugin_proto_msgTypes[7] + mi := &file_internal_plugin_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -539,7 +598,7 @@ func (x *ConfigureProvider_Request) String() string { func (*ConfigureProvider_Request) ProtoMessage() {} func (x *ConfigureProvider_Request) ProtoReflect() protoreflect.Message { - mi := &file_internal_plugin_proto_msgTypes[7] + mi := &file_internal_plugin_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -576,6 +635,20 @@ func (x *ConfigureProvider_Request) GetConfig() []byte { return nil } +func (x *ConfigureProvider_Request) GetDisableDelete() bool { + if x != nil { + return x.DisableDelete + } + return false +} + +func (x *ConfigureProvider_Request) GetExtraFields() []byte { + if x != nil { + return x.ExtraFields + } + return nil +} + type ConfigureProvider_Response struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -587,7 +660,7 @@ type ConfigureProvider_Response struct { func (x *ConfigureProvider_Response) Reset() { *x = ConfigureProvider_Response{} if protoimpl.UnsafeEnabled { - mi := &file_internal_plugin_proto_msgTypes[8] + mi := &file_internal_plugin_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -600,7 +673,7 @@ func (x *ConfigureProvider_Response) String() string { func (*ConfigureProvider_Response) ProtoMessage() {} func (x *ConfigureProvider_Response) ProtoReflect() protoreflect.Message { - mi := &file_internal_plugin_proto_msgTypes[8] + mi := &file_internal_plugin_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -635,7 +708,7 @@ type FetchResources_Request struct { func (x *FetchResources_Request) Reset() { *x = FetchResources_Request{} if protoimpl.UnsafeEnabled { - mi := &file_internal_plugin_proto_msgTypes[9] + mi := &file_internal_plugin_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -648,7 +721,7 @@ func (x *FetchResources_Request) String() string { func (*FetchResources_Request) ProtoMessage() {} func (x *FetchResources_Request) ProtoReflect() protoreflect.Message { - mi := &file_internal_plugin_proto_msgTypes[9] + mi := &file_internal_plugin_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -687,7 +760,7 @@ type FetchResources_Response struct { func (x *FetchResources_Response) Reset() { *x = FetchResources_Response{} if protoimpl.UnsafeEnabled { - mi := &file_internal_plugin_proto_msgTypes[10] + mi := &file_internal_plugin_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -700,7 +773,7 @@ func (x *FetchResources_Response) String() string { func (*FetchResources_Response) ProtoMessage() {} func (x *FetchResources_Response) ProtoReflect() protoreflect.Message { - mi := &file_internal_plugin_proto_msgTypes[10] + mi := &file_internal_plugin_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -746,7 +819,7 @@ type GetProviderSchema_Request struct { func (x *GetProviderSchema_Request) Reset() { *x = GetProviderSchema_Request{} if protoimpl.UnsafeEnabled { - mi := &file_internal_plugin_proto_msgTypes[12] + mi := &file_internal_plugin_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -759,7 +832,7 @@ func (x *GetProviderSchema_Request) String() string { func (*GetProviderSchema_Request) ProtoMessage() {} func (x *GetProviderSchema_Request) ProtoReflect() protoreflect.Message { - mi := &file_internal_plugin_proto_msgTypes[12] + mi := &file_internal_plugin_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -788,7 +861,7 @@ type GetProviderSchema_Response struct { func (x *GetProviderSchema_Response) Reset() { *x = GetProviderSchema_Response{} if protoimpl.UnsafeEnabled { - mi := &file_internal_plugin_proto_msgTypes[13] + mi := &file_internal_plugin_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -801,7 +874,7 @@ func (x *GetProviderSchema_Response) String() string { func (*GetProviderSchema_Response) ProtoMessage() {} func (x *GetProviderSchema_Response) ProtoReflect() protoreflect.Message { - mi := &file_internal_plugin_proto_msgTypes[13] + mi := &file_internal_plugin_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -847,7 +920,7 @@ type GetProviderConfig_Request struct { func (x *GetProviderConfig_Request) Reset() { *x = GetProviderConfig_Request{} if protoimpl.UnsafeEnabled { - mi := &file_internal_plugin_proto_msgTypes[15] + mi := &file_internal_plugin_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -860,7 +933,7 @@ func (x *GetProviderConfig_Request) String() string { func (*GetProviderConfig_Request) ProtoMessage() {} func (x *GetProviderConfig_Request) ProtoReflect() protoreflect.Message { - mi := &file_internal_plugin_proto_msgTypes[15] + mi := &file_internal_plugin_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -889,7 +962,7 @@ type GetProviderConfig_Response struct { func (x *GetProviderConfig_Response) Reset() { *x = GetProviderConfig_Response{} if protoimpl.UnsafeEnabled { - mi := &file_internal_plugin_proto_msgTypes[16] + mi := &file_internal_plugin_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -902,7 +975,7 @@ func (x *GetProviderConfig_Response) String() string { func (*GetProviderConfig_Response) ProtoMessage() {} func (x *GetProviderConfig_Response) ProtoReflect() protoreflect.Message { - mi := &file_internal_plugin_proto_msgTypes[16] + mi := &file_internal_plugin_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -943,9 +1016,9 @@ var File_internal_plugin_proto protoreflect.FileDescriptor var file_internal_plugin_proto_rawDesc = []byte{ 0x0a, 0x15, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x6c, 0x75, 0x67, 0x69, - 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc2, - 0x01, 0x0a, 0x11, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x50, 0x72, 0x6f, 0x76, - 0x69, 0x64, 0x65, 0x72, 0x1a, 0x8a, 0x01, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x8a, + 0x02, 0x0a, 0x11, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x50, 0x72, 0x6f, 0x76, + 0x69, 0x64, 0x65, 0x72, 0x1a, 0xd2, 0x01, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2d, 0x0a, 0x12, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x71, 0x75, 0x65, 0x72, 0x79, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, @@ -954,116 +1027,129 @@ var file_internal_plugin_proto_rawDesc = []byte{ 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x1a, 0x20, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, - 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, - 0x72, 0x6f, 0x72, 0x22, 0xaf, 0x02, 0x0a, 0x0e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x1a, 0x27, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x1a, - 0xf3, 0x01, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x64, 0x0a, 0x12, - 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, - 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, - 0x11, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x63, - 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, - 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x1a, - 0x44, 0x0a, 0x16, 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x73, 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, 0x08, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x8a, 0x02, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, - 0x76, 0x69, 0x64, 0x65, 0x72, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x1a, 0x09, 0x0a, 0x07, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0xe9, 0x01, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x12, 0x5e, 0x0a, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x74, 0x61, - 0x62, 0x6c, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x70, 0x72, 0x6f, + 0x67, 0x12, 0x24, 0x0a, 0x0d, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, + 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x78, 0x74, 0x72, 0x61, + 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x65, 0x78, + 0x74, 0x72, 0x61, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x1a, 0x20, 0x0a, 0x08, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0xaf, 0x02, 0x0a, 0x0e, + 0x46, 0x65, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x1a, 0x27, + 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x1a, 0xf3, 0x01, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x64, 0x0a, 0x12, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, + 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x35, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x2e, 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x11, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, + 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x0d, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x6f, 0x75, 0x6e, + 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x1a, 0x44, 0x0a, 0x16, 0x46, 0x69, 0x6e, 0x69, 0x73, + 0x68, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 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, 0x08, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x8a, 0x02, + 0x0a, 0x11, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x53, 0x63, 0x68, + 0x65, 0x6d, 0x61, 0x1a, 0x09, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0xe9, + 0x01, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x5e, 0x0a, 0x0f, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, + 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x61, + 0x62, 0x6c, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0e, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x1a, 0x4f, 0x0a, 0x13, 0x52, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, + 0x65, 0x79, 0x12, 0x22, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x70, 0x0a, 0x11, 0x47, 0x65, + 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, + 0x09, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x50, 0x0a, 0x08, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0xda, 0x01, 0x0a, + 0x05, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x0a, 0x07, + 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x07, 0x63, 0x6f, + 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x12, 0x2a, 0x0a, 0x09, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x09, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x12, 0x3a, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x48, + 0x00, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x88, 0x01, 0x01, 0x42, 0x0a, 0x0a, + 0x08, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x38, 0x0a, 0x14, 0x54, 0x61, 0x62, + 0x6c, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x4b, 0x65, 0x79, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x4b, + 0x65, 0x79, 0x73, 0x22, 0x65, 0x0a, 0x06, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x12, 0x12, 0x0a, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, + 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x50, 0x0a, 0x11, 0x43, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, + 0x29, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x64, 0x73, + 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x64, 0x73, 0x6e, 0x2a, 0x97, 0x02, 0x0a, + 0x0a, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x49, + 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x42, 0x4f, 0x4f, 0x4c, + 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x53, 0x4d, 0x41, 0x4c, 0x4c, 0x49, 0x4e, 0x54, 0x10, 0x02, + 0x12, 0x07, 0x0a, 0x03, 0x49, 0x4e, 0x54, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x42, 0x49, 0x47, + 0x49, 0x4e, 0x54, 0x10, 0x04, 0x12, 0x09, 0x0a, 0x05, 0x46, 0x4c, 0x4f, 0x41, 0x54, 0x10, 0x05, + 0x12, 0x08, 0x0a, 0x04, 0x55, 0x55, 0x49, 0x44, 0x10, 0x06, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x54, + 0x52, 0x49, 0x4e, 0x47, 0x10, 0x07, 0x12, 0x0e, 0x0a, 0x0a, 0x42, 0x59, 0x54, 0x45, 0x5f, 0x41, + 0x52, 0x52, 0x41, 0x59, 0x10, 0x08, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, + 0x5f, 0x41, 0x52, 0x52, 0x41, 0x59, 0x10, 0x09, 0x12, 0x0d, 0x0a, 0x09, 0x49, 0x4e, 0x54, 0x5f, + 0x41, 0x52, 0x52, 0x41, 0x59, 0x10, 0x0a, 0x12, 0x0d, 0x0a, 0x09, 0x54, 0x49, 0x4d, 0x45, 0x53, + 0x54, 0x41, 0x4d, 0x50, 0x10, 0x0b, 0x12, 0x08, 0x0a, 0x04, 0x4a, 0x53, 0x4f, 0x4e, 0x10, 0x0c, + 0x12, 0x0e, 0x0a, 0x0a, 0x55, 0x55, 0x49, 0x44, 0x5f, 0x41, 0x52, 0x52, 0x41, 0x59, 0x10, 0x0d, + 0x12, 0x08, 0x0a, 0x04, 0x49, 0x4e, 0x45, 0x54, 0x10, 0x0e, 0x12, 0x0e, 0x0a, 0x0a, 0x49, 0x4e, + 0x45, 0x54, 0x5f, 0x41, 0x52, 0x52, 0x41, 0x59, 0x10, 0x0f, 0x12, 0x08, 0x0a, 0x04, 0x43, 0x49, + 0x44, 0x52, 0x10, 0x10, 0x12, 0x0e, 0x0a, 0x0a, 0x43, 0x49, 0x44, 0x52, 0x5f, 0x41, 0x52, 0x52, + 0x41, 0x59, 0x10, 0x11, 0x12, 0x0c, 0x0a, 0x08, 0x4d, 0x41, 0x43, 0x5f, 0x41, 0x44, 0x44, 0x52, + 0x10, 0x12, 0x12, 0x12, 0x0a, 0x0e, 0x4d, 0x41, 0x43, 0x5f, 0x41, 0x44, 0x44, 0x52, 0x5f, 0x41, + 0x52, 0x52, 0x41, 0x59, 0x10, 0x13, 0x2a, 0x1e, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x4f, 0x53, 0x54, + 0x47, 0x52, 0x45, 0x53, 0x10, 0x00, 0x32, 0xeb, 0x02, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x76, 0x69, + 0x64, 0x65, 0x72, 0x12, 0x58, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, + 0x65, 0x72, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x53, 0x63, 0x68, 0x65, + 0x6d, 0x61, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x53, 0x63, - 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x52, 0x0e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, - 0x73, 0x1a, 0x4f, 0x0a, 0x13, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x61, 0x62, - 0x6c, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x22, 0x0a, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, - 0x38, 0x01, 0x22, 0x70, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, - 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x09, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x50, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, - 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, - 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x63, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x22, 0x92, 0x01, 0x0a, 0x05, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x12, - 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x0a, 0x07, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x18, - 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, - 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x07, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x12, 0x2a, 0x0a, - 0x09, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x09, - 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x65, 0x0a, 0x06, 0x43, 0x6f, 0x6c, - 0x75, 0x6d, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x04, 0x74, 0x79, 0x70, - 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, - 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, - 0x22, 0x50, 0x0a, 0x11, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x65, - 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x29, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, - 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, - 0x12, 0x10, 0x0a, 0x03, 0x64, 0x73, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x64, - 0x73, 0x6e, 0x2a, 0x97, 0x02, 0x0a, 0x0a, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x79, 0x70, - 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x08, - 0x0a, 0x04, 0x42, 0x4f, 0x4f, 0x4c, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x53, 0x4d, 0x41, 0x4c, - 0x4c, 0x49, 0x4e, 0x54, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x49, 0x4e, 0x54, 0x10, 0x03, 0x12, - 0x0a, 0x0a, 0x06, 0x42, 0x49, 0x47, 0x49, 0x4e, 0x54, 0x10, 0x04, 0x12, 0x09, 0x0a, 0x05, 0x46, - 0x4c, 0x4f, 0x41, 0x54, 0x10, 0x05, 0x12, 0x08, 0x0a, 0x04, 0x55, 0x55, 0x49, 0x44, 0x10, 0x06, - 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x07, 0x12, 0x0e, 0x0a, 0x0a, - 0x42, 0x59, 0x54, 0x45, 0x5f, 0x41, 0x52, 0x52, 0x41, 0x59, 0x10, 0x08, 0x12, 0x10, 0x0a, 0x0c, - 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x5f, 0x41, 0x52, 0x52, 0x41, 0x59, 0x10, 0x09, 0x12, 0x0d, - 0x0a, 0x09, 0x49, 0x4e, 0x54, 0x5f, 0x41, 0x52, 0x52, 0x41, 0x59, 0x10, 0x0a, 0x12, 0x0d, 0x0a, - 0x09, 0x54, 0x49, 0x4d, 0x45, 0x53, 0x54, 0x41, 0x4d, 0x50, 0x10, 0x0b, 0x12, 0x08, 0x0a, 0x04, - 0x4a, 0x53, 0x4f, 0x4e, 0x10, 0x0c, 0x12, 0x0e, 0x0a, 0x0a, 0x55, 0x55, 0x49, 0x44, 0x5f, 0x41, - 0x52, 0x52, 0x41, 0x59, 0x10, 0x0d, 0x12, 0x08, 0x0a, 0x04, 0x49, 0x4e, 0x45, 0x54, 0x10, 0x0e, - 0x12, 0x0e, 0x0a, 0x0a, 0x49, 0x4e, 0x45, 0x54, 0x5f, 0x41, 0x52, 0x52, 0x41, 0x59, 0x10, 0x0f, - 0x12, 0x08, 0x0a, 0x04, 0x43, 0x49, 0x44, 0x52, 0x10, 0x10, 0x12, 0x0e, 0x0a, 0x0a, 0x43, 0x49, - 0x44, 0x52, 0x5f, 0x41, 0x52, 0x52, 0x41, 0x59, 0x10, 0x11, 0x12, 0x0c, 0x0a, 0x08, 0x4d, 0x41, - 0x43, 0x5f, 0x41, 0x44, 0x44, 0x52, 0x10, 0x12, 0x12, 0x12, 0x0a, 0x0e, 0x4d, 0x41, 0x43, 0x5f, - 0x41, 0x44, 0x44, 0x52, 0x5f, 0x41, 0x52, 0x52, 0x41, 0x59, 0x10, 0x13, 0x2a, 0x1e, 0x0a, 0x0e, - 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0c, - 0x0a, 0x08, 0x50, 0x4f, 0x53, 0x54, 0x47, 0x52, 0x45, 0x53, 0x10, 0x00, 0x32, 0xeb, 0x02, 0x0a, - 0x08, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x58, 0x0a, 0x11, 0x47, 0x65, 0x74, - 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x20, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, - 0x65, 0x72, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x76, - 0x69, 0x64, 0x65, 0x72, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x58, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, - 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x58, 0x0a, - 0x11, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, - 0x65, 0x72, 0x12, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x75, 0x72, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2e, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, 0x0e, 0x46, 0x65, 0x74, 0x63, 0x68, - 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, - 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x42, 0x0b, 0x5a, 0x09, 0x2f, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x58, 0x0a, + 0x11, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x12, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, + 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, + 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x58, 0x0a, 0x11, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x75, 0x72, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x20, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x50, 0x72, + 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, + 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x51, 0x0a, 0x0e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x73, 0x12, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x46, 0x65, 0x74, 0x63, + 0x68, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x30, 0x01, 0x42, 0x0b, 0x5a, 0x09, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, + 0x6c, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1079,7 +1165,7 @@ func file_internal_plugin_proto_rawDescGZIP() []byte { } var file_internal_plugin_proto_enumTypes = make([]protoimpl.EnumInfo, 2) -var file_internal_plugin_proto_msgTypes = make([]protoimpl.MessageInfo, 17) +var file_internal_plugin_proto_msgTypes = make([]protoimpl.MessageInfo, 18) var file_internal_plugin_proto_goTypes = []interface{}{ (ColumnType)(0), // 0: proto.ColumnType (ConnectionType)(0), // 1: proto.ConnectionType @@ -1088,41 +1174,43 @@ var file_internal_plugin_proto_goTypes = []interface{}{ (*GetProviderSchema)(nil), // 4: proto.GetProviderSchema (*GetProviderConfig)(nil), // 5: proto.GetProviderConfig (*Table)(nil), // 6: proto.Table - (*Column)(nil), // 7: proto.Column - (*ConnectionDetails)(nil), // 8: proto.ConnectionDetails - (*ConfigureProvider_Request)(nil), // 9: proto.ConfigureProvider.Request - (*ConfigureProvider_Response)(nil), // 10: proto.ConfigureProvider.Response - (*FetchResources_Request)(nil), // 11: proto.FetchResources.Request - (*FetchResources_Response)(nil), // 12: proto.FetchResources.Response - nil, // 13: proto.FetchResources.Response.FinishedResourcesEntry - (*GetProviderSchema_Request)(nil), // 14: proto.GetProviderSchema.Request - (*GetProviderSchema_Response)(nil), // 15: proto.GetProviderSchema.Response - nil, // 16: proto.GetProviderSchema.Response.ResourceTablesEntry - (*GetProviderConfig_Request)(nil), // 17: proto.GetProviderConfig.Request - (*GetProviderConfig_Response)(nil), // 18: proto.GetProviderConfig.Response + (*TableCreationOptions)(nil), // 7: proto.TableCreationOptions + (*Column)(nil), // 8: proto.Column + (*ConnectionDetails)(nil), // 9: proto.ConnectionDetails + (*ConfigureProvider_Request)(nil), // 10: proto.ConfigureProvider.Request + (*ConfigureProvider_Response)(nil), // 11: proto.ConfigureProvider.Response + (*FetchResources_Request)(nil), // 12: proto.FetchResources.Request + (*FetchResources_Response)(nil), // 13: proto.FetchResources.Response + nil, // 14: proto.FetchResources.Response.FinishedResourcesEntry + (*GetProviderSchema_Request)(nil), // 15: proto.GetProviderSchema.Request + (*GetProviderSchema_Response)(nil), // 16: proto.GetProviderSchema.Response + nil, // 17: proto.GetProviderSchema.Response.ResourceTablesEntry + (*GetProviderConfig_Request)(nil), // 18: proto.GetProviderConfig.Request + (*GetProviderConfig_Response)(nil), // 19: proto.GetProviderConfig.Response } var file_internal_plugin_proto_depIdxs = []int32{ - 7, // 0: proto.Table.columns:type_name -> proto.Column + 8, // 0: proto.Table.columns:type_name -> proto.Column 6, // 1: proto.Table.relations:type_name -> proto.Table - 0, // 2: proto.Column.type:type_name -> proto.ColumnType - 1, // 3: proto.ConnectionDetails.type:type_name -> proto.ConnectionType - 8, // 4: proto.ConfigureProvider.Request.connection:type_name -> proto.ConnectionDetails - 13, // 5: proto.FetchResources.Response.finished_resources:type_name -> proto.FetchResources.Response.FinishedResourcesEntry - 16, // 6: proto.GetProviderSchema.Response.resource_tables:type_name -> proto.GetProviderSchema.Response.ResourceTablesEntry - 6, // 7: proto.GetProviderSchema.Response.ResourceTablesEntry.value:type_name -> proto.Table - 14, // 8: proto.Provider.GetProviderSchema:input_type -> proto.GetProviderSchema.Request - 17, // 9: proto.Provider.GetProviderConfig:input_type -> proto.GetProviderConfig.Request - 9, // 10: proto.Provider.ConfigureProvider:input_type -> proto.ConfigureProvider.Request - 11, // 11: proto.Provider.FetchResources:input_type -> proto.FetchResources.Request - 15, // 12: proto.Provider.GetProviderSchema:output_type -> proto.GetProviderSchema.Response - 18, // 13: proto.Provider.GetProviderConfig:output_type -> proto.GetProviderConfig.Response - 10, // 14: proto.Provider.ConfigureProvider:output_type -> proto.ConfigureProvider.Response - 12, // 15: proto.Provider.FetchResources:output_type -> proto.FetchResources.Response - 12, // [12:16] is the sub-list for method output_type - 8, // [8:12] is the sub-list for method input_type - 8, // [8:8] is the sub-list for extension type_name - 8, // [8:8] is the sub-list for extension extendee - 0, // [0:8] is the sub-list for field type_name + 7, // 2: proto.Table.options:type_name -> proto.TableCreationOptions + 0, // 3: proto.Column.type:type_name -> proto.ColumnType + 1, // 4: proto.ConnectionDetails.type:type_name -> proto.ConnectionType + 9, // 5: proto.ConfigureProvider.Request.connection:type_name -> proto.ConnectionDetails + 14, // 6: proto.FetchResources.Response.finished_resources:type_name -> proto.FetchResources.Response.FinishedResourcesEntry + 17, // 7: proto.GetProviderSchema.Response.resource_tables:type_name -> proto.GetProviderSchema.Response.ResourceTablesEntry + 6, // 8: proto.GetProviderSchema.Response.ResourceTablesEntry.value:type_name -> proto.Table + 15, // 9: proto.Provider.GetProviderSchema:input_type -> proto.GetProviderSchema.Request + 18, // 10: proto.Provider.GetProviderConfig:input_type -> proto.GetProviderConfig.Request + 10, // 11: proto.Provider.ConfigureProvider:input_type -> proto.ConfigureProvider.Request + 12, // 12: proto.Provider.FetchResources:input_type -> proto.FetchResources.Request + 16, // 13: proto.Provider.GetProviderSchema:output_type -> proto.GetProviderSchema.Response + 19, // 14: proto.Provider.GetProviderConfig:output_type -> proto.GetProviderConfig.Response + 11, // 15: proto.Provider.ConfigureProvider:output_type -> proto.ConfigureProvider.Response + 13, // 16: proto.Provider.FetchResources:output_type -> proto.FetchResources.Response + 13, // [13:17] is the sub-list for method output_type + 9, // [9:13] is the sub-list for method input_type + 9, // [9:9] is the sub-list for extension type_name + 9, // [9:9] is the sub-list for extension extendee + 0, // [0:9] is the sub-list for field type_name } func init() { file_internal_plugin_proto_init() } @@ -1192,7 +1280,7 @@ func file_internal_plugin_proto_init() { } } file_internal_plugin_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Column); i { + switch v := v.(*TableCreationOptions); i { case 0: return &v.state case 1: @@ -1204,7 +1292,7 @@ func file_internal_plugin_proto_init() { } } file_internal_plugin_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ConnectionDetails); i { + switch v := v.(*Column); i { case 0: return &v.state case 1: @@ -1216,7 +1304,7 @@ func file_internal_plugin_proto_init() { } } file_internal_plugin_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ConfigureProvider_Request); i { + switch v := v.(*ConnectionDetails); i { case 0: return &v.state case 1: @@ -1228,7 +1316,7 @@ func file_internal_plugin_proto_init() { } } file_internal_plugin_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ConfigureProvider_Response); i { + switch v := v.(*ConfigureProvider_Request); i { case 0: return &v.state case 1: @@ -1240,7 +1328,7 @@ func file_internal_plugin_proto_init() { } } file_internal_plugin_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FetchResources_Request); i { + switch v := v.(*ConfigureProvider_Response); i { case 0: return &v.state case 1: @@ -1252,6 +1340,18 @@ func file_internal_plugin_proto_init() { } } file_internal_plugin_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FetchResources_Request); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_internal_plugin_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*FetchResources_Response); i { case 0: return &v.state @@ -1263,7 +1363,7 @@ func file_internal_plugin_proto_init() { return nil } } - file_internal_plugin_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + file_internal_plugin_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetProviderSchema_Request); i { case 0: return &v.state @@ -1275,7 +1375,7 @@ func file_internal_plugin_proto_init() { return nil } } - file_internal_plugin_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + file_internal_plugin_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetProviderSchema_Response); i { case 0: return &v.state @@ -1287,7 +1387,7 @@ func file_internal_plugin_proto_init() { return nil } } - file_internal_plugin_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + file_internal_plugin_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetProviderConfig_Request); i { case 0: return &v.state @@ -1299,7 +1399,7 @@ func file_internal_plugin_proto_init() { return nil } } - file_internal_plugin_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + file_internal_plugin_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetProviderConfig_Response); i { case 0: return &v.state @@ -1312,13 +1412,14 @@ func file_internal_plugin_proto_init() { } } } + file_internal_plugin_proto_msgTypes[4].OneofWrappers = []interface{}{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_internal_plugin_proto_rawDesc, NumEnums: 2, - NumMessages: 17, + NumMessages: 18, NumExtensions: 0, NumServices: 1, }, diff --git a/cqproto/internal/plugin.proto b/cqproto/internal/plugin.proto index 9c77fc5f..210cd996 100644 --- a/cqproto/internal/plugin.proto +++ b/cqproto/internal/plugin.proto @@ -2,7 +2,6 @@ syntax = "proto3"; package proto; option go_package = "/internal"; - service Provider { // Information about what a provider supports/expects rpc GetProviderSchema(GetProviderSchema.Request) returns (GetProviderSchema.Response); @@ -26,6 +25,10 @@ message ConfigureProvider { ConnectionDetails connection = 2; // Holds information such as credentials, regions, accounts, etc' bytes config = 3; + // Disables auto delete of table data before fetch of resources + bool disableDelete = 4; + // Allows to inject & override fields into resource tables, use this carefully to override fields + bytes extraFields = 5; } message Response { string error = 1; @@ -72,7 +75,11 @@ message Table { string description = 2; repeated Column columns = 3; repeated Table relations = 4; + optional TableCreationOptions options = 5; +} +message TableCreationOptions { + repeated string PrimaryKeys = 1; } message Column { diff --git a/cqproto/provider.go b/cqproto/provider.go index c95e3c47..abad4c0e 100644 --- a/cqproto/provider.go +++ b/cqproto/provider.go @@ -67,6 +67,10 @@ type ConfigureProviderRequest struct { Connection ConnectionDetails // Config is the configuration the user supplied for the provider Config []byte + // DisableDelete configures providers to skip deletion of data before resource fetch + DisableDelete bool + // Fields to inject to every resource on insert + ExtraFields map[string]interface{} } type ConfigureProviderResponse struct { diff --git a/go.mod b/go.mod index fff12770..603f2e22 100644 --- a/go.mod +++ b/go.mod @@ -26,6 +26,7 @@ require ( github.com/jhump/protoreflect v1.8.2 // indirect github.com/lib/pq v1.10.1 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/hashstructure v1.1.0 github.com/modern-go/reflect2 v1.0.1 github.com/oklog/run v1.1.0 // indirect github.com/stretchr/objx v0.3.0 // indirect diff --git a/go.sum b/go.sum index 6cf1f5da..f8869c3f 100644 --- a/go.sum +++ b/go.sum @@ -422,6 +422,8 @@ github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZX github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/hashstructure v1.1.0 h1:P6P1hdjqAAknpY/M1CGipelZgp+4y9ja9kmUZPXP+H0= +github.com/mitchellh/hashstructure v1.1.0/go.mod h1:xUDAozZz0Wmdiufv0uyhnHkUTN6/6d8ulp4AwfLKrmA= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= diff --git a/provider/migrator.go b/provider/migrator.go index 320ba302..5f4efc68 100644 --- a/provider/migrator.go +++ b/provider/migrator.go @@ -2,83 +2,57 @@ package provider import ( "context" + "fmt" "reflect" "runtime" "strconv" "strings" - "github.com/thoas/go-funk" - - "github.com/georgysavva/scany/pgxscan" + "github.com/huandu/go-sqlbuilder" "github.com/cloudquery/cq-provider-sdk/provider/schema" + "github.com/georgysavva/scany/pgxscan" "github.com/hashicorp/go-hclog" - "github.com/huandu/go-sqlbuilder" + "github.com/jackc/pgx/v4/pgxpool" + "github.com/thoas/go-funk" ) -const queryTableColumns = `SELECT array_agg(column_name::text) as columns FROM information_schema.columns WHERE table_name = $1` - -const addColumnToTable = `ALTER TABLE %s ADD COLUMN IF NOT EXISTS %v %v;` +const ( + // MaxTableLength in postgres is 63 when building _fk or _pk we want to truncate the name to 60 chars max + maxTableName = 60 + queryTableColumns = `SELECT array_agg(column_name::text) as columns FROM information_schema.columns WHERE table_name = $1` + addColumnToTable = `ALTER TABLE %s ADD COLUMN IF NOT EXISTS %v %v;` +) -// Migrator handles creation of schema.Table in database if they don't exist +// Migrator handles creation of schema.Table in database if they don't exist, and migration of tables if provider was upgraded. type Migrator struct { - db schema.Database log hclog.Logger } -func NewMigrator(db schema.Database, log hclog.Logger) Migrator { - return Migrator{ - db, +func NewMigrator(log hclog.Logger) *Migrator { + return &Migrator{ log, } } -func (m Migrator) upgradeTable(ctx context.Context, t *schema.Table) error { - - rows, err := m.db.Query(ctx, queryTableColumns, t.Name) - if err != nil { - return err - } - - var existingColumns struct { - Columns []string - } - - if err := pgxscan.ScanOne(&existingColumns, rows); err != nil { - return err - } - - columnsToAdd, _ := funk.DifferenceString(t.ColumnNames(), existingColumns.Columns) - for _, d := range columnsToAdd { - m.log.Debug("adding column", "column", d) - col := t.Column(d) - if col == nil { - m.log.Warn("column missing from table, not adding it", "table", t.Name, "column", d) - continue - } - sql, _ := sqlbuilder.Buildf(addColumnToTable, sqlbuilder.Raw(t.Name), sqlbuilder.Raw(d), sqlbuilder.Raw(schema.GetPgTypeFromType(col.Type))).BuildWithFlavor(sqlbuilder.PostgreSQL) - if err := m.db.Exec(ctx, sql); err != nil { - return err - } - } - return nil - -} - -func (m Migrator) CreateTable(ctx context.Context, t *schema.Table, parent *schema.Table) error { +func (m Migrator) CreateTable(ctx context.Context, conn *pgxpool.Conn, t *schema.Table, parent *schema.Table) error { // Build a SQL to create a table. ctb := sqlbuilder.CreateTable(t.Name).IfNotExists() - ctb.Define("id", "uuid", "NOT NULL", "PRIMARY KEY") + for _, c := range schema.GetDefaultSDKColumns() { + ctb.Define(c.Name, schema.GetPgTypeFromType(c.Type)) + } + m.buildColumns(ctb, t.Columns, parent) + ctb.Define(fmt.Sprintf("constraint %s_pk primary key(%s)", truncateTableName(t.Name), strings.Join(t.PrimaryKeys(), ","))) sql, _ := ctb.BuildWithFlavor(sqlbuilder.PostgreSQL) m.log.Debug("creating table if not exists", "table", t.Name) - if err := m.db.Exec(ctx, sql); err != nil { + if _, err := conn.Exec(ctx, sql); err != nil { return err } m.log.Debug("migrating table columns if required", "table", t.Name) - if err := m.upgradeTable(ctx, t); err != nil { + if err := m.upgradeTable(ctx, conn, t); err != nil { return err } @@ -90,25 +64,63 @@ func (m Migrator) CreateTable(ctx context.Context, t *schema.Table, parent *sche // Create relation tables for _, r := range t.Relations { m.log.Debug("creating table relation", "table", r.Name) - if err := m.CreateTable(ctx, r, t); err != nil { + if err := m.CreateTable(ctx, conn, r, t); err != nil { return err } } return nil } -func GetFunctionName(i interface{}) string { - return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name() +func (m Migrator) upgradeTable(ctx context.Context, conn *pgxpool.Conn, t *schema.Table) error { + rows, err := conn.Query(ctx, queryTableColumns, t.Name) + if err != nil { + return err + } + + var existingColumns struct { + Columns []string + } + + if err := pgxscan.ScanOne(&existingColumns, rows); err != nil { + return err + } + + columnsToAdd, _ := funk.DifferenceString(t.ColumnNames(), existingColumns.Columns) + for _, d := range columnsToAdd { + m.log.Debug("adding column", "column", d) + col := t.Column(d) + if col == nil { + m.log.Warn("column missing from table, not adding it", "table", t.Name, "column", d) + continue + } + sql, _ := sqlbuilder.Buildf(addColumnToTable, sqlbuilder.Raw(t.Name), sqlbuilder.Raw(d), sqlbuilder.Raw(schema.GetPgTypeFromType(col.Type))).BuildWithFlavor(sqlbuilder.PostgreSQL) + if _, err := conn.Exec(ctx, sql); err != nil { + return err + } + } + return nil + } func (m Migrator) buildColumns(ctb *sqlbuilder.CreateTableBuilder, cc []schema.Column, parent *schema.Table) { for _, c := range cc { defs := []string{strconv.Quote(c.Name), schema.GetPgTypeFromType(c.Type)} // TODO: This is a bit ugly. Think of a better way - if strings.HasSuffix(GetFunctionName(c.Resolver), "ParentIdResolver") { + resolverName := getFunctionName(c.Resolver) + if strings.HasSuffix(resolverName, "ParentIdResolver") || strings.HasSuffix(resolverName, "ParentHasFieldResolver") { defs = append(defs, "REFERENCES", parent.Name, "ON DELETE CASCADE") } - ctb.Define(defs...) } } + +func getFunctionName(i interface{}) string { + return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name() +} + +func truncateTableName(name string) string { + if len(name) > maxTableName { + return name[:maxTableName] + } + return name +} diff --git a/provider/provider.go b/provider/provider.go index 6e0148b3..3cd35381 100644 --- a/provider/provider.go +++ b/provider/provider.go @@ -42,6 +42,10 @@ type Provider struct { db schema.Database // meta is the provider's client created when configure is called meta schema.ClientMeta + // Whether provider should all Delete on every table before fetching + disableDelete bool + // Add extra fields to all resources, these fields don't show up in documentation and are used for internal CQ testing. + extraFields map[string]interface{} } func (p *Provider) GetProviderSchema(_ context.Context, _ *cqproto.GetProviderSchemaRequest) (*cqproto.GetProviderSchemaResponse, error) { @@ -67,26 +71,17 @@ func (p *Provider) GetProviderConfig(_ context.Context, _ *cqproto.GetProviderCo } func (p *Provider) ConfigureProvider(ctx context.Context, request *cqproto.ConfigureProviderRequest) (*cqproto.ConfigureProviderResponse, error) { + if p.meta != nil { + return &cqproto.ConfigureProviderResponse{Error: fmt.Sprintf("provider %s was already configured", p.Name)}, nil + } + conn, err := schema.NewPgDatabase(ctx, request.Connection.DSN) if err != nil { return nil, err } + p.disableDelete = request.DisableDelete p.db = conn - // Create tables - m := NewMigrator(p.db, p.Logger) - for _, t := range p.ResourceMap { - // validate table - if err := schema.ValidateTable(t); err != nil { - p.Logger.Error("table validation failed", "table", t.Name, "error", err) - return &cqproto.ConfigureProviderResponse{}, err - } - - if err := m.CreateTable(ctx, t, nil); err != nil { - p.Logger.Error("failed to create table", "table", t.Name, "error", err) - return &cqproto.ConfigureProviderResponse{}, err - } - } - + p.extraFields = request.ExtraFields providerConfig := p.Config() if err := defaults.Set(providerConfig); err != nil { return &cqproto.ConfigureProviderResponse{}, err @@ -122,7 +117,7 @@ func (p *Provider) FetchResources(ctx context.Context, request *cqproto.FetchRes if !ok { return fmt.Errorf("plugin %s does not provide resource %s", p.Name, resource) } - execData := schema.NewExecutionData(p.db, p.Logger, table) + execData := schema.NewExecutionData(p.db, p.Logger, table, p.disableDelete, p.extraFields) p.Logger.Debug("fetching table...", "provider", p.Name, "table", table.Name) // Save resource aside r := resource diff --git a/provider/providertest/integration.go b/provider/providertest/integration.go index 0d204c84..8401e2fc 100644 --- a/provider/providertest/integration.go +++ b/provider/providertest/integration.go @@ -92,11 +92,15 @@ func IntegrationTest(t *testing.T, providerCreator func() *provider.Provider, re } log.Printf("%s verify fields\n", resource.Table.Name) - conn, err := setupDatabase() + pool, err := setupDatabase() if err != nil { t.Fatal(err) } - defer conn.Close(context.Background()) + conn, err := pool.Acquire(context.Background()) + if err != nil { + t.Fatal(err) + } + defer conn.Release() err = verifyFields(resource, conn) if err != nil { diff --git a/provider/providertest/resource.go b/provider/providertest/resource.go index 378d54e6..eef0c623 100644 --- a/provider/providertest/resource.go +++ b/provider/providertest/resource.go @@ -7,6 +7,8 @@ import ( "os" "testing" + "github.com/jackc/pgx/v4/pgxpool" + "github.com/cloudquery/cq-provider-sdk/cqproto" "github.com/cloudquery/cq-provider-sdk/logging" "github.com/cloudquery/cq-provider-sdk/provider" @@ -16,7 +18,6 @@ import ( "github.com/hashicorp/go-hclog" "github.com/hashicorp/hcl/v2/gohcl" "github.com/hashicorp/hcl/v2/hclwrite" - "github.com/jackc/pgx/v4" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/tmccombs/hcl2json/convert" @@ -37,10 +38,22 @@ func TestResource(t *testing.T, providerCreator func() *provider.Provider, resou if err := faker.SetRandomMapAndSliceMaxSize(1); err != nil { t.Fatal(err) } - conn, err := setupDatabase() + ctx := context.Background() + + pool, err := setupDatabase() if err != nil { t.Fatal(err) } + conn, err := pool.Acquire(ctx) + if err != nil { + t.Fatal(err) + } + defer conn.Release() + l := logging.New(hclog.DefaultOptions) + migrator := provider.NewMigrator(l) + if err := migrator.CreateTable(ctx, conn, resource.Table, nil); err != nil { + assert.FailNow(t, "failed to create tables %s", err) + } // Write configuration as a block and extract it out passing that specific block data as part of the configure provider f := hclwrite.NewFile() f.Body().AppendBlock(gohcl.EncodeAsBlock(resource.Config, "configuration")) @@ -52,7 +65,7 @@ func TestResource(t *testing.T, providerCreator func() *provider.Provider, resou require.Nil(t, err) testProvider := providerCreator() - testProvider.Logger = logging.New(hclog.DefaultOptions) + testProvider.Logger = l testProvider.Configure = resource.Configure _, err = testProvider.ConfigureProvider(context.Background(), &cqproto.ConfigureProviderRequest{ CloudQueryVersion: "", @@ -85,18 +98,18 @@ func (f fakeResourceSender) Send(r *cqproto.FetchResourcesResponse) error { return nil } -func setupDatabase() (*pgx.Conn, error) { - dbCfg, err := pgx.ParseConfig(getEnv("DATABASE_URL", +func setupDatabase() (*pgxpool.Pool, error) { + dbCfg, err := pgxpool.ParseConfig(getEnv("DATABASE_URL", "host=localhost user=postgres password=pass DB.name=postgres port=5432")) if err != nil { return nil, fmt.Errorf("failed to parse config. %w", err) } ctx := context.Background() - conn, err := pgx.ConnectConfig(ctx, dbCfg) + pool, err := pgxpool.ConnectConfig(ctx, dbCfg) if err != nil { return nil, fmt.Errorf("unable to connect to database. %w", err) } - return conn, nil + return pool, nil } diff --git a/provider/schema/database.go b/provider/schema/database.go index 09323d55..22bc7e13 100644 --- a/provider/schema/database.go +++ b/provider/schema/database.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "strconv" + "strings" "github.com/jackc/pgx/v4" @@ -36,8 +37,13 @@ func NewPgDatabase(ctx context.Context, dsn string) (*PgDatabase, error) { // Insert inserts all resources to given table, table and resources are assumed from same table. func (p PgDatabase) Insert(ctx context.Context, t *Table, resources []*Resource) error { + if len(resources) == 0 { + return nil + } + // It is safe to assume that all resources have the same columns + cols := quoteColumns(resources[0].columns) psql := sq.StatementBuilder.PlaceholderFormat(sq.Dollar) - sqlStmt := psql.Insert(t.Name).Columns(quoteColumns(t.ColumnNames())...) + sqlStmt := psql.Insert(t.Name).Columns(cols...).Suffix(fmt.Sprintf("ON CONFLICT ON CONSTRAINT %s_pk DO UPDATE SET %s", t.Name, buildReplaceColumns(cols))) for _, res := range resources { if res.table != t { return fmt.Errorf("resource table expected %s got %s", t.Name, res.table.Name) @@ -133,3 +139,11 @@ func quoteColumns(columns []string) []string { } return columns } + +func buildReplaceColumns(columns []string) string { + replaceColumns := make([]string, len(columns)) + for i, c := range columns { + replaceColumns[i] = fmt.Sprintf("%[1]s = EXCLUDED.%[1]s", c) + } + return strings.Join(replaceColumns, ",") +} diff --git a/provider/schema/execution.go b/provider/schema/execution.go index 13edc6bd..d1927fd6 100644 --- a/provider/schema/execution.go +++ b/provider/schema/execution.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "os" + "reflect" "runtime/debug" "sync/atomic" @@ -19,23 +20,26 @@ type ClientMeta interface { // ExecutionData marks all the related execution info passed to TableResolver and ColumnResolver giving access to the Runner's meta type ExecutionData struct { - // The table this execution is associated with + // Table this execution is associated with Table *Table // Database connection to insert data into Db Database // Logger associated with this execution Logger hclog.Logger - // Column is set if execution is passed to ColumnResolver - Column *Column + // disableDelete allows to disable deletion of table data for this execution + disableDelete bool + // extraFields to be passed to each created resource in the execution + extraFields map[string]interface{} } // NewExecutionData Create a new execution data -func NewExecutionData(db Database, logger hclog.Logger, table *Table) ExecutionData { +func NewExecutionData(db Database, logger hclog.Logger, table *Table, disableDelete bool, extraFields map[string]interface{}) ExecutionData { return ExecutionData{ - Table: table, - Db: db, - Logger: logger, - Column: nil, + Table: table, + Db: db, + Logger: logger, + disableDelete: disableDelete, + extraFields: extraFields, } } @@ -64,15 +68,17 @@ func (e ExecutionData) ResolveTable(ctx context.Context, meta ClientMeta, parent func (e ExecutionData) WithTable(t *Table) ExecutionData { return ExecutionData{ - Table: t, - Db: e.Db, - Logger: e.Logger, + Table: t, + Db: e.Db, + Logger: e.Logger, + disableDelete: e.disableDelete, + extraFields: e.extraFields, } } func (e ExecutionData) callTableResolve(ctx context.Context, client ClientMeta, parent *Resource) (uint64, error) { - if parent == nil && e.Table.DeleteFilter != nil { + if !e.disableDelete && parent == nil && e.Table.DeleteFilter != nil { // Delete previous fetch if err := e.Db.Delete(ctx, e.Table, e.Table.DeleteFilter(client)); err != nil { client.Logger().Debug("cleaning table previous fetch", "table", e.Table.Name) @@ -120,12 +126,11 @@ func (e ExecutionData) callTableResolve(ctx context.Context, client ClientMeta, func (e ExecutionData) resolveResources(ctx context.Context, meta ClientMeta, parent *Resource, objects []interface{}) error { var resources = make([]*Resource, len(objects)) for i, o := range objects { - resources[i] = NewResourceData(e.Table, parent, o) + resources[i] = NewResourceData(e.Table, parent, o, e.extraFields) if err := e.resolveResourceValues(ctx, meta, resources[i]); err != nil { return err } } - // Before inserting resolve all table column resolvers if err := e.Db.Insert(ctx, e.Table, resources); err != nil { e.Logger.Error("failed to insert to db", "error", err) @@ -151,11 +156,16 @@ func (e ExecutionData) resolveResourceValues(ctx context.Context, meta ClientMet return err } // call PostRowResolver if defined after columns have been resolved - if resource.table.PostResourceResolver == nil { - return nil + if resource.table.PostResourceResolver != nil { + if err := resource.table.PostResourceResolver(ctx, meta, resource); err != nil { + return err + } } - if err := resource.table.PostResourceResolver(ctx, meta, resource); err != nil { - return err + // Finally generate cq_id for resource + for _, c := range GetDefaultSDKColumns() { + if err := c.Resolver(ctx, meta, resource, c); err != nil { + return err + } } return nil } @@ -183,3 +193,26 @@ func (e ExecutionData) resolveColumns(ctx context.Context, meta ClientMeta, reso } return nil } + +func interfaceSlice(slice interface{}) []interface{} { + // if value is nil return nil + if slice == nil { + return nil + } + s := reflect.ValueOf(slice) + // Keep the distinction between nil and empty slice input + if s.Kind() == reflect.Ptr && s.Elem().Kind() == reflect.Slice && s.Elem().IsNil() { + return nil + } + if s.Kind() != reflect.Slice { + return []interface{}{slice} + } + + ret := make([]interface{}, s.Len()) + + for i := 0; i < s.Len(); i++ { + ret[i] = s.Index(i).Interface() + } + + return ret +} diff --git a/provider/schema/execution_test.go b/provider/schema/execution_test.go index f56d8875..aae356a4 100644 --- a/provider/schema/execution_test.go +++ b/provider/schema/execution_test.go @@ -112,13 +112,13 @@ func TestExecutionData_ResolveTable(t *testing.T) { Output: nil, }) mockedClient.On("Logger", mock.Anything).Return(logger) - exec := NewExecutionData(mockDb, logger, testTable) + exec := NewExecutionData(mockDb, logger, testTable, false, nil) t.Run("failing table resolver", func(t *testing.T) { testTable.Resolver = failingTableResolver _, err := exec.ResolveTable(context.Background(), mockedClient, nil) assert.Error(t, err) - execFailing := NewExecutionData(mockDb, logger, testBadColumnResolverTable) + execFailing := NewExecutionData(mockDb, logger, testBadColumnResolverTable, false, nil) _, err = execFailing.ResolveTable(context.Background(), mockedClient, nil) assert.Error(t, err) }) @@ -169,7 +169,7 @@ func TestExecutionData_ResolveTable(t *testing.T) { }) t.Run("test resolving with default column values", func(t *testing.T) { - execDefault := NewExecutionData(mockDb, logger, testDefaultsTable) + execDefault := NewExecutionData(mockDb, logger, testDefaultsTable, false, nil) mockDb.On("Insert", mock.Anything, testDefaultsTable, mock.Anything).Return(nil) testDefaultsTable.Resolver = func(ctx context.Context, meta ClientMeta, parent *Resource, res chan interface{}) error { res <- testDefaultsTableData{Name: nil} @@ -184,6 +184,54 @@ func TestExecutionData_ResolveTable(t *testing.T) { assert.Nil(t, err) assert.Equal(t, expectedResource.data["name"], "defaultValue") }) + + t.Run("disable delete", func(t *testing.T) { + exec := NewExecutionData(mockDb, logger, testTable, true, nil) + testTable.Resolver = dataReturningSingleResolver + testTable.DeleteFilter = func(meta ClientMeta) []interface{} { + return nil + } + var expectedResource *Resource + testTable.PostResourceResolver = func(ctx context.Context, meta ClientMeta, parent *Resource) error { + err := parent.Set("name", "other") + assert.Nil(t, err) + expectedResource = parent + return nil + } + mockDb.On("Delete", mock.Anything, testTable, mock.Anything).Return(nil) + mockDb.On("Insert", mock.Anything, testTable, mock.Anything).Return(nil) + mockDb.AssertNumberOfCalls(t, "Delete", 0) + _, err := exec.ResolveTable(context.Background(), mockedClient, nil) + mockDb.AssertNumberOfCalls(t, "Delete", 0) + assert.Equal(t, expectedResource.data["name"], "other") + assert.Nil(t, err) + exec = NewExecutionData(mockDb, logger, testTable, false, nil) + _, err = exec.ResolveTable(context.Background(), mockedClient, nil) + mockDb.AssertNumberOfCalls(t, "Delete", 1) + assert.Nil(t, err) + }) + + t.Run("inject fields into execution", func(t *testing.T) { + exec := NewExecutionData(mockDb, logger, testTable, false, map[string]interface{}{"injected_field": 1}) + testTable.Resolver = dataReturningSingleResolver + var expectedResource *Resource + testTable.PostResourceResolver = func(ctx context.Context, meta ClientMeta, parent *Resource) error { + err := parent.Set("name", "other") + assert.Nil(t, err) + expectedResource = parent + return nil + } + mockDb.On("Insert", mock.Anything, testTable, mock.Anything).Return(nil) + count, err := exec.ResolveTable(context.Background(), mockedClient, nil) + assert.Equal(t, count, uint64(1)) + assert.Nil(t, err) + assert.Equal(t, expectedResource.data["name"], "other") + assert.Equal(t, 1, expectedResource.extraFields["injected_field"]) + values, err := expectedResource.Values() + assert.Nil(t, err) + assert.Equal(t, []string{"name", "name_no_prefix", "prefix_name", "cq_id", "meta", "injected_field"}, expectedResource.columns) + assert.Equal(t, []interface{}{"other", "name_no_prefix", "prefix_name", expectedResource.cqId, expectedResource.Get("meta"), 1}, values) + }) } // ClientMeta is an autogenerated mock type for the ClientMeta type diff --git a/provider/schema/meta.go b/provider/schema/meta.go new file mode 100644 index 00000000..2021ed8b --- /dev/null +++ b/provider/schema/meta.go @@ -0,0 +1,33 @@ +package schema + +import ( + "context" + "time" +) + +var ( + meta = Column{ + Name: "meta", + Type: TypeJSON, + Description: "Meta column holds fetch information", + Resolver: func(ctx context.Context, meta ClientMeta, resource *Resource, c Column) error { + return resource.Set(c.Name, map[string]interface{}{"last_updated": time.Now().UTC()}) + }, + } + cqIdColumn = Column{ + Name: "cq_id", + Type: TypeUUID, + Description: "Unique CloudQuery Id added to every resource", + Resolver: func(ctx context.Context, meta ClientMeta, resource *Resource, c Column) error { + if err := resource.GenerateCQId(); err != nil { + return err + } + return resource.Set(c.Name, resource.Id()) + }, + } +) + +// GetDefaultSDKColumns Default columns of the SDK, these columns are added to each table by default +func GetDefaultSDKColumns() []Column { + return []Column{cqIdColumn, meta} +} diff --git a/provider/schema/resolvers.go b/provider/schema/resolvers.go index d47e3117..0fdce8a9 100644 --- a/provider/schema/resolvers.go +++ b/provider/schema/resolvers.go @@ -2,40 +2,31 @@ package schema import ( "context" - "reflect" "github.com/thoas/go-funk" ) +// PathResolver resolves a field in the Resource.Item +// +// Examples: +// PathResolver("Field") +// PathResolver("InnerStruct.Field") +// PathResolver("InnerStruct.InnerInnerStruct.Field") func PathResolver(path string) ColumnResolver { return func(_ context.Context, meta ClientMeta, r *Resource, c Column) error { return r.Set(c.Name, funk.Get(r.Item, path, funk.WithAllowZero())) } } +// ParentIdResolver resolves the cq_id from the parent +// if you want to reference the parent's primary keys use ParentFieldResolver as required. func ParentIdResolver(_ context.Context, _ ClientMeta, r *Resource, c Column) error { return r.Set(c.Name, r.Parent.Id()) } -func interfaceSlice(slice interface{}) []interface{} { - // if value is nil return nil - if slice == nil { - return nil +// ParentFieldResolver resolves a field from the parent +func ParentFieldResolver(name string) ColumnResolver { + return func(_ context.Context, _ ClientMeta, r *Resource, c Column) error { + return r.Set(c.Name, r.Parent.Get(name)) } - s := reflect.ValueOf(slice) - // Keep the distinction between nil and empty slice input - if s.Kind() == reflect.Ptr && s.Elem().Kind() == reflect.Slice && s.Elem().IsNil() { - return nil - } - if s.Kind() != reflect.Slice { - return []interface{}{slice} - } - - ret := make([]interface{}, s.Len()) - - for i := 0; i < s.Len(); i++ { - ret[i] = s.Index(i).Interface() - } - - return ret } diff --git a/provider/schema/resolvers_test.go b/provider/schema/resolvers_test.go index 5a3aa5de..5f3565c6 100644 --- a/provider/schema/resolvers_test.go +++ b/provider/schema/resolvers_test.go @@ -17,30 +17,28 @@ type testStruct struct { unexported bool } +var pathTestTable = &Table{ + Columns: []Column{ + { + Name: "test", + Type: TypeString, + }, + { + Name: "int_value", + Type: TypeInt, + }, + { + Name: "unexported", + Type: TypeBool, + }, + }, +} + func TestPathResolver(t *testing.T) { r1 := PathResolver("Inner.Value") r2 := PathResolver("Value") r3 := PathResolver("unexported") - resource := &Resource{ - Item: testStruct{Inner: innerStruct{Value: "bla"}, Value: 5, unexported: false}, - data: map[string]interface{}{}, - table: &Table{ - Columns: []Column{ - { - Name: "test", - Type: TypeString, - }, - { - Name: "int_value", - Type: TypeInt, - }, - { - Name: "unexported", - Type: TypeBool, - }, - }, - }, - } + resource := NewResourceData(pathTestTable, nil, testStruct{Inner: innerStruct{Value: "bla"}, Value: 5, unexported: false}, nil) err := r1(context.TODO(), nil, resource, Column{Name: "test"}) assert.Nil(t, err) diff --git a/provider/schema/resource.go b/provider/schema/resource.go index 143ef570..7ba4311b 100644 --- a/provider/schema/resource.go +++ b/provider/schema/resource.go @@ -1,8 +1,10 @@ package schema import ( + "crypto" "fmt" + "github.com/mitchellh/hashstructure" "github.com/thoas/go-funk" "github.com/google/uuid" @@ -16,47 +18,96 @@ type Resource struct { // Set if this is an embedded table Parent *Resource // internal fields - table *Table - data map[string]interface{} - id uuid.UUID + table *Table + data map[string]interface{} + cqId uuid.UUID + extraFields map[string]interface{} + columns []string } -func NewResourceData(t *Table, parent *Resource, item interface{}) *Resource { +func NewResourceData(t *Table, parent *Resource, item interface{}, extraFields map[string]interface{}) *Resource { return &Resource{ - Item: item, - Parent: parent, - table: t, - data: make(map[string]interface{}), - id: uuid.New(), + Item: item, + Parent: parent, + table: t, + data: make(map[string]interface{}), + cqId: uuid.New(), + columns: getResourceColumns(t, extraFields), + extraFields: extraFields, } } -func (r Resource) Get(key string) interface{} { +func (r *Resource) Get(key string) interface{} { return r.data[key] } -func (r Resource) Set(key string, value interface{}) error { - columnExists := funk.ContainsString(r.table.ColumnNames(), key) +func (r *Resource) Set(key string, value interface{}) error { + columnExists := funk.ContainsString(r.columns, key) if !columnExists { - return fmt.Errorf("column %s does not exits", key) + return fmt.Errorf("column %s does not exist", key) } r.data[key] = value return nil } -func (r Resource) Id() uuid.UUID { - return r.id +func (r *Resource) Id() uuid.UUID { + return r.cqId } -func (r Resource) Values() ([]interface{}, error) { +func (r *Resource) Values() ([]interface{}, error) { values := make([]interface{}, 0) - values = append(values, r.id) - for _, c := range r.table.Columns { + for _, c := range append(r.table.Columns, GetDefaultSDKColumns()...) { v := r.Get(c.Name) if err := c.ValidateType(v); err != nil { return nil, err } values = append(values, v) } + for _, v := range r.extraFields { + values = append(values, v) + } return values, nil } + +func (r *Resource) GenerateCQId() error { + if len(r.table.Options.PrimaryKeys) == 0 { + return nil + } + objs := make([]interface{}, len(r.table.PrimaryKeys())) + for i, pk := range r.table.PrimaryKeys() { + value := r.Get(pk) + if value == nil { + return fmt.Errorf("failed to generate cq_id for %s, pk field missing %s", r.table.Name, pk) + } + objs[i] = value + } + id, err := hashUUID(objs) + if err != nil { + return err + } + r.cqId = id + return nil +} + +func hashUUID(objs interface{}) (uuid.UUID, error) { + // Use SHA1 because it's fast and is reasonably enough protected against accidental collisions. + // There is no scenario here where intentional created collisions could do harm. + digester := crypto.SHA1.New() + hash, err := hashstructure.Hash(objs, nil) + if err != nil { + return uuid.Nil, err + } + if _, err := fmt.Fprint(digester, hash); err != nil { + return uuid.Nil, err + } + data := digester.Sum(nil) + return uuid.NewSHA1(uuid.Nil, data), nil +} + +func getResourceColumns(t *Table, fields map[string]interface{}) []string { + columns := t.ColumnNames() + for k := range fields { + columns = append(columns, k) + } + return columns +} diff --git a/provider/schema/resources_test.go b/provider/schema/resources_test.go index acd0a801..e76fbfeb 100644 --- a/provider/schema/resources_test.go +++ b/provider/schema/resources_test.go @@ -46,6 +46,17 @@ var testZeroTable = &Table{ }, } +var testPrimaryKeyTable = &Table{ + Name: "test_pk_table", + Options: TableCreationOptions{PrimaryKeys: []string{"primary_key_str"}}, + Columns: []Column{ + { + Name: "primary_key_str", + Type: TypeString, + }, + }, +} + type zeroValuedStruct struct { ZeroBool bool `default:"false"` ZeroInt int `default:"0"` @@ -56,15 +67,38 @@ type zeroValuedStruct struct { ZeroString string `default:""` } +// TestResourcePrimaryKey checks resource id generation when primary key is set on table +func TestResourcePrimaryKey(t *testing.T) { + r := NewResourceData(testPrimaryKeyTable, nil, nil, nil) + // save random id + randomId := r.cqId + assert.Error(t, r.GenerateCQId(), "Error expected, primary key value not set") + // Id shouldn't change + assert.Equal(t, randomId, r.cqId) + err := r.Set("primary_key_str", "test") + assert.Nil(t, err) + assert.Nil(t, r.GenerateCQId()) + assert.NotEqual(t, randomId, r.cqId) + randomId = r.cqId + assert.Nil(t, r.GenerateCQId()) + assert.Equal(t, randomId, r.cqId) +} + +// TestResourcePrimaryKey checks resource id generation when primary key is set on table +func TestResourceAddColumns(t *testing.T) { + r := NewResourceData(testPrimaryKeyTable, nil, nil, map[string]interface{}{"new_field": 1}) + assert.Equal(t, []string{"primary_key_str", "cq_id", "meta", "new_field"}, r.columns) +} + func TestResourceColumns(t *testing.T) { - r := NewResourceData(testTable, nil, nil) + r := NewResourceData(testTable, nil, nil, nil) errf := r.Set("name", "test") assert.Nil(t, errf) assert.Equal(t, r.Get("name"), "test") v, err := r.Values() assert.Nil(t, err) - assert.Equal(t, v, []interface{}{r.id, "test", nil, nil}) + assert.Equal(t, v, []interface{}{"test", nil, nil, nil, nil}) // Set invalid type to resource errf = r.Set("name", 5) assert.Nil(t, errf) @@ -81,7 +115,7 @@ func TestResourceColumns(t *testing.T) { assert.Nil(t, errf) v, err = r.Values() assert.Nil(t, err) - assert.Equal(t, v, []interface{}{r.id, "test", "name_no_prefix", "prefix_name"}) + assert.Equal(t, v, []interface{}{"test", "name_no_prefix", "prefix_name", nil, nil}) // check non existing col err = r.Set("non_exist_col", "test") @@ -100,49 +134,50 @@ func TestResourceResolveColumns(t *testing.T) { t.Run("test resolve column normal", func(t *testing.T) { object := testTableStruct{} _ = defaults.Set(&object) - r := NewResourceData(testTable, nil, object) - assert.Equal(t, r.id, r.Id()) + r := NewResourceData(testTable, nil, object, nil) + assert.Equal(t, r.cqId, r.Id()) // columns should be resolved from ColumnResolver functions or default functions logger := logging.New(&hclog.LoggerOptions{ Name: "test_log", Level: hclog.Error, Output: nil, }) - exec := NewExecutionData(nil, logger, testTable) + exec := NewExecutionData(nil, logger, testTable, false, nil) err := exec.resolveColumns(context.TODO(), mockedClient, r, testTable.Columns) assert.Nil(t, err) v, err := r.Values() assert.Nil(t, err) - assert.Equal(t, v, []interface{}{r.id, "test", "name_no_prefix", "prefix_name"}) + assert.Equal(t, v, []interface{}{"test", "name_no_prefix", "prefix_name", nil, nil}) }) t.Run("test resolve zero columns", func(t *testing.T) { object := zeroValuedStruct{} _ = defaults.Set(&object) - r := NewResourceData(testZeroTable, nil, object) - assert.Equal(t, r.id, r.Id()) + r := NewResourceData(testZeroTable, nil, object, nil) + assert.Equal(t, r.cqId, r.Id()) // columns should be resolved from ColumnResolver functions or default functions logger := logging.New(&hclog.LoggerOptions{ Name: "test_log", Level: hclog.Error, Output: nil, }) - exec := NewExecutionData(nil, logger, testZeroTable) + exec := NewExecutionData(nil, logger, testZeroTable, false, nil) err := exec.resolveColumns(context.TODO(), mockedClient, r, testZeroTable.Columns) assert.Nil(t, err) v, err := r.Values() assert.Nil(t, err) - assert.Equal(t, []interface{}{r.id, false, 0, true}, v[:4]) - assert.Equal(t, 0, *v[5].(*int)) - assert.Equal(t, 5, *v[6].(*int)) - assert.Equal(t, "", v[7].(string)) + assert.Equal(t, []interface{}{false, 0, true}, v[:3]) + assert.Equal(t, 0, *v[4].(*int)) + assert.Equal(t, 5, *v[5].(*int)) + assert.Equal(t, "", v[6].(string)) + assert.Equal(t, nil, v[7]) + assert.Equal(t, nil, v[8]) object.ZeroIntPtr = nil - r = NewResourceData(testZeroTable, nil, object) + r = NewResourceData(testZeroTable, nil, object, nil) err = exec.resolveColumns(context.TODO(), mockedClient, r, testZeroTable.Columns) assert.Nil(t, err) v, _ = r.Values() - assert.Equal(t, nil, v[5]) + assert.Equal(t, nil, v[4]) }) - } diff --git a/provider/schema/table.go b/provider/schema/table.go index 5d440ed3..c1104869 100644 --- a/provider/schema/table.go +++ b/provider/schema/table.go @@ -37,6 +37,8 @@ type Table struct { DeleteFilter func(meta ClientMeta) []interface{} // Post resource resolver is called after all columns have been resolved, and before resource is inserted to database. PostResourceResolver RowResolver + // Options allow to modify how the table is defined when created + Options TableCreationOptions } // ColumnNames returns all collected columns name of table (including all inner embedded columns) @@ -45,7 +47,10 @@ func (t Table) ColumnNames() []string { for i, c := range t.Columns { cn[i] = c.Name } - return append([]string{"id"}, cn...) + for _, c := range GetDefaultSDKColumns() { + cn = append(cn, c.Name) + } + return cn } func (t Table) Column(name string) *Column { @@ -56,3 +61,17 @@ func (t Table) Column(name string) *Column { } return nil } + +func (t Table) PrimaryKeys() []string { + if len(t.Options.PrimaryKeys) > 0 { + return t.Options.PrimaryKeys + } + return []string{"cq_id"} +} + +// TableCreationOptions allow to modify how table is created such as defining primary keys, indices, foreign keys and contraints. +type TableCreationOptions struct { + // List of columns to set as primary keys, if HashPrimaryKeys is true the column values will be used to generate an Id + // and a "id" column will be created for the table. If this nil a random unique Id is generated. + PrimaryKeys []string +} diff --git a/provider/schema/table_test.go b/provider/schema/table_test.go index 399cff4a..300cf52e 100644 --- a/provider/schema/table_test.go +++ b/provider/schema/table_test.go @@ -18,7 +18,7 @@ var tableDefinitionTestCases = []tableTestCase{ }, }, }, - ExpectedColumnNames: []string{"id", "some_string"}, + ExpectedColumnNames: []string{"some_string", "cq_id", "meta"}, ExpectedHasId: false, }, { @@ -36,7 +36,7 @@ var tableDefinitionTestCases = []tableTestCase{ }, }, }, - ExpectedColumnNames: []string{"id", "some_string", "some_int"}, + ExpectedColumnNames: []string{"some_string", "some_int", "cq_id", "meta"}, ExpectedHasId: true, }, { @@ -62,7 +62,7 @@ var tableDefinitionTestCases = []tableTestCase{ }, }, }, - ExpectedColumnNames: []string{"id", "some_string", "some_int", "embedded_some_string", "embedded_some_int"}, + ExpectedColumnNames: []string{"some_string", "some_int", "embedded_some_string", "embedded_some_int", "cq_id", "meta"}, }, { @@ -84,7 +84,7 @@ var tableDefinitionTestCases = []tableTestCase{ }, }, }, - ExpectedColumnNames: []string{"id", "some_int", "embedded_some_string", "embedded_inner_some_int"}, + ExpectedColumnNames: []string{"some_int", "embedded_some_string", "embedded_inner_some_int", "cq_id", "meta"}, }, { Name: "simpleTableWithEmbedded", @@ -109,7 +109,7 @@ var tableDefinitionTestCases = []tableTestCase{ }, }, }, - ExpectedColumnNames: []string{"id", "some_string", "some_int", "some_string_no_prefix", "some_int_no_prefix"}, + ExpectedColumnNames: []string{"some_string", "some_int", "some_string_no_prefix", "some_int_no_prefix", "cq_id", "meta"}, }, } @@ -122,6 +122,6 @@ type tableTestCase struct { func TestTableDefinitionUseCases(t *testing.T) { for _, c := range tableDefinitionTestCases { - assert.Equal(t, c.Table.ColumnNames(), c.ExpectedColumnNames, "failed case %s", c.Name) + assert.Equal(t, c.ExpectedColumnNames, c.Table.ColumnNames(), "failed case %s", c.Name) } }