ARB
query_expr.h
Go to the documentation of this file.
1 // ============================================================= //
2 // //
3 // File : query_expr.h //
4 // Purpose : gui independent query functionality //
5 // //
6 // Coded by Ralf Westram (coder@reallysoft.de) in April 2017 //
7 // http://www.arb-home.de/ //
8 // //
9 // ============================================================= //
10 
11 #ifndef QUERY_EXPR_H
12 #define QUERY_EXPR_H
13 
14 #ifndef SMARTPTR_H
15 #include <smartptr.h>
16 #endif
17 #ifndef ARB_MATCH_H
18 #include <arb_match.h>
19 #endif
20 #ifndef ARBDBT_H
21 #include <arbdbt.h>
22 #endif
23 #ifndef GB_ACI_H
24 #include <gb_aci.h>
25 #endif
26 #ifndef _GLIBCXX_STRING
27 #include <string>
28 #endif
29 
30 #define qe_assert(cond) arb_assert(cond)
31 
32 // --------------------------------------------------------------------------------
33 // Provides query logic as used in ARB species search & query:
34 //
35 // - multiple query expressions
36 // - combinable via AND and OR (w/o precedence!)
37 // - invertible (global "not")
38 // - query expression consists of
39 // - some key (e.g. name of DB-field)
40 // - equal / not-equal operator
41 // - a match expression (wildcard, numeric compare, ACI, regexpr, ...)
42 // - combining operator (AND/OR)
43 // - provides "hit reason" for each positive hit
44 //
45 //
46 // To implement specific queries derive from classes QueryTarget and QueryKey.
47 // - QueryTarget-derivate shall be used by client to iterate over queried "things"
48 // - QueryKey-derivate defines how to access the (user-defined) specific key of the target
49 // i.e. how to retrieve the data that actually will be queried vs. match expressions.
50 //
51 // Create an instance of QueryExpr (e.g. from AWAR defined values),
52 // loop your QueryTarget-derivate over all targets and
53 // ask your QueryExpr-instance whether it matches the current target.
54 //
55 //
56 // Example usage:
57 // ../DB_QUERY/db_query.cxx@TargetItem
58 // ../DB_QUERY/db_query.cxx@ItemQueryKey
59 // --------------------------------------------------------------------------------
60 
61 
62 #define MAX_SHOWN_DATA_SIZE 500
63 
65 
66 enum query_type {
79 };
80 
82  QKEY_EXPLICIT, // query should match one explicit target (e.g. a specific DB-field)
83  QKEY_ANY, // query should match one of many targets - no matter which (e.g. any DB-field)
84  QKEY_ALL, // query should match all targets (e.g. all DB-fields)
85  QKEY_ANY_REC, // like QKEY_ANY (but descend through all sub-containers)
86  QKEY_ALL_REC, // like QKEY_ALL (dito)
87 };
88 
89 class QueryTarget : virtual Noncopyable {
90  // Points to a specific target (e.g. a species).
91  // Can be matched using a QueryKey.
92 
93  GBL_env env;
94 
95 public:
96  QueryTarget(GBDATA *gb_main, const char *treename) : env(gb_main, treename) {}
97  virtual ~QueryTarget() {}
98 
99  GBDATA *get_gb_main() const { return env.get_gb_main(); }
100  const GBL_env& get_env() const { return env; }
101 
102  // virtual interface:
103  virtual GBDATA *get_ACI_item() const = 0; // may NOT return NULp!
104  // ----------
105 };
106 
107 class QueryKey {
108  query_key_type type; // type of search key
109 
110 public:
112  type(type_)
113  {}
114  virtual ~QueryKey() {}
115 
116  // virtual interface:
117  virtual char *get_target_data(const QueryTarget& target, GB_ERROR& error) const = 0; // retrieve content of target-key (e.g. species field)
118 
119  virtual const char *get_name() const = 0; // name of target (e.g. for reports)
120  virtual bool iterate() const = 0; // iterate key to next entry (not for QKEY_EXPLICIT)
121  virtual void reset() const = 0; // reset iteration
122  // ----------
123 
124  bool next() const {
125  if (type == QKEY_EXPLICIT) return false; // explicit keys cannot iterate
126  return iterate();
127  }
128 
129  query_key_type get_type() const { return type; }
130  void negate() {
131  switch (type) {
132  case QKEY_EXPLICIT: break;
133  case QKEY_ALL: type = QKEY_ANY; break; // not match all keys <=> mismatch any key
134  case QKEY_ALL_REC: type = QKEY_ANY_REC; break;
135  case QKEY_ANY: type = QKEY_ALL; break; // not match any key <=> mismatch all keys
136  case QKEY_ANY_REC: type = QKEY_ALL_REC; break;
137  }
138  }
139 };
141 
142 struct ExplicitQueryKey: public QueryKey {
145  {}
147 
148  // virtual interface:
149  char *get_target_data(const QueryTarget& target, GB_ERROR& error) const OVERRIDE = 0; // retrieve content of target-key (e.g. species field)
150  const char *get_name() const OVERRIDE = 0; // name of target (e.g. for reports)
151 
152  // implement part of QueryKey interface:
153  bool iterate() const { return false; } // iterate key to next entry (not for QKEY_EXPLICIT)
154  void reset() const {} // reset iteration
155 };
156 
157 class QueryExpr : virtual Noncopyable {
158  query_operator op; // operator (AND or OR)
159  QueryKeyPtr qkey; // what to search (specialized by caller)
160 
161  bool Not; // true means "don't match"
162  char *expr; // search expression
163 
164  query_type type; // type of 'query'
165  struct XQuery : virtual Noncopyable { // used for some values of 'type'
167  GBS_regex *regexp;
168  float number;
169  XQuery() : regexp(NULp) {}
170  ~XQuery() { GBS_free_regexpr(regexp); }
171  } xquery;
172 
173  mutable char *error; // either set by matches() or manually via setError(); once set all future matches fail
174  mutable char *lastACIresult; // result of last ACI query
175 
176  QueryExpr *next;
177 
178  // --------------------
179 
180  void detect_query_type();
181  QueryExpr *remove_tail();
182 
183  bool first_matches(const QueryTarget& target, char*& matched_data) const;
184  bool shallMatch() const { return !Not; }
185 
186  const char *get_last_ACI_result() const { return type == AQT_ACI ? lastACIresult : NULp; }
187 
188 public:
189 
190  QueryExpr(query_operator aqo, QueryKeyPtr key, bool not_equal, const char *expression);
192  free(expr);
193  free(lastACIresult);
194  free(error);
195  delete next;
196  }
197 
198  void append(QueryExpr*& tail);
199 
200  query_key_type get_key_type() const { return qkey->get_type(); }
201 
202  QueryKey& get_key() { return *qkey; }
203  const QueryKey& get_key() const { return *qkey; }
204 
205  void negate(); // expr -> !expr
206 
207  bool matches(const QueryTarget& target, std::string& hit_reason) const;
208 
209  GB_ERROR getError(int count = 0) const;
210  void setError(GB_ERROR error_) const {
211  qe_assert(!error); // refuse to overwrite errors
212  error = strdup(error_);
213  }
214 
215 #if defined(DEBUG)
216  std::string dump_str() const {
217  return std::string(qkey->get_name()) + (Not ? "!=" : "==") + expr;
218  }
219  void dump(std::string *prev = NULp) const {
220  std::string mine = dump_str();
221  if (prev) {
222  std::string both = *prev+' ';
223  switch (op) {
224  case AND: both += "&&"; break;
225  case OR: both += "||"; break;
226  default: qe_assert(0); break;
227  }
228  both += ' '+mine;
229  mine = both;
230 
231  if (next) mine = '('+mine+')';
232  }
233 
234  if (next) next->dump(&mine);
235  else fputs(mine.c_str(), stdout);
236  }
237 #endif // DEBUG
238 };
239 
240 #else
241 #error query_expr.h included twice
242 #endif // QUERY_EXPR_H
const char * GB_ERROR
Definition: arb_core.h:25
virtual void reset() const =0
return string(buffer, length)
char * get_target_data(const QueryTarget &target, GB_ERROR &error) const OVERRIDE=0
const GBL_env & get_env() const
Definition: query_expr.h:100
GBDATA * get_gb_main() const
Definition: query_expr.h:99
virtual const char * get_name() const =0
virtual bool iterate() const =0
Definition: macke.h:201
bool next() const
Definition: query_expr.h:124
SmartPtr< QueryKey > QueryKeyPtr
Definition: query_expr.h:140
void reset() const
Definition: query_expr.h:154
void negate()
Definition: query_expr.h:130
static void error(const char *msg)
Definition: mkptypes.cxx:96
query_key_type
Definition: query_expr.h:81
char * str
Definition: defines.h:20
virtual char * get_target_data(const QueryTarget &target, GB_ERROR &error) const =0
query_type
Definition: query_expr.h:66
virtual ~QueryKey()
Definition: query_expr.h:114
void append(QueryExpr *&tail)
Definition: query_expr.cxx:46
~ExplicitQueryKey() OVERRIDE
Definition: query_expr.h:146
query_key_type get_type() const
Definition: query_expr.h:129
fputs(TRACE_PREFIX, stderr)
const char * get_name() const OVERRIDE=0
#define qe_assert(cond)
Definition: query_expr.h:30
bool iterate() const
Definition: query_expr.h:153
#define OVERRIDE
Definition: cxxforward.h:112
bool matches(const QueryTarget &target, std::string &hit_reason) const
Definition: query_expr.cxx:277
query_operator
Definition: query_expr.h:64
const QueryKey & get_key() const
Definition: query_expr.h:203
void negate()
Definition: query_expr.cxx:56
query_key_type get_key_type() const
Definition: query_expr.h:200
void GBS_free_regexpr(GBS_regex *toFree)
Definition: arb_match.cxx:62
#define NULp
Definition: cxxforward.h:116
GB_ERROR getError(int count=0) const
Definition: query_expr.cxx:77
QueryTarget(GBDATA *gb_main, const char *treename)
Definition: query_expr.h:96
Definition: query_expr.h:64
void setError(GB_ERROR error_) const
Definition: query_expr.h:210
QueryKey(query_key_type type_)
Definition: query_expr.h:111
GBDATA * gb_main
Definition: adname.cxx:32
QueryExpr(query_operator aqo, QueryKeyPtr key, bool not_equal, const char *expression)
Definition: query_expr.cxx:16
GBDATA * get_gb_main() const
Definition: gb_aci.h:135
QueryKey & get_key()
Definition: query_expr.h:202
virtual ~QueryTarget()
Definition: query_expr.h:97
virtual GBDATA * get_ACI_item() const =0
Definition: query_expr.h:64