ostafen / clover

A lightweight document-oriented NoSQL database written in pure Golang.
MIT License
680 stars 55 forks source link

Add Contains() criteria #45

Closed kastolars closed 2 years ago

kastolars commented 2 years ago

44

Contains criteria that checks if a given slice is a subset of the field slice in a document.

The runtime of the function is linear, only because I first populate a map of the field values and their frequencies. While this does require O(n) extra memory where n is the size of the document field, the other approach I had was a quadratic runtime, which would be slower and doesn't handle duplicate elements (such as in the case of say, "myfield": [4,4,4,2,4].)

Here is the quadratic implementation, which works for the test cases I added:

func (f *field) Contains(elems ...interface{}) *Criteria {
    return &Criteria{
        p: func(doc *Document) bool {
            docValue := doc.Get(f.name)
            if docValue == nil || reflect.TypeOf(docValue).Kind() != reflect.Slice {
                return false
            }
            rv := reflect.ValueOf(docValue)
            len := rv.Len()

        OuterLoop:
            for _, elem := range elems {
                normElem, err := normalize(elem)
                if err == nil {
                    for i := 0; i < len; i++ {
                        if reflect.DeepEqual(normElem, rv.Index(i).Interface()) {
                            break OuterLoop
                        }
                    }
                }
                return false
            }
            return true
        },
    }
}

I also added a new test data file, as adding the 3 test cases from the original issue caused many current test cases to fail and I didn't want to mess with that since they can always be retrofit I guess.

Looking forward to some feedback here.

kastolars commented 2 years ago

Okay should be good now