github.com/balzaczyy/golucene@v0.0.0-20151210033525-d0be9ee89713/queryparser/classic/queryParserBase.go (about) 1 package classic 2 3 import ( 4 "errors" 5 "fmt" 6 "github.com/balzaczyy/golucene/core/analysis" 7 "github.com/balzaczyy/golucene/core/search" 8 "strings" 9 ) 10 11 const ( 12 CONJ_NONE = iota 13 CONJ_AND 14 CONJ_OR 15 ) 16 17 const ( 18 MOD_NONE = 0 19 MOD_NOT = 10 20 MOD_REQ = 11 21 ) 22 23 type QueryParserBaseSPI interface { 24 ReInit(CharStream) 25 TopLevelQuery(string) (search.Query, error) 26 } 27 28 type QueryParserBase struct { 29 *QueryBuilder 30 31 spi QueryParserBaseSPI 32 33 operator Operator 34 35 field string 36 phraseSlop int 37 38 autoGeneratePhraseQueries bool 39 } 40 41 func newQueryParserBase(spi QueryParserBaseSPI) *QueryParserBase { 42 return &QueryParserBase{ 43 QueryBuilder: newQueryBuilder(), 44 spi: spi, 45 operator: OP_OR, 46 } 47 } 48 49 // L116 50 func (qp *QueryParserBase) Parse(query string) (res search.Query, err error) { 51 qp.spi.ReInit(newFastCharStream(strings.NewReader(query))) 52 if res, err = qp.spi.TopLevelQuery(qp.field); err != nil { 53 return nil, errors.New(fmt.Sprintf("Cannot parse '%v': %v", query, err)) 54 } 55 if res != nil { 56 return res, nil 57 } 58 return qp.newBooleanQuery(false), nil 59 } 60 61 // L408 62 func (qp *QueryParserBase) addClause(clauses []*search.BooleanClause, 63 conj, mods int, q search.Query) []*search.BooleanClause { 64 var required, prohibited bool 65 66 // If this term is introduced by AND, make the preceding term required, 67 // unless it's already prohibited 68 if len(clauses) > 0 && conj == CONJ_AND { 69 panic("not implemented yet") 70 } 71 72 if len(clauses) > 0 && qp.operator == OP_AND && conj == CONJ_OR { 73 panic("not implemented yet") 74 } 75 76 // We might have been passed an empty query; the term might have been 77 // filtered away by the analyzer. 78 if q == nil { 79 return clauses 80 } 81 82 if qp.operator == OP_OR { 83 // We set REQUIRED if we're introduced by AND or +; PROHIBITED if 84 // introduced by NOT or -; make sure not to set both. 85 prohibited = (mods == MOD_NOT) 86 required = (mods == MOD_REQ) 87 if conj == CONJ_AND && !prohibited { 88 required = true 89 } 90 } else { 91 panic("not implemented yet") 92 } 93 if required { 94 panic("not implemented yet") 95 } else if !prohibited { 96 return append(clauses, qp.newBooleanClause(q, search.SHOULD)) 97 } else { 98 panic("not implemented yet") 99 } 100 } 101 102 // L461 103 func (qp *QueryParserBase) fieldQuery(field, queryText string, quoted bool) search.Query { 104 return qp.newFieldQuery(qp.analyzer, field, queryText, quoted) 105 } 106 107 func (qp *QueryParserBase) newFieldQuery(analyzer analysis.Analyzer, 108 field, queryText string, quoted bool) search.Query { 109 110 var occur search.Occur 111 if qp.operator == OP_AND { 112 occur = search.MUST 113 } else { 114 occur = search.SHOULD 115 } 116 return qp.createFieldQuery(analyzer, occur, field, queryText, 117 quoted || qp.autoGeneratePhraseQueries, qp.phraseSlop) 118 } 119 120 // L539 121 122 func (qp *QueryParserBase) newBooleanClause(q search.Query, occur search.Occur) *search.BooleanClause { 123 return search.NewBooleanClause(q, occur) 124 } 125 126 // L676 127 /* 128 Factory method for generating query, given a set of clauses. 129 By default creates a boolean query composed of clauses passed in. 130 131 Can be overridden by extending classes, to modify query being 132 returned. 133 */ 134 func (qp *QueryParserBase) booleanQuery(clauses []*search.BooleanClause) (search.Query, error) { 135 return qp.booleanQueryDisableCoord(clauses, false) 136 } 137 138 func (qp *QueryParserBase) booleanQueryDisableCoord(clauses []*search.BooleanClause, disableCoord bool) (search.Query, error) { 139 if len(clauses) == 0 { 140 return nil, nil // all clause words were filetered away by the analyzer. 141 } 142 query := qp.newBooleanQuery(disableCoord) 143 for _, clause := range clauses { 144 query.AddClause(clause) 145 } 146 return query, nil 147 } 148 149 // L827 150 func (qp *QueryParserBase) handleBareTokenQuery(qField string, 151 term, fuzzySlop *Token, prefix, wildcard, fuzzy, regexp bool) (q search.Query, err error) { 152 153 var termImage string 154 if termImage, err = qp.discardEscapeChar(term.image); err != nil { 155 return nil, err 156 } 157 if wildcard { 158 panic("not implemented yet") 159 } else if prefix { 160 panic("not implemented yet") 161 } else if regexp { 162 panic("not implemented yet") 163 } else if fuzzy { 164 panic("not implemented yet") 165 } else { 166 return qp.fieldQuery(qField, termImage, false), nil 167 } 168 } 169 170 // L876 171 func (qp *QueryParserBase) handleBoost(q search.Query, boost *Token) search.Query { 172 if boost != nil { 173 panic("not implemented yet") 174 } 175 return q 176 } 177 178 // L906 179 func (qp *QueryParserBase) discardEscapeChar(input string) (string, error) { 180 output := make([]rune, len(input)) 181 182 length := 0 183 184 lastCharWasEscapeChar := false 185 186 codePointMultiplier := 0 187 188 // codePoint := 0 189 190 for _, curChar := range input { 191 if codePointMultiplier > 0 { 192 panic("not implemented yet") 193 } else if lastCharWasEscapeChar { 194 panic("not implemented yet") 195 } else { 196 if curChar == '\\' { 197 lastCharWasEscapeChar = true 198 } else { 199 output[length] = curChar 200 length++ 201 } 202 } 203 } 204 205 if codePointMultiplier > 0 { 206 return "", errors.New("Truncated unicode escape sequence.") 207 } 208 if lastCharWasEscapeChar { 209 return "", errors.New("Term can not end with escape character.") 210 } 211 return string(output), nil 212 }