github.com/SaurabhDubey-Groww/go-cloud@v0.0.0-20221124105541-b26c29285fd8/docstore/memdocstore/query.go (about)

     1  // Copyright 2019 The Go Cloud Development Kit Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     https://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package memdocstore
    16  
    17  import (
    18  	"context"
    19  	"io"
    20  	"reflect"
    21  	"sort"
    22  	"strings"
    23  	"time"
    24  
    25  	"gocloud.dev/docstore/driver"
    26  )
    27  
    28  func (c *collection) RunGetQuery(_ context.Context, q *driver.Query) (driver.DocumentIterator, error) {
    29  	if q.BeforeQuery != nil {
    30  		if err := q.BeforeQuery(func(interface{}) bool { return false }); err != nil {
    31  			return nil, err
    32  		}
    33  	}
    34  
    35  	c.mu.Lock()
    36  	defer c.mu.Unlock()
    37  
    38  	var resultDocs []storedDoc
    39  	for _, doc := range c.docs {
    40  		if filtersMatch(q.Filters, doc) {
    41  			resultDocs = append(resultDocs, doc)
    42  		}
    43  	}
    44  	if q.OrderByField != "" {
    45  		sortDocs(resultDocs, q.OrderByField, q.OrderAscending)
    46  	}
    47  
    48  	if q.Limit > 0 && len(resultDocs) > q.Limit {
    49  		resultDocs = resultDocs[:q.Limit]
    50  	}
    51  
    52  	// Include the key field in the field paths if there is one.
    53  	var fps [][]string
    54  	if len(q.FieldPaths) > 0 && c.keyField != "" {
    55  		fps = append([][]string{{c.keyField}}, q.FieldPaths...)
    56  	} else {
    57  		fps = q.FieldPaths
    58  	}
    59  
    60  	return &docIterator{
    61  		docs:       resultDocs,
    62  		fieldPaths: fps,
    63  		revField:   c.opts.RevisionField,
    64  	}, nil
    65  }
    66  
    67  func filtersMatch(fs []driver.Filter, doc storedDoc) bool {
    68  	for _, f := range fs {
    69  		if !filterMatches(f, doc) {
    70  			return false
    71  		}
    72  	}
    73  	return true
    74  }
    75  
    76  func filterMatches(f driver.Filter, doc storedDoc) bool {
    77  	docval, err := getAtFieldPath(doc, f.FieldPath)
    78  	// missing or bad field path => no match
    79  	if err != nil {
    80  		return false
    81  	}
    82  	c, ok := compare(docval, f.Value)
    83  	if !ok {
    84  		return false
    85  	}
    86  	return applyComparison(f.Op, c)
    87  }
    88  
    89  // op is one of the five permitted docstore operators ("=", "<", etc.)
    90  // c is the result of strings.Compare or the like.
    91  // TODO(jba): dedup from gcpfirestore/query?
    92  func applyComparison(op string, c int) bool {
    93  	switch op {
    94  	case driver.EqualOp:
    95  		return c == 0
    96  	case ">":
    97  		return c > 0
    98  	case "<":
    99  		return c < 0
   100  	case ">=":
   101  		return c >= 0
   102  	case "<=":
   103  		return c <= 0
   104  	default:
   105  		panic("bad op")
   106  	}
   107  }
   108  
   109  func compare(x1, x2 interface{}) (int, bool) {
   110  	v1 := reflect.ValueOf(x1)
   111  	v2 := reflect.ValueOf(x2)
   112  	if v1.Kind() == reflect.String && v2.Kind() == reflect.String {
   113  		return strings.Compare(v1.String(), v2.String()), true
   114  	}
   115  	if cmp, err := driver.CompareNumbers(v1, v2); err == nil {
   116  		return cmp, true
   117  	}
   118  	if t1, ok := x1.(time.Time); ok {
   119  		if t2, ok := x2.(time.Time); ok {
   120  			return driver.CompareTimes(t1, t2), true
   121  		}
   122  	}
   123  	return 0, false
   124  }
   125  
   126  func sortDocs(docs []storedDoc, field string, asc bool) {
   127  	sort.Slice(docs, func(i, j int) bool {
   128  		c, ok := compare(docs[i][field], docs[j][field])
   129  		if !ok {
   130  			return false
   131  		}
   132  		if asc {
   133  			return c < 0
   134  		}
   135  		return c > 0
   136  	})
   137  }
   138  
   139  type docIterator struct {
   140  	docs       []storedDoc
   141  	fieldPaths [][]string
   142  	revField   string
   143  	err        error
   144  }
   145  
   146  func (it *docIterator) Next(ctx context.Context, doc driver.Document) error {
   147  	if it.err != nil {
   148  		return it.err
   149  	}
   150  	if len(it.docs) == 0 {
   151  		it.err = io.EOF
   152  		return it.err
   153  	}
   154  	if err := decodeDoc(it.docs[0], doc, it.fieldPaths); err != nil {
   155  		it.err = err
   156  		return it.err
   157  	}
   158  	it.docs = it.docs[1:]
   159  	return nil
   160  }
   161  
   162  func (it *docIterator) Stop() { it.err = io.EOF }
   163  
   164  func (it *docIterator) As(i interface{}) bool { return false }
   165  
   166  func (c *collection) QueryPlan(q *driver.Query) (string, error) {
   167  	return "", nil
   168  }