Skip to content

Commit

Permalink
Add Filter with index wesovilabs#40
Browse files Browse the repository at this point in the history
  • Loading branch information
somen440 committed Feb 26, 2019
1 parent acab397 commit 85e57a3
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 42 deletions.
5 changes: 3 additions & 2 deletions internal/filter/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ func (c *cacheType) get(itemsType, funcType reflect.Type) *filterInfo {
}

type filterInfo struct {
fnValue reflect.Value
fnInputType reflect.Type
fnValue reflect.Value
fnIn1Type reflect.Type
fnIn2Type reflect.Type
}
8 changes: 5 additions & 3 deletions internal/filter/dispatcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,12 @@ var dispatcher = map[string]dispatchFunction{
}

func dispatch(items reflect.Value, function interface{}, info *filterInfo) (bool, reflect.Value) {
input := info.fnInputType.String()
input := info.fnIn1Type.String()
if fnVal, ok := dispatcher[input]; ok {
res := reflect.ValueOf(fnVal(items, function))
return true, res
if info.fnIn2Type == nil {
res := reflect.ValueOf(fnVal(items, function))
return true, res
}
}
return false, reflect.ValueOf(nil)
}
Expand Down
61 changes: 31 additions & 30 deletions internal/filter/dispatcher_test.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
package filter

import (
"github.com/stretchr/testify/assert"
"github.com/wesovilabs/koazee/utils"
"reflect"
"testing"

"github.com/stretchr/testify/assert"
"github.com/wesovilabs/koazee/utils"
)

func Test_filterString(t *testing.T) {
typeElement := reflect.TypeOf(utils.ArrayString[1])
info := &filterInfo{fnInputType: typeElement}
info := &filterInfo{fnIn1Type: typeElement}
fn := func(element string) bool { return element != utils.ArrayString[1] }
found, output := dispatch(reflect.ValueOf(utils.ArrayString), fn, info)
assert.True(t, found)
Expand All @@ -18,7 +19,7 @@ func Test_filterString(t *testing.T) {

func Test_filterPtrString(t *testing.T) {
typeElement := reflect.TypeOf(utils.ArrayStringPtr[1])
info := &filterInfo{fnInputType: typeElement}
info := &filterInfo{fnIn1Type: typeElement}
fn := func(element *string) bool { return *element != *utils.ArrayStringPtr[1] }
found, output := dispatch(reflect.ValueOf(utils.ArrayStringPtr), fn, info)
assert.True(t, found)
Expand All @@ -27,7 +28,7 @@ func Test_filterPtrString(t *testing.T) {

func Test_filterBool(t *testing.T) {
typeElement := reflect.TypeOf(utils.ArrayBool[1])
info := &filterInfo{fnInputType: typeElement}
info := &filterInfo{fnIn1Type: typeElement}
fn := func(element bool) bool { return element != utils.ArrayBool[1] }
found, output := dispatch(reflect.ValueOf(utils.ArrayBool), fn, info)
assert.True(t, found)
Expand All @@ -36,7 +37,7 @@ func Test_filterBool(t *testing.T) {

func Test_filterPtrBool(t *testing.T) {
typeElement := reflect.TypeOf(utils.ArrayBoolPtr[1])
info := &filterInfo{fnInputType: typeElement}
info := &filterInfo{fnIn1Type: typeElement}
fn := func(element *bool) bool { return *element != *utils.ArrayBoolPtr[1] }
found, output := dispatch(reflect.ValueOf(utils.ArrayBoolPtr), fn, info)
assert.True(t, found)
Expand All @@ -45,7 +46,7 @@ func Test_filterPtrBool(t *testing.T) {

func Test_filterInt(t *testing.T) {
typeElement := reflect.TypeOf(utils.ArrayInt[1])
info := &filterInfo{fnInputType: typeElement}
info := &filterInfo{fnIn1Type: typeElement}
fn := func(element int) bool { return element != utils.ArrayInt[1] }
found, output := dispatch(reflect.ValueOf(utils.ArrayInt), fn, info)
assert.True(t, found)
Expand All @@ -54,7 +55,7 @@ func Test_filterInt(t *testing.T) {

func Test_filterPtrInt(t *testing.T) {
typeElement := reflect.TypeOf(utils.ArrayIntPtr[1])
info := &filterInfo{fnInputType: typeElement}
info := &filterInfo{fnIn1Type: typeElement}
fn := func(element *int) bool { return *element != *utils.ArrayIntPtr[1] }
found, output := dispatch(reflect.ValueOf(utils.ArrayIntPtr), fn, info)
assert.True(t, found)
Expand All @@ -63,7 +64,7 @@ func Test_filterPtrInt(t *testing.T) {

func Test_filterInt8(t *testing.T) {
typeElement := reflect.TypeOf(utils.ArrayInt8[1])
info := &filterInfo{fnInputType: typeElement}
info := &filterInfo{fnIn1Type: typeElement}
fn := func(element int8) bool { return element != utils.ArrayInt8[1] }
found, output := dispatch(reflect.ValueOf(utils.ArrayInt8), fn, info)
assert.True(t, found)
Expand All @@ -72,7 +73,7 @@ func Test_filterInt8(t *testing.T) {

func Test_filterPtrInt8(t *testing.T) {
typeElement := reflect.TypeOf(utils.ArrayInt8Ptr[1])
info := &filterInfo{fnInputType: typeElement}
info := &filterInfo{fnIn1Type: typeElement}
fn := func(element *int8) bool { return *element != *utils.ArrayInt8Ptr[1] }
found, output := dispatch(reflect.ValueOf(utils.ArrayInt8Ptr), fn, info)
assert.True(t, found)
Expand All @@ -81,7 +82,7 @@ func Test_filterPtrInt8(t *testing.T) {

func Test_filterInt16(t *testing.T) {
typeElement := reflect.TypeOf(utils.ArrayInt16[1])
info := &filterInfo{fnInputType: typeElement}
info := &filterInfo{fnIn1Type: typeElement}
fn := func(element int16) bool { return element != utils.ArrayInt16[1] }
found, output := dispatch(reflect.ValueOf(utils.ArrayInt16), fn, info)
assert.True(t, found)
Expand All @@ -90,7 +91,7 @@ func Test_filterInt16(t *testing.T) {

func Test_filterPtrInt16(t *testing.T) {
typeElement := reflect.TypeOf(utils.ArrayInt16Ptr[1])
info := &filterInfo{fnInputType: typeElement}
info := &filterInfo{fnIn1Type: typeElement}
fn := func(element *int16) bool { return *element != *utils.ArrayInt16Ptr[1] }
found, output := dispatch(reflect.ValueOf(utils.ArrayInt16Ptr), fn, info)
assert.True(t, found)
Expand All @@ -99,7 +100,7 @@ func Test_filterPtrInt16(t *testing.T) {

func Test_filterInt32(t *testing.T) {
typeElement := reflect.TypeOf(utils.ArrayInt32[1])
info := &filterInfo{fnInputType: typeElement}
info := &filterInfo{fnIn1Type: typeElement}
fn := func(element int32) bool { return element != utils.ArrayInt32[1] }
found, output := dispatch(reflect.ValueOf(utils.ArrayInt32), fn, info)
assert.True(t, found)
Expand All @@ -108,7 +109,7 @@ func Test_filterInt32(t *testing.T) {

func Test_filterPtrInt32(t *testing.T) {
typeElement := reflect.TypeOf(utils.ArrayInt32Ptr[1])
info := &filterInfo{fnInputType: typeElement}
info := &filterInfo{fnIn1Type: typeElement}
fn := func(element *int32) bool { return *element != *utils.ArrayInt32Ptr[1] }
found, output := dispatch(reflect.ValueOf(utils.ArrayInt32Ptr), fn, info)
assert.True(t, found)
Expand All @@ -117,7 +118,7 @@ func Test_filterPtrInt32(t *testing.T) {

func Test_filterInt64(t *testing.T) {
typeElement := reflect.TypeOf(utils.ArrayInt64[1])
info := &filterInfo{fnInputType: typeElement}
info := &filterInfo{fnIn1Type: typeElement}
fn := func(element int64) bool { return element != utils.ArrayInt64[1] }
found, output := dispatch(reflect.ValueOf(utils.ArrayInt64), fn, info)
assert.True(t, found)
Expand All @@ -126,7 +127,7 @@ func Test_filterInt64(t *testing.T) {

func Test_filterPtrInt64(t *testing.T) {
typeElement := reflect.TypeOf(utils.ArrayInt64Ptr[1])
info := &filterInfo{fnInputType: typeElement}
info := &filterInfo{fnIn1Type: typeElement}
fn := func(element *int64) bool { return *element != *utils.ArrayInt64Ptr[1] }
found, output := dispatch(reflect.ValueOf(utils.ArrayInt64Ptr), fn, info)
assert.True(t, found)
Expand All @@ -135,7 +136,7 @@ func Test_filterPtrInt64(t *testing.T) {

func Test_filterUint(t *testing.T) {
typeElement := reflect.TypeOf(utils.ArrayUint[1])
info := &filterInfo{fnInputType: typeElement}
info := &filterInfo{fnIn1Type: typeElement}
fn := func(element uint) bool { return element != utils.ArrayUint[1] }
found, output := dispatch(reflect.ValueOf(utils.ArrayUint), fn, info)
assert.True(t, found)
Expand All @@ -144,7 +145,7 @@ func Test_filterUint(t *testing.T) {

func Test_filterPtrUint(t *testing.T) {
typeElement := reflect.TypeOf(utils.ArrayUintPtr[1])
info := &filterInfo{fnInputType: typeElement}
info := &filterInfo{fnIn1Type: typeElement}
fn := func(element *uint) bool { return *element != *utils.ArrayUintPtr[1] }
found, output := dispatch(reflect.ValueOf(utils.ArrayUintPtr), fn, info)
assert.True(t, found)
Expand All @@ -153,7 +154,7 @@ func Test_filterPtrUint(t *testing.T) {

func Test_filterUint8(t *testing.T) {
typeElement := reflect.TypeOf(utils.ArrayUint8[1])
info := &filterInfo{fnInputType: typeElement}
info := &filterInfo{fnIn1Type: typeElement}
fn := func(element uint8) bool { return element != utils.ArrayUint8[1] }
found, output := dispatch(reflect.ValueOf(utils.ArrayUint8), fn, info)
assert.True(t, found)
Expand All @@ -162,7 +163,7 @@ func Test_filterUint8(t *testing.T) {

func Test_filterPtrUint8(t *testing.T) {
typeElement := reflect.TypeOf(utils.ArrayUint8Ptr[1])
info := &filterInfo{fnInputType: typeElement}
info := &filterInfo{fnIn1Type: typeElement}
fn := func(element *uint8) bool { return *element != *utils.ArrayUint8Ptr[1] }
found, output := dispatch(reflect.ValueOf(utils.ArrayUint8Ptr), fn, info)
assert.True(t, found)
Expand All @@ -171,7 +172,7 @@ func Test_filterPtrUint8(t *testing.T) {

func Test_filterUint16(t *testing.T) {
typeElement := reflect.TypeOf(utils.ArrayUint16[1])
info := &filterInfo{fnInputType: typeElement}
info := &filterInfo{fnIn1Type: typeElement}
fn := func(element uint16) bool { return element != utils.ArrayUint16[1] }
found, output := dispatch(reflect.ValueOf(utils.ArrayUint16), fn, info)
assert.True(t, found)
Expand All @@ -180,7 +181,7 @@ func Test_filterUint16(t *testing.T) {

func Test_filterPtrUint16(t *testing.T) {
typeElement := reflect.TypeOf(utils.ArrayUint16Ptr[1])
info := &filterInfo{fnInputType: typeElement}
info := &filterInfo{fnIn1Type: typeElement}
fn := func(element *uint16) bool { return *element != *utils.ArrayUint16Ptr[1] }
found, output := dispatch(reflect.ValueOf(utils.ArrayUint16Ptr), fn, info)
assert.True(t, found)
Expand All @@ -189,7 +190,7 @@ func Test_filterPtrUint16(t *testing.T) {

func Test_filterUint32(t *testing.T) {
typeElement := reflect.TypeOf(utils.ArrayUint32[1])
info := &filterInfo{fnInputType: typeElement}
info := &filterInfo{fnIn1Type: typeElement}
fn := func(element uint32) bool { return element != utils.ArrayUint32[1] }
found, output := dispatch(reflect.ValueOf(utils.ArrayUint32), fn, info)
assert.True(t, found)
Expand All @@ -198,7 +199,7 @@ func Test_filterUint32(t *testing.T) {

func Test_filterPtrUint32(t *testing.T) {
typeElement := reflect.TypeOf(utils.ArrayUint32Ptr[1])
info := &filterInfo{fnInputType: typeElement}
info := &filterInfo{fnIn1Type: typeElement}
fn := func(element *uint32) bool { return *element != *utils.ArrayUint32Ptr[1] }
found, output := dispatch(reflect.ValueOf(utils.ArrayUint32Ptr), fn, info)
assert.True(t, found)
Expand All @@ -207,7 +208,7 @@ func Test_filterPtrUint32(t *testing.T) {

func Test_filterUint64(t *testing.T) {
typeElement := reflect.TypeOf(utils.ArrayUint64[1])
info := &filterInfo{fnInputType: typeElement}
info := &filterInfo{fnIn1Type: typeElement}
fn := func(element uint64) bool { return element != utils.ArrayUint64[1] }
found, output := dispatch(reflect.ValueOf(utils.ArrayUint64), fn, info)
assert.True(t, found)
Expand All @@ -216,7 +217,7 @@ func Test_filterUint64(t *testing.T) {

func Test_filterPtrUint64(t *testing.T) {
typeElement := reflect.TypeOf(utils.ArrayUint64Ptr[1])
info := &filterInfo{fnInputType: typeElement}
info := &filterInfo{fnIn1Type: typeElement}
fn := func(element *uint64) bool { return *element != *utils.ArrayUint64Ptr[1] }
found, output := dispatch(reflect.ValueOf(utils.ArrayUint64Ptr), fn, info)
assert.True(t, found)
Expand All @@ -225,7 +226,7 @@ func Test_filterPtrUint64(t *testing.T) {

func Test_filterFloat32(t *testing.T) {
typeElement := reflect.TypeOf(utils.ArrayFloat32[1])
info := &filterInfo{fnInputType: typeElement}
info := &filterInfo{fnIn1Type: typeElement}
fn := func(element float32) bool { return element != utils.ArrayFloat32[1] }
found, output := dispatch(reflect.ValueOf(utils.ArrayFloat32), fn, info)
assert.True(t, found)
Expand All @@ -234,7 +235,7 @@ func Test_filterFloat32(t *testing.T) {

func Test_filterPtrFloat32(t *testing.T) {
typeElement := reflect.TypeOf(utils.ArrayFloat32Ptr[1])
info := &filterInfo{fnInputType: typeElement}
info := &filterInfo{fnIn1Type: typeElement}
fn := func(element *float32) bool { return *element != *utils.ArrayFloat32Ptr[1] }
found, output := dispatch(reflect.ValueOf(utils.ArrayFloat32Ptr), fn, info)
assert.True(t, found)
Expand All @@ -243,7 +244,7 @@ func Test_filterPtrFloat32(t *testing.T) {

func Test_filterFloat64(t *testing.T) {
typeElement := reflect.TypeOf(utils.ArrayFloat64[1])
info := &filterInfo{fnInputType: typeElement}
info := &filterInfo{fnIn1Type: typeElement}
fn := func(element float64) bool { return element != utils.ArrayFloat64[1] }
found, output := dispatch(reflect.ValueOf(utils.ArrayFloat64), fn, info)
assert.True(t, found)
Expand All @@ -252,7 +253,7 @@ func Test_filterFloat64(t *testing.T) {

func Test_filterPtrFloat64(t *testing.T) {
typeElement := reflect.TypeOf(utils.ArrayFloat64Ptr[1])
info := &filterInfo{fnInputType: typeElement}
info := &filterInfo{fnIn1Type: typeElement}
fn := func(element *float64) bool { return *element != *utils.ArrayFloat64Ptr[1] }
found, output := dispatch(reflect.ValueOf(utils.ArrayFloat64Ptr), fn, info)
assert.True(t, found)
Expand Down
38 changes: 33 additions & 5 deletions internal/filter/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,21 @@ func (op *Filter) Run() (reflect.Value, *errors.Error) {
return result, nil
}

if op.ItemsValue.Type().Kind() == reflect.Map {
newItems := reflect.MakeMap(op.ItemsValue.Type())
fn := reflect.ValueOf(op.Func)
for _, key := range op.ItemsValue.MapKeys() {
item := op.ItemsValue.MapIndex(key)
argv := make([]reflect.Value, 2)
argv[0] = item
argv[1] = key
if fn.Call(argv)[0].Bool() {
newItems.SetMapIndex(key, item)
}
}
return newItems, nil
}

newItems := reflect.MakeSlice(reflect.SliceOf(op.ItemsType), 0, 0)
fn := reflect.ValueOf(op.Func)
for index := 0; index < op.ItemsValue.Len(); index++ {
Expand All @@ -50,24 +65,37 @@ func (op *Filter) validate() (*filterInfo, *errors.Error) {
if function.Type().Kind() != reflect.Func {
return nil, errors.InvalidArgument(OpCode, "The filter operation requires a function as argument")
}
if function.Type().NumIn() != 1 {
return nil, errors.InvalidArgument(OpCode, "The provided function must retrieve 1 argument")
fnNumIn := function.Type().NumIn()
if fnNumIn != 1 && fnNumIn != 2 {
return nil, errors.InvalidArgument(OpCode, "The provided function must retrieve 1 or 2 argument")
}
if function.Type().NumOut() != 1 {
return nil, errors.InvalidArgument(OpCode, "The provided function must return 1 value")
}
fnOut := reflect.New(function.Type().Out(0)).Elem()
fnIn := reflect.New(function.Type().In(0)).Elem()
fnIn1 := reflect.New(function.Type().In(0)).Elem()

if fnIn.Type() != op.ItemsType {
if fnIn1.Type() != op.ItemsType {
return nil, errors.InvalidArgument(OpCode,
"The type of the argument in the provided function must be %s",
op.ItemsType.String())
}
if fnOut.Kind() != reflect.Bool {
return nil, errors.InvalidArgument(OpCode, "The type of the Output in the provided function must be bool")
}
item.fnInputType = fnIn.Type()
item.fnIn1Type = fnIn1.Type()

if fnNumIn == 2 {
fnIn2 := reflect.New(function.Type().In(1)).Elem()
keyType := op.ItemsValue.MapKeys()[0].Type()
if fnIn2.Type() != keyType {
return nil, errors.InvalidArgument(OpCode,
"The type of the argument 2 in the provided function must be %s",
keyType.String())
}
item.fnIn2Type = fnIn2.Type()
}

cache.add(op.ItemsType, fnType, item)
return item, nil
}
21 changes: 19 additions & 2 deletions stream/filter_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package stream_test

import (
"github.com/wesovilabs/koazee/internal/filter"
"testing"

"github.com/wesovilabs/koazee/internal/filter"

"github.com/wesovilabs/koazee"
"github.com/wesovilabs/koazee/errors"

Expand Down Expand Up @@ -34,7 +35,7 @@ func TestStream_Filter_validation(t *testing.T) {
**/
assert.Equal(
t,
errors.InvalidArgument(filter.OpCode, "The provided function must retrieve 1 argument"),
errors.InvalidArgument(filter.OpCode, "The provided function must retrieve 1 or 2 argument"),
koazee.StreamOf([]int{2, 3, 2}).Filter(func() {}).Out().Err())

assert.Equal(
Expand All @@ -53,3 +54,19 @@ func TestStream_Filter_validation(t *testing.T) {
koazee.StreamOf([]int{2, 3, 2}).Filter(func(val int) string { return "a" }).Out().Err())

}

func TestStream_Filter_WithIndex(t *testing.T) {
expect := map[string]int{
"a": 1,
"c": 3,
}
actual := stream.New(map[string]int{
"a": 1,
"b": 2,
"c": 3,
}).
Filter(func(val int, key string) bool {
return val == 1 || key == "c"
}).Out().Val()
assert.Equal(t, expect, actual)
}

0 comments on commit 85e57a3

Please sign in to comment.