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 }