Add set indexing for paths (#1922)

This commit is contained in:
Ben Kalman
2016-06-28 10:03:00 -07:00
committed by GitHub
parent 55e067802d
commit 54970c34f0
2 changed files with 46 additions and 26 deletions

View File

@@ -180,22 +180,30 @@ func newHashIndexPart(h hash.Hash) hashIndexPart {
}
func (hip hashIndexPart) Resolve(v Value) (res Value) {
m, ok := v.(Map)
if !ok {
var seq orderedSequence
var getCurrentValue func(cur *sequenceCursor) Value
switch v := v.(type) {
case Set:
seq = v.seq
getCurrentValue = func(cur *sequenceCursor) Value { return cur.current().(Value) }
case Map:
seq = v.seq
getCurrentValue = func(cur *sequenceCursor) Value { return cur.current().(mapEntry).value }
default:
return nil
}
cur := newCursorAt(m.seq, orderedKeyFromHash(hip.h), false, false)
cur := newCursorAt(seq, orderedKeyFromHash(hip.h), false, false)
if !cur.valid() {
return nil
}
entry := cur.current().(mapEntry)
if entry.key.Hash() != hip.h {
if getCurrentKey(cur).h != hip.h {
return nil
}
return entry.value
return getCurrentValue(cur)
}
func (hip hashIndexPart) String() string {

View File

@@ -94,48 +94,60 @@ func TestPathHashIndex(t *testing.T) {
b := Bool(true)
br := NewRef(b)
i := Number(0)
s := String("foo")
l := NewList(b, i, s)
str := String("foo")
l := NewList(b, i, str)
lr := NewRef(l)
m := NewMap(
b, br,
br, i,
i, s,
i, str,
l, lr,
lr, b,
)
s := NewSet(b, br, i, str, l, lr)
hashStr := func(v Value) string {
return fmt.Sprintf("[#%s]", v.Hash())
}
resolvesTo := func(col, exp, val Value) {
assertPathResolvesTo(assert, exp, col, NewPath().AddHashIndex(val.Hash()))
assertPathStringResolvesTo(assert, exp, col, hashStr(val))
}
// Primitives are only addressable by their values.
assertPathResolvesTo(assert, nil, m, NewPath().AddHashIndex(b.Hash()))
assertPathStringResolvesTo(assert, nil, m, hashStr(b))
assertPathResolvesTo(assert, nil, m, NewPath().AddHashIndex(i.Hash()))
assertPathStringResolvesTo(assert, nil, m, hashStr(i))
assertPathResolvesTo(assert, nil, m, NewPath().AddHashIndex(s.Hash()))
assertPathStringResolvesTo(assert, nil, m, hashStr(s))
resolvesTo(m, nil, b)
resolvesTo(m, nil, i)
resolvesTo(m, nil, str)
resolvesTo(s, nil, b)
resolvesTo(s, nil, i)
resolvesTo(s, nil, str)
// Other values are only addressable by their hashes.
assertPathResolvesTo(assert, i, m, NewPath().AddHashIndex(br.Hash()))
assertPathStringResolvesTo(assert, i, m, hashStr(br))
assertPathResolvesTo(assert, lr, m, NewPath().AddHashIndex(l.Hash()))
assertPathStringResolvesTo(assert, lr, m, hashStr(l))
assertPathResolvesTo(assert, b, m, NewPath().AddHashIndex(lr.Hash()))
assertPathStringResolvesTo(assert, b, m, hashStr(lr))
resolvesTo(m, i, br)
resolvesTo(m, lr, l)
resolvesTo(m, b, lr)
resolvesTo(s, br, br)
resolvesTo(s, l, l)
resolvesTo(s, lr, lr)
// Lists cannot be addressed by hashes, obviously.
assertPathResolvesTo(assert, nil, l, NewPath().AddHashIndex(i.Hash()))
assertPathStringResolvesTo(assert, nil, l, hashStr(i))
resolvesTo(l, nil, i)
}
func TestPathHashIndexOfSingletonMap(t *testing.T) {
func TestPathHashIndexOfSingletonCollection(t *testing.T) {
// This test is to make sure we don't accidentally return |b| if it's the only element.
assert := assert.New(t)
resolvesToNil := func(col, val Value) {
assertPathResolvesTo(assert, nil, col, NewPath().AddHashIndex(val.Hash()))
assertPathStringResolvesTo(assert, nil, col, fmt.Sprintf("[#%s]", val.Hash()))
}
b := Bool(true)
m := NewMap(b, b)
assertPathResolvesTo(assert, nil, m, NewPath().AddHashIndex(b.Hash()))
resolvesToNil(NewMap(b, b), b)
resolvesToNil(NewSet(b), b)
}
func TestPathMulti(t *testing.T) {