2 * @brief Xapian::Query API class
4 /* Copyright (C) 2011,2012,2013,2015 Olly Betts
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 #include "xapian/query.h"
24 #include "queryinternal.h"
30 #include "vectortermlist.h"
36 // Extra () are needed to resolve ambiguity with method declaration.
37 const Query
Query::MatchAll((string()));
39 const Query
Query::MatchNothing
;
41 Query::Query(const string
& term
, Xapian::termcount wqf
, Xapian::termpos pos
)
42 : internal(new Xapian::Internal::QueryTerm(term
, wqf
, pos
))
44 LOGCALL_CTOR(API
, "Query", term
| wqf
| pos
);
47 Query::Query(Xapian::PostingSource
* source
)
48 : internal(new Xapian::Internal::QueryPostingSource(source
))
50 LOGCALL_CTOR(API
, "Query", source
);
53 Query::Query(double factor
, const Xapian::Query
& subquery
)
55 LOGCALL_CTOR(API
, "Query", factor
| subquery
);
57 if (!subquery
.empty())
58 internal
= new Xapian::Internal::QueryScaleWeight(factor
, subquery
);
61 Query::Query(op op_
, const Xapian::Query
& subquery
, double factor
)
63 LOGCALL_CTOR(API
, "Query", op_
| subquery
| factor
);
65 if (rare(op_
!= OP_SCALE_WEIGHT
))
66 throw Xapian::InvalidArgumentError("op must be OP_SCALE_WEIGHT");
67 // If the subquery is MatchNothing then generate Query() which matches
69 if (subquery
.internal
.get())
70 internal
= new Xapian::Internal::QueryScaleWeight(factor
, subquery
);
73 Query::Query(op op_
, Xapian::valueno slot
, const std::string
& limit
)
75 LOGCALL_CTOR(API
, "Query", op_
| slot
| limit
);
77 if (op_
== OP_VALUE_GE
) {
79 internal
= MatchAll
.internal
;
81 internal
= new Xapian::Internal::QueryValueGE(slot
, limit
);
82 } else if (usual(op_
== OP_VALUE_LE
)) {
83 internal
= new Xapian::Internal::QueryValueLE(slot
, limit
);
85 throw Xapian::InvalidArgumentError("op must be OP_VALUE_LE or OP_VALUE_GE");
89 Query::Query(op op_
, Xapian::valueno slot
,
90 const std::string
& begin
, const std::string
& end
)
92 LOGCALL_CTOR(API
, "Query", op_
| slot
| begin
| end
);
94 if (rare(op_
!= OP_VALUE_RANGE
))
95 throw Xapian::InvalidArgumentError("op must be OP_VALUE_RANGE");
96 // If begin > end then generate Query() which matches nothing.
98 internal
= new Xapian::Internal::QueryValueLE(slot
, end
);
99 } else if (usual(begin
<= end
)) {
100 internal
= new Xapian::Internal::QueryValueRange(slot
, begin
, end
);
105 const std::string
& pattern
,
106 Xapian::termcount max_expansion
,
110 LOGCALL_CTOR(API
, "Query", op_
| pattern
| max_expansion
| max_type
| combiner
);
111 if (rare(op_
!= OP_WILDCARD
))
112 throw Xapian::InvalidArgumentError("op must be OP_WILDCARD");
113 if (rare(combiner
!= OP_SYNONYM
&& combiner
!= OP_MAX
&& combiner
!= OP_OR
))
114 throw Xapian::InvalidArgumentError("combiner must be OP_SYNONYM or OP_MAX or OP_OR");
115 internal
= new Xapian::Internal::QueryWildcard(pattern
,
122 Query::get_terms_begin() const
125 return TermIterator();
127 vector
<pair
<Xapian::termpos
, string
> > terms
;
128 internal
->gather_terms(static_cast<void*>(&terms
));
129 sort(terms
.begin(), terms
.end());
132 const string
* old_term
= NULL
;
133 Xapian::termpos old_pos
= 0;
134 for (auto && i
: terms
) {
135 // Remove duplicates (same term at the same position).
136 if (old_term
&& old_pos
== i
.first
&& *old_term
== i
.second
)
139 v
.push_back(i
.second
);
141 old_term
= &(i
.second
);
143 return TermIterator(new VectorTermList(v
.begin(), v
.end()));
147 Query::get_unique_terms_begin() const
150 return TermIterator();
152 vector
<pair
<Xapian::termpos
, string
> > terms
;
153 internal
->gather_terms(static_cast<void*>(&terms
));
154 sort(terms
.begin(), terms
.end(), [](
155 const pair
<Xapian::termpos
, string
>& a
,
156 const pair
<Xapian::termpos
, string
>& b
) {
157 return a
.second
< b
.second
;
161 const string
* old_term
= NULL
;
162 for (auto && i
: terms
) {
163 // Remove duplicate term names.
164 if (old_term
&& *old_term
== i
.second
)
167 v
.push_back(i
.second
);
168 old_term
= &(i
.second
);
170 return TermIterator(new VectorTermList(v
.begin(), v
.end()));
174 Query::get_length() const XAPIAN_NOEXCEPT
176 return (internal
.get() ? internal
->get_length() : 0);
180 Query::serialise() const
184 internal
->serialise(result
);
189 Query::unserialise(const string
& s
, const Registry
& reg
)
191 const char * p
= s
.data();
192 const char * end
= p
+ s
.size();
193 Query::Internal
* q
= Query::Internal::unserialise(&p
, end
, reg
);
199 Query::get_type() const XAPIAN_NOEXCEPT
202 return Xapian::Query::LEAF_MATCH_NOTHING
;
203 return internal
->get_type();
207 Query::get_num_subqueries() const XAPIAN_NOEXCEPT
209 return internal
.get() ? internal
->get_num_subqueries() : 0;
213 Query::get_subquery(size_t n
) const
215 return internal
->get_subquery(n
);
219 Query::get_description() const
221 string desc
= "Query(";
223 desc
+= internal
->get_description();
229 Query::init(op op_
, size_t n_subqueries
, Xapian::termcount parameter
)
232 op_
!= OP_NEAR
&& op_
!= OP_PHRASE
&& op_
!= OP_ELITE_SET
)
233 throw InvalidArgumentError("parameter only valid with OP_NEAR, "
234 "OP_PHRASE or OP_ELITE_SET");
238 internal
= new Xapian::Internal::QueryAnd(n_subqueries
);
241 internal
= new Xapian::Internal::QueryOr(n_subqueries
);
244 internal
= new Xapian::Internal::QueryAndNot(n_subqueries
);
247 internal
= new Xapian::Internal::QueryXor(n_subqueries
);
250 internal
= new Xapian::Internal::QueryAndMaybe(n_subqueries
);
253 internal
= new Xapian::Internal::QueryFilter(n_subqueries
);
256 internal
= new Xapian::Internal::QueryNear(n_subqueries
,
260 internal
= new Xapian::Internal::QueryPhrase(n_subqueries
,
264 internal
= new Xapian::Internal::QueryEliteSet(n_subqueries
,
268 internal
= new Xapian::Internal::QuerySynonym(n_subqueries
);
271 internal
= new Xapian::Internal::QueryMax(n_subqueries
);
274 throw InvalidArgumentError("op not valid with a list of subqueries");
279 Query::add_subquery(const Xapian::Query
& subquery
)
281 // We could handle this in a type-safe way, but we'd need to at least
282 // declare Xapian::Internal::QueryBranch in the API header, which seems
283 // less desirable than a static_cast<> here.
284 Xapian::Internal::QueryBranch
* branch_query
=
285 static_cast<Xapian::Internal::QueryBranch
*>(internal
.get());
286 Assert(branch_query
);
287 branch_query
->add_subquery(subquery
);
293 Xapian::Internal::QueryBranch
* branch_query
=
294 static_cast<Xapian::Internal::QueryBranch
*>(internal
.get());
296 internal
= branch_query
->done();