From b0f126e2e85e7b917d3759c53499cda0f6a5fdf4 Mon Sep 17 00:00:00 2001 From: Aman Mangal Date: Thu, 4 Jul 2019 03:05:00 +0530 Subject: [PATCH 1/2] Update dgo repo in vendor (#3612) --- .../dgraph-io/dgo/protos/api/api.pb.go | 202 +++++++++++------- vendor/vendor.json | 18 +- 2 files changed, 136 insertions(+), 84 deletions(-) diff --git a/vendor/github.com/dgraph-io/dgo/protos/api/api.pb.go b/vendor/github.com/dgraph-io/dgo/protos/api/api.pb.go index 00a78e736a1..103c8e7db2a 100644 --- a/vendor/github.com/dgraph-io/dgo/protos/api/api.pb.go +++ b/vendor/github.com/dgraph-io/dgo/protos/api/api.pb.go @@ -348,6 +348,7 @@ type Mutation struct { SetNquads []byte `protobuf:"bytes,3,opt,name=set_nquads,json=setNquads,proto3" json:"set_nquads,omitempty"` DelNquads []byte `protobuf:"bytes,4,opt,name=del_nquads,json=delNquads,proto3" json:"del_nquads,omitempty"` Query string `protobuf:"bytes,5,opt,name=query,proto3" json:"query,omitempty"` + Cond string `protobuf:"bytes,6,opt,name=cond,proto3" json:"cond,omitempty"` Set []*NQuad `protobuf:"bytes,10,rep,name=set,proto3" json:"set,omitempty"` Del []*NQuad `protobuf:"bytes,11,rep,name=del,proto3" json:"del,omitempty"` StartTs uint64 `protobuf:"varint,13,opt,name=start_ts,json=startTs,proto3" json:"start_ts,omitempty"` @@ -426,6 +427,13 @@ func (m *Mutation) GetQuery() string { return "" } +func (m *Mutation) GetCond() string { + if m != nil { + return m.Cond + } + return "" +} + func (m *Mutation) GetSet() []*NQuad { if m != nil { return m.Set @@ -1710,12 +1718,12 @@ func init() { func init() { proto.RegisterFile("api.proto", fileDescriptor_00212fb1f9d3bf1c) } var fileDescriptor_00212fb1f9d3bf1c = []byte{ - // 1616 bytes of a gzipped FileDescriptorProto + // 1625 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x57, 0x5f, 0x73, 0x1b, 0x49, 0x11, 0xd7, 0xea, 0xdf, 0xee, 0xb6, 0x64, 0x47, 0x0c, 0xe4, 0xd0, 0xd9, 0x97, 0xc4, 0xd9, 0xab, 0xba, 0x98, 0x4b, 0x9d, 0x1e, 0x7c, 0x55, 0x1c, 0xf0, 0x26, 0xdb, 0x3a, 0xac, 0x94, 0x4f, 0xce, 0x8d, 0x85, 0xab, 0x78, 0x52, 0x8d, 0xb5, 0x63, 0x65, 0x93, 0xcd, 0xce, 0x66, 0x66, 0x64, 0x47, - 0x7c, 0x00, 0xde, 0xef, 0x85, 0xe2, 0x6b, 0xf0, 0x19, 0xe0, 0x81, 0x37, 0xa8, 0xe2, 0x89, 0x37, + 0x7c, 0x00, 0xde, 0xef, 0x85, 0xe2, 0x6b, 0xf0, 0x19, 0x78, 0xe1, 0x0d, 0xaa, 0x78, 0x81, 0x37, 0x30, 0xc5, 0xf7, 0xa0, 0xba, 0x67, 0xd6, 0x96, 0x73, 0xa9, 0x00, 0x4f, 0xea, 0xfe, 0xfd, 0x7a, 0x76, 0xba, 0x7b, 0xba, 0x7b, 0x46, 0x10, 0x8b, 0x32, 0x1b, 0x94, 0x5a, 0x59, 0xc5, 0x1a, 0xa2, 0xcc, 0x92, 0xdf, 0xd6, 0x21, 0xe4, 0xf2, 0xcd, 0x52, 0x1a, 0xcb, 0x7e, 0x04, 0xad, 0x37, 0x4b, @@ -1736,82 +1744,83 @@ var fileDescriptor_00212fb1f9d3bf1c = []byte{ 0x87, 0xc3, 0x78, 0x45, 0x26, 0x7f, 0x0c, 0x20, 0x1a, 0x1a, 0x93, 0x2d, 0x0a, 0x99, 0xb2, 0xa7, 0xd0, 0x5c, 0x66, 0xa9, 0xe9, 0x07, 0xe4, 0xc2, 0x8f, 0x69, 0x45, 0x45, 0x0e, 0x7e, 0x95, 0xa5, 0xd5, 0x69, 0xa0, 0x11, 0xfb, 0x09, 0x84, 0x73, 0xb7, 0x23, 0x85, 0xfb, 0x1e, 0x47, 0x2a, 0xfe, - 0x7f, 0x75, 0x06, 0xd3, 0x7b, 0xb3, 0xcb, 0xff, 0x95, 0xde, 0x3f, 0xd5, 0x21, 0xfa, 0x66, 0x69, + 0x7f, 0x75, 0x06, 0xd3, 0x7b, 0xb3, 0xcb, 0xff, 0x95, 0xde, 0xbf, 0xd5, 0x21, 0xfa, 0x66, 0x69, 0x85, 0xcd, 0x54, 0x41, 0x65, 0x22, 0xed, 0x6c, 0x2d, 0xc5, 0xa1, 0x91, 0xf6, 0x19, 0x66, 0xf9, 0x11, 0x74, 0x52, 0x99, 0x4b, 0x2b, 0x1d, 0x5b, 0x27, 0x16, 0x1c, 0x44, 0x06, 0x0f, 0x00, 0x70, 0x6d, 0xf1, 0x66, 0x29, 0x52, 0x43, 0x09, 0xee, 0xf2, 0xd8, 0x48, 0x3b, 0x21, 0x00, 0xe9, 0x54, - 0xe6, 0x15, 0xdd, 0x74, 0x74, 0x2a, 0x73, 0x4f, 0xdf, 0x94, 0x78, 0x6b, 0xbd, 0xc4, 0x3f, 0x81, - 0x86, 0x91, 0xb6, 0x0f, 0x94, 0x54, 0xa0, 0xc8, 0x27, 0xdf, 0x2e, 0x45, 0xca, 0x11, 0x46, 0x36, - 0x95, 0x79, 0xbf, 0xf3, 0x7d, 0x36, 0x95, 0xf9, 0x87, 0x4a, 0xfe, 0x01, 0xc0, 0x5c, 0xbd, 0x7e, - 0x9d, 0xd9, 0x59, 0xa1, 0xae, 0xa8, 0xe8, 0x23, 0x1e, 0x3b, 0x64, 0xa2, 0xae, 0xd8, 0x1e, 0xdc, - 0xcf, 0x16, 0x85, 0xd2, 0x72, 0x96, 0x15, 0xa9, 0x7c, 0x3b, 0x9b, 0xab, 0xe2, 0x22, 0xcf, 0xe6, - 0xd6, 0x17, 0xfd, 0x0f, 0x1d, 0x39, 0x46, 0xee, 0xc0, 0x53, 0xc9, 0xbf, 0x03, 0x88, 0x4f, 0x4a, - 0xa9, 0x5d, 0x1e, 0x3f, 0xba, 0x29, 0x49, 0x77, 0x06, 0x55, 0xf5, 0x6d, 0x43, 0x9c, 0x6a, 0x55, - 0xce, 0x84, 0xb5, 0xda, 0x1f, 0x45, 0x84, 0xc0, 0xd0, 0x5a, 0x8d, 0x0e, 0x3b, 0x32, 0xcf, 0x29, - 0x7d, 0x11, 0x0f, 0x89, 0xcb, 0x73, 0x36, 0x00, 0x12, 0x67, 0xaa, 0xa4, 0xcc, 0x6d, 0xee, 0xdd, - 0xa7, 0x68, 0x6f, 0x36, 0x1c, 0x1c, 0x6a, 0x55, 0x9e, 0x94, 0xbc, 0x9d, 0xd2, 0x2f, 0x25, 0x1b, - 0xed, 0xdd, 0x99, 0xbb, 0x94, 0xd2, 0xce, 0x67, 0x08, 0x24, 0x3f, 0x87, 0xb6, 0x5b, 0xc0, 0x22, - 0x68, 0x4e, 0x4e, 0x26, 0xa3, 0x5e, 0x8d, 0x85, 0xd0, 0x18, 0x1e, 0x1f, 0xf7, 0x02, 0x84, 0x0e, - 0x87, 0xd3, 0x61, 0xaf, 0x8e, 0xd2, 0x70, 0x3a, 0xe5, 0xbd, 0x06, 0x4a, 0xd3, 0x5f, 0x3f, 0x1f, - 0xf5, 0x9a, 0xc9, 0x03, 0x08, 0x9f, 0x8b, 0x55, 0xae, 0x44, 0x8a, 0xbd, 0x78, 0x28, 0xac, 0xa8, - 0x7a, 0x11, 0xe5, 0xe4, 0x0f, 0x01, 0xc0, 0x6d, 0x19, 0xdf, 0x39, 0x83, 0xe0, 0xee, 0x19, 0x6c, - 0x83, 0xcf, 0x38, 0x72, 0x75, 0xe2, 0x22, 0x07, 0x4c, 0x0d, 0xeb, 0x43, 0x28, 0xce, 0x95, 0xb6, - 0x32, 0xad, 0x32, 0xe1, 0x55, 0xdc, 0xf4, 0x95, 0x5c, 0x61, 0x01, 0x35, 0x76, 0x63, 0x4e, 0x32, - 0xd6, 0x4e, 0xa9, 0x65, 0x6a, 0xfa, 0x2d, 0x02, 0x9d, 0x72, 0x67, 0xae, 0x6d, 0x7c, 0x60, 0xae, - 0x25, 0x21, 0xb4, 0x0e, 0x5e, 0xc8, 0xf9, 0xab, 0x64, 0x1b, 0xc2, 0x33, 0xa9, 0x0d, 0x1e, 0x60, - 0x0f, 0x1a, 0x56, 0x2c, 0xaa, 0x0e, 0xb2, 0x62, 0x91, 0xfc, 0x2d, 0x80, 0xd0, 0x2f, 0x65, 0x4f, - 0xa0, 0x71, 0xdb, 0xeb, 0xf7, 0xd7, 0xbf, 0x3a, 0x18, 0x57, 0x9d, 0x8e, 0x16, 0xec, 0x2b, 0xec, - 0x89, 0x37, 0x4b, 0x59, 0xcc, 0xb3, 0x62, 0x41, 0x51, 0x6e, 0xfa, 0xd9, 0x50, 0xd9, 0x9f, 0xde, - 0xd0, 0x7c, 0xcd, 0x74, 0xeb, 0xa7, 0x10, 0x8d, 0xdf, 0xd3, 0xcd, 0x1b, 0xef, 0xe9, 0xe6, 0xe6, - 0x7a, 0x37, 0x0f, 0x00, 0x6e, 0xbf, 0xc8, 0xee, 0x41, 0xe7, 0xe0, 0x78, 0x3c, 0x9a, 0x4c, 0x67, - 0xa7, 0xe3, 0x43, 0x3c, 0xe4, 0x7b, 0xd0, 0x39, 0x1d, 0xf1, 0xb3, 0x11, 0x77, 0x40, 0x90, 0x7c, - 0x87, 0x51, 0xb9, 0x11, 0x82, 0x45, 0x53, 0x0a, 0x6d, 0xb2, 0x62, 0x31, 0x2b, 0xaa, 0xe3, 0x8a, - 0x3d, 0x32, 0x31, 0xec, 0x53, 0xd8, 0x28, 0xb5, 0x9a, 0x4b, 0x53, 0x59, 0xb8, 0xcd, 0xbb, 0xb7, - 0xe0, 0xc4, 0xe0, 0x94, 0x90, 0xc5, 0x5c, 0xa5, 0xde, 0xa4, 0x41, 0x26, 0x50, 0x41, 0x13, 0xc3, - 0x1e, 0x43, 0xd7, 0x6a, 0x51, 0x98, 0x52, 0x69, 0x8b, 0x16, 0x4d, 0xb2, 0xe8, 0xdc, 0x60, 0x13, - 0x93, 0xfc, 0x3d, 0x80, 0x16, 0xf5, 0x31, 0x96, 0x81, 0x59, 0x9e, 0xbf, 0x94, 0x73, 0xeb, 0x4f, - 0xa2, 0x52, 0xd9, 0x27, 0x10, 0xe3, 0x29, 0x67, 0x73, 0x61, 0xab, 0x99, 0x76, 0x0b, 0x60, 0x6d, - 0x29, 0xb2, 0x9b, 0x65, 0xae, 0x80, 0x62, 0x1e, 0x39, 0x60, 0x9c, 0xb2, 0x2f, 0xa0, 0xeb, 0x49, - 0x97, 0xc3, 0x26, 0xd5, 0x86, 0x1b, 0x1f, 0xd4, 0x1e, 0xbc, 0xe3, 0x78, 0x52, 0x30, 0xd7, 0xb9, - 0x38, 0x97, 0x79, 0x35, 0x98, 0x48, 0xc1, 0x32, 0xcc, 0x45, 0xb1, 0xe8, 0xb7, 0x09, 0x24, 0x99, - 0x25, 0xd0, 0xbe, 0x10, 0x73, 0x69, 0x4d, 0x3f, 0x5c, 0x9b, 0x48, 0x5f, 0x23, 0xc4, 0x3d, 0x93, - 0xfc, 0xb3, 0x0e, 0x2d, 0xf7, 0xdd, 0xc7, 0x38, 0x4f, 0x2f, 0xc4, 0x32, 0x27, 0x3f, 0x5c, 0x7c, - 0x47, 0x35, 0x9c, 0xa8, 0x04, 0x9e, 0x89, 0x9c, 0x3d, 0x80, 0xf8, 0x7c, 0x65, 0xa5, 0x21, 0x03, - 0x1a, 0xb8, 0x47, 0x35, 0x1e, 0x11, 0x84, 0xf4, 0xc7, 0x10, 0x66, 0x85, 0x5b, 0x8d, 0x31, 0x36, - 0x8e, 0x6a, 0xbc, 0x9d, 0x15, 0xb4, 0x72, 0x1b, 0xa2, 0x73, 0xa5, 0x72, 0xe2, 0x30, 0xbe, 0xe8, - 0xa8, 0xc6, 0x43, 0x44, 0xfc, 0x3a, 0x63, 0x35, 0x71, 0x2d, 0xbf, 0x6b, 0xdb, 0x58, 0x8d, 0xd4, - 0x23, 0x80, 0x54, 0x2d, 0xcf, 0x73, 0x49, 0x2c, 0x06, 0x17, 0x1c, 0xd5, 0x78, 0xec, 0x30, 0xbf, - 0x76, 0x21, 0x15, 0xb1, 0xa1, 0x77, 0xa8, 0xbd, 0x90, 0xca, 0xef, 0x99, 0x0a, 0xeb, 0x56, 0x46, - 0x9e, 0x0b, 0x11, 0x41, 0xf2, 0x53, 0xe8, 0xa2, 0x68, 0xb3, 0xd7, 0xce, 0x20, 0xf6, 0x06, 0x9d, - 0x0a, 0xf5, 0x46, 0xa5, 0x30, 0xe6, 0x4a, 0xe9, 0x94, 0x8c, 0xc0, 0x7b, 0xd7, 0xa9, 0x50, 0xef, - 0xc1, 0x32, 0x73, 0x7c, 0x07, 0x6b, 0x07, 0x3d, 0x58, 0x66, 0x48, 0xed, 0xb7, 0xa0, 0x71, 0x29, - 0xf2, 0xe4, 0x2f, 0x01, 0xb4, 0x28, 0xeb, 0xff, 0xed, 0x1e, 0xec, 0xfa, 0xce, 0x61, 0x5f, 0x40, - 0x74, 0x29, 0xf2, 0x99, 0x5d, 0x95, 0x92, 0x52, 0xb9, 0xb9, 0xc7, 0x6e, 0xcf, 0x0e, 0x8b, 0x62, - 0xba, 0x2a, 0x25, 0x0f, 0x2f, 0x9d, 0x80, 0xd3, 0xdd, 0xaa, 0x57, 0xb2, 0xa8, 0xa6, 0x90, 0xd7, - 0xf0, 0xe3, 0x22, 0xcf, 0x84, 0xa9, 0x4a, 0x85, 0x94, 0x64, 0x08, 0xa1, 0xff, 0x02, 0x03, 0x68, - 0x9f, 0x4e, 0xf9, 0x78, 0xf2, 0x4b, 0x37, 0x6f, 0xc7, 0x93, 0x69, 0x2f, 0x60, 0x31, 0xb4, 0xbe, - 0x3e, 0x3e, 0x19, 0x4e, 0xdd, 0xc0, 0xdd, 0x3f, 0x39, 0x39, 0xee, 0x35, 0x58, 0x17, 0xa2, 0xc3, - 0xe1, 0x74, 0x34, 0x1d, 0x7f, 0x83, 0x43, 0xf7, 0x3a, 0x00, 0xb8, 0x7d, 0xcf, 0xdc, 0x2d, 0xfe, - 0xe0, 0xdd, 0xe2, 0x67, 0xd0, 0xa4, 0x40, 0x5c, 0x57, 0x90, 0x8c, 0x9e, 0xd1, 0x55, 0xe6, 0xa7, - 0xa9, 0x53, 0xf0, 0x3b, 0xe4, 0x79, 0xf6, 0x1b, 0xa9, 0x7d, 0x28, 0xb7, 0x00, 0x36, 0x9f, 0x96, - 0x97, 0x52, 0x1b, 0x77, 0x81, 0x44, 0xbc, 0x52, 0xf1, 0x6b, 0x73, 0xb5, 0x2c, 0x2c, 0x15, 0x48, - 0xc4, 0x9d, 0x42, 0x2d, 0x91, 0x19, 0x4b, 0x75, 0x11, 0x71, 0x92, 0x31, 0x53, 0xcb, 0xd2, 0x48, - 0x6d, 0xa9, 0x22, 0x22, 0xee, 0xb5, 0x9b, 0xf6, 0x89, 0xbd, 0xad, 0x28, 0x16, 0xc9, 0x02, 0xba, - 0xc7, 0x6a, 0x81, 0x63, 0xd1, 0x3d, 0x7a, 0x71, 0xad, 0x91, 0x3a, 0x4b, 0xab, 0x3b, 0xd4, 0x69, - 0x6c, 0x0b, 0xa2, 0xaa, 0x1e, 0xaa, 0x2b, 0xb4, 0xd2, 0x71, 0x46, 0x69, 0x79, 0xa1, 0xa5, 0x79, - 0x31, 0xa3, 0x40, 0x7c, 0xf3, 0x77, 0x3d, 0x38, 0x45, 0x2c, 0x19, 0x41, 0xe3, 0xd9, 0x95, 0xc5, - 0x71, 0x27, 0xe6, 0x38, 0xb9, 0x66, 0x2f, 0xaf, 0xaa, 0xf9, 0x12, 0x3b, 0x04, 0xe9, 0x47, 0xd0, - 0xa9, 0x3e, 0x85, 0xbc, 0xdb, 0x09, 0x3c, 0xf4, 0xec, 0xca, 0xee, 0x7d, 0x57, 0x87, 0xf6, 0xe1, - 0x42, 0x8b, 0xf2, 0x05, 0x7b, 0x0a, 0x2d, 0x72, 0x9d, 0xfd, 0xc0, 0xcd, 0xf6, 0xb5, 0x30, 0xb6, - 0x36, 0xfc, 0xbb, 0xdc, 0x3d, 0x60, 0x93, 0x1a, 0xfb, 0x0c, 0x5a, 0xdf, 0xd2, 0xe3, 0xa6, 0xbb, - 0xfe, 0x62, 0xff, 0xbe, 0xdd, 0x2e, 0xb4, 0xe9, 0x5d, 0x26, 0x99, 0xa3, 0xaa, 0x47, 0x9a, 0xb7, - 0xac, 0x1e, 0x97, 0x49, 0x8d, 0x3d, 0x81, 0xd6, 0x30, 0xb7, 0x52, 0xb3, 0xcd, 0xbb, 0xaf, 0x82, - 0x2d, 0xb7, 0x83, 0xbf, 0xaf, 0x93, 0x1a, 0xfb, 0x12, 0x36, 0x0e, 0xe8, 0x8a, 0x3d, 0xd1, 0x43, - 0xbc, 0x4f, 0xd9, 0xbb, 0xef, 0xce, 0xad, 0x77, 0x81, 0xa4, 0xc6, 0x3e, 0x87, 0x2e, 0x5d, 0x8f, - 0xd5, 0xd5, 0xe8, 0xc6, 0x1a, 0x41, 0x7e, 0x03, 0xcf, 0x24, 0xb5, 0xfd, 0xdd, 0x3f, 0x5f, 0x3f, - 0x0c, 0xfe, 0x7a, 0xfd, 0x30, 0xf8, 0xc7, 0xf5, 0xc3, 0xe0, 0xf7, 0xff, 0x7a, 0x58, 0x83, 0x38, - 0x53, 0x83, 0x94, 0xb2, 0xb4, 0xdf, 0x71, 0xd9, 0x7a, 0x8e, 0xff, 0x71, 0xce, 0xdb, 0xf4, 0x57, - 0xe7, 0xcb, 0xff, 0x04, 0x00, 0x00, 0xff, 0xff, 0x79, 0x5f, 0x49, 0xac, 0xf7, 0x0c, 0x00, 0x00, + 0xe6, 0x15, 0xdd, 0x74, 0x74, 0x2a, 0x73, 0x4f, 0xdf, 0x94, 0x78, 0x6b, 0xbd, 0xc4, 0x19, 0x34, + 0xe7, 0xaa, 0x48, 0xfb, 0x6d, 0x02, 0x49, 0x66, 0x9f, 0x40, 0xc3, 0x48, 0xdb, 0x07, 0x4a, 0x34, + 0x50, 0x36, 0x26, 0xdf, 0x2e, 0x45, 0xca, 0x11, 0x46, 0x36, 0x95, 0x79, 0xbf, 0xf3, 0x7d, 0x36, + 0x95, 0xf9, 0x87, 0xda, 0xe0, 0x01, 0xc0, 0x5c, 0xbd, 0x7e, 0x9d, 0xd9, 0x59, 0xa1, 0xae, 0xa8, + 0x11, 0x22, 0x1e, 0x3b, 0x64, 0xa2, 0xae, 0xd8, 0x1e, 0xdc, 0xcf, 0x16, 0x85, 0xd2, 0x72, 0x96, + 0x15, 0xa9, 0x7c, 0x3b, 0x9b, 0xab, 0xe2, 0x22, 0xcf, 0xe6, 0xd6, 0x37, 0xc2, 0x0f, 0x1d, 0x39, + 0x46, 0xee, 0xc0, 0x53, 0xc9, 0xbf, 0x03, 0x88, 0x4f, 0x4a, 0xa9, 0x5d, 0x6e, 0x3f, 0xba, 0x29, + 0x53, 0x77, 0x2e, 0x55, 0x45, 0x6e, 0x43, 0x9c, 0x6a, 0x55, 0xce, 0x84, 0xb5, 0xda, 0x1f, 0x4f, + 0x84, 0xc0, 0xd0, 0x5a, 0x8d, 0x0e, 0x3b, 0x32, 0xcf, 0x29, 0xa5, 0x11, 0x0f, 0x89, 0xcb, 0x73, + 0x36, 0x00, 0x12, 0x67, 0xaa, 0xa4, 0x6c, 0x6e, 0xee, 0xdd, 0xa7, 0x68, 0x6f, 0x36, 0x1c, 0x1c, + 0x6a, 0x55, 0x9e, 0x94, 0xbc, 0x9d, 0xd2, 0x2f, 0x1d, 0x00, 0xda, 0xbb, 0x3a, 0x70, 0x69, 0xa6, + 0x9d, 0xcf, 0x10, 0x48, 0x7e, 0x0e, 0x6d, 0xb7, 0x80, 0x45, 0xd0, 0x9c, 0x9c, 0x4c, 0x46, 0xbd, + 0x1a, 0x0b, 0xa1, 0x31, 0x3c, 0x3e, 0xee, 0x05, 0x08, 0x1d, 0x0e, 0xa7, 0xc3, 0x5e, 0x1d, 0xa5, + 0xe1, 0x74, 0xca, 0x7b, 0x0d, 0x94, 0xa6, 0xbf, 0x7e, 0x3e, 0xea, 0x35, 0x93, 0x07, 0x10, 0x3e, + 0x17, 0xab, 0x5c, 0x89, 0x14, 0x0f, 0xec, 0x50, 0x58, 0x51, 0xf5, 0x27, 0xca, 0xc9, 0x1f, 0x02, + 0x80, 0xdb, 0xd2, 0xbe, 0x73, 0x06, 0xc1, 0xdd, 0x33, 0xd8, 0x06, 0x9f, 0x71, 0xe4, 0xea, 0xc4, + 0x45, 0x0e, 0x98, 0x1a, 0xd6, 0x87, 0x50, 0x9c, 0x2b, 0x6d, 0x65, 0x5a, 0x65, 0xc2, 0xab, 0xb8, + 0xe9, 0x2b, 0xb9, 0xc2, 0xa2, 0x6a, 0x60, 0x95, 0xa0, 0x8c, 0xf5, 0x54, 0x6a, 0x99, 0x9a, 0x7e, + 0x8b, 0x40, 0xa7, 0xdc, 0x99, 0x75, 0x1b, 0x1f, 0x98, 0x75, 0x49, 0x08, 0xad, 0x83, 0x17, 0x72, + 0xfe, 0x2a, 0xd9, 0x86, 0xf0, 0x4c, 0x6a, 0x83, 0x07, 0xd8, 0x83, 0x86, 0x15, 0x8b, 0xaa, 0xab, + 0xac, 0x58, 0x24, 0x7f, 0x0d, 0x20, 0xf4, 0x4b, 0xd9, 0x13, 0x68, 0xdc, 0xf6, 0xff, 0xfd, 0xf5, + 0xaf, 0x0e, 0xc6, 0x55, 0xf7, 0xa3, 0x05, 0xfb, 0x0a, 0xfb, 0xe4, 0xcd, 0x52, 0x16, 0xf3, 0xac, + 0x58, 0x50, 0x94, 0x9b, 0x7e, 0x5e, 0x54, 0xf6, 0xa7, 0x37, 0x34, 0x5f, 0x33, 0xdd, 0xfa, 0x29, + 0x44, 0xe3, 0xf7, 0x74, 0xf8, 0xc6, 0x7b, 0x3a, 0xbc, 0xb9, 0xde, 0xe1, 0x03, 0x80, 0xdb, 0x2f, + 0xb2, 0x7b, 0xd0, 0x39, 0x38, 0x1e, 0x8f, 0x26, 0xd3, 0xd9, 0xe9, 0xf8, 0x10, 0x0f, 0xf9, 0x1e, + 0x74, 0x4e, 0x47, 0xfc, 0x6c, 0xc4, 0x1d, 0x10, 0x24, 0xdf, 0x61, 0x54, 0x6e, 0xac, 0x60, 0xd1, + 0x94, 0x42, 0x9b, 0xac, 0x58, 0xcc, 0x8a, 0xea, 0xb8, 0x62, 0x8f, 0x4c, 0x0c, 0xfb, 0x14, 0x36, + 0x4a, 0xad, 0xe6, 0xd2, 0x54, 0x16, 0x6e, 0xf3, 0xee, 0x2d, 0x38, 0x31, 0x38, 0x39, 0x64, 0x31, + 0x57, 0xa9, 0x37, 0x69, 0x90, 0x09, 0x54, 0xd0, 0xc4, 0xb0, 0xc7, 0xd0, 0xb5, 0x5a, 0x14, 0xa6, + 0x54, 0xda, 0xa2, 0x45, 0x93, 0x2c, 0x3a, 0x37, 0xd8, 0xc4, 0x24, 0x7f, 0x0f, 0xa0, 0x45, 0x7d, + 0x8c, 0x65, 0x60, 0x96, 0xe7, 0x2f, 0xe5, 0xdc, 0xfa, 0x93, 0xa8, 0x54, 0xf6, 0x09, 0xc4, 0x78, + 0xca, 0xd9, 0x5c, 0xd8, 0x6a, 0xce, 0xdd, 0x02, 0x58, 0x5b, 0x8a, 0xec, 0x66, 0x99, 0x2b, 0xa0, + 0x98, 0x47, 0x0e, 0x18, 0xa7, 0xec, 0x0b, 0xe8, 0x7a, 0xd2, 0xe5, 0xb0, 0x49, 0xb5, 0xe1, 0xc6, + 0x07, 0xb5, 0x07, 0xef, 0x38, 0x9e, 0x14, 0xcc, 0x75, 0x2e, 0xce, 0x65, 0x5e, 0x0d, 0x2b, 0x52, + 0xb0, 0x0c, 0x73, 0x51, 0x2c, 0xaa, 0x61, 0x85, 0x32, 0x4b, 0xa0, 0x7d, 0x21, 0xe6, 0xd2, 0x9a, + 0x7e, 0xb8, 0x36, 0x91, 0xbe, 0x46, 0x88, 0x7b, 0x26, 0xf9, 0x67, 0x1d, 0x5a, 0xee, 0xbb, 0x8f, + 0x71, 0xc6, 0x5e, 0x88, 0x65, 0x4e, 0x7e, 0xb8, 0xf8, 0x8e, 0x6a, 0x38, 0x65, 0x09, 0x3c, 0x13, + 0x39, 0x7b, 0x00, 0xf1, 0xf9, 0xca, 0x4a, 0x43, 0x06, 0x34, 0x84, 0x8f, 0x6a, 0x3c, 0x22, 0x08, + 0xe9, 0x8f, 0x21, 0xcc, 0x0a, 0xb7, 0x1a, 0x63, 0x6c, 0x1c, 0xd5, 0x78, 0x3b, 0x2b, 0x68, 0xe5, + 0x36, 0x44, 0xe7, 0x4a, 0xe5, 0xc4, 0x61, 0x7c, 0xd1, 0x51, 0x8d, 0x87, 0x88, 0xf8, 0x75, 0xc6, + 0x6a, 0xe2, 0x5a, 0x7e, 0xd7, 0xb6, 0xb1, 0x1a, 0xa9, 0x47, 0x00, 0xa9, 0x5a, 0x9e, 0xe7, 0x92, + 0x58, 0x0c, 0x2e, 0x38, 0xaa, 0xf1, 0xd8, 0x61, 0x7e, 0xed, 0x42, 0x2a, 0x62, 0x43, 0xef, 0x50, + 0x7b, 0x21, 0x95, 0xdf, 0x33, 0x15, 0xd6, 0xad, 0x8c, 0x3c, 0x17, 0x22, 0x82, 0xe4, 0xa7, 0xd0, + 0x45, 0xd1, 0x66, 0xaf, 0x9d, 0x41, 0xec, 0x0d, 0x3a, 0x15, 0xea, 0x8d, 0x4a, 0x61, 0xcc, 0x95, + 0xd2, 0x29, 0x19, 0x81, 0xf7, 0xae, 0x53, 0xa1, 0xde, 0x83, 0x65, 0xe6, 0xf8, 0x0e, 0xd6, 0x0e, + 0x7a, 0xb0, 0xcc, 0x90, 0xda, 0x6f, 0x41, 0xe3, 0x52, 0xe4, 0xc9, 0x9f, 0x03, 0x68, 0x51, 0xd6, + 0xff, 0xdb, 0xdd, 0xd8, 0xf5, 0x9d, 0xc3, 0xbe, 0x80, 0xe8, 0x52, 0xe4, 0x33, 0xbb, 0x2a, 0x25, + 0xa5, 0x72, 0x73, 0x8f, 0xdd, 0x9e, 0x1d, 0x16, 0xc5, 0x74, 0x55, 0x4a, 0x1e, 0x5e, 0x3a, 0x01, + 0xa7, 0xbb, 0x55, 0xaf, 0x64, 0x51, 0x4d, 0x21, 0xaf, 0xe1, 0xc7, 0x45, 0x9e, 0x09, 0x53, 0x95, + 0x0a, 0x29, 0xc9, 0x10, 0x42, 0xff, 0x05, 0x06, 0xd0, 0x3e, 0x9d, 0xf2, 0xf1, 0xe4, 0x97, 0x6e, + 0xde, 0x8e, 0x27, 0xd3, 0x5e, 0xc0, 0x62, 0x68, 0x7d, 0x7d, 0x7c, 0x32, 0x9c, 0xba, 0x81, 0xbb, + 0x7f, 0x72, 0x72, 0xdc, 0x6b, 0xb0, 0x2e, 0x44, 0x87, 0xc3, 0xe9, 0x68, 0x3a, 0xfe, 0x06, 0x87, + 0xee, 0x75, 0x00, 0x70, 0xfb, 0xc6, 0xb9, 0x5b, 0xfc, 0xc1, 0xbb, 0xc5, 0xcf, 0xa0, 0x49, 0x81, + 0xb8, 0xae, 0x20, 0x19, 0x3d, 0xa3, 0xab, 0xcc, 0x4f, 0x53, 0xa7, 0xe0, 0x77, 0xc8, 0xf3, 0xec, + 0x37, 0x52, 0xfb, 0x50, 0x6e, 0x01, 0x6c, 0x3e, 0x2d, 0x2f, 0xa5, 0x36, 0xee, 0x02, 0x89, 0x78, + 0xa5, 0xe2, 0xd7, 0xe6, 0x6a, 0x59, 0x58, 0x2a, 0x90, 0x88, 0x3b, 0x85, 0x5a, 0x22, 0x33, 0x96, + 0xea, 0x22, 0xe2, 0x24, 0x63, 0xa6, 0x96, 0xa5, 0x91, 0xda, 0x52, 0x45, 0x44, 0xdc, 0x6b, 0x37, + 0xed, 0x13, 0x7b, 0x5b, 0x51, 0x2c, 0x92, 0x05, 0x74, 0x8f, 0xd5, 0x02, 0xc7, 0xa2, 0x7b, 0x08, + 0xe3, 0x5a, 0x23, 0x75, 0x96, 0x56, 0x77, 0xa8, 0xd3, 0xd8, 0x16, 0x44, 0x55, 0x3d, 0x54, 0x57, + 0x68, 0xa5, 0xe3, 0x8c, 0xd2, 0xf2, 0x42, 0x4b, 0xf3, 0x62, 0x46, 0x81, 0xf8, 0xe6, 0xef, 0x7a, + 0x70, 0x8a, 0x58, 0x32, 0x82, 0xc6, 0xb3, 0x2b, 0x8b, 0xe3, 0x4e, 0xcc, 0x71, 0x72, 0xcd, 0x5e, + 0x5e, 0x55, 0xf3, 0x25, 0x76, 0x08, 0xd2, 0x8f, 0xa0, 0x53, 0x7d, 0x0a, 0x79, 0xb7, 0x13, 0x78, + 0xe8, 0xd9, 0x95, 0xdd, 0xfb, 0xae, 0x0e, 0xed, 0xc3, 0x85, 0x16, 0xe5, 0x0b, 0xf6, 0x14, 0x5a, + 0xe4, 0x3a, 0xfb, 0x81, 0x9b, 0xed, 0x6b, 0x61, 0x6c, 0x6d, 0xf8, 0xb7, 0xba, 0x7b, 0xd4, 0x26, + 0x35, 0xf6, 0x19, 0xb4, 0xbe, 0xa5, 0x07, 0x4f, 0x77, 0xfd, 0x15, 0xff, 0x7d, 0xbb, 0x5d, 0x68, + 0xd3, 0x5b, 0x4d, 0x32, 0x47, 0x55, 0x0f, 0x37, 0x6f, 0x59, 0x3d, 0x38, 0x93, 0x1a, 0x7b, 0x02, + 0xad, 0x61, 0x6e, 0xa5, 0x66, 0x9b, 0x77, 0x5f, 0x05, 0x5b, 0x6e, 0x07, 0x7f, 0x5f, 0x27, 0x35, + 0xf6, 0x25, 0x6c, 0x1c, 0xd0, 0x15, 0x7b, 0xa2, 0x87, 0x78, 0x9f, 0xb2, 0x77, 0xdf, 0xa2, 0x5b, + 0xef, 0x02, 0x49, 0x8d, 0x7d, 0x0e, 0x5d, 0xba, 0x1e, 0xab, 0xab, 0xd1, 0x8d, 0x35, 0x82, 0xfc, + 0x06, 0x9e, 0x49, 0x6a, 0xfb, 0xbb, 0x7f, 0xba, 0x7e, 0x18, 0xfc, 0xe5, 0xfa, 0x61, 0xf0, 0x8f, + 0xeb, 0x87, 0xc1, 0xef, 0xff, 0xf5, 0xb0, 0x06, 0x71, 0xa6, 0x06, 0x29, 0x65, 0x69, 0xbf, 0xe3, + 0xb2, 0xf5, 0x1c, 0xff, 0xf7, 0x9c, 0xb7, 0xe9, 0xef, 0xcf, 0x97, 0xff, 0x09, 0x00, 0x00, 0xff, + 0xff, 0x0c, 0xdf, 0xc0, 0xae, 0x0b, 0x0d, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -2385,6 +2394,13 @@ func (m *Mutation) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x52 } } + if len(m.Cond) > 0 { + i -= len(m.Cond) + copy(dAtA[i:], m.Cond) + i = encodeVarintApi(dAtA, i, uint64(len(m.Cond))) + i-- + dAtA[i] = 0x32 + } if len(m.Query) > 0 { i -= len(m.Query) copy(dAtA[i:], m.Query) @@ -3418,6 +3434,10 @@ func (m *Mutation) Size() (n int) { if l > 0 { n += 1 + l + sovApi(uint64(l)) } + l = len(m.Cond) + if l > 0 { + n += 1 + l + sovApi(uint64(l)) + } if len(m.Set) > 0 { for _, e := range m.Set { l = e.Size() @@ -4853,6 +4873,38 @@ func (m *Mutation) Unmarshal(dAtA []byte) error { } m.Query = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Cond", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApi + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthApi + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthApi + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Cond = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex case 10: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Set", wireType) diff --git a/vendor/vendor.json b/vendor/vendor.json index c2f37606a2a..32a17a5f6db 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -509,26 +509,26 @@ { "checksumSHA1": "kKrPMMzl8wnZ8Ml1WGHcNO2X0cI=", "path": "github.com/dgraph-io/dgo", - "revision": "3d281925f1d38f1c0428a8a447acb9375d190f78", - "revisionTime": "2019-08-01T00:43:48Z" + "revision": "3b57e1cfe339248e6533c15837c6925c96afddac", + "revisionTime": "2019-08-07T02:29:24Z" }, { - "checksumSHA1": "fhrMMWddafarfjBrQay+geKj0SQ=", + "checksumSHA1": "qPsGsoFTZRG9sahD7zOvWQ37vjA=", "path": "github.com/dgraph-io/dgo/protos/api", - "revision": "3d281925f1d38f1c0428a8a447acb9375d190f78", - "revisionTime": "2019-08-01T00:43:48Z" + "revision": "3b57e1cfe339248e6533c15837c6925c96afddac", + "revisionTime": "2019-08-07T02:29:24Z" }, { "checksumSHA1": "6J5Im9lklapzLqF+qbHiATHD9iQ=", "path": "github.com/dgraph-io/dgo/x", - "revision": "3d281925f1d38f1c0428a8a447acb9375d190f78", - "revisionTime": "2019-08-01T00:43:48Z" + "revision": "3b57e1cfe339248e6533c15837c6925c96afddac", + "revisionTime": "2019-08-07T02:29:24Z" }, { "checksumSHA1": "YOS7SDK4NjeABDXH3c1Jr9OuQYo=", "path": "github.com/dgraph-io/dgo/y", - "revision": "3d281925f1d38f1c0428a8a447acb9375d190f78", - "revisionTime": "2019-08-01T00:43:48Z" + "revision": "3b57e1cfe339248e6533c15837c6925c96afddac", + "revisionTime": "2019-08-07T02:29:24Z" }, { "checksumSHA1": "vXF9AIdgl4GPyn8/zU6L22dVNHo=", From d6af37853169fccd5b266606c8d23beacdb66187 Mon Sep 17 00:00:00 2001 From: Aman Mangal Date: Tue, 6 Aug 2019 13:12:18 -0700 Subject: [PATCH 2/2] Add support for Conditional Upsert (#3612) --- dgraph/cmd/alpha/http.go | 7 + dgraph/cmd/alpha/upsert_test.go | 658 +++++++++++++++++++++++++++----- edgraph/server.go | 119 ++++-- gql/parser_mutation.go | 34 +- gql/state.go | 95 ++--- gql/upsert_test.go | 215 +++++++++-- 6 files changed, 916 insertions(+), 212 deletions(-) diff --git a/dgraph/cmd/alpha/http.go b/dgraph/cmd/alpha/http.go index 080ff55d9be..f006d631c47 100644 --- a/dgraph/cmd/alpha/http.go +++ b/dgraph/cmd/alpha/http.go @@ -326,6 +326,13 @@ func mutationHandler(w http.ResponseWriter, r *http.Request) { return } } + if condText, ok := ms["cond"]; ok && condText != nil { + mu.Cond, err = strconv.Unquote(string(condText.bs)) + if err != nil { + x.SetStatus(w, x.ErrorInvalidRequest, err.Error()) + return + } + } case "application/rdf": // Parse N-Quads. diff --git a/dgraph/cmd/alpha/upsert_test.go b/dgraph/cmd/alpha/upsert_test.go index 677e86747ac..1a9a84e8544 100644 --- a/dgraph/cmd/alpha/upsert_test.go +++ b/dgraph/cmd/alpha/upsert_test.go @@ -17,13 +17,13 @@ package alpha import ( + "fmt" "strings" "sync" "testing" - "github.com/dgraph-io/dgraph/testutil" - "github.com/dgraph-io/dgo/y" + "github.com/dgraph-io/dgraph/testutil" "github.com/stretchr/testify/require" ) @@ -45,16 +45,16 @@ func TestUpsertExample0(t *testing.T) { // Mutation with wrong name m1 := ` upsert { - mutation { - set { - uid(v) "Wrong" . - uid(v) "ashish@dgraph.io" . + query { + me(func: eq(email, "email@company.io")) { + v as uid } } - query { - me(func: eq(email, "ashish@dgraph.io")) { - v as uid + mutation { + set { + uid(v) "Wrong" . + uid(v) "email@company.io" . } } }` @@ -80,15 +80,15 @@ upsert { // mutation with correct name m2 := ` upsert { - mutation { - set { - uid(v) "Ashish" . + query { + me(func: eq(email, "email@company.io")) { + v as uid } } - query { - me(func: eq(email, "ashish@dgraph.io")) { - v as uid + mutation { + set { + uid(v) "Ashish" . } } }` @@ -110,7 +110,7 @@ func TestUpsertExample0JSON(t *testing.T) { // Mutation with wrong name m1 := ` { - "query": "{me(func: eq(email, \"ashish@dgraph.io\")) {v as uid}}", + "query": "{me(func: eq(email, \"email@company.io\")) {v as uid}}", "set": [ { "uid": "uid(v)", @@ -118,7 +118,7 @@ func TestUpsertExample0JSON(t *testing.T) { }, { "uid": "uid(v)", - "email": "ashish@dgraph.io" + "email": "email@company.io" } ] }` @@ -142,7 +142,7 @@ func TestUpsertExample0JSON(t *testing.T) { // mutation with correct name m2 := ` { - "query": "{me(func: eq(email, \"ashish@dgraph.io\")) {v as uid}}", + "query": "{me(func: eq(email, \"email@company.io\")) {v as uid}}", "set": [ { "uid": "uid(v)", @@ -169,12 +169,6 @@ friend: uid @reverse .`)) m1 := ` upsert { - mutation { - set { - _:user1 "45" . - } - } - query { me(func: eq(age, 34)) { ...fragmentA @@ -188,6 +182,12 @@ upsert { fragment fragmentA { uid } + + mutation { + set { + _:user1 "45" . + } + } }` _, _, _, err := mutationWithTs(m1, "application/rdf", false, true, true, 0) require.Contains(t, err.Error(), "upsert query block has no variables") @@ -201,12 +201,6 @@ friend: uid @reverse .`)) m1 := ` upsert { - mutation { - set { - uid(variable) "45" . - } - } - query { me(func: eq(age, 34)) { friend { @@ -218,6 +212,12 @@ upsert { fragment fragmentA { variable as uid } + + mutation { + set { + uid(variable) "45" . + } + } }` keys, preds, _, err := mutationWithTs(m1, "application/rdf", false, true, true, 0) require.NoError(t, err) @@ -257,13 +257,6 @@ friend: uid @reverse .`)) m1 := ` upsert { - mutation { - set { - uid(42) "45" . - uid(variable) "45" . - } - } - query { me(func: eq(age, 34)) { friend { @@ -275,6 +268,13 @@ upsert { fragment fragmentA { variable as uid } + + mutation { + set { + uid(42) "45" . + uid(variable) "45" . + } + } }` _, _, _, err := mutationWithTs(m1, "application/rdf", false, true, true, 0) require.Contains(t, err.Error(), "Some variables are used but not defined") @@ -291,12 +291,6 @@ friend: uid @reverse .`)) m1 := ` upsert { - mutation { - set { - uid(var2) "45" . - } - } - query { me(func: eq(age, 34)) { var2 as uid @@ -310,6 +304,12 @@ upsert { var1 as uid name } + + mutation { + set { + uid(var2) "45" . + } + } }` _, _, _, err := mutationWithTs(m1, "application/rdf", false, true, true, 0) require.Contains(t, err.Error(), "Some variables are defined but not used") @@ -340,12 +340,6 @@ friend: uid @reverse .`)) m1 := ` upsert { - mutation { - set { - uid( u) "true" . - } - } - query { var(func: has(age)) { a as age @@ -357,6 +351,12 @@ upsert { age } } + + mutation { + set { + uid( u) "true" . + } + } }` _, _, _, err = mutationWithTs(m1, "application/rdf", false, true, true, 0) require.NoError(t, err) @@ -377,17 +377,17 @@ upsert { m2 := ` upsert { - mutation { - delete { - uid (u1) * . - } - } - query { user1(func: eq(name@en, "user1")) { u1 as uid } } + + mutation { + delete { + uid (u1) * . + } + } }` _, _, _, err = mutationWithTs(m2, "application/rdf", false, true, true, 0) require.NoError(t, err) @@ -427,12 +427,6 @@ friend: uid @reverse .`)) m1 := ` upsert { - mutation { - set { - uid ( u1 ) uid ( u2 ) . - } - } - query { user1(func: eq(name@en, "user1")) { u1 as uid @@ -442,6 +436,12 @@ upsert { u2 as uid } } + + mutation { + set { + uid ( u1 ) uid ( u2 ) . + } + } }` _, _, _, err = mutationWithTs(m1, "application/rdf", false, true, true, 0) require.NoError(t, err) @@ -460,12 +460,6 @@ upsert { m2 := ` upsert { - mutation { - delete { - uid (u1) uid ( u2 ) . - } - } - query { user1(func: eq(name@en, "user1")) { u1 as uid @@ -475,6 +469,12 @@ upsert { u2 as uid } } + + mutation { + delete { + uid (u1) uid ( u2 ) . + } + } }` _, _, _, err = mutationWithTs(m2, "application/rdf", false, true, true, 0) require.NoError(t, err) @@ -515,14 +515,13 @@ friend: uid @reverse .`)) m1 := ` { + "query": "{var(func: has(age)) {a as age} oldest(func: uid(a), orderdesc: val(a), first: 1) {u as uid}}", "set": [ { "uid": "uid(u)", "oldest": "true" } - ], - - "query": "{var(func: has(age)) {a as age} oldest(func: uid(a), orderdesc: val(a), first: 1) {u as uid}}" + ] }` _, _, _, err = mutationWithTs(m1, "application/json", false, true, true, 0) require.NoError(t, err) @@ -543,14 +542,13 @@ friend: uid @reverse .`)) m2 := ` { + "query": "{user1(func: eq(name@en, \"user1\")) {u1 as uid}}", "delete": [ { "uid": "uid (u1)", "name": null } - ], - - "query": "{user1(func: eq(name@en, \"user1\")) {u1 as uid}}" + ] }` _, _, _, err = mutationWithTs(m2, "application/json", false, true, true, 0) require.NoError(t, err) @@ -590,14 +588,13 @@ friend: uid @reverse .`)) m1 := ` { + "query": "{user1(func: eq(name@en, \"user1\")) {u1 as uid} user2(func: eq(name@en, \"user2\")) {u2 as uid}}", "set": [ { "uid": "uid(u1)", "friend": "uid (u2 ) " } - ], - - "query": "{user1(func: eq(name@en, \"user1\")) {u1 as uid} user2(func: eq(name@en, \"user2\")) {u2 as uid}}" + ] }` _, _, _, err = mutationWithTs(m1, "application/json", false, true, true, 0) require.NoError(t, err) @@ -616,14 +613,13 @@ friend: uid @reverse .`)) m3 := ` { + "query": "{user1(func: eq(name@en, \"user1\")) {u1 as uid} user2(func: eq(name@en, \"user2\")) {u2 as uid}}", "delete": [ { "uid": "uid (u1)", "friend": "uid ( u2 )" } - ], - - "query": "{user1(func: eq(name@en, \"user1\")) {u1 as uid} user2(func: eq(name@en, \"user2\")) {u2 as uid}}" + ] }` _, _, _, err = mutationWithTs(m3, "application/json", false, true, true, 0) require.NoError(t, err) @@ -647,18 +643,18 @@ func TestUpsertBlankNodeWithVar(t *testing.T) { m := ` upsert { + query { + users(func: eq(name, "user1")) { + u as uid + } + } + mutation { set { uid(u) "user1" . _:u "user2" . } } - - query { - users(func: eq(name, "user1")) { - u as uid - } - } }` _, _, _, err := mutationWithTs(m, "application/rdf", false, true, true, 0) require.NoError(t, err) @@ -685,6 +681,20 @@ friend: uid @reverse .`)) m := ` upsert { + query { + user1(func: eq(email, "user1@dgraph.io")) { + u1 as uid + } + + user2(func: eq(email, "user2@dgraph.io")) { + u2 as uid + } + + user3(func: eq(email, "user3@dgraph.io")) { + u3 as uid + } + } + mutation { set { uid(u1) "user1@dgraph.io" . @@ -700,20 +710,6 @@ upsert { uid(u3) * . } } - - query { - user1(func: eq(email, "user1@dgraph.io")) { - u1 as uid - } - - user2(func: eq(email, "user2@dgraph.io")) { - u2 as uid - } - - user3(func: eq(email, "user3@dgraph.io")) { - u3 as uid - } - } }` doUpsert := func(wg *sync.WaitGroup) { defer wg.Done() @@ -775,22 +771,476 @@ friend: uid @reverse .`)) m := ` upsert { + query { + user1(func: eq(name@en, "user1")) { + u1 as uid + } + + user2(func: eq(name@en, "user2")) { + u2 as uid + } + } + mutation { delete { uid (u1) uid ( u2 ) . } } +}` + _, _, _, err := mutationWithTs(m, "application/rdf", false, true, true, 0) + require.NoError(t, err) +} + +func TestConditionalUpsertExample0(t *testing.T) { + require.NoError(t, dropAll()) + require.NoError(t, alterSchema(`email: string @index(exact) .`)) + // Mutation with wrong name + m1 := ` +upsert { query { - user1(func: eq(name@en, "user1")) { - u1 as uid + me(func: eq(email, "email@company.io")) { + v as uid } + } - user2(func: eq(name@en, "user2")) { - u2 as uid + mutation @if(eq(len(v), 0)) { + set { + uid(v) "Wrong" . + uid(v) "email@company.io" . } } }` - _, _, _, err := mutationWithTs(m, "application/rdf", false, true, true, 0) + keys, preds, _, err := mutationWithTs(m1, "application/rdf", false, true, true, 0) + require.NoError(t, err) + require.True(t, len(keys) == 0) + require.True(t, contains(preds, "email")) + require.True(t, contains(preds, "name")) + + // Trying again, should be a NOOP + _, _, _, err = mutationWithTs(m1, "application/rdf", false, true, true, 0) + require.NoError(t, err) + + // query should return the wrong name + q1 := ` +{ + q(func: has(email)) { + uid + name + email + } +}` + res, _, err := queryWithTs(q1, "application/graphql+-", "", 0) + require.NoError(t, err) + require.Contains(t, res, "Wrong") + + // mutation with correct name + m2 := ` +upsert { + query { + me(func: eq(email, "email@company.io")) { + v as uid + } + } + + mutation @if(eq(len(v), 1)) { + set { + uid(v) "Ashish" . + } + } +}` + keys, preds, _, err = mutationWithTs(m2, "application/rdf", false, true, true, 0) require.NoError(t, err) + require.True(t, len(keys) == 0) + require.True(t, contains(preds, "name")) + + // query should return correct name + res, _, err = queryWithTs(q1, "application/graphql+-", "", 0) + require.NoError(t, err) + require.Contains(t, res, "Ashish") +} + +func TestConditionalUpsertExample0JSON(t *testing.T) { + require.NoError(t, dropAll()) + require.NoError(t, alterSchema(`email: string @index(exact) .`)) + + // Mutation with wrong name + m1 := ` +{ + "query": "{me(func: eq(email, \"email@company.io\")) {v as uid}}", + "cond": " @if(eq(len(v), 0)) ", + "set": [ + { + "uid": "uid(v)", + "name": "Wrong" + }, + { + "uid": "uid(v)", + "email": "email@company.io" + } + ] +}` + keys, _, _, err := mutationWithTs(m1, "application/json", false, true, true, 0) + require.NoError(t, err) + require.True(t, len(keys) == 0) + + // query should return the wrong name + q1 := ` +{ + q(func: has(email)) { + uid + name + email + } +}` + res, _, err := queryWithTs(q1, "application/graphql+-", "", 0) + require.NoError(t, err) + require.Contains(t, res, "Wrong") + + // mutation with correct name + m2 := ` +{ + "query": "{me(func: eq(email, \"email@company.io\")) {v as uid}}", + "cond": "@if(eq(len(v), 1))", + "set": [ + { + "uid": "uid(v)", + "name": "Ashish" + } + ] +}` + keys, preds, _, err := mutationWithTs(m2, "application/json", false, true, true, 0) + require.NoError(t, err) + require.True(t, len(keys) == 0) + require.True(t, contains(preds, "name")) + + // query should return correct name + res, _, err = queryWithTs(q1, "application/graphql+-", "", 0) + require.NoError(t, err) + require.Contains(t, res, "Ashish") +} + +func populateCompanyData(t *testing.T) { + require.NoError(t, alterSchema(` +email: string @index(exact) . +works_for: string @index(exact) . +works_with: [uid] .`)) + + m1 := ` +{ + set { + _:user1 "user1" . + _:user1 "user1@company1.io" . + _:user1 "company1" . + + _:user2 "user2" . + _:user2 "user2@company1.io" . + _:user2 "company1" . + + _:user3 "user3" . + _:user3 "user3@company2.io" . + _:user3 "company2" . + + _:user4 "user4" . + _:user4 "user4@company2.io" . + _:user4 "company2" . + } +}` + _, _, _, err := mutationWithTs(m1, "application/rdf", false, true, true, 0) + require.NoError(t, err) +} + +func TestUpsertMultiValue(t *testing.T) { + require.NoError(t, dropAll()) + populateCompanyData(t) + + // add color to all employees of company1 + m2 := ` +upsert { + query { + me(func: eq(works_for, "company1")) { + u as uid + } + } + + mutation { + set { + uid(u) "red" . + } + } +}` + keys, preds, _, err := mutationWithTs(m2, "application/rdf", false, true, true, 0) + require.NoError(t, err) + require.True(t, len(keys) == 0) + require.True(t, contains(preds, "color")) + require.False(t, contains(preds, "works_for")) + + q2 := ` +{ + q(func: eq(works_for, "%s")) { + name + works_for + color + works_with + } +}` + res, _, err := queryWithTs(fmt.Sprintf(q2, "company1"), "application/graphql+-", "", 0) + require.NoError(t, err) + testutil.CompareJSON(t, `{"data":{"q":[{"name":"user1","works_for":"company1","color":"red"},`+ + `{"name":"user2","works_for":"company1","color":"red"}]}}`, res) + + // delete color for employess of company1 and set color for employees of company2 + m3 := ` +upsert { + query { + c1 as var(func: eq(works_for, "company1")) + c2 as var(func: eq(works_for, "company2")) + } + + mutation @if(le(len(c1), 100) AND lt(len(c2), 100)) { + delete { + uid(c1) * . + } + + set { + uid(c2) "blue" . + } + } +}` + keys, preds, _, err = mutationWithTs(m3, "application/rdf", false, true, true, 0) + require.NoError(t, err) + + // The following mutation should have no effect on the state of the database + m4 := ` +upsert { + query { + c1 as var(func: eq(works_for, "company1")) + c2 as var(func: eq(works_for, "company2")) + } + + mutation @if(gt(len(c1), 2) OR ge(len(c2), 3)) { + delete { + uid(c1) * . + } + + set { + uid(c2) "blue" . + } + } +}` + keys, preds, _, err = mutationWithTs(m4, "application/rdf", false, true, true, 0) + require.NoError(t, err) + + res, _, err = queryWithTs(fmt.Sprintf(q2, "company1"), "application/graphql+-", "", 0) + require.NoError(t, err) + testutil.CompareJSON(t, `{"data":{"q":[{"name":"user1","works_for":"company1"},`+ + `{"name":"user2","works_for":"company1"}]}}`, res) + + res, _, err = queryWithTs(fmt.Sprintf(q2, "company2"), "application/graphql+-", "", 0) + require.NoError(t, err) + testutil.CompareJSON(t, `{"data":{"q":[{"name":"user3","works_for":"company2","color":"blue"},`+ + `{"name":"user4","works_for":"company2","color":"blue"}]}}`, res) +} + +func TestUpsertMultiValueEdge(t *testing.T) { + require.NoError(t, dropAll()) + populateCompanyData(t) + + // All employees of company1 now works with all employees of company2 + m1 := ` +upsert { + query { + c1 as var(func: eq(works_for, "company1")) + c2 as var(func: eq(works_for, "company2")) + } + + mutation @if(eq(len(c1), 2) AND eq(len(c2), 2)) { + set { + uid(c1) uid(c2) . + uid(c2) uid(c1) . + } + } +}` + _, _, _, err := mutationWithTs(m1, "application/rdf", false, true, true, 0) + require.NoError(t, err) + + q1 := ` +{ + q(func: eq(works_for, "%s")) { + name + works_with { + name + } + } +}` + res, _, err := queryWithTs(fmt.Sprintf(q1, "company1"), "application/graphql+-", "", 0) + require.NoError(t, err) + testutil.CompareJSON(t, `{"data":{"q":[{"name":"user2","works_with":[{"name":"user3"},{"name":"user4"}]},`+ + `{"name":"user1","works_with":[{"name":"user3"},{"name":"user4"}]}]}}`, res) + + res, _, err = queryWithTs(fmt.Sprintf(q1, "company2"), "application/graphql+-", "", 0) + require.NoError(t, err) + testutil.CompareJSON(t, `{"data":{"q":[{"name":"user3","works_with":[{"name":"user1"},{"name":"user2"}]},`+ + `{"name":"user4","works_with":[{"name":"user1"},{"name":"user2"}]}]}}`, res) + + // user1 and user3 do not work with each other anymore + m2 := ` +upsert { + query { + u1 as var(func: eq(email, "user1@company1.io")) + u3 as var(func: eq(email, "user3@company2.io")) + } + + mutation @if(eq(len(u1), 1) AND eq(len(u3), 1)) { + delete { + uid (u1) uid (u3) . + uid (u3) uid (u1) . + } + } +}` + _, _, _, err = mutationWithTs(m2, "application/rdf", false, true, true, 0) + require.NoError(t, err) + + res, _, err = queryWithTs(fmt.Sprintf(q1, "company1"), "application/graphql+-", "", 0) + require.NoError(t, err) + testutil.CompareJSON(t, `{"data":{"q":[{"name":"user1","works_with":[{"name":"user4"}]},`+ + `{"name":"user2","works_with":[{"name":"user4"},{"name":"user3"}]}]}}`, res) + + res, _, err = queryWithTs(fmt.Sprintf(q1, "company2"), "application/graphql+-", "", 0) + require.NoError(t, err) + testutil.CompareJSON(t, `{"data":{"q":[{"name":"user3","works_with":[{"name":"user2"}]},`+ + `{"name":"user4","works_with":[{"name":"user1"},{"name":"user2"}]}]}}`, res) +} + +func TestUpsertEdgeWithBlankNode(t *testing.T) { + require.NoError(t, dropAll()) + populateCompanyData(t) + + // Add a new employee who works with every employee in company2 + m1 := ` +upsert { + query { + c1 as var(func: eq(works_for, "company1")) + c2 as var(func: eq(works_for, "company2")) + } + + mutation @if(lt(len(c1), 3)) { + set { + _:user5 "user5" . + _:user5 "user5@company1.io" . + _:user5 "company1" . + _:user5 uid(c2) . + } + } +}` + _, _, _, err := mutationWithTs(m1, "application/rdf", false, true, true, 0) + require.NoError(t, err) + + q1 := ` +{ + q(func: eq(email, "user5@company1.io")) { + name + email + works_for + works_with { + name + } + } +}` + res, _, err := queryWithTs(q1, "application/graphql+-", "", 0) + require.NoError(t, err) + testutil.CompareJSON(t, `{"data":{"q":[{"name":"user5","email":"user5@company1.io",`+ + `"works_for":"company1","works_with":[{"name":"user3"},{"name":"user4"}]}]}}`, res) +} + +func TestConditionalUpsertWithFilterErr(t *testing.T) { + require.NoError(t, dropAll()) + populateCompanyData(t) + + m1 := ` +upsert { + query { + me(func: eq(email, "email@company.io")) { + v as uid + } + } + + mutation @filter(eq(len(v), 0)) { + set { + uid(v) "Wrong" . + uid(v) "email@company.io" . + } + } +}` + _, _, _, err := mutationWithTs(m1, "application/rdf", false, true, true, 0) + require.Contains(t, err.Error(), "Expected @if, found [@filter]") +} + +func TestConditionalUpsertMissingAtErr(t *testing.T) { + require.NoError(t, dropAll()) + populateCompanyData(t) + + m1 := ` +upsert { + query { + me(func: eq(email, "email@company.io")) { + v as uid + } + } + + mutation if(eq(len(v), 0)) { + set { + uid(v) "Wrong" . + uid(v) "email@company.io" . + } + } +}` + _, _, _, err := mutationWithTs(m1, "application/rdf", false, true, true, 0) + require.Contains(t, err.Error(), `Unrecognized character inside mutation: U+0028 '('`) +} + +func TestConditionalUpsertDoubleIfErr(t *testing.T) { + require.NoError(t, dropAll()) + populateCompanyData(t) + + m1 := ` +upsert { + query { + me(func: eq(email, "email@company.io")) { + v as uid + } + } + + mutation @if(eq(len(v), 0)) @if(eq(len(v), 0)) { + set { + uid(v) "Wrong" . + uid(v) "email@company.io" . + } + } +}` + _, _, _, err := mutationWithTs(m1, "application/rdf", false, true, true, 0) + require.Contains(t, err.Error(), "Expected { at the start of block") +} + +func TestConditionalUpsertMissingRightRoundErr(t *testing.T) { + require.NoError(t, dropAll()) + populateCompanyData(t) + + m1 := ` +upsert { + query { + me(func: eq(email, "email@company.io")) { + v as uid + } + } + + mutation @if(eq(len(v), 0) { + set { + uid(v) "Wrong" . + uid(v) "email@company.io" . + } + } +}` + _, _, _, err := mutationWithTs(m1, "application/rdf", false, true, true, 0) + require.Contains(t, err.Error(), "Matching brackets not found") } diff --git a/edgraph/server.go b/edgraph/server.go index d2d88a3c4a4..68a539398fe 100644 --- a/edgraph/server.go +++ b/edgraph/server.go @@ -21,8 +21,10 @@ import ( "encoding/json" "fmt" "math" + "math/rand" "os" "sort" + "strconv" "strings" "time" "unicode" @@ -577,40 +579,79 @@ func doQueryInUpsert(ctx context.Context, mu *api.Mutation, gmu *gql.Mutation) ( return l, nil } + upsertQuery := mu.Query needVars := findVars(gmu) + isCondUpsert := strings.TrimSpace(mu.Cond) != "" + varName := fmt.Sprintf("__dgraph%d__", rand.Int()) + if isCondUpsert { + // @if in upsert is same as @filter in the query + cond := strings.Replace(mu.Cond, "@if", "@filter", 1) + + // Add dummy query to evaluate the @if directive, ok to use uid(0) because + // dgraph doesn't check for existence of UIDs until we query for other predicates. + // Here, we are only querying for uid predicate in the dummy query. + // + // For example if - mu.Query = { + // me(...) {...} + // } + // + // Then, upsertQuery = { + // me(...) {...} + // __dgraph0__ as var(func: uid(0)) @if(...) + // } + // + // The variable __dgraph0__ will - + // * be empty if the condition is true + // * have 1 UID (the 0 UID) if the condition is false + upsertQuery = strings.TrimSuffix(strings.TrimSpace(mu.Query), "}") + upsertQuery += varName + ` as var(func: uid(0)) ` + cond + `}` + needVars = append(needVars, varName) + } + startParsingTime := time.Now() parsedReq, err := gql.ParseWithNeedVars(gql.Request{ - Str: mu.Query, + Str: upsertQuery, Variables: make(map[string]string), }, needVars) l.Parsing += time.Since(startParsingTime) if err != nil { - return nil, errors.Wrapf(err, "while parsing query: %q", mu.Query) + return nil, errors.Wrapf(err, "while parsing query: %q", upsertQuery) } if err := validateQuery(parsedReq.Query); err != nil { - return nil, errors.Wrapf(err, "while validating query: %q", mu.Query) + return nil, errors.Wrapf(err, "while validating query: %q", upsertQuery) } qr := query.Request{Latency: l, GqlQuery: &parsedReq, ReadTs: mu.StartTs} if err := qr.ProcessQuery(ctx); err != nil { - return nil, errors.Wrapf(err, "while processing query: %q", mu.Query) + return nil, errors.Wrapf(err, "while processing query: %q", upsertQuery) } if len(qr.Vars) <= 0 { return nil, errors.Errorf("upsert query block has no variables") } - // TODO(Aman): allow multiple values for each variable. // If a variable doesn't have any UID, we generate one ourselves later. - varToUID := make(map[string]string) + varToUID := make(map[string][]string) for name, v := range qr.Vars { - if v.Uids == nil { + if v.Uids == nil || len(v.Uids.Uids) <= 0 { continue } - if len(v.Uids.Uids) > 1 { - return nil, errors.Errorf("more than one values found for var (%s)", name) - } else if len(v.Uids.Uids) == 1 { - varToUID[name] = fmt.Sprintf("%d", v.Uids.Uids[0]) + + uids := make([]string, len(v.Uids.Uids)) + for i, u := range v.Uids.Uids { + uids[i] = strconv.FormatUint(u, 10) + } + varToUID[name] = uids + } + + // If @if condition is false, no need to process the mutations + if isCondUpsert { + v, ok := qr.Vars[varName] + isMut := ok && v.Uids != nil && len(v.Uids.Uids) == 1 + if !isMut { + gmu.Set = nil + gmu.Del = nil + return l, nil } } @@ -650,39 +691,65 @@ func findVars(gmu *gql.Mutation) []string { // updateMutations does following transformations: // * uid(v) -> 0x123 -- If v is defined in query block // * uid(v) -> _:uid(v) -- Otherwise -func updateMutations(gmu *gql.Mutation, varToUID map[string]string) { - getNewVal := func(s string) string { +func updateMutations(gmu *gql.Mutation, varToUID map[string][]string) { + getNewVals := func(s string) []string { if strings.HasPrefix(s, "uid(") { varName := s[4 : len(s)-1] - if uid, ok := varToUID[varName]; ok { - return uid + if uids, ok := varToUID[varName]; ok { + return uids } - return "_:" + s + return []string{"_:" + s} } - return s + return []string{s} + } + + getNewNQuad := func(nq *api.NQuad, s, o string) *api.NQuad { + // The following copy is fine because we only modify Subject and ObjectId. + // The pointer values are not modified across different copies of NQuad. + n := *nq + + n.Subject = s + n.ObjectId = o + return &n } // Remove the mutations from gmu.Del when no UID was found. - gmuDel := gmu.Del[:0] + gmuDel := make([]*api.NQuad, 0, len(gmu.Del)) for _, nq := range gmu.Del { - nq.Subject = getNewVal(nq.Subject) - nq.ObjectId = getNewVal(nq.ObjectId) - - if !strings.HasPrefix(nq.Subject, "_:uid(") && - !strings.HasPrefix(nq.ObjectId, "_:uid(") { + // if Subject or/and Object are variables, each NQuad can result + // in multiple NQuads if any variable stores more than one UIDs. + newSubs := getNewVals(nq.Subject) + newObs := getNewVals(nq.ObjectId) + + for _, s := range newSubs { + for _, o := range newObs { + // Blank node has no meaning in case of deletion. + if strings.HasPrefix(s, "_:uid(") || + strings.HasPrefix(o, "_:uid(") { + continue + } - gmuDel = append(gmuDel, nq) + gmuDel = append(gmuDel, getNewNQuad(nq, s, o)) + } } } gmu.Del = gmuDel // Update the values in mutation block from the query block. + gmuSet := make([]*api.NQuad, 0, len(gmu.Set)) for _, nq := range gmu.Set { - nq.Subject = getNewVal(nq.Subject) - nq.ObjectId = getNewVal(nq.ObjectId) + newSubs := getNewVals(nq.Subject) + newObs := getNewVals(nq.ObjectId) + + for _, s := range newSubs { + for _, o := range newObs { + gmuSet = append(gmuSet, getNewNQuad(nq, s, o)) + } + } } + gmu.Set = gmuSet } // Query handles queries and returns the data. diff --git a/gql/parser_mutation.go b/gql/parser_mutation.go index d8c8d9798e1..76b6fca6f72 100644 --- a/gql/parser_mutation.go +++ b/gql/parser_mutation.go @@ -39,11 +39,11 @@ func ParseMutation(mutation string) (mu *api.Mutation, err error) { item := it.Item() switch item.Typ { case itemUpsertBlock: - if mu, err = ParseUpsertBlock(it); err != nil { + if mu, err = parseUpsertBlock(it); err != nil { return nil, err } case itemLeftCurl: - if mu, err = ParseMutationBlock(it); err != nil { + if mu, err = parseMutationBlock(it); err != nil { return nil, err } default: @@ -58,11 +58,11 @@ func ParseMutation(mutation string) (mu *api.Mutation, err error) { return mu, nil } -// ParseUpsertBlock parses the upsert block -func ParseUpsertBlock(it *lex.ItemIterator) (*api.Mutation, error) { +// parseUpsertBlock parses the upsert block +func parseUpsertBlock(it *lex.ItemIterator) (*api.Mutation, error) { var mu *api.Mutation - var queryText string - var queryFound bool + var queryText, condText string + var queryFound, condFound bool // ===>upsert<=== {...} if !it.Next() { @@ -109,10 +109,26 @@ func ParseUpsertBlock(it *lex.ItemIterator) (*api.Mutation, error) { if !it.Next() { return nil, it.Errorf("Unexpected end of upsert block") } + + // upsert { mutation ===>@if(...)<=== {....} query{...}} + item = it.Item() + if item.Typ == itemUpsertBlockOpContent { + if condFound { + return nil, it.Errorf("Multiple @if directive inside upsert block") + } + condFound = true + condText = item.Val + if !it.Next() { + return nil, it.Errorf("Unexpected end of upsert block") + } + } + + // upsert @if(...) ===>{<=== ....} var err error - if mu, err = ParseMutationBlock(it); err != nil { + if mu, err = parseMutationBlock(it); err != nil { return nil, err } + mu.Cond = condText // upsert { mutation{...} ===>fragment<==={...}} case item.Typ == itemUpsertBlockOp && item.Val == "fragment": @@ -133,8 +149,8 @@ func ParseUpsertBlock(it *lex.ItemIterator) (*api.Mutation, error) { return nil, it.Errorf("Invalid upsert block") } -// ParseMutationBlock parses the mutation block -func ParseMutationBlock(it *lex.ItemIterator) (*api.Mutation, error) { +// parseMutationBlock parses the mutation block +func parseMutationBlock(it *lex.ItemIterator) (*api.Mutation, error) { var mu api.Mutation item := it.Item() diff --git a/gql/state.go b/gql/state.go index e1d12645065..4ca6c90a7b7 100644 --- a/gql/state.go +++ b/gql/state.go @@ -91,20 +91,14 @@ func lexIdentifyBlock(l *lex.Lexer) lex.StateFn { // lexNameBlock lexes the blocks, for now, only upsert block func lexNameBlock(l *lex.Lexer) lex.StateFn { - for { - // The caller already checked isNameBegin, and absorbed one rune. - r := l.Next() - if isNameSuffix(r) { - continue - } - l.Backup() - switch word := l.Input[l.Start:l.Pos]; word { - case "upsert": - l.Emit(itemUpsertBlock) - return lexUpsertBlock - default: - return l.Errorf("Invalid block: [%s]", word) - } + // The caller already checked isNameBegin, and absorbed one rune. + l.AcceptRun(isNameSuffix) + switch word := l.Input[l.Start:l.Pos]; word { + case "upsert": + l.Emit(itemUpsertBlock) + return lexUpsertBlock + default: + return l.Errorf("Invalid block: [%s]", word) } } @@ -138,59 +132,76 @@ func lexUpsertBlock(l *lex.Lexer) lex.StateFn { // lexNameUpsertOp parses the operation names inside upsert block func lexNameUpsertOp(l *lex.Lexer) lex.StateFn { - for { - // The caller already checked isNameBegin, and absorbed one rune. - r := l.Next() - if isNameSuffix(r) { - continue - } - l.Backup() - word := l.Input[l.Start:l.Pos] - switch word { - case "query": - l.Emit(itemUpsertBlockOp) - return lexBlockContent - case "mutation": - l.Emit(itemUpsertBlockOp) - return lexInsideMutation - case "fragment": - l.Emit(itemUpsertBlockOp) - return lexBlockContent - default: - return l.Errorf("Invalid operation type: %s", word) - } + // The caller already checked isNameBegin, and absorbed one rune. + l.AcceptRun(isNameSuffix) + word := l.Input[l.Start:l.Pos] + switch word { + case "query": + l.Emit(itemUpsertBlockOp) + return lexBlockContent + case "mutation": + l.Emit(itemUpsertBlockOp) + return lexInsideMutation + case "fragment": + l.Emit(itemUpsertBlockOp) + return lexBlockContent + default: + return l.Errorf("Invalid operation type: %s", word) } } // lexBlockContent lexes and absorbs the text inside a block (covered by braces). func lexBlockContent(l *lex.Lexer) lex.StateFn { + return lexContent(l, leftCurl, rightCurl, lexUpsertBlock) +} + +// lexIfContent lexes the whole of @if directive in a mutation block (covered by small brackets) +func lexIfContent(l *lex.Lexer) lex.StateFn { + if r := l.Next(); r != at { + return l.Errorf("Expected [@], found; [%#U]", r) + } + + l.AcceptRun(isNameSuffix) + word := l.Input[l.Start:l.Pos] + if word != "@if" { + return l.Errorf("Expected @if, found [%v]", word) + } + + return lexContent(l, '(', ')', lexInsideMutation) +} + +func lexContent(l *lex.Lexer, leftRune, rightRune rune, returnTo lex.StateFn) lex.StateFn { depth := 0 for { switch l.Next() { case lex.EOF: - return l.Errorf("Unclosed block (matching braces not found)") + return l.Errorf("Matching brackets not found") case quote: if err := l.LexQuotedString(); err != nil { return l.Errorf(err.Error()) } - case leftCurl: + case leftRune: depth++ - case rightCurl: + case rightRune: depth-- if depth < 0 { - return l.Errorf("Unopened } found") + return l.Errorf("Unopened %c found", rightRune) } else if depth == 0 { l.Emit(itemUpsertBlockOpContent) - return lexUpsertBlock + return returnTo } } } + } func lexInsideMutation(l *lex.Lexer) lex.StateFn { l.Mode = lexInsideMutation for { switch r := l.Next(); { + case r == at: + l.Backup() + return lexIfContent case r == rightCurl: l.Depth-- l.Emit(itemRightCurl) @@ -586,10 +597,8 @@ func lexOperationType(l *lex.Lexer) lex.StateFn { l.Emit(itemOpType) return lexInsideSchema } else { - l.Errorf("Invalid operation type: %s", word) + return l.Errorf("Invalid operation type: %s", word) } - - return lexQuery } // lexArgName lexes and emits the name part of an argument. diff --git a/gql/upsert_test.go b/gql/upsert_test.go index de02e6c53e4..7318d0616ad 100644 --- a/gql/upsert_test.go +++ b/gql/upsert_test.go @@ -79,12 +79,6 @@ upsert { func TestMultipleQueryErr(t *testing.T) { query := ` upsert { - mutation { - set { - "_:user1" "45" . - } - } - query { me(func: eq(age, 34)) { uid @@ -104,6 +98,12 @@ upsert { } } } + + mutation { + set { + "_:user1" "45" . + } + } } ` _, err := ParseMutation(query) @@ -159,12 +159,6 @@ upsert { func TestUpsertWithFragment(t *testing.T) { query := ` upsert { - mutation { - set { - "_:user1" "45" . - } - } - query { me(func: eq(age, 34)) { ...fragmentA @@ -178,6 +172,12 @@ upsert { fragment fragmentA { uid } + + mutation { + set { + "_:user1" "45" . + } + } } ` _, err := ParseMutation(query) @@ -187,12 +187,6 @@ upsert { func TestUpsertEx1(t *testing.T) { query := ` upsert { - mutation { - set { - "_:user1" "45" . - } - } - query { me(func: eq(age, "{")) { uid @@ -202,6 +196,12 @@ upsert { } } } + + mutation { + set { + "_:user1" "45" . + } + } } ` _, err := ParseMutation(query) @@ -213,6 +213,18 @@ func TestUpsertWithSpaces(t *testing.T) { upsert { + query + + { + me(func: eq(age, "{")) { + uid + friend { + uid + age + } + } + } + mutation { @@ -223,11 +235,23 @@ upsert # This is a comment "_:user1" "{vishesh" . }} +} +` + _, err := ParseMutation(query) + require.Nil(t, err) +} - query +func TestUpsertWithBlankNode(t *testing.T) { + query := ` +upsert { + mutation { + set { + "_:user1" "45" . + } + } - { - me(func: eq(age, "{")) { + query { + me(func: eq(age, 34)) { uid friend { uid @@ -241,7 +265,7 @@ upsert require.Nil(t, err) } -func TestUpsertWithBlankNode(t *testing.T) { +func TestUpsertMutationThenQuery(t *testing.T) { query := ` upsert { query { @@ -265,17 +289,63 @@ upsert { require.Nil(t, err) } -func TestUpsertMutationThenQuery(t *testing.T) { +func TestUpsertWithFilter(t *testing.T) { query := ` upsert { + query { + me(func: eq(age, 34)) @filter(ge(name, "user")) { + uid + friend { + uid + age + } + } + } + mutation { set { - "_:user1" "45" . + uid(a) "45" + uid(b) "45" . } } +} +` + _, err := ParseMutation(query) + require.Nil(t, err) +} +func TestConditionalUpsertWithNewlines(t *testing.T) { + query := ` +upsert { query { - me(func: eq(age, 34)) { + me(func: eq(age, 34)) @filter(ge(name, "user")) { + m as uid + friend { + f as uid + age + } + } + } + + mutation @if(eq(len(m), 1) + AND + gt(len(f), 0)) { + set { + uid(m) "45" . + uid(f) "45" . + } + } +} +` + _, err := ParseMutation(query) + require.Nil(t, err) +} + +func TestConditionalUpsertFuncTree(t *testing.T) { + query := ` +upsert { + query { + me(func: eq(age, 34)) @filter(ge(name, "user")) { uid friend { uid @@ -283,18 +353,103 @@ upsert { } } } + + mutation @if( ( eq(len(m), 1) + OR + lt(90, len(h))) + AND + gt(len(f), 0)) { + set { + uid(m) "45" . + uid(f) "45" . + } + } } ` _, err := ParseMutation(query) require.Nil(t, err) } -func TestUpsertWithFilter(t *testing.T) { +func TestConditionalUpsertMultipleFuncArg(t *testing.T) { + query := ` +upsert { + query { + me(func: eq(age, 34)) @filter(ge(name, "user")) { + uid + friend { + uid + age + } + } + } + + mutation @if( ( eq(len(m), len(t)) + OR + lt(90, len(h))) + AND + gt(len(f), 0)) { + set { + uid(m) "45" . + uid(f) "45" . + } + } +} +` + _, err := ParseMutation(query) + require.Nil(t, err) +} + +func TestConditionalUpsertErrMissingRightRound(t *testing.T) { + query := ` +upsert { + query { + me(func: eq(age, 34)) @filter(ge(name, "user")) { + uid + friend { + uid + age + } + } + } + + mutation @if(eq(len(m, 1) + AND + gt(len(f), 0)) { + set { + uid(m) "45" . + uid(f) "45" . + } + } +} +` + _, err := ParseMutation(query) + require.Contains(t, err.Error(), "Matching brackets not found") +} + +func TestConditionalUpsertErrUnclosed(t *testing.T) { query := `upsert { - mutation { + mutation @if(eq(len(m), 1) AND gt(len(f), 0))` + _, err := ParseMutation(query) + require.Contains(t, err.Error(), "Unclosed mutation action") +} + +func TestConditionalUpsertErrInvalidIf(t *testing.T) { + query := `upsert { + mutation @if` + _, err := ParseMutation(query) + require.Contains(t, err.Error(), "Matching brackets not found") +} + +func TestConditionalUpsertErrWrongIf(t *testing.T) { + query := `upsert { + mutation @fi( ( eq(len(m), 1) + OR + lt(len(h), 90)) + AND + gt(len(f), 0)) { set { - uid(a) "45" - uid(b) "45" . + uid(m) "45" . + uid(f) "45" . } } @@ -310,5 +465,5 @@ func TestUpsertWithFilter(t *testing.T) { } ` _, err := ParseMutation(query) - require.Nil(t, err) + require.Contains(t, err.Error(), "Expected @if, found [@fi]") }