Skip to content

Commit

Permalink
Support searching with multiple indexes
Browse files Browse the repository at this point in the history
Signed-off-by: yah01 <[email protected]>
  • Loading branch information
yah01 committed Jun 12, 2022
1 parent f30266e commit 8bdb474
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 0 deletions.
11 changes: 11 additions & 0 deletions map.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,17 @@ func (imap *IndexMap[K, V]) GetAllBy(indexName string, key any) []*V {
return values.Collect()
}

// Return all values the seeked by the key,
// nil if index or key not exists.
func (imap *IndexMap[K, V]) GetAllByMulti(indexName string, key any) []*V {
values := imap.getAllBy(indexName, key)
if values == nil {
return nil
}

return values.Collect()
}

// Return true if the value with given key exists,
// false otherwise.
func (imap *IndexMap[K, V]) Contain(key K) bool {
Expand Down
95 changes: 95 additions & 0 deletions search.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package indexmap

import (
"github.com/yah01/container"
"github.com/yah01/indexmap/utils"
)

const (
lookupTypeNone lookupType = iota
lookupTypeAnd
lookupTypeOr
lookupTypeExclude
)

type lookupType int

type indexLookup struct {
lookupType lookupType
indexName string
keys []any
}

type SearchStream[K comparable, V any] struct {
chain []*indexLookup

imap *IndexMap[K, V]
}

func (stream *SearchStream[K, V]) And(indexName string, keys ...any) *SearchStream[K, V] {
stream.chain = append(stream.chain, &indexLookup{
lookupType: lookupTypeAnd,
indexName: indexName,
keys: keys,
})

return stream
}

func (stream *SearchStream[K, V]) Or(indexName string, keys ...any) *SearchStream[K, V] {
stream.chain = append(stream.chain, &indexLookup{
lookupType: lookupTypeOr,
indexName: indexName,
keys: keys,
})

return stream
}

func (stream *SearchStream[K, V]) Exclude(indexName string, keys ...any) *SearchStream[K, V] {
stream.chain = append(stream.chain, &indexLookup{
lookupType: lookupTypeExclude,
indexName: indexName,
keys: keys,
})

return stream
}

func (stream *SearchStream[K, V]) Excute() []*V {
values := make(container.Set[*V])

for _, lookup := range stream.chain {
result := stream.executeLookup(lookup)

switch lookup.lookupType {
case lookupTypeAnd:
utils.IntersectSet(values, result)

case lookupTypeOr:
utils.UnionSet(values, result)

case lookupTypeExclude:
utils.ExceptSet(values, result)
}
}

return values.Collect()
}

func (stream *SearchStream[K, V]) executeLookup(lookup *indexLookup) container.Set[*V] {
result := make(container.Set[*V])
for i := range lookup.keys {
utils.UnionSet(result,
stream.imap.getAllBy(lookup.indexName, lookup.keys[i]))
}

return result
}

func (imap *IndexMap[K, V]) Search() *SearchStream[K, V] {
return &SearchStream[K, V]{
chain: make([]*indexLookup, 0),
imap: imap,
}
}
7 changes: 7 additions & 0 deletions search_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package indexmap

import "testing"

func TestSearch(t *testing.T) {

}
23 changes: 23 additions & 0 deletions utils/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package utils

import "github.com/yah01/container"

func UnionSet[T comparable](dst container.Set[T], src container.Set[T]) {
for elem := range src {
dst.Insert(elem)
}
}

func IntersectSet[T comparable](dst container.Set[T], src container.Set[T]) {
for elem := range dst {
if !src.Contain(elem) {
delete(dst, elem)
}
}
}

func ExceptSet[T comparable](dst container.Set[T], src container.Set[T]) {
for elem := range src {
delete(dst, elem)
}
}

0 comments on commit 8bdb474

Please sign in to comment.