Merge pull request #262 from neonstalwart/string-comparison-iterator
add string comparison to value comparison iterator
This commit is contained in:
commit
13640290ce
3 changed files with 148 additions and 13 deletions
|
|
@ -47,11 +47,18 @@ func (qs *store) NodesAllIterator() graph.Iterator { return &Null{} }
|
||||||
func (qs *store) QuadsAllIterator() graph.Iterator { return &Null{} }
|
func (qs *store) QuadsAllIterator() graph.Iterator { return &Null{} }
|
||||||
|
|
||||||
func (qs *store) NameOf(v graph.Value) string {
|
func (qs *store) NameOf(v graph.Value) string {
|
||||||
i := v.(int)
|
switch v.(type) {
|
||||||
if i < 0 || i >= len(qs.data) {
|
case int:
|
||||||
|
i := v.(int)
|
||||||
|
if i < 0 || i >= len(qs.data) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return qs.data[i]
|
||||||
|
case string:
|
||||||
|
return v.(string)
|
||||||
|
default:
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return qs.data[i]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (qs *store) Size() int64 { return 0 }
|
func (qs *store) Size() int64 { return 0 }
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,6 @@ func (it *Comparison) UID() uint64 {
|
||||||
// Here's the non-boilerplate part of the ValueComparison iterator. Given a value
|
// Here's the non-boilerplate part of the ValueComparison iterator. Given a value
|
||||||
// and our operator, determine whether or not we meet the requirement.
|
// and our operator, determine whether or not we meet the requirement.
|
||||||
func (it *Comparison) doComparison(val graph.Value) bool {
|
func (it *Comparison) doComparison(val graph.Value) bool {
|
||||||
//TODO(barakmich): Implement string comparison.
|
|
||||||
nodeStr := it.qs.NameOf(val)
|
nodeStr := it.qs.NameOf(val)
|
||||||
switch cVal := it.val.(type) {
|
switch cVal := it.val.(type) {
|
||||||
case int:
|
case int:
|
||||||
|
|
@ -86,6 +85,8 @@ func (it *Comparison) doComparison(val graph.Value) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return RunIntOp(intVal, it.op, cVal)
|
return RunIntOp(intVal, it.op, cVal)
|
||||||
|
case string:
|
||||||
|
return RunStrOp(nodeStr, it.op, cVal)
|
||||||
default:
|
default:
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
@ -110,6 +111,21 @@ func RunIntOp(a int64, op Operator, b int64) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RunStrOp(a string, op Operator, b string) bool {
|
||||||
|
switch op {
|
||||||
|
case compareLT:
|
||||||
|
return a < b
|
||||||
|
case compareLTE:
|
||||||
|
return a <= b
|
||||||
|
case compareGT:
|
||||||
|
return a > b
|
||||||
|
case compareGTE:
|
||||||
|
return a >= b
|
||||||
|
default:
|
||||||
|
panic("Unknown operator type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (it *Comparison) Reset() {
|
func (it *Comparison) Reset() {
|
||||||
it.subIt.Reset()
|
it.subIt.Reset()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var simpleStore = &store{data: []string{"0", "1", "2", "3", "4", "5"}}
|
var simpleStore = &store{data: []string{"0", "1", "2", "3", "4", "5"}}
|
||||||
|
var stringStore = &store{data: []string{"foo", "bar", "baz", "echo"}}
|
||||||
|
|
||||||
func simpleFixedIterator() *Fixed {
|
func simpleFixedIterator() *Fixed {
|
||||||
f := NewFixed(Identity)
|
f := NewFixed(Identity)
|
||||||
|
|
@ -32,42 +33,92 @@ func simpleFixedIterator() *Fixed {
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func stringFixedIterator() *Fixed {
|
||||||
|
f := NewFixed(Identity)
|
||||||
|
for _, value := range stringStore.data {
|
||||||
|
f.Add(value)
|
||||||
|
}
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
var comparisonTests = []struct {
|
var comparisonTests = []struct {
|
||||||
message string
|
message string
|
||||||
operand graph.Value
|
operand graph.Value
|
||||||
operator Operator
|
operator Operator
|
||||||
expect []string
|
expect []string
|
||||||
|
qs graph.QuadStore
|
||||||
|
iterator func() *Fixed
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
message: "successful int64 less than comparison",
|
message: "successful int64 less than comparison",
|
||||||
operand: int64(3),
|
operand: int64(3),
|
||||||
operator: compareLT,
|
operator: compareLT,
|
||||||
expect: []string{"0", "1", "2"},
|
expect: []string{"0", "1", "2"},
|
||||||
|
qs: simpleStore,
|
||||||
|
iterator: simpleFixedIterator,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
message: "empty int64 less than comparison",
|
message: "empty int64 less than comparison",
|
||||||
operand: int64(0),
|
operand: int64(0),
|
||||||
operator: compareLT,
|
operator: compareLT,
|
||||||
expect: nil,
|
expect: nil,
|
||||||
|
qs: simpleStore,
|
||||||
|
iterator: simpleFixedIterator,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
message: "successful int64 greater than comparison",
|
message: "successful int64 greater than comparison",
|
||||||
operand: int64(2),
|
operand: int64(2),
|
||||||
operator: compareGT,
|
operator: compareGT,
|
||||||
expect: []string{"3", "4"},
|
expect: []string{"3", "4"},
|
||||||
|
qs: simpleStore,
|
||||||
|
iterator: simpleFixedIterator,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
message: "successful int64 greater than or equal comparison",
|
message: "successful int64 greater than or equal comparison",
|
||||||
operand: int64(2),
|
operand: int64(2),
|
||||||
operator: compareGTE,
|
operator: compareGTE,
|
||||||
expect: []string{"2", "3", "4"},
|
expect: []string{"2", "3", "4"},
|
||||||
|
qs: simpleStore,
|
||||||
|
iterator: simpleFixedIterator,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
message: "successful string less than comparison",
|
||||||
|
operand: "echo",
|
||||||
|
operator: compareLT,
|
||||||
|
expect: []string{"bar", "baz"},
|
||||||
|
qs: stringStore,
|
||||||
|
iterator: stringFixedIterator,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
message: "empty string less than comparison",
|
||||||
|
operand: "",
|
||||||
|
operator: compareLT,
|
||||||
|
expect: nil,
|
||||||
|
qs: stringStore,
|
||||||
|
iterator: stringFixedIterator,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
message: "successful string greater than comparison",
|
||||||
|
operand: "echo",
|
||||||
|
operator: compareGT,
|
||||||
|
expect: []string{"foo"},
|
||||||
|
qs: stringStore,
|
||||||
|
iterator: stringFixedIterator,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
message: "successful string greater than or equal comparison",
|
||||||
|
operand: "echo",
|
||||||
|
operator: compareGTE,
|
||||||
|
expect: []string{"foo", "echo"},
|
||||||
|
qs: stringStore,
|
||||||
|
iterator: stringFixedIterator,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValueComparison(t *testing.T) {
|
func TestValueComparison(t *testing.T) {
|
||||||
for _, test := range comparisonTests {
|
for _, test := range comparisonTests {
|
||||||
qs := simpleStore
|
qs := test.qs
|
||||||
vc := NewComparison(simpleFixedIterator(), test.operator, test.operand, qs)
|
vc := NewComparison(test.iterator(), test.operator, test.operand, qs)
|
||||||
|
|
||||||
var got []string
|
var got []string
|
||||||
for vc.Next() {
|
for vc.Next() {
|
||||||
|
|
@ -84,52 +135,113 @@ var vciContainsTests = []struct {
|
||||||
operator Operator
|
operator Operator
|
||||||
check graph.Value
|
check graph.Value
|
||||||
expect bool
|
expect bool
|
||||||
|
qs graph.QuadStore
|
||||||
|
val graph.Value
|
||||||
|
iterator func() *Fixed
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
message: "1 is less than 2",
|
message: "1 is less than 2",
|
||||||
operator: compareGTE,
|
operator: compareGTE,
|
||||||
check: 1,
|
check: 1,
|
||||||
expect: false,
|
expect: false,
|
||||||
|
qs: simpleStore,
|
||||||
|
val: int64(2),
|
||||||
|
iterator: simpleFixedIterator,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
message: "2 is greater than or equal to 2",
|
message: "2 is greater than or equal to 2",
|
||||||
operator: compareGTE,
|
operator: compareGTE,
|
||||||
check: 2,
|
check: 2,
|
||||||
expect: true,
|
expect: true,
|
||||||
|
qs: simpleStore,
|
||||||
|
val: int64(2),
|
||||||
|
iterator: simpleFixedIterator,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
message: "3 is greater than or equal to 2",
|
message: "3 is greater than or equal to 2",
|
||||||
operator: compareGTE,
|
operator: compareGTE,
|
||||||
check: 3,
|
check: 3,
|
||||||
expect: true,
|
expect: true,
|
||||||
|
qs: simpleStore,
|
||||||
|
val: int64(2),
|
||||||
|
iterator: simpleFixedIterator,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
message: "5 is absent from iterator",
|
message: "5 is absent from iterator",
|
||||||
operator: compareGTE,
|
operator: compareGTE,
|
||||||
check: 5,
|
check: 5,
|
||||||
expect: false,
|
expect: false,
|
||||||
|
qs: simpleStore,
|
||||||
|
val: int64(2),
|
||||||
|
iterator: simpleFixedIterator,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
message: "foo is greater than or equal to echo",
|
||||||
|
operator: compareGTE,
|
||||||
|
check: "foo",
|
||||||
|
expect: true,
|
||||||
|
qs: stringStore,
|
||||||
|
val: "echo",
|
||||||
|
iterator: stringFixedIterator,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
message: "echo is greater than or equal to echo",
|
||||||
|
operator: compareGTE,
|
||||||
|
check: "echo",
|
||||||
|
expect: true,
|
||||||
|
qs: stringStore,
|
||||||
|
val: "echo",
|
||||||
|
iterator: stringFixedIterator,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
message: "foo is missing from the iterator",
|
||||||
|
operator: compareLTE,
|
||||||
|
check: "foo",
|
||||||
|
expect: false,
|
||||||
|
qs: stringStore,
|
||||||
|
val: "echo",
|
||||||
|
iterator: stringFixedIterator,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestVCIContains(t *testing.T) {
|
func TestVCIContains(t *testing.T) {
|
||||||
for _, test := range vciContainsTests {
|
for _, test := range vciContainsTests {
|
||||||
vc := NewComparison(simpleFixedIterator(), test.operator, int64(2), simpleStore)
|
vc := NewComparison(test.iterator(), test.operator, test.val, test.qs)
|
||||||
if vc.Contains(test.check) != test.expect {
|
if vc.Contains(test.check) != test.expect {
|
||||||
t.Errorf("Failed to show %s", test.message)
|
t.Errorf("Failed to show %s", test.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var comparisonIteratorTests = []struct {
|
||||||
|
message string
|
||||||
|
qs graph.QuadStore
|
||||||
|
val graph.Value
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
message: "2 is absent from iterator",
|
||||||
|
qs: simpleStore,
|
||||||
|
val: int64(2),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
message: "'missing' is absent from iterator",
|
||||||
|
qs: stringStore,
|
||||||
|
val: "missing",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
func TestComparisonIteratorErr(t *testing.T) {
|
func TestComparisonIteratorErr(t *testing.T) {
|
||||||
wantErr := errors.New("unique")
|
wantErr := errors.New("unique")
|
||||||
errIt := newTestIterator(false, wantErr)
|
errIt := newTestIterator(false, wantErr)
|
||||||
|
|
||||||
vc := NewComparison(errIt, compareLT, int64(2), simpleStore)
|
for _, test := range comparisonIteratorTests {
|
||||||
|
vc := NewComparison(errIt, compareLT, test.val, test.qs)
|
||||||
|
|
||||||
if vc.Next() != false {
|
if vc.Next() != false {
|
||||||
t.Errorf("Comparison iterator did not pass through initial 'false'")
|
t.Errorf("Comparison iterator did not pass through initial 'false': %s", test.message)
|
||||||
}
|
}
|
||||||
if vc.Err() != wantErr {
|
if vc.Err() != wantErr {
|
||||||
t.Errorf("Comparison iterator did not pass through underlying Err")
|
t.Errorf("Comparison iterator did not pass through underlying Err: %s", test.message)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue