Add IS_SUBSTRING operator for use in API resource filtering. (#645)
* Add IS_SUBSTRING operator for use in API resource filtering. This should allow substring matches on fields like names and labels and so on. Also bump the version of Mastermind/squirrel so we get the new 'like' operator for use when building the SQL query. Additionally, I also had to fix the generate_api.sh script which had a bug (it modified the wrong file permissions before), and add a dummy service to generate Swagger definitions for the Filter itself (this was a hack in the previous Makefile that I lost when we moved to Bazel). * Add comments for DummyFilterService * Add more comments * change errors returned * fix import
This commit is contained in:
parent
8c6dfd14b6
commit
5a9e3ff14b
|
|
@ -472,7 +472,7 @@ go_repository(
|
|||
|
||||
go_repository(
|
||||
name = "com_github_masterminds_squirrel",
|
||||
commit = "a6b93000bd21",
|
||||
commit = "fa735ea14f09",
|
||||
importpath = "github.com/Masterminds/squirrel",
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,10 @@ message Predicate {
|
|||
// Checks if the value is a member of a given array, which should be one of
|
||||
// |int_values|, |long_values| or |string_values|.
|
||||
IN = 8;
|
||||
|
||||
// Checks if the value contains |string_value| as a substring match. Only
|
||||
// applies to |string_value|.
|
||||
IS_SUBSTRING = 9;
|
||||
}
|
||||
Op op = 1;
|
||||
|
||||
|
|
@ -115,4 +119,10 @@ message Filter {
|
|||
repeated Predicate predicates = 1;
|
||||
}
|
||||
|
||||
|
||||
// This dummy service is required so that grpc-gateway will generate Swagger
|
||||
// definitions for the Filter message. Otherwise, it does not get generated
|
||||
// since Filter itself is not used in any of the RPC calls - only a serialized
|
||||
// encoded version of it is used.
|
||||
service DummyFilterService {
|
||||
rpc GetFilter(Filter) returns (Filter) {}
|
||||
}
|
||||
|
|
@ -34,12 +34,13 @@ bazel build @com_github_go_swagger//cmd/swagger
|
|||
# Build .pb.go and .gw.pb.go files from the proto sources.
|
||||
bazel build //backend/api:api_generated_go_sources
|
||||
|
||||
set -x
|
||||
# Copy the generated files into the source tree and add license.
|
||||
for f in $GENERATED_GO_PROTO_FILES; do
|
||||
name=$(basename ${f})
|
||||
cp $f go_client/${name}
|
||||
chmod 766 $f
|
||||
${AUTOGEN_CMD} -i --no-tlc -c "Google LLC" -l apache go_client/${name}
|
||||
target=go_client/$(basename ${f})
|
||||
cp $f $target
|
||||
chmod 766 $target
|
||||
${AUTOGEN_CMD} -i --no-tlc -c "Google LLC" -l apache $target
|
||||
done
|
||||
|
||||
# Generate and copy back into source tree .swagger.json files.
|
||||
|
|
|
|||
|
|
@ -23,6 +23,11 @@ import math "math"
|
|||
import timestamp "github.com/golang/protobuf/ptypes/timestamp"
|
||||
import _ "google.golang.org/genproto/googleapis/api/annotations"
|
||||
|
||||
import (
|
||||
context "golang.org/x/net/context"
|
||||
grpc "google.golang.org/grpc"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
|
|
@ -45,6 +50,7 @@ const (
|
|||
Predicate_LESS_THAN Predicate_Op = 6
|
||||
Predicate_LESS_THAN_EQUALS Predicate_Op = 7
|
||||
Predicate_IN Predicate_Op = 8
|
||||
Predicate_IS_SUBSTRING Predicate_Op = 9
|
||||
)
|
||||
|
||||
var Predicate_Op_name = map[int32]string{
|
||||
|
|
@ -56,6 +62,7 @@ var Predicate_Op_name = map[int32]string{
|
|||
6: "LESS_THAN",
|
||||
7: "LESS_THAN_EQUALS",
|
||||
8: "IN",
|
||||
9: "IS_SUBSTRING",
|
||||
}
|
||||
var Predicate_Op_value = map[string]int32{
|
||||
"UNKNOWN": 0,
|
||||
|
|
@ -66,13 +73,14 @@ var Predicate_Op_value = map[string]int32{
|
|||
"LESS_THAN": 6,
|
||||
"LESS_THAN_EQUALS": 7,
|
||||
"IN": 8,
|
||||
"IS_SUBSTRING": 9,
|
||||
}
|
||||
|
||||
func (x Predicate_Op) String() string {
|
||||
return proto.EnumName(Predicate_Op_name, int32(x))
|
||||
}
|
||||
func (Predicate_Op) EnumDescriptor() ([]byte, []int) {
|
||||
return fileDescriptor_filter_acfa53e1ea44e70d, []int{0, 0}
|
||||
return fileDescriptor_filter_836b9ddef08e4ec1, []int{0, 0}
|
||||
}
|
||||
|
||||
type Predicate struct {
|
||||
|
|
@ -96,7 +104,7 @@ func (m *Predicate) Reset() { *m = Predicate{} }
|
|||
func (m *Predicate) String() string { return proto.CompactTextString(m) }
|
||||
func (*Predicate) ProtoMessage() {}
|
||||
func (*Predicate) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_filter_acfa53e1ea44e70d, []int{0}
|
||||
return fileDescriptor_filter_836b9ddef08e4ec1, []int{0}
|
||||
}
|
||||
func (m *Predicate) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Predicate.Unmarshal(m, b)
|
||||
|
|
@ -398,7 +406,7 @@ func (m *IntValues) Reset() { *m = IntValues{} }
|
|||
func (m *IntValues) String() string { return proto.CompactTextString(m) }
|
||||
func (*IntValues) ProtoMessage() {}
|
||||
func (*IntValues) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_filter_acfa53e1ea44e70d, []int{1}
|
||||
return fileDescriptor_filter_836b9ddef08e4ec1, []int{1}
|
||||
}
|
||||
func (m *IntValues) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_IntValues.Unmarshal(m, b)
|
||||
|
|
@ -436,7 +444,7 @@ func (m *StringValues) Reset() { *m = StringValues{} }
|
|||
func (m *StringValues) String() string { return proto.CompactTextString(m) }
|
||||
func (*StringValues) ProtoMessage() {}
|
||||
func (*StringValues) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_filter_acfa53e1ea44e70d, []int{2}
|
||||
return fileDescriptor_filter_836b9ddef08e4ec1, []int{2}
|
||||
}
|
||||
func (m *StringValues) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_StringValues.Unmarshal(m, b)
|
||||
|
|
@ -474,7 +482,7 @@ func (m *LongValues) Reset() { *m = LongValues{} }
|
|||
func (m *LongValues) String() string { return proto.CompactTextString(m) }
|
||||
func (*LongValues) ProtoMessage() {}
|
||||
func (*LongValues) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_filter_acfa53e1ea44e70d, []int{3}
|
||||
return fileDescriptor_filter_836b9ddef08e4ec1, []int{3}
|
||||
}
|
||||
func (m *LongValues) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_LongValues.Unmarshal(m, b)
|
||||
|
|
@ -512,7 +520,7 @@ func (m *Filter) Reset() { *m = Filter{} }
|
|||
func (m *Filter) String() string { return proto.CompactTextString(m) }
|
||||
func (*Filter) ProtoMessage() {}
|
||||
func (*Filter) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_filter_acfa53e1ea44e70d, []int{4}
|
||||
return fileDescriptor_filter_836b9ddef08e4ec1, []int{4}
|
||||
}
|
||||
func (m *Filter) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Filter.Unmarshal(m, b)
|
||||
|
|
@ -548,38 +556,113 @@ func init() {
|
|||
proto.RegisterEnum("api.Predicate_Op", Predicate_Op_name, Predicate_Op_value)
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("backend/api/filter.proto", fileDescriptor_filter_acfa53e1ea44e70d) }
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ context.Context
|
||||
var _ grpc.ClientConn
|
||||
|
||||
var fileDescriptor_filter_acfa53e1ea44e70d = []byte{
|
||||
// 469 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x4c, 0x92, 0xd1, 0x6e, 0xd3, 0x30,
|
||||
0x14, 0x86, 0x9b, 0x78, 0x49, 0x9b, 0xd3, 0xae, 0x0b, 0x06, 0x41, 0x54, 0x81, 0x16, 0x3a, 0x84,
|
||||
0x72, 0x95, 0x4a, 0xe5, 0x66, 0xb7, 0x45, 0x0a, 0x64, 0xa2, 0x4a, 0xc1, 0xed, 0xe0, 0xb2, 0x72,
|
||||
0xb7, 0xac, 0xb2, 0xd6, 0xc5, 0x56, 0xed, 0x21, 0xf1, 0x00, 0xbc, 0x05, 0x0f, 0x8b, 0x62, 0x27,
|
||||
0x6e, 0xee, 0x7a, 0xce, 0xf9, 0x7e, 0xf7, 0xff, 0x4f, 0x0e, 0x44, 0x3b, 0x7a, 0xf7, 0x58, 0x56,
|
||||
0xf7, 0x33, 0x2a, 0xd8, 0xec, 0x81, 0x1d, 0x54, 0x79, 0x4c, 0xc5, 0x91, 0x2b, 0x8e, 0x11, 0x15,
|
||||
0x6c, 0xf2, 0x76, 0xcf, 0xf9, 0xfe, 0x50, 0xea, 0x29, 0xad, 0x2a, 0xae, 0xa8, 0x62, 0xbc, 0x92,
|
||||
0x06, 0x99, 0x5c, 0x36, 0x53, 0x5d, 0xed, 0x9e, 0x1f, 0x66, 0x8a, 0x3d, 0x95, 0x52, 0xd1, 0x27,
|
||||
0x61, 0x80, 0xe9, 0xbf, 0x33, 0x08, 0xbe, 0x1f, 0xcb, 0x7b, 0x76, 0x47, 0x55, 0x89, 0xdf, 0x83,
|
||||
0xcb, 0x45, 0xe4, 0xc4, 0x4e, 0x32, 0x9e, 0xbf, 0x48, 0xa9, 0x60, 0xa9, 0x9d, 0xa5, 0x2b, 0x41,
|
||||
0x5c, 0x2e, 0x70, 0x08, 0xe8, 0xb1, 0xfc, 0x13, 0xb9, 0xb1, 0x93, 0x04, 0xa4, 0xfe, 0x89, 0xdf,
|
||||
0x41, 0xc0, 0x2a, 0xb5, 0xfd, 0x4d, 0x0f, 0xcf, 0x65, 0x84, 0x62, 0x27, 0xf1, 0xf2, 0x1e, 0x19,
|
||||
0xb0, 0x4a, 0xfd, 0xac, 0x3b, 0xf8, 0x12, 0xe0, 0xc0, 0xab, 0x7d, 0x33, 0x3f, 0x8b, 0x9d, 0x04,
|
||||
0xe5, 0x3d, 0x12, 0xd4, 0x3d, 0x03, 0x5c, 0xc1, 0x48, 0xaa, 0x23, 0xb3, 0x88, 0x57, 0x3f, 0x9d,
|
||||
0xf7, 0xc8, 0xd0, 0x74, 0x0d, 0x94, 0xc1, 0x85, 0xb5, 0xde, 0x70, 0x7e, 0xec, 0x24, 0xc3, 0xf9,
|
||||
0x24, 0x35, 0x11, 0xd3, 0x36, 0x62, 0xba, 0x69, 0xb9, 0xbc, 0x47, 0xc6, 0x56, 0x64, 0x9e, 0x99,
|
||||
0x01, 0x58, 0xaf, 0x32, 0xea, 0xeb, 0x17, 0xc6, 0x3a, 0xe8, 0x4d, 0xe3, 0x57, 0xd6, 0xe6, 0x5a,
|
||||
0xf3, 0x12, 0xcf, 0x61, 0x78, 0x72, 0x2f, 0xa3, 0x81, 0x56, 0x5c, 0x68, 0xc5, 0xb2, 0x4d, 0x50,
|
||||
0x4b, 0xc0, 0xe6, 0x91, 0xf8, 0x1a, 0xce, 0xbb, 0x81, 0x64, 0x14, 0x68, 0x95, 0x59, 0xe8, 0xfa,
|
||||
0x14, 0xaa, 0xd6, 0x8d, 0x3a, 0x21, 0xe5, 0xf4, 0xaf, 0x03, 0xee, 0x4a, 0xe0, 0x21, 0xf4, 0x6f,
|
||||
0x8b, 0x6f, 0xc5, 0xea, 0x57, 0x11, 0xf6, 0x30, 0x80, 0x9f, 0xfd, 0xb8, 0x5d, 0x2c, 0xd7, 0xa1,
|
||||
0x83, 0xc7, 0x00, 0xc5, 0x6a, 0xb3, 0x6d, 0x6a, 0x17, 0x87, 0x30, 0xfa, 0x4a, 0xb2, 0xc5, 0x26,
|
||||
0x23, 0xdb, 0x4d, 0xbe, 0x28, 0x42, 0x84, 0xdf, 0xc0, 0xcb, 0x6e, 0xa7, 0x45, 0x3d, 0x7c, 0x0e,
|
||||
0xc1, 0x32, 0x5b, 0xaf, 0x0d, 0xe7, 0xe3, 0x57, 0x10, 0xda, 0xb2, 0x85, 0xfa, 0xd8, 0x07, 0xf7,
|
||||
0xa6, 0x08, 0x07, 0x9f, 0xfb, 0xe0, 0x69, 0xeb, 0xd3, 0x2b, 0x08, 0xec, 0x62, 0xf0, 0x6b, 0xf0,
|
||||
0x9b, 0x40, 0x4e, 0x8c, 0x12, 0x8f, 0x34, 0xd5, 0xf4, 0x23, 0x8c, 0xba, 0xa9, 0x3a, 0x9c, 0x1b,
|
||||
0xa3, 0x24, 0xb0, 0xdc, 0x07, 0x80, 0xd3, 0xce, 0x3a, 0x14, 0x8a, 0x51, 0x82, 0x2c, 0x75, 0x0d,
|
||||
0xfe, 0x17, 0x7d, 0xe5, 0x38, 0x05, 0x10, 0xed, 0xf9, 0x99, 0xff, 0x6c, 0x3f, 0x96, 0xbd, 0x4a,
|
||||
0xd2, 0x21, 0x76, 0xbe, 0x3e, 0x81, 0x4f, 0xff, 0x03, 0x00, 0x00, 0xff, 0xff, 0x8d, 0x24, 0xfb,
|
||||
0x88, 0x32, 0x03, 0x00, 0x00,
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
const _ = grpc.SupportPackageIsVersion4
|
||||
|
||||
// DummyFilterServiceClient is the client API for DummyFilterService service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
||||
type DummyFilterServiceClient interface {
|
||||
GetFilter(ctx context.Context, in *Filter, opts ...grpc.CallOption) (*Filter, error)
|
||||
}
|
||||
|
||||
type dummyFilterServiceClient struct {
|
||||
cc *grpc.ClientConn
|
||||
}
|
||||
|
||||
func NewDummyFilterServiceClient(cc *grpc.ClientConn) DummyFilterServiceClient {
|
||||
return &dummyFilterServiceClient{cc}
|
||||
}
|
||||
|
||||
func (c *dummyFilterServiceClient) GetFilter(ctx context.Context, in *Filter, opts ...grpc.CallOption) (*Filter, error) {
|
||||
out := new(Filter)
|
||||
err := c.cc.Invoke(ctx, "/api.DummyFilterService/GetFilter", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// DummyFilterServiceServer is the server API for DummyFilterService service.
|
||||
type DummyFilterServiceServer interface {
|
||||
GetFilter(context.Context, *Filter) (*Filter, error)
|
||||
}
|
||||
|
||||
func RegisterDummyFilterServiceServer(s *grpc.Server, srv DummyFilterServiceServer) {
|
||||
s.RegisterService(&_DummyFilterService_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _DummyFilterService_GetFilter_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(Filter)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(DummyFilterServiceServer).GetFilter(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/api.DummyFilterService/GetFilter",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(DummyFilterServiceServer).GetFilter(ctx, req.(*Filter))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
var _DummyFilterService_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "api.DummyFilterService",
|
||||
HandlerType: (*DummyFilterServiceServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "GetFilter",
|
||||
Handler: _DummyFilterService_GetFilter_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "backend/api/filter.proto",
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("backend/api/filter.proto", fileDescriptor_filter_836b9ddef08e4ec1) }
|
||||
|
||||
var fileDescriptor_filter_836b9ddef08e4ec1 = []byte{
|
||||
// 514 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x4c, 0x92, 0xcf, 0x6e, 0xda, 0x40,
|
||||
0x10, 0xc6, 0xfd, 0x27, 0x18, 0x3c, 0x10, 0xe2, 0x6e, 0xab, 0xd6, 0x42, 0xad, 0xe2, 0x92, 0xaa,
|
||||
0xf5, 0xc9, 0x48, 0xf4, 0x92, 0x4b, 0x0f, 0x44, 0xa5, 0x80, 0x8a, 0x4c, 0xbb, 0x86, 0xf6, 0x88,
|
||||
0x0c, 0xd9, 0xa0, 0x55, 0xc0, 0x5e, 0xb1, 0x4b, 0xa4, 0x3c, 0x49, 0xdf, 0xa2, 0xcf, 0x18, 0x79,
|
||||
0xd7, 0x5e, 0x7c, 0x63, 0x66, 0x7e, 0xdf, 0xf0, 0x7d, 0xeb, 0x01, 0x7f, 0x93, 0x6e, 0x1f, 0x49,
|
||||
0x76, 0x3f, 0x48, 0x19, 0x1d, 0x3c, 0xd0, 0xbd, 0x20, 0xc7, 0x88, 0x1d, 0x73, 0x91, 0x23, 0x3b,
|
||||
0x65, 0xb4, 0xf7, 0x7e, 0x97, 0xe7, 0xbb, 0x3d, 0x91, 0xd3, 0x34, 0xcb, 0x72, 0x91, 0x0a, 0x9a,
|
||||
0x67, 0x5c, 0x21, 0xbd, 0xeb, 0x72, 0x2a, 0xab, 0xcd, 0xe9, 0x61, 0x20, 0xe8, 0x81, 0x70, 0x91,
|
||||
0x1e, 0x98, 0x02, 0xfa, 0xff, 0x2f, 0xc0, 0xfd, 0x75, 0x24, 0xf7, 0x74, 0x9b, 0x0a, 0x82, 0x3e,
|
||||
0x82, 0x95, 0x33, 0xdf, 0x0c, 0xcc, 0xb0, 0x3b, 0x7c, 0x15, 0xa5, 0x8c, 0x46, 0x7a, 0x16, 0x2d,
|
||||
0x18, 0xb6, 0x72, 0x86, 0x3c, 0xb0, 0x1f, 0xc9, 0xb3, 0x6f, 0x05, 0x66, 0xe8, 0xe2, 0xe2, 0x27,
|
||||
0xfa, 0x00, 0x2e, 0xcd, 0xc4, 0xfa, 0x29, 0xdd, 0x9f, 0x88, 0x6f, 0x07, 0x66, 0xd8, 0x98, 0x1a,
|
||||
0xb8, 0x45, 0x33, 0xf1, 0xa7, 0xe8, 0xa0, 0x6b, 0x80, 0x7d, 0x9e, 0xed, 0xca, 0xf9, 0x45, 0x60,
|
||||
0x86, 0xf6, 0xd4, 0xc0, 0x6e, 0xd1, 0x53, 0xc0, 0x0d, 0x74, 0xb8, 0x38, 0x52, 0x8d, 0x34, 0x8a,
|
||||
0xd5, 0x53, 0x03, 0xb7, 0x55, 0x57, 0x41, 0x63, 0xb8, 0xd2, 0xd6, 0x4b, 0xce, 0x09, 0xcc, 0xb0,
|
||||
0x3d, 0xec, 0x45, 0x2a, 0x62, 0x54, 0x45, 0x8c, 0x96, 0x15, 0x37, 0x35, 0x70, 0x57, 0x8b, 0xd4,
|
||||
0x9a, 0x01, 0x80, 0xf6, 0xca, 0xfd, 0xa6, 0xdc, 0xd0, 0x95, 0x41, 0x67, 0xa5, 0x5f, 0x5e, 0x98,
|
||||
0xab, 0xcc, 0x73, 0x34, 0x84, 0xf6, 0xd9, 0x3d, 0xf7, 0x5b, 0x52, 0x71, 0x25, 0x15, 0xf3, 0x2a,
|
||||
0x41, 0x21, 0x01, 0x9d, 0x87, 0xa3, 0x5b, 0xb8, 0xac, 0x07, 0xe2, 0xbe, 0x2b, 0x55, 0xea, 0x41,
|
||||
0x93, 0x73, 0xa8, 0x42, 0xd7, 0xa9, 0x85, 0xe4, 0xfd, 0x7f, 0x26, 0x58, 0x0b, 0x86, 0xda, 0xd0,
|
||||
0x5c, 0xc5, 0x3f, 0xe3, 0xc5, 0xdf, 0xd8, 0x33, 0x10, 0x80, 0x33, 0xfe, 0xbd, 0x1a, 0xcd, 0x13,
|
||||
0xcf, 0x44, 0x5d, 0x80, 0x78, 0xb1, 0x5c, 0x97, 0xb5, 0x85, 0x3c, 0xe8, 0x4c, 0xf0, 0x78, 0xb4,
|
||||
0x1c, 0xe3, 0xf5, 0x72, 0x3a, 0x8a, 0x3d, 0x1b, 0xbd, 0x83, 0xd7, 0xf5, 0x4e, 0x85, 0x36, 0xd0,
|
||||
0x25, 0xb8, 0xf3, 0x71, 0x92, 0x28, 0xce, 0x41, 0x6f, 0xc0, 0xd3, 0x65, 0x05, 0x35, 0x91, 0x03,
|
||||
0xd6, 0x2c, 0xf6, 0x5a, 0xc5, 0xde, 0x59, 0xb2, 0x4e, 0x56, 0x77, 0xc9, 0x12, 0xcf, 0xe2, 0x89,
|
||||
0xe7, 0xde, 0x35, 0xa1, 0x21, 0xc3, 0xf4, 0x6f, 0xc0, 0xd5, 0x4f, 0x85, 0xde, 0x82, 0x53, 0x46,
|
||||
0x34, 0x03, 0x3b, 0x6c, 0xe0, 0xb2, 0xea, 0x7f, 0x86, 0x4e, 0x3d, 0x67, 0x8d, 0xb3, 0x02, 0x3b,
|
||||
0x74, 0x35, 0xf7, 0x09, 0xe0, 0xfc, 0x8a, 0x35, 0xca, 0x0e, 0xec, 0xd0, 0xd6, 0xd4, 0x2d, 0x38,
|
||||
0x3f, 0xe4, 0xdd, 0xa3, 0x08, 0x80, 0x55, 0x07, 0xa9, 0xfe, 0xb3, 0xfa, 0x7c, 0xfa, 0x4e, 0x71,
|
||||
0x8d, 0x18, 0x7e, 0x03, 0xf4, 0xfd, 0x74, 0x38, 0x3c, 0x2b, 0x79, 0x42, 0x8e, 0x4f, 0x74, 0x4b,
|
||||
0xd0, 0x17, 0x70, 0x27, 0x44, 0x94, 0x2b, 0xdb, 0x52, 0xae, 0x8a, 0x5e, 0xbd, 0xe8, 0x1b, 0x1b,
|
||||
0x47, 0xde, 0xd4, 0xd7, 0x97, 0x00, 0x00, 0x00, 0xff, 0xff, 0xbf, 0x08, 0x4b, 0x8b, 0x83, 0x03,
|
||||
0x00, 0x00,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,5 +15,108 @@
|
|||
"application/json"
|
||||
],
|
||||
"paths": {},
|
||||
"definitions": {}
|
||||
"definitions": {
|
||||
"PredicateOp": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"UNKNOWN",
|
||||
"EQUALS",
|
||||
"NOT_EQUALS",
|
||||
"GREATER_THAN",
|
||||
"GREATER_THAN_EQUALS",
|
||||
"LESS_THAN",
|
||||
"LESS_THAN_EQUALS",
|
||||
"IN",
|
||||
"IS_SUBSTRING"
|
||||
],
|
||||
"default": "UNKNOWN",
|
||||
"description": "Op is the operation to apply.\n\n - EQUALS: Operators on scalar values. Only applies to one of |int_value|,\n|long_value|, |string_value| or |timestamp_value|.\n - IN: Checks if the value is a member of a given array, which should be one of\n|int_values|, |long_values| or |string_values|.\n - IS_SUBSTRING: Checks if the value contains |string_value| as a substring match. Only\napplies to |string_value|."
|
||||
},
|
||||
"apiFilter": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"predicates": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/apiPredicate"
|
||||
},
|
||||
"description": "All predicates are AND-ed when this filter is applied."
|
||||
}
|
||||
},
|
||||
"description": "Filter is used to filter resources returned from a ListXXX request.\n\nExample filters:\n1) Filter runs with status = 'Running'\nfilter {\n predicate {\n key: \"status\"\n op: EQUALS\n string_value: \"Running\"\n }\n}\n\n2) Filter runs that succeeded since Dec 1, 2018\nfilter {\n predicate {\n key: \"status\"\n op: EQUALS\n string_value: \"Succeeded\"\n }\n predicate {\n key: \"created_at\"\n op: GREATER_THAN\n timestamp_value {\n seconds: 1543651200\n }\n }\n}\n\n3) Filter runs with one of labels 'label_1' or 'label_2'\n\nfilter {\n predicate {\n key: \"label\"\n op: IN\n string_values {\n value: 'label_1'\n value: 'label_2'\n }\n }\n}"
|
||||
},
|
||||
"apiIntValues": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"values": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"apiLongValues": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"values": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"format": "int64"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"apiPredicate": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"op": {
|
||||
"$ref": "#/definitions/PredicateOp"
|
||||
},
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"int_value": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"long_value": {
|
||||
"type": "string",
|
||||
"format": "int64"
|
||||
},
|
||||
"string_value": {
|
||||
"type": "string"
|
||||
},
|
||||
"timestamp_value": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "Timestamp values will be converted to Unix time (seconds since the epoch)\nprior to being used in a filtering operation."
|
||||
},
|
||||
"int_values": {
|
||||
"$ref": "#/definitions/apiIntValues",
|
||||
"description": "Array values below are only meant to be used by the IN operator."
|
||||
},
|
||||
"long_values": {
|
||||
"$ref": "#/definitions/apiLongValues"
|
||||
},
|
||||
"string_values": {
|
||||
"$ref": "#/definitions/apiStringValues"
|
||||
}
|
||||
},
|
||||
"description": "Predicate captures individual conditions that must be true for a resource\nbeing filtered."
|
||||
},
|
||||
"apiStringValues": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"values": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import (
|
|||
|
||||
"github.com/Masterminds/squirrel"
|
||||
"github.com/golang/protobuf/ptypes"
|
||||
"github.com/kubeflow/pipelines/backend/src/common/util"
|
||||
|
||||
api "github.com/kubeflow/pipelines/backend/api/go_client"
|
||||
)
|
||||
|
|
@ -38,6 +39,8 @@ type Filter struct {
|
|||
lte map[string]interface{}
|
||||
|
||||
in map[string]interface{}
|
||||
|
||||
substring map[string]interface{}
|
||||
}
|
||||
|
||||
// New creates a new Filter from parsing the API filter protocol buffer.
|
||||
|
|
@ -51,6 +54,7 @@ func New(filterProto *api.Filter) (*Filter, error) {
|
|||
lt: make(map[string]interface{}),
|
||||
lte: make(map[string]interface{}),
|
||||
in: make(map[string]interface{}),
|
||||
substring: make(map[string]interface{}),
|
||||
}
|
||||
|
||||
if err := f.parseFilterProto(); err != nil {
|
||||
|
|
@ -68,7 +72,7 @@ func NewWithKeyMap(filterProto *api.Filter, keyMap map[string]string) (*Filter,
|
|||
for _, pred := range filterProto.Predicates {
|
||||
k, ok := keyMap[pred.Key]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no support for filtering on unrecognized field %q", pred.Key)
|
||||
return nil, util.NewInvalidInputError("no support for filtering on unrecognized field %q", pred.Key)
|
||||
}
|
||||
pred.Key = k
|
||||
}
|
||||
|
|
@ -107,6 +111,16 @@ func (f *Filter) AddToSelect(sb squirrel.SelectBuilder) squirrel.SelectBuilder {
|
|||
sb = sb.Where(squirrel.Eq(f.in))
|
||||
}
|
||||
|
||||
if len(f.substring) > 0 {
|
||||
like := make(squirrel.Like)
|
||||
// Modify each string value v so it looks like %v% so we are doing a substring
|
||||
// match with the LIKE operator.
|
||||
for k, v := range f.substring {
|
||||
like[k] = fmt.Sprintf("%%%s%%", v)
|
||||
}
|
||||
sb = sb.Where(like)
|
||||
}
|
||||
|
||||
return sb
|
||||
}
|
||||
|
||||
|
|
@ -115,17 +129,25 @@ func checkPredicate(p *api.Predicate) error {
|
|||
case api.Predicate_IN:
|
||||
switch t := p.Value.(type) {
|
||||
case *api.Predicate_IntValue, *api.Predicate_LongValue, *api.Predicate_StringValue, *api.Predicate_TimestampValue:
|
||||
return fmt.Errorf("cannot use IN operator with scalar type %T", t)
|
||||
return util.NewInvalidInputError("cannot use IN operator with scalar type %T", t)
|
||||
}
|
||||
|
||||
case api.Predicate_EQUALS, api.Predicate_NOT_EQUALS, api.Predicate_GREATER_THAN, api.Predicate_GREATER_THAN_EQUALS, api.Predicate_LESS_THAN, api.Predicate_LESS_THAN_EQUALS:
|
||||
switch t := p.Value.(type) {
|
||||
case *api.Predicate_IntValues, *api.Predicate_LongValues, *api.Predicate_StringValues:
|
||||
return fmt.Errorf("cannot use scalar operator %v on array type %T", p.Op, t)
|
||||
return util.NewInvalidInputError("cannot use scalar operator %v on array type %T", p.Op, t)
|
||||
}
|
||||
|
||||
case api.Predicate_IS_SUBSTRING:
|
||||
switch t := p.Value.(type) {
|
||||
case *api.Predicate_StringValue:
|
||||
return nil
|
||||
default:
|
||||
return util.NewInvalidInputError("cannot use non string value type %T with operator %v", p.Op, t)
|
||||
}
|
||||
|
||||
default:
|
||||
return fmt.Errorf("invalid predicate operation: %v", p.Op)
|
||||
return util.NewInvalidInputError("invalid predicate operation: %v", p.Op)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
@ -153,8 +175,10 @@ func (f *Filter) parseFilterProto() error {
|
|||
m = f.lte
|
||||
case api.Predicate_IN:
|
||||
m = f.in
|
||||
case api.Predicate_IS_SUBSTRING:
|
||||
m = f.substring
|
||||
default:
|
||||
return fmt.Errorf("invalid predicate operation: %v", pred.Op)
|
||||
return util.NewInvalidInputError("invalid predicate operation: %v", pred.Op)
|
||||
}
|
||||
|
||||
if err := addPredicateValue(m, pred); err != nil {
|
||||
|
|
@ -176,7 +200,7 @@ func addPredicateValue(m map[string]interface{}, p *api.Predicate) error {
|
|||
case *api.Predicate_TimestampValue:
|
||||
ts, err := ptypes.Timestamp(p.GetTimestampValue())
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid timestamp: %v", err)
|
||||
return util.NewInvalidInputError("invalid timestamp: %v", err)
|
||||
}
|
||||
m[p.Key] = ts.Unix()
|
||||
|
||||
|
|
@ -202,10 +226,10 @@ func addPredicateValue(m map[string]interface{}, p *api.Predicate) error {
|
|||
m[p.Key] = v
|
||||
|
||||
case nil:
|
||||
return fmt.Errorf("no value set for predicate on key %q", p.Key)
|
||||
return util.NewInvalidInputError("no value set for predicate on key %q", p.Key)
|
||||
|
||||
default:
|
||||
return fmt.Errorf("unknown value type in Filter for predicate key %q: %T", p.Key, t)
|
||||
return util.NewInvalidInputError("unknown value type in Filter for predicate key %q: %T", p.Key, t)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -65,6 +65,11 @@ func TestValidNewFilters(t *testing.T) {
|
|||
long_values { values: 100 values: 200 } }`,
|
||||
&Filter{in: map[string]interface{}{"longvalues": []int64{100, 200}}},
|
||||
},
|
||||
{
|
||||
`predicates {
|
||||
key: "label" op: IS_SUBSTRING string_value: "label_substring" }`,
|
||||
&Filter{substring: map[string]interface{}{"label": "label_substring"}},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
|
@ -109,6 +114,14 @@ func TestInvalidFilters(t *testing.T) {
|
|||
`predicates { key: "total" op: LESS_THAN_EQUALS
|
||||
long_values { values: 10 values: 20} }`,
|
||||
},
|
||||
{
|
||||
`predicates { key: "total" op: IS_SUBSTRING
|
||||
long_values { values: 10 values: 20} }`,
|
||||
},
|
||||
{
|
||||
`predicates { key: "total" op: IS_SUBSTRING
|
||||
int_values { values: 10 values: 20} }`,
|
||||
},
|
||||
|
||||
{
|
||||
`predicates { key: "total" op: IN int_value: 10 }`,
|
||||
|
|
@ -195,6 +208,11 @@ func TestAddToSelect(t *testing.T) {
|
|||
"SELECT mycolumn WHERE label IN (?,?)",
|
||||
[]interface{}{"l1", "l2"},
|
||||
},
|
||||
{
|
||||
`predicates { key: "label" op: IS_SUBSTRING string_value: "label_substring" }`,
|
||||
"SELECT mycolumn WHERE label LIKE ?",
|
||||
[]interface{}{"%label_substring%"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
|
|
|||
4
go.mod
4
go.mod
|
|
@ -2,7 +2,7 @@ module github.com/kubeflow/pipelines
|
|||
|
||||
require (
|
||||
github.com/BurntSushi/toml v0.3.1 // indirect
|
||||
github.com/Masterminds/squirrel v0.0.0-20170825200431-a6b93000bd21
|
||||
github.com/Masterminds/squirrel v0.0.0-20190107164353-fa735ea14f09
|
||||
github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f
|
||||
github.com/argoproj/argo v2.2.0+incompatible
|
||||
github.com/cenkalti/backoff v2.0.0+incompatible
|
||||
|
|
@ -46,8 +46,6 @@ require (
|
|||
github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be // indirect
|
||||
github.com/jtolds/gls v4.2.1+incompatible // indirect
|
||||
github.com/kataras/iris v10.6.7+incompatible
|
||||
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
|
||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
|
||||
github.com/lib/pq v1.0.0 // indirect
|
||||
github.com/mattbaird/jsonpatch v0.0.0-20171005235357-81af80346b1a // indirect
|
||||
github.com/mattn/go-sqlite3 v1.9.0
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ
|
|||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/Masterminds/squirrel v0.0.0-20170825200431-a6b93000bd21 h1:7+Xpo0TxPIBqSHVktrR1VYU2LSNTrJ3B79nVzE74nPA=
|
||||
github.com/Masterminds/squirrel v0.0.0-20170825200431-a6b93000bd21/go.mod h1:xnKTFzjGUiZtiOagBsfnvomW+nJg2usB1ZpordQWqNM=
|
||||
github.com/Masterminds/squirrel v0.0.0-20190107164353-fa735ea14f09 h1:enWVS77aJkLWVIUExiqF6A8eWTVzCXUKUvkST3/wyKI=
|
||||
github.com/Masterminds/squirrel v0.0.0-20190107164353-fa735ea14f09/go.mod h1:yaPeOnPG5ZRwL9oKdTsO/prlkPbXWZlRVMQ/gGlzIuA=
|
||||
github.com/PuerkitoBio/purell v1.1.0 h1:rmGxhojJlM0tuKtfdvliR84CFHljx9ag64t2xmVkjK4=
|
||||
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
|
||||
|
|
|
|||
Loading…
Reference in New Issue