Module: check_mk
Branch: master
Commit: 4993cf10ad4ff3f04bb29036da929ecc71ecffe0
URL:
http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=4993cf10ad4ff3…
Author: Sven Panne <sp(a)mathias-kettner.de>
Date: Tue Oct 24 14:07:45 2017 +0200
5192 Added new filter operators for list-valued columns
Previously only 4 operators were available for filtering list-valued
columns:
<ul>
<li<tt>=</tt>: checks that the list is empty</li>
<li><tt>!=</tt>: checks that the list is non-empty</li>
<li><tt><</tt>: checks that an element is not contained in the
list using equality</li>
<li><tt>>=</tt>: checks that an element is contained in the
list using equality</li>
</ul>
6 new operators have been added:
<ul>
<li><tt><=</tt>: checks that an element is contained in the
list using case-insensitive equality</li>
<li><tt>></tt>: checks that an element is not contained in the
list using case-insensitive equality</li>
<li><tt>~</tt>: checks that an element is contained in the list using
a substring regex match</li>
<li><tt>!~</tt>: checks that an element is not contained in the list
using a substring regex match</li>
<li><tt>~~</tt>: checks that an element is contained in the list
using a case-insensitive substring regex match</li>
<li><tt>!~~</tt>: checks that an element is not contained in the list
using a case-insensitive substring regex match</li>
</ul>
Change-Id: I47288a1a87817c3ef66b5167a7aad602b184083d
---
.werks/5192 | 29 ++++++++++++++++
livestatus/src/ListFilter.cc | 81 ++++++++++++++++++++++++++++++++++----------
livestatus/src/ListFilter.h | 18 +++++++---
3 files changed, 106 insertions(+), 22 deletions(-)
diff --git a/.werks/5192 b/.werks/5192
new file mode 100644
index 0000000..999c353
--- /dev/null
+++ b/.werks/5192
@@ -0,0 +1,29 @@
+Title: Added new filter operators for list-valued columns
+Level: 1
+Component: livestatus
+Compatible: compat
+Edition: cre
+Version: 1.5.0i1
+Date: 1508845760
+Class: feature
+
+Previously only 4 operators were available for filtering list-valued
+columns:
+
+<ul>
+ <li<tt>=</tt>: checks that the list is empty</li>
+ <li><tt>!=</tt>: checks that the list is non-empty</li>
+ <li><tt><</tt>: checks that an element is not contained in
the list using equality</li>
+ <li><tt>>=</tt>: checks that an element is contained in the
list using equality</li>
+</ul>
+
+6 new operators have been added:
+
+<ul>
+ <li><tt><=</tt>: checks that an element is contained in the
list using case-insensitive equality</li>
+ <li><tt>></tt>: checks that an element is not contained in
the list using case-insensitive equality</li>
+ <li><tt>~</tt>: checks that an element is contained in the list
using a substring regex match</li>
+ <li><tt>!~</tt>: checks that an element is not contained in the list
using a substring regex match</li>
+ <li><tt>~~</tt>: checks that an element is contained in the list
using a case-insensitive substring regex match</li>
+ <li><tt>!~~</tt>: checks that an element is not contained in the
list using a case-insensitive substring regex match</li>
+</ul>
diff --git a/livestatus/src/ListFilter.cc b/livestatus/src/ListFilter.cc
index e0bd25d..aa58b71 100644
--- a/livestatus/src/ListFilter.cc
+++ b/livestatus/src/ListFilter.cc
@@ -24,41 +24,86 @@
#include "ListFilter.h"
#include <algorithm>
-#include <ostream>
-#include <vector>
+#include <cstring>
+#include <sstream>
+#include <string>
#include "ListColumn.h"
#include "Logger.h"
#include "Row.h"
ListFilter::ListFilter(const ListColumn &column, RelationalOperator relOp,
- std::string element)
- : _column(column), _relOp(relOp), _element(std::move(element)) {}
+ std::string value)
+ : _column(column), _relOp(relOp), _ref_string(std::move(value)) {
+ switch (_relOp) {
+ case RelationalOperator::matches:
+ case RelationalOperator::doesnt_match:
+ case RelationalOperator::matches_icase:
+ case RelationalOperator::doesnt_match_icase:
+ _regex.assign(_ref_string,
+ (_relOp == RelationalOperator::matches_icase ||
+ _relOp == RelationalOperator::doesnt_match_icase)
+ ? std::regex::extended | std::regex::icase
+ : std::regex::extended);
+ break;
+ case RelationalOperator::equal:
+ case RelationalOperator::not_equal:
+ case RelationalOperator::equal_icase:
+ case RelationalOperator::not_equal_icase:
+ case RelationalOperator::less:
+ case RelationalOperator::greater_or_equal:
+ case RelationalOperator::greater:
+ case RelationalOperator::less_or_equal:
+ break;
+ }
+}
bool ListFilter::accepts(Row row, const contact *auth_user,
std::chrono::seconds /* timezone_offset */) const {
switch (_relOp) {
case RelationalOperator::equal:
+ if (!_ref_string.empty()) {
+ Informational(_column.logger())
+ << "Sorry, equality for lists implemented only for
emptiness";
+ return false;
+ }
+ return !any(row, auth_user,
+ [](const std::string &) { return true; });
case RelationalOperator::not_equal:
- if (!_element.empty()) {
+ if (!_ref_string.empty()) {
Informational(_column.logger())
- << "Sorry, equality for lists implemented only for
emptyness";
+ << "Sorry, inequality for lists implemented only for
emptiness";
+ return false;
}
- return _column.getValue(row, auth_user).empty() ==
- (_relOp == RelationalOperator::equal);
- case RelationalOperator::less:
- case RelationalOperator::greater_or_equal: {
- auto val = _column.getValue(row, auth_user);
- return (std::find(val.begin(), val.end(), _element) == val.end()) ==
- (_relOp == RelationalOperator::less);
- }
+ return any(row, auth_user,
+ [](const std::string &) { return true; });
case RelationalOperator::matches:
- case RelationalOperator::doesnt_match:
- case RelationalOperator::equal_icase:
- case RelationalOperator::not_equal_icase:
case RelationalOperator::matches_icase:
+ return any(row, auth_user, [&](const std::string &elem) {
+ return regex_search(elem, _regex);
+ });
+ case RelationalOperator::doesnt_match:
case RelationalOperator::doesnt_match_icase:
+ return !any(row, auth_user, [&](const std::string &elem) {
+ return regex_search(elem, _regex);
+ });
+ case RelationalOperator::less:
+ return !any(row, auth_user, [&](const std::string &elem) {
+ return _ref_string == elem;
+ });
+ case RelationalOperator::greater_or_equal:
+ return any(row, auth_user, [&](const std::string &elem) {
+ return _ref_string == elem;
+ });
case RelationalOperator::greater:
+ return !any(row, auth_user, [&](const std::string &elem) {
+ return strcasecmp(_ref_string.c_str(), elem.c_str()) == 0;
+ });
case RelationalOperator::less_or_equal:
+ return any(row, auth_user, [&](const std::string &elem) {
+ return strcasecmp(_ref_string.c_str(), elem.c_str()) == 0;
+ });
+ case RelationalOperator::equal_icase:
+ case RelationalOperator::not_equal_icase:
Informational(_column.logger())
<< "Sorry. Operator " << _relOp
<< " for list columns not implemented.";
@@ -71,7 +116,7 @@ const std::string *ListFilter::valueForIndexing(
const std::string &column_name) const {
switch (_relOp) {
case RelationalOperator::greater_or_equal:
- return column_name == columnName() ? &_element : nullptr;
+ return column_name == columnName() ? &_ref_string : nullptr;
case RelationalOperator::equal:
case RelationalOperator::not_equal:
case RelationalOperator::matches:
diff --git a/livestatus/src/ListFilter.h b/livestatus/src/ListFilter.h
index 0de2b2b..6fde087 100644
--- a/livestatus/src/ListFilter.h
+++ b/livestatus/src/ListFilter.h
@@ -26,18 +26,21 @@
#define ListFilter_h
#include "config.h" // IWYU pragma: keep
+#include <algorithm>
#include <chrono>
+#include <regex>
#include <string>
+#include <vector>
#include "ColumnFilter.h"
+#include "ListColumn.h"
+#include "Row.h"
#include "contact_fwd.h"
#include "opids.h"
-class ListColumn;
-class Row;
class ListFilter : public ColumnFilter {
public:
ListFilter(const ListColumn &column, RelationalOperator relOp,
- std::string element);
+ std::string value);
bool accepts(Row row, const contact *auth_user,
std::chrono::seconds timezone_offset) const override;
const std::string *valueForIndexing(
@@ -47,7 +50,14 @@ public:
private:
const ListColumn &_column;
const RelationalOperator _relOp;
- const std::string _element;
+ const std::string _ref_string;
+ std::regex _regex;
+
+ template <typename UnaryPredicate>
+ bool any(Row row, const contact *auth_user, UnaryPredicate pred) const {
+ auto val = _column.getValue(row, auth_user);
+ return std::any_of(val.begin(), val.end(), pred);
+ }
};
#endif // ListFilter_h