1// Copieright (c) 2014 Couchbase, Inc. 2// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 3// except in compliance with the License. You may obtain a copy of the License at 4// http://www.apache.org/licenses/LICENSE-2.0 5// Unless required by applicable law or agreed to in writing, software distributed under the 6// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 7// either express or implied. See the License for the specific language governing permissions 8// and limitations under the License. 9 10package value 11 12import ( 13 "fmt" 14 json "github.com/couchbase/go_json" 15 "io" 16 "strings" 17 "unicode" 18 19 "github.com/couchbase/query/util" 20) 21 22/* 23stringValue is defined as type string. 24*/ 25type stringValue string 26 27/* 28Define a value representing an empty string and 29assign it to EMPTY_STRING_VALUE. 30*/ 31var EMPTY_STRING_VALUE Value = stringValue("") 32 33/* 34Use built-in JSON string marshalling, which handles special 35characters. 36*/ 37func (this stringValue) String() string { 38 bytes, err := json.MarshalNoEscape(string(this)) 39 if err != nil { 40 // We should not get here. 41 panic(fmt.Sprintf("Error marshaling Value %v: %v", this, err)) 42 } 43 return string(bytes) 44} 45 46/* 47Use built-in JSON string marshalling, which handles special 48characters. 49*/ 50func (this stringValue) MarshalJSON() ([]byte, error) { 51 return json.MarshalNoEscape(string(this)) 52} 53 54func (this stringValue) WriteJSON(w io.Writer, prefix, indent string) error { 55 b, err := json.MarshalNoEscape(string(this)) 56 if err != nil { 57 return err 58 } 59 _, err = w.Write(b) 60 return err 61} 62 63/* 64Type STRING. 65*/ 66func (this stringValue) Type() Type { 67 return STRING 68} 69 70func (this stringValue) Actual() interface{} { 71 return string(this) 72} 73 74func (this stringValue) ActualForIndex() interface{} { 75 return string(this) 76} 77 78/* 79If other is type stringValue and is the same as the receiver 80return true. 81*/ 82func (this stringValue) Equals(other Value) Value { 83 other = other.unwrap() 84 switch other := other.(type) { 85 case missingValue: 86 return other 87 case *nullValue: 88 return other 89 case stringValue: 90 if this == other { 91 return TRUE_VALUE 92 } 93 } 94 95 return FALSE_VALUE 96} 97 98func (this stringValue) EquivalentTo(other Value) bool { 99 other = other.unwrap() 100 switch other := other.(type) { 101 case stringValue: 102 return this == other 103 default: 104 return false 105 } 106} 107 108/* 109If other is type stringValue, compare with receiver, 110if its less than (string comparison) return -1, greater 111than return 1, otherwise return 0. For value of type 112parsedValue and annotated value call collate again with the 113value. The default behavior is to return the position wrt 114others type. 115*/ 116func (this stringValue) Collate(other Value) int { 117 other = other.unwrap() 118 switch other := other.(type) { 119 case stringValue: 120 if this < other { 121 return -1 122 } else if this > other { 123 return 1 124 } else { 125 return 0 126 } 127 default: 128 return int(STRING - other.Type()) 129 } 130} 131 132func (this stringValue) Compare(other Value) Value { 133 other = other.unwrap() 134 switch other := other.(type) { 135 case missingValue: 136 return other 137 case *nullValue: 138 return other 139 default: 140 return intValue(this.Collate(other)) 141 } 142} 143 144/* 145If length of string greater than 0, its a valid string. 146Return true. 147*/ 148func (this stringValue) Truth() bool { 149 return len(this) > 0 150} 151 152/* 153Return receiver. 154*/ 155func (this stringValue) Copy() Value { 156 return this 157} 158 159/* 160Return receiver. 161*/ 162func (this stringValue) CopyForUpdate() Value { 163 return this 164} 165 166/* 167Calls missingField. 168*/ 169func (this stringValue) Field(field string) (Value, bool) { 170 return missingField(field), false 171} 172 173/* 174Not valid for string. 175*/ 176func (this stringValue) SetField(field string, val interface{}) error { 177 return Unsettable(field) 178} 179 180/* 181Not valid for string. 182*/ 183func (this stringValue) UnsetField(field string) error { 184 return Unsettable(field) 185} 186 187/* 188Calls missingIndex. 189*/ 190func (this stringValue) Index(index int) (Value, bool) { 191 return missingIndex(index), false 192} 193 194/* 195Not valid for string. 196*/ 197func (this stringValue) SetIndex(index int, val interface{}) error { 198 return Unsettable(index) 199} 200 201/* 202Returns NULL_VALUE 203*/ 204func (this stringValue) Slice(start, end int) (Value, bool) { 205 return NULL_VALUE, false 206} 207 208/* 209Returns NULL_VALUE 210*/ 211func (this stringValue) SliceTail(start int) (Value, bool) { 212 return NULL_VALUE, false 213} 214 215/* 216Returns the input buffer as is. 217*/ 218func (this stringValue) Descendants(buffer []interface{}) []interface{} { 219 return buffer 220} 221 222/* 223No fields to list. Hence return nil. 224*/ 225func (this stringValue) Fields() map[string]interface{} { 226 return nil 227} 228 229func (this stringValue) FieldNames(buffer []string) []string { 230 return nil 231} 232 233/* 234Returns the input buffer as is. 235*/ 236func (this stringValue) DescendantPairs(buffer []util.IPair) []util.IPair { 237 return buffer 238} 239 240/* 241Append a low-valued byte to string. 242*/ 243func (this stringValue) Successor() Value { 244 return stringValue(string(this) + " ") 245} 246 247func (this stringValue) Recycle() { 248} 249 250func (this stringValue) Tokens(set *Set, options Value) *Set { 251 tokens := _STRING_TOKENS_POOL.Get() 252 defer _STRING_TOKENS_POOL.Put(tokens) 253 254 this.tokens(tokens, options, "", nil) 255 for t, _ := range tokens { 256 set.Add(stringValue(t)) 257 } 258 259 return set 260} 261 262func (this stringValue) ContainsToken(token, options Value) bool { 263 if token.Type() != STRING { 264 return false 265 } 266 267 tokens := _STRING_TOKENS_POOL.Get() 268 defer _STRING_TOKENS_POOL.Put(tokens) 269 270 str := token.Actual().(string) 271 return this.tokens(tokens, options, str, nil) 272} 273 274func (this stringValue) ContainsMatchingToken(matcher MatchFunc, options Value) bool { 275 tokens := _STRING_TOKENS_POOL.Get() 276 defer _STRING_TOKENS_POOL.Put(tokens) 277 278 return this.tokens(tokens, options, "", matcher) 279} 280 281func (this stringValue) unwrap() Value { 282 return this 283} 284 285func (this stringValue) tokens(set map[string]bool, options Value, 286 token string, matcher MatchFunc) bool { 287 288 // Set case folding function, if specified. 289 caseFunc := func(s string) string { return s } 290 if caseOption, ok := options.Field("case"); ok && caseOption.Type() == STRING { 291 caseStr := caseOption.Actual().(string) 292 switch strings.ToLower(caseStr) { 293 case "lower": 294 caseFunc = strings.ToLower 295 case "upper": 296 caseFunc = strings.ToUpper 297 } 298 } 299 300 var fields []string 301 split := true 302 303 // To split or not to split. 304 if splitOption, ok := options.Field("split"); ok && 305 splitOption.Type() == BOOLEAN && !splitOption.Truth() { 306 307 split = false 308 309 // To trim or not to trim. 310 if trimOption, ok := options.Field("trim"); ok && 311 trimOption.Type() == BOOLEAN && !trimOption.Truth() { 312 fields = []string{string(this)} 313 } else { 314 fields = []string{strings.TrimSpace(string(this))} 315 } 316 } 317 318 // Tokenize alphanumerics. 319 if split { 320 fields = strings.FieldsFunc(string(this), 321 func(c rune) bool { 322 return !unicode.IsLetter(c) && !unicode.IsNumber(c) 323 }) 324 } 325 326 for _, field := range fields { 327 f := caseFunc(field) 328 if f == token || (matcher != nil && matcher(f)) { 329 return true 330 } 331 332 set[f] = true 333 } 334 335 if !split { 336 return false 337 } 338 339 // Return if not tokenizing specials. 340 if specialsOption, ok := options.Field("specials"); !(ok && 341 specialsOption.Type() == BOOLEAN && specialsOption.Truth()) { 342 return false 343 } 344 345 // Tokenize specials. Specials can be used to preserve email 346 // addresses, URLs, hyphenated phone numbers, etc. 347 348 // First tokenize on whitespace and parentheses only. 349 fields = strings.FieldsFunc(string(this), 350 func(c rune) bool { 351 return unicode.IsSpace(c) || 352 c == '(' || c == ')' || 353 c == '[' || c == ']' || 354 c == '{' || c == '}' 355 }) 356 357 // Right trim special characters. 358 for _, field := range fields { 359 f := strings.TrimRightFunc(field, 360 func(c rune) bool { 361 return !unicode.IsLetter(c) && !unicode.IsNumber(c) 362 }) 363 364 if f != "" { 365 f = caseFunc(f) 366 if f == token || (matcher != nil && matcher(f)) { 367 return true 368 } 369 370 set[f] = true 371 } 372 } 373 374 return false 375} 376 377var _STRING_TOKENS_POOL = util.NewStringBoolPool(64) 378