eintopf.info@v0.13.16/service/search/filter.go (about)

     1  // Copyright (C) 2022 The Eintopf authors
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Affero General Public License as
     5  // published by the Free Software Foundation, either version 3 of the
     6  // License, or (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU Affero General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Affero General Public License
    14  // along with this program.  If not, see <https://www.gnu.org/licenses/>.
    15  
    16  package search
    17  
    18  import (
    19  	"fmt"
    20  	"time"
    21  
    22  	"github.com/blevesearch/bleve/v2"
    23  	"github.com/blevesearch/bleve/v2/search/query"
    24  )
    25  
    26  type Filter interface {
    27  	filterQuery() query.Query
    28  	CacheKey() string
    29  }
    30  
    31  // TermsFilter can be used to filter documents containing one of the provided
    32  // terms in the field. If the field contains mutiple terms, only one must match.
    33  type TermsFilter struct {
    34  	Field string   `json:"field"`
    35  	Terms []string `json:"terms"`
    36  }
    37  
    38  // CacheKey returns the same string for all identical filters.
    39  func (t *TermsFilter) CacheKey() string {
    40  	cacheKey := t.Field
    41  	for _, term := range t.Terms {
    42  		cacheKey += term
    43  	}
    44  	return cacheKey
    45  }
    46  
    47  func (t *TermsFilter) filterQuery() query.Query {
    48  	if len(t.Terms) == 0 {
    49  		return nil
    50  	}
    51  	query := bleve.NewBooleanQuery()
    52  	for _, term := range t.Terms {
    53  		// Note: we use a match phrase query instead of a term query, since the
    54  		// term query is exact and won't match if one of the words/elements
    55  		// match.
    56  		matchQuery := bleve.NewMatchPhraseQuery(term)
    57  		matchQuery.SetField(fieldKey(t.Field))
    58  		query.AddShould(matchQuery)
    59  	}
    60  	return query
    61  }
    62  
    63  type NumericRangeFilter struct {
    64  	Field string   `json:"field"`
    65  	Min   *float64 `json:"min"`
    66  	Max   *float64 `json:"max"`
    67  }
    68  
    69  // CacheKey returns the same string for all identical filters.
    70  func (n *NumericRangeFilter) CacheKey() string {
    71  	return fmt.Sprintf("%s-%d-%d", n.Field, n.Min, n.Max)
    72  }
    73  
    74  func (n *NumericRangeFilter) filterQuery() query.Query {
    75  	query := bleve.NewNumericRangeQuery(n.Min, n.Max)
    76  	query.SetField(fieldKey(n.Field))
    77  	return query
    78  }
    79  
    80  type DateRangeFilter struct {
    81  	Field string    `json:"field"`
    82  	Min   time.Time `json:"min"`
    83  	Max   time.Time `json:"max"`
    84  }
    85  
    86  // CacheKey returns the same string for all identical filters.
    87  func (d *DateRangeFilter) CacheKey() string {
    88  	return d.Field + d.Min.String() + d.Max.String()
    89  }
    90  
    91  func (d *DateRangeFilter) filterQuery() query.Query {
    92  	query := bleve.NewDateRangeQuery(d.Min, d.Max)
    93  	query.SetField(fieldKey(d.Field))
    94  	return query
    95  }
    96  
    97  type BoolFilter struct {
    98  	Field string `json:"field"`
    99  	Value bool   `json:"value"`
   100  }
   101  
   102  func (b *BoolFilter) CacheKey() string {
   103  	return fmt.Sprintf("%s%t", b.Field, b.Value)
   104  }
   105  
   106  func (b *BoolFilter) filterQuery() query.Query {
   107  	query := bleve.NewBoolFieldQuery(b.Value)
   108  	query.SetField(fieldKey(b.Field))
   109  	return query
   110  }
   111  
   112  type NotFilter struct {
   113  	Filter Filter
   114  }
   115  
   116  func (n *NotFilter) CacheKey() string {
   117  	return fmt.Sprintf("not-%s", n.Filter.CacheKey())
   118  }
   119  
   120  func (n *NotFilter) filterQuery() query.Query {
   121  	query := bleve.NewBooleanQuery()
   122  	query.MustNot = n.Filter.filterQuery()
   123  
   124  	return query
   125  }