1 /////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2009-2014 Alan Wright. All rights reserved.
3 // Distributable under the terms of either the Apache License (Version 2.0)
4 // or the GNU Lesser General Public License.
5 /////////////////////////////////////////////////////////////////////////////
6 
7 #include "LuceneInc.h"
8 #include "TermRangeTermEnum.h"
9 #include "IndexReader.h"
10 #include "Term.h"
11 #include "Collator.h"
12 #include "StringUtils.h"
13 #include "VariantUtils.h"
14 
15 namespace Lucene {
16 
TermRangeTermEnum(const IndexReaderPtr & reader,const String & field,StringValue lowerTermText,StringValue upperTermText,bool includeLower,bool includeUpper,const CollatorPtr & collator)17 TermRangeTermEnum::TermRangeTermEnum(const IndexReaderPtr& reader, const String& field, StringValue lowerTermText,
18                                      StringValue upperTermText, bool includeLower, bool includeUpper, const CollatorPtr& collator) {
19     this->collator = collator;
20     this->_endEnum = false;
21     this->upperTermText = upperTermText;
22     this->lowerTermText = lowerTermText;
23     this->includeLower = includeLower;
24     this->includeUpper = includeUpper;
25     this->field = field;
26 
27     // do a little bit of normalization: open ended range queries should always be inclusive.
28     if (VariantUtils::isNull(this->lowerTermText)) {
29         this->includeLower = true;
30     }
31 
32     if (VariantUtils::isNull(this->upperTermText)) {
33         this->includeUpper = true;
34     }
35 
36     String startTermText(collator ? L"" : VariantUtils::get<String>(this->lowerTermText));
37     setEnum(reader->terms(newLucene<Term>(this->field, startTermText)));
38 }
39 
~TermRangeTermEnum()40 TermRangeTermEnum::~TermRangeTermEnum() {
41 }
42 
difference()43 double TermRangeTermEnum::difference() {
44     return 1.0;
45 }
46 
endEnum()47 bool TermRangeTermEnum::endEnum() {
48     return _endEnum;
49 }
50 
termCompare(const TermPtr & term)51 bool TermRangeTermEnum::termCompare(const TermPtr& term) {
52     if (!collator) {
53         // Use Unicode code point ordering
54         bool checkLower = false;
55         if (!includeLower) { // make adjustments to set to exclusive
56             checkLower = true;
57         }
58         if (term && term->field() == field) {
59             if (!checkLower || VariantUtils::isNull(lowerTermText) || term->text().compare(VariantUtils::get<String>(lowerTermText)) > 0) {
60                 checkLower = false;
61                 if (!VariantUtils::isNull(upperTermText)) {
62                     int32_t compare = VariantUtils::get<String>(upperTermText).compare(term->text());
63                     // if beyond the upper term, or is exclusive and this is equal to the upper term, break out
64                     if (compare < 0 || (!includeUpper && compare == 0)) {
65                         _endEnum = true;
66                         return false;
67                     }
68                 }
69                 return true;
70             }
71         } else {
72             // break
73             _endEnum = true;
74             return false;
75         }
76         return false;
77     } else {
78         if (term && term->field() == field) {
79             if ((VariantUtils::isNull(lowerTermText) ||
80                     (includeLower ? collator->compare(term->text(), VariantUtils::get<String>(lowerTermText)) >= 0 :
81                      collator->compare(term->text(), VariantUtils::get<String>(lowerTermText)) > 0)) &&
82                     (VariantUtils::isNull(upperTermText) ||
83                      (includeUpper ? collator->compare(term->text(), VariantUtils::get<String>(upperTermText)) <= 0 :
84                       collator->compare(term->text(), VariantUtils::get<String>(upperTermText)) < 0))) {
85                 return true;
86             }
87             return false;
88         }
89         _endEnum = true;
90         return false;
91     }
92 }
93 
94 }
95