diff --git a/dgraph/cmd/alpha/http_test.go b/dgraph/cmd/alpha/http_test.go index 686b99c20e8..33a00ffd755 100644 --- a/dgraph/cmd/alpha/http_test.go +++ b/dgraph/cmd/alpha/http_test.go @@ -428,7 +428,7 @@ func TestTransactionBasic(t *testing.T) { require.Equal(t, 2, len(mr.preds)) var parsedPreds []string for _, pred := range mr.preds { - p := strings.Split(pred, "-")[1] + p := strings.SplitN(pred, "-", 2)[1] parsedPreds = append(parsedPreds, x.ParseAttr(p)) } sort.Strings(parsedPreds) diff --git a/dgraph/cmd/alpha/upsert_test.go b/dgraph/cmd/alpha/upsert_test.go index 28d756a1c5e..3ead1e35a49 100644 --- a/dgraph/cmd/alpha/upsert_test.go +++ b/dgraph/cmd/alpha/upsert_test.go @@ -39,7 +39,7 @@ type QueryResult struct { func splitPreds(ps []string) []string { for i, p := range ps { - ps[i] = x.ParseAttr(strings.Split(p, "-")[1]) + ps[i] = x.ParseAttr(strings.SplitN(p, "-", 2)[1]) } return ps diff --git a/dgraph/cmd/zero/oracle.go b/dgraph/cmd/zero/oracle.go index 43f633e3150..de1f169f194 100644 --- a/dgraph/cmd/zero/oracle.go +++ b/dgraph/cmd/zero/oracle.go @@ -370,7 +370,7 @@ func (s *Server) commit(ctx context.Context, src *api.TxnContext) error { checkPreds := func() error { // Check if any of these tablets is being moved. If so, abort the transaction. for _, pkey := range src.Preds { - splits := strings.Split(pkey, "-") + splits := strings.SplitN(pkey, "-", 2) if len(splits) < 2 { return errors.Errorf("Unable to find group id in %s", pkey) } @@ -378,7 +378,7 @@ func (s *Server) commit(ctx context.Context, src *api.TxnContext) error { if err != nil { return errors.Wrapf(err, "unable to parse group id from %s", pkey) } - pred := strings.Join(splits[1:], "-") + pred := splits[1] tablet := s.ServingTablet(pred) if tablet == nil { return errors.Errorf("Tablet for %s is nil", pred) diff --git a/edgraph/server.go b/edgraph/server.go index 31e6a14827b..54a533bac40 100644 --- a/edgraph/server.go +++ b/edgraph/server.go @@ -1061,16 +1061,7 @@ func filterTablets(ctx context.Context, ms *pb.MembershipState) error { return errors.Errorf("Namespace not found in JWT.") } if namespace == x.GalaxyNamespace { - // For galaxy namespace, we don't want to filter out the predicates. We only format the - // namespace to human readable form. - for _, group := range ms.Groups { - tablets := make(map[string]*pb.Tablet) - for tabletName, tablet := range group.Tablets { - tablet.Predicate = x.FormatNsAttr(tablet.Predicate) - tablets[x.FormatNsAttr(tabletName)] = tablet - } - group.Tablets = tablets - } + // For galaxy namespace, we don't want to filter out the predicates. return nil } for _, group := range ms.GetGroups() { diff --git a/posting/index.go b/posting/index.go index ee310b5d30f..26388178179 100644 --- a/posting/index.go +++ b/posting/index.go @@ -592,7 +592,7 @@ func (r *rebuilder) Run(ctx context.Context) error { glog.V(1).Infof( "Rebuilding index for predicate %s: Starting process. StartTs=%d. Prefix=\n%s\n", - x.FormatNsAttr(r.attr), r.startTs, hex.Dump(r.prefix)) + r.attr, r.startTs, hex.Dump(r.prefix)) // Counter is used here to ensure that all keys are committed at different timestamp. // We set it to 1 in case there are no keys found and NewStreamAt is called with ts=0. @@ -600,8 +600,7 @@ func (r *rebuilder) Run(ctx context.Context) error { tmpWriter := tmpDB.NewManagedWriteBatch() stream := pstore.NewStreamAt(r.startTs) - stream.LogPrefix = fmt.Sprintf("Rebuilding index for predicate %s (1/2):", - x.FormatNsAttr(r.attr)) + stream.LogPrefix = fmt.Sprintf("Rebuilding index for predicate %s (1/2):", r.attr) stream.Prefix = r.prefix stream.KeyToList = func(key []byte, itr *badger.Iterator) (*bpb.KVList, error) { // We should return quickly if the context is no longer valid. @@ -663,21 +662,19 @@ func (r *rebuilder) Run(ctx context.Context) error { return err } glog.V(1).Infof("Rebuilding index for predicate %s: building temp index took: %v\n", - x.FormatNsAttr(r.attr), time.Since(start)) + r.attr, time.Since(start)) // Now we write all the created posting lists to disk. - glog.V(1).Infof("Rebuilding index for predicate %s: writing index to badger", - x.FormatNsAttr(r.attr)) + glog.V(1).Infof("Rebuilding index for predicate %s: writing index to badger", r.attr) start = time.Now() defer func() { glog.V(1).Infof("Rebuilding index for predicate %s: writing index took: %v\n", - x.FormatNsAttr(r.attr), time.Since(start)) + r.attr, time.Since(start)) }() writer := pstore.NewManagedWriteBatch() tmpStream := tmpDB.NewStreamAt(counter) - tmpStream.LogPrefix = fmt.Sprintf("Rebuilding index for predicate %s (2/2):", - x.FormatNsAttr(r.attr)) + tmpStream.LogPrefix = fmt.Sprintf("Rebuilding index for predicate %s (2/2):", r.attr) tmpStream.KeyToList = func(key []byte, itr *badger.Iterator) (*bpb.KVList, error) { l, err := ReadPostingList(key, itr) if err != nil { @@ -720,8 +717,7 @@ func (r *rebuilder) Run(ctx context.Context) error { if err := tmpStream.Orchestrate(ctx); err != nil { return err } - glog.V(1).Infof("Rebuilding index for predicate %s: Flushing all writes.\n", - x.FormatNsAttr(r.attr)) + glog.V(1).Infof("Rebuilding index for predicate %s: Flushing all writes.\n", r.attr) return writer.Flush() } diff --git a/posting/list_test.go b/posting/list_test.go index 5decc303572..a727ed7067a 100644 --- a/posting/list_test.go +++ b/posting/list_test.go @@ -559,7 +559,7 @@ func TestAddMutation_mrjn2(t *testing.T) { } func TestAddMutation_gru(t *testing.T) { - key := x.DataKey("question.tag", 0x01) + key := x.DataKey(x.GalaxyAttr("question.tag"), 0x01) ol, err := getNew(key, ps, math.MaxUint64) require.NoError(t, err) @@ -592,7 +592,7 @@ func TestAddMutation_gru(t *testing.T) { } func TestAddMutation_gru2(t *testing.T) { - key := x.DataKey("question.tag", 0x100) + key := x.DataKey(x.GalaxyAttr("question.tag"), 0x100) ol, err := getNew(key, ps, math.MaxUint64) require.NoError(t, err) @@ -639,7 +639,7 @@ func TestAddMutation_gru2(t *testing.T) { func TestAddAndDelMutation(t *testing.T) { // Ensure each test uses unique key since we don't clear the postings // after each test - key := x.DataKey("dummy_key", 0x927) + key := x.DataKey(x.GalaxyAttr("dummy_key"), 0x927) ol, err := getNew(key, ps, math.MaxUint64) require.NoError(t, err) @@ -878,7 +878,7 @@ func createMultiPartList(t *testing.T, size int, addFacet bool) (*List, int) { defer setMaxListSize(maxListSize) maxListSize = 5000 - key := x.DataKey(uuid.New().String(), 1331) + key := x.DataKey(x.GalaxyAttr(uuid.New().String()), 1331) ol, err := getNew(key, ps, math.MaxUint64) require.NoError(t, err) commits := 0 @@ -926,7 +926,7 @@ func createAndDeleteMultiPartList(t *testing.T, size int) (*List, int) { defer setMaxListSize(maxListSize) maxListSize = 10000 - key := x.DataKey(uuid.New().String(), 1331) + key := x.DataKey(x.GalaxyAttr(uuid.New().String()), 1331) ol, err := getNew(key, ps, math.MaxUint64) require.NoError(t, err) commits := 0 @@ -1087,7 +1087,7 @@ func TestBinSplit(t *testing.T) { defer func() { maxListSize = originalListSize }() - key := x.DataKey(uuid.New().String(), 1331) + key := x.DataKey(x.GalaxyAttr(uuid.New().String()), 1331) ol, err := getNew(key, ps, math.MaxUint64) require.NoError(t, err) for i := 1; i <= size; i++ { @@ -1268,7 +1268,7 @@ func TestMultiPartListDeleteAndAdd(t *testing.T) { maxListSize = 5000 // Add entries to the maps. - key := x.DataKey(uuid.New().String(), 1331) + key := x.DataKey(x.GalaxyAttr(uuid.New().String()), 1331) ol, err := getNew(key, ps, math.MaxUint64) require.NoError(t, err) for i := 1; i <= size; i++ { @@ -1407,7 +1407,7 @@ func TestRecursiveSplits(t *testing.T) { // Create a list that should be split recursively. size := int(1e5) - key := x.DataKey(uuid.New().String(), 1331) + key := x.DataKey(x.GalaxyAttr(uuid.New().String()), 1331) ol, err := getNew(key, ps, math.MaxUint64) require.NoError(t, err) commits := 0 diff --git a/worker/groups.go b/worker/groups.go index 378029bfec8..a8a0b043513 100644 --- a/worker/groups.go +++ b/worker/groups.go @@ -487,7 +487,7 @@ func (g *groupi) sendTablet(tablet *pb.Tablet) (*pb.Tablet, error) { } if out.GroupId == groups().groupId() { - glog.Infof("Serving tablet for: %v\n", x.FormatNsAttr(tablet.GetPredicate())) + glog.Infof("Serving tablet for: %v\n", tablet.GetPredicate()) } return out, nil } @@ -534,7 +534,7 @@ func (g *groupi) Inform(preds []string) ([]*pb.Tablet, error) { } if t.GroupId == groups().groupId() { - glog.Infof("Serving tablet for: %v\n", x.FormatNsAttr(t.GetPredicate())) + glog.Infof("Serving tablet for: %v\n", t.GetPredicate()) } } g.Unlock() diff --git a/x/keys.go b/x/keys.go index 1b1bf078ba1..86d3a9322c4 100644 --- a/x/keys.go +++ b/x/keys.go @@ -57,6 +57,8 @@ const ( IgnoreBytes = "1-8" // NamespaceOffset is the offset in badger key from which the next 8 bytes contain namespace. NamespaceOffset = 1 + // NsSeparator is the separator between between the namespace and attribute. + NsSeparator = "-" ) func NamespaceToBytes(ns uint64) []byte { @@ -67,7 +69,7 @@ func NamespaceToBytes(ns uint64) []byte { // NamespaceAttr is used to generate attr from namespace. func NamespaceAttr(ns uint64, attr string) string { - return string(NamespaceToBytes(ns)) + attr + return uintToStr(ns) + NsSeparator + attr } func NamespaceAttrList(ns uint64, preds []string) []string { @@ -84,21 +86,25 @@ func GalaxyAttr(attr string) string { // ParseNamespaceAttr returns the namespace and attr from the given value. func ParseNamespaceAttr(attr string) (uint64, string) { - return binary.BigEndian.Uint64([]byte(attr[:8])), attr[8:] + splits := strings.SplitN(attr, NsSeparator, 2) + return strToUint(splits[0]), splits[1] } func ParseNamespaceBytes(attr string) ([]byte, string) { - return []byte(attr[:8]), attr[8:] + splits := strings.SplitN(attr, NsSeparator, 2) + ns := make([]byte, 8) + binary.BigEndian.PutUint64(ns, strToUint(splits[0])) + return ns, splits[1] } // ParseAttr returns the attr from the given value. func ParseAttr(attr string) string { - return attr[8:] + return strings.SplitN(attr, NsSeparator, 2)[1] } // ParseNamespace returns the namespace from the given value. func ParseNamespace(attr string) uint64 { - return binary.BigEndian.Uint64([]byte(attr[:8])) + return strToUint(strings.SplitN(attr, NsSeparator, 2)[0]) } func ParseAttrList(attrs []string) []string { @@ -109,13 +115,19 @@ func ParseAttrList(attrs []string) []string { return resp } -func IsReverseAttr(attr string) bool { - return attr[8] == '~' +// For consistency, use base16 to encode/decode the namespace. +func strToUint(s string) uint64 { + ns, err := strconv.ParseUint(s, 16, 64) + Check(err) + return ns +} +func uintToStr(ns uint64) string { + return strconv.FormatUint(ns, 16) } -func FormatNsAttr(attr string) string { - ns, attr := ParseNamespaceAttr(attr) - return strconv.FormatUint(ns, 10) + "-" + attr +func IsReverseAttr(attr string) bool { + pred := strings.SplitN(attr, NsSeparator, 2)[1] + return pred[0] == '~' } func ExtractNamespaceFromPredicate(predicate string) (uint64, error) { @@ -143,19 +155,18 @@ func writeAttr(buf []byte, attr string) []byte { // genKey creates the key and writes the initial bytes (type byte, length of attribute, // and the attribute itself). It leaves the rest of the key empty for further processing -// if necessary. -func generateKey(typeByte byte, attr string, totalLen int) []byte { - AssertTrue(totalLen >= 1+2+len(attr)) - - buf := make([]byte, totalLen) - buf[0] = typeByte +// if necessary. It also returns next index from where further processing should be done. +func generateKey(typeByte byte, attr string, extra int) ([]byte, int) { // Separate namespace and attribute from attr and write namespace in the first 8 bytes of key. namespace, attr := ParseNamespaceBytes(attr) + prefixLen := 1 + 8 + 2 + len(attr) // byteType + ns + len(pred) + pred + buf := make([]byte, prefixLen+extra) + buf[0] = typeByte AssertTrue(copy(buf[1:], namespace) == 8) rest := buf[9:] writeAttr(rest, attr) - return buf + return buf, prefixLen } // SchemaKey returns schema key for given attribute. Schema keys are stored @@ -166,7 +177,8 @@ func generateKey(typeByte byte, attr string, totalLen int) []byte { // byte 1-2: length of attr // next len(attr) bytes: value of attr func SchemaKey(attr string) []byte { - return generateKey(ByteSchema, attr, 1+2+len(attr)) + key, _ := generateKey(ByteSchema, attr, 0) + return key } // TypeKey returns type key for given type name. Type keys are stored separately @@ -177,7 +189,8 @@ func SchemaKey(attr string) []byte { // byte 1-2: length of typeName // next len(attr) bytes: value of attr (the type name) func TypeKey(attr string) []byte { - return generateKey(ByteType, attr, 1+2+len(attr)) + key, _ := generateKey(ByteType, attr, 0) + return key } // DataKey generates a data key with the given attribute and UID. @@ -191,9 +204,8 @@ func TypeKey(attr string) []byte { // next eight bytes (optional): if the key corresponds to a split list, the startUid of // the split stored in this key and the first byte will be sets to ByteSplit. func DataKey(attr string, uid uint64) []byte { - prefixLen := 1 + 2 + len(attr) - totalLen := prefixLen + 1 + 8 - buf := generateKey(DefaultPrefix, attr, totalLen) + extra := 1 + 8 // ByteData + UID + buf, prefixLen := generateKey(DefaultPrefix, attr, extra) rest := buf[prefixLen:] rest[0] = ByteData @@ -214,9 +226,8 @@ func DataKey(attr string, uid uint64) []byte { // next eight bytes (optional): if the key corresponds to a split list, the startUid of // the split stored in this key. func ReverseKey(attr string, uid uint64) []byte { - prefixLen := 1 + 2 + len(attr) - totalLen := prefixLen + 1 + 8 - buf := generateKey(DefaultPrefix, attr, totalLen) + extra := 1 + 8 // ByteReverse + UID + buf, prefixLen := generateKey(DefaultPrefix, attr, extra) rest := buf[prefixLen:] rest[0] = ByteReverse @@ -237,9 +248,8 @@ func ReverseKey(attr string, uid uint64) []byte { // next eight bytes (optional): if the key corresponds to a split list, the startUid of // the split stored in this key. func IndexKey(attr, term string) []byte { - prefixLen := 1 + 2 + len(attr) - totalLen := prefixLen + 1 + len(term) - buf := generateKey(DefaultPrefix, attr, totalLen) + extra := 1 + len(term) // ByteIndex + term + buf, prefixLen := generateKey(DefaultPrefix, attr, extra) rest := buf[prefixLen:] rest[0] = ByteIndex @@ -259,9 +269,8 @@ func IndexKey(attr, term string) []byte { // next byte: data type prefix (set to ByteCount or ByteCountRev) // next four bytes: value of count. func CountKey(attr string, count uint32, reverse bool) []byte { - prefixLen := 1 + 2 + len(attr) - totalLen := prefixLen + 1 + 4 - buf := generateKey(DefaultPrefix, attr, totalLen) + extra := 1 + 4 // ByteCount + Count + buf, prefixLen := generateKey(DefaultPrefix, attr, extra) rest := buf[prefixLen:] if reverse { @@ -346,14 +355,9 @@ func (p ParsedKey) IsOfType(typ byte) bool { // SkipPredicate returns the first key after the keys corresponding to the predicate // of this key. Useful when iterating in the reverse order. func (p ParsedKey) SkipPredicate() []byte { - buf := make([]byte, 1+2+len(p.Attr)+1) - buf[0] = p.bytePrefix - ns, attr := ParseNamespaceBytes(p.Attr) - AssertTrue(copy(buf[1:], ns) == 8) - rest := buf[9:] - k := writeAttr(rest, attr) - AssertTrue(len(k) == 1) - k[0] = 0xFF + buf, prefixLen := generateKey(p.bytePrefix, p.Attr, 1) + AssertTrue(len(buf[prefixLen:]) == 1) + buf[prefixLen] = 0xFF return buf } @@ -374,56 +378,33 @@ func (p ParsedKey) SkipType() []byte { // DataPrefix returns the prefix for data keys. func (p ParsedKey) DataPrefix() []byte { - buf := make([]byte, 1+2+len(p.Attr)+1) - buf[0] = p.bytePrefix - ns, attr := ParseNamespaceBytes(p.Attr) - AssertTrue(copy(buf[1:], ns) == 8) - rest := buf[9:] - k := writeAttr(rest, attr) - AssertTrue(len(k) == 1) - k[0] = ByteData + buf, prefixLen := generateKey(p.bytePrefix, p.Attr, 1) + buf[prefixLen] = ByteData return buf } // IndexPrefix returns the prefix for index keys. func (p ParsedKey) IndexPrefix() []byte { - buf := make([]byte, 1+2+len(p.Attr)+1) - buf[0] = DefaultPrefix - ns, attr := ParseNamespaceBytes(p.Attr) - AssertTrue(copy(buf[1:], ns) == 8) - rest := buf[9:] - k := writeAttr(rest, attr) - AssertTrue(len(k) == 1) - k[0] = ByteIndex + buf, prefixLen := generateKey(DefaultPrefix, p.Attr, 1) + buf[prefixLen] = ByteIndex return buf } // ReversePrefix returns the prefix for index keys. func (p ParsedKey) ReversePrefix() []byte { - buf := make([]byte, 1+2+len(p.Attr)+1) - buf[0] = DefaultPrefix - ns, attr := ParseNamespaceBytes(p.Attr) - AssertTrue(copy(buf[1:], ns) == 8) - rest := buf[9:] - k := writeAttr(rest, attr) - AssertTrue(len(k) == 1) - k[0] = ByteReverse + buf, prefixLen := generateKey(DefaultPrefix, p.Attr, 1) + buf[prefixLen] = ByteReverse return buf } // CountPrefix returns the prefix for count keys. func (p ParsedKey) CountPrefix(reverse bool) []byte { - buf := make([]byte, 1+2+len(p.Attr)+1) - buf[0] = p.bytePrefix - ns, attr := ParseNamespaceBytes(p.Attr) - AssertTrue(copy(buf[1:], ns) == 8) - rest := buf[9:] - k := writeAttr(rest, attr) - AssertTrue(len(k) == 1) + buf, prefixLen := generateKey(DefaultPrefix, p.Attr, 1) + buf[prefixLen] = ByteReverse if reverse { - k[0] = ByteCountRev + buf[prefixLen] = ByteCountRev } else { - k[0] = ByteCount + buf[prefixLen] = ByteCount } return buf } @@ -509,12 +490,8 @@ func TypePrefix() []byte { // PredicatePrefix returns the prefix for all keys belonging to this predicate except schema key. func PredicatePrefix(predicate string) []byte { - buf := make([]byte, 1+2+len(predicate)) - buf[0] = DefaultPrefix - ns, predicate := ParseNamespaceBytes(predicate) - AssertTrue(copy(buf[1:], ns) == 8) - k := writeAttr(buf[9:], predicate) - AssertTrue(len(k) == 0) + buf, prefixLen := generateKey(DefaultPrefix, predicate, 0) + AssertTrue(len(buf) == prefixLen) return buf } @@ -569,7 +546,7 @@ func Parse(key []byte) (ParsedKey, error) { if len(k) < sz { return p, errors.Errorf("Invalid size %v for key %v", sz, key) } - p.Attr = string(namespace) + string(k[:sz]) + p.Attr = NamespaceAttr(binary.BigEndian.Uint64(namespace), string(k[:sz])) k = k[sz:] switch p.bytePrefix { diff --git a/x/keys_test.go b/x/keys_test.go index e77d071be24..bfb1e58c90e 100644 --- a/x/keys_test.go +++ b/x/keys_test.go @@ -17,6 +17,7 @@ package x import ( + "encoding/json" "fmt" "math" "sort" @@ -29,8 +30,8 @@ func TestNameSpace(t *testing.T) { ns := uint64(133) attr := "name" nsAttr := NamespaceAttr(ns, attr) - require.Equal(t, 8+len(attr), len(nsAttr)) - parsedAttr := ParseAttr(nsAttr) + parsedNs, parsedAttr := ParseNamespaceAttr(nsAttr) + require.Equal(t, ns, parsedNs) require.Equal(t, attr, parsedAttr) } @@ -39,7 +40,7 @@ func TestDataKey(t *testing.T) { // key with uid = 0 is invalid uid = 0 - key := DataKey(NamespaceAttr(GalaxyNamespace, "bad uid"), uid) + key := DataKey(GalaxyAttr("bad uid"), uid) _, err := Parse(key) require.Error(t, err) @@ -47,7 +48,7 @@ func TestDataKey(t *testing.T) { // Use the uid to derive the attribute so it has variable length and the test // can verify that multiple sizes of attr work correctly. sattr := fmt.Sprintf("attr:%d", uid) - key := DataKey(NamespaceAttr(GalaxyNamespace, sattr), uid) + key := DataKey(GalaxyAttr(sattr), uid) pk, err := Parse(key) require.NoError(t, err) @@ -59,14 +60,14 @@ func TestDataKey(t *testing.T) { keys := make([]string, 0, 1024) for uid = 1024; uid >= 1; uid-- { - key := DataKey(NamespaceAttr(GalaxyNamespace, "testing.key"), uid) + key := DataKey(GalaxyAttr("testing.key"), uid) keys = append(keys, string(key)) } // Test that sorting is as expected. sort.Strings(keys) require.True(t, sort.StringsAreSorted(keys)) for i, key := range keys { - exp := DataKey(NamespaceAttr(GalaxyNamespace, "testing.key"), uint64(i+1)) + exp := DataKey(GalaxyAttr("testing.key"), uint64(i+1)) require.Equal(t, string(exp), key) } } @@ -76,7 +77,7 @@ func TestParseDataKeyWithStartUid(t *testing.T) { startUid := uint64(math.MaxUint64) for uid = 1; uid < 1001; uid++ { sattr := fmt.Sprintf("attr:%d", uid) - key := DataKey(NamespaceAttr(GalaxyNamespace, sattr), uid) + key := DataKey(GalaxyAttr(sattr), uid) key, err := SplitKey(key, startUid) require.NoError(t, err) pk, err := Parse(key) @@ -96,7 +97,7 @@ func TestIndexKey(t *testing.T) { sattr := fmt.Sprintf("attr:%d", uid) sterm := fmt.Sprintf("term:%d", uid) - key := IndexKey(NamespaceAttr(GalaxyNamespace, sattr), sterm) + key := IndexKey(GalaxyAttr(sattr), sterm) pk, err := Parse(key) require.NoError(t, err) @@ -113,7 +114,7 @@ func TestIndexKeyWithStartUid(t *testing.T) { sattr := fmt.Sprintf("attr:%d", uid) sterm := fmt.Sprintf("term:%d", uid) - key := IndexKey(NamespaceAttr(GalaxyNamespace, sattr), sterm) + key := IndexKey(GalaxyAttr(sattr), sterm) key, err := SplitKey(key, startUid) require.NoError(t, err) pk, err := Parse(key) @@ -132,7 +133,7 @@ func TestReverseKey(t *testing.T) { for uid = 1; uid < 1001; uid++ { sattr := fmt.Sprintf("attr:%d", uid) - key := ReverseKey(NamespaceAttr(GalaxyNamespace, sattr), uid) + key := ReverseKey(GalaxyAttr(sattr), uid) pk, err := Parse(key) require.NoError(t, err) @@ -148,7 +149,7 @@ func TestReverseKeyWithStartUid(t *testing.T) { for uid = 1; uid < 1001; uid++ { sattr := fmt.Sprintf("attr:%d", uid) - key := ReverseKey(NamespaceAttr(GalaxyNamespace, sattr), uid) + key := ReverseKey(GalaxyAttr(sattr), uid) key, err := SplitKey(key, startUid) require.NoError(t, err) pk, err := Parse(key) @@ -167,7 +168,7 @@ func TestCountKey(t *testing.T) { for count = 0; count < 1001; count++ { sattr := fmt.Sprintf("attr:%d", count) - key := CountKey(NamespaceAttr(GalaxyNamespace, sattr), count, true) + key := CountKey(GalaxyAttr(sattr), count, true) pk, err := Parse(key) require.NoError(t, err) @@ -183,7 +184,7 @@ func TestCountKeyWithStartUid(t *testing.T) { for count = 0; count < 1001; count++ { sattr := fmt.Sprintf("attr:%d", count) - key := CountKey(NamespaceAttr(GalaxyNamespace, sattr), count, true) + key := CountKey(GalaxyAttr(sattr), count, true) key, err := SplitKey(key, startUid) require.NoError(t, err) pk, err := Parse(key) @@ -202,7 +203,7 @@ func TestSchemaKey(t *testing.T) { for uid = 0; uid < 1001; uid++ { sattr := fmt.Sprintf("attr:%d", uid) - key := SchemaKey(NamespaceAttr(GalaxyNamespace, sattr)) + key := SchemaKey(GalaxyAttr(sattr)) pk, err := Parse(key) require.NoError(t, err) @@ -216,7 +217,7 @@ func TestTypeKey(t *testing.T) { for uid = 0; uid < 1001; uid++ { sattr := fmt.Sprintf("attr:%d", uid) - key := TypeKey(NamespaceAttr(GalaxyNamespace, sattr)) + key := TypeKey(GalaxyAttr(sattr)) pk, err := Parse(key) require.NoError(t, err) @@ -236,16 +237,16 @@ func TestBadStartUid(t *testing.T) { require.Error(t, err) } - key := DataKey(NamespaceAttr(GalaxyNamespace, "aa"), 1) + key := DataKey(GalaxyAttr("aa"), 1) testKey(key) - key = ReverseKey(NamespaceAttr(GalaxyNamespace, "aa"), 1) + key = ReverseKey(GalaxyAttr("aa"), 1) testKey(key) - key = CountKey(NamespaceAttr(GalaxyNamespace, "aa"), 0, false) + key = CountKey(GalaxyAttr("aa"), 0, false) testKey(key) - key = CountKey(NamespaceAttr(GalaxyNamespace, "aa"), 0, true) + key = CountKey(GalaxyAttr("aa"), 0, true) testKey(key) } @@ -271,7 +272,35 @@ func TestBadKeys(t *testing.T) { // key with uid = 0 is invalid uid := 0 - key = DataKey(NamespaceAttr(GalaxyNamespace, "bad uid"), uint64(uid)) + key = DataKey(GalaxyAttr("bad uid"), uint64(uid)) _, err = Parse(key) require.Error(t, err) } + +func TestJsonMarshal(t *testing.T) { + type predicate struct { + Predicate string `json:"predicate,omitempty"` + } + + p := &predicate{Predicate: NamespaceAttr(129, "name")} + b, err := json.Marshal(p) + require.NoError(t, err) + + var p2 predicate + require.NoError(t, json.Unmarshal(b, &p2)) + ns, attr := ParseNamespaceAttr(p2.Predicate) + require.Equal(t, uint64(129), ns) + require.Equal(t, "name", attr) +} + +func TestNsSeparator(t *testing.T) { + uid := uint64(10) + pred := "name" + NsSeparator + "surname" + key := DataKey(GalaxyAttr(pred), uid) + pk, err := Parse(key) + require.NoError(t, err) + require.Equal(t, uid, pk.Uid) + ns, attr := ParseNamespaceAttr(pk.Attr) + require.Equal(t, GalaxyNamespace, ns) + require.Equal(t, pred, attr) +}