1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
/*
** Copyright (C) 2017 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public License
** as published by the Free Software Foundation; either version 2.1
** of the License, or (at your option) any later version.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public
** License along with this library; if not, write to the Free
** Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
** 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
#include <xapian.h>
#include "parser/xapian.hh"
using namespace Mux;
static Xapian::Query
xapian_query_op (const Mux::Tree& tree)
{
Xapian::Query::op op;
switch (tree.node.type) {
case Node::Type::OpNot: // OpNot x ::= <all> AND NOT x
if (tree.children.size() != 1)
throw std::runtime_error ("invalid # of children");
return Xapian::Query (Xapian::Query::OP_AND_NOT,
Xapian::Query::MatchAll,
xapian_query(tree.children.front()));
case Node::Type::OpAnd: op = Xapian::Query::OP_AND; break;
case Node::Type::OpOr: op = Xapian::Query::OP_OR; break;
case Node::Type::OpXor: op = Xapian::Query::OP_XOR; break;
case Node::Type::OpAndNot: op = Xapian::Query::OP_AND_NOT; break;
default: throw std::runtime_error ("invalid op"); // bug
}
std::vector<Xapian::Query> childvec;
for (const auto& subtree: tree.children)
childvec.emplace_back(xapian_query(subtree));
return Xapian::Query(op, childvec.begin(), childvec.end());
}
static Xapian::Query
make_query (const Value* val, const std::string& str, bool maybe_wildcard)
{
#ifndef XAPIAN_HAVE_OP_WILDCARD
return Xapian::Query(val->prefix + str);
#else
const auto vlen{str.length()};
if (!maybe_wildcard || vlen <= 1 || str[vlen - 1] != '*')
return Xapian::Query(val->prefix + str);
else
return Xapian::Query(Xapian::Query::OP_WILDCARD,
val->prefix + str.substr(0, vlen - 1));
#endif/*XAPIAN_HAVE_OP_WILDCARD*/
}
static Xapian::Query
xapian_query_value (const Mux::Tree& tree)
{
const auto v = dynamic_cast<Value*> (tree.node.data.get());
if (!v->phrase)
return make_query(v, v->value, true/*maybe-wildcard*/);
const auto parts = split (v->value, " ");
if (parts.empty())
return Xapian::Query::MatchNothing; // shouldn't happen
if (parts.size() == 1)
return make_query(v, parts.front(), true/*maybe-wildcard*/);
std::vector<Xapian::Query> phvec;
for (const auto p: parts)
phvec.emplace_back(make_query(v, p, false/*no wildcards*/));
return Xapian::Query (Xapian::Query::OP_PHRASE, phvec.begin(), phvec.end());
}
static Xapian::Query
xapian_query_range (const Mux::Tree& tree)
{
const auto r { dynamic_cast<Range *>(tree.node.data.get()) };
return Xapian::Query(Xapian::Query::OP_VALUE_RANGE, (Xapian::valueno)r->id,
r->lower, r->upper);
}
Xapian::Query
Mux::xapian_query (const Mux::Tree& tree)
{
switch (tree.node.type) {
case Node::Type::Empty:
return Xapian::Query();
case Node::Type::OpNot:
case Node::Type::OpAnd:
case Node::Type::OpOr:
case Node::Type::OpXor:
case Node::Type::OpAndNot:
return xapian_query_op (tree);
case Node::Type::Value:
return xapian_query_value (tree);
case Node::Type::Range:
return xapian_query_range (tree);
default:
throw std::runtime_error ("invalid query"); // bug
}
}
|