# operator-specific value
OP_EQUAL = "="
OP_NOT_EQUAL = "!="
+OP_LT = "<"
+OP_LE = "<="
+OP_GT = ">"
+OP_GE = ">="
OP_REGEXP = "=~"
OP_CONTAINS = "=[]"
#: Characters used for detecting user-written filters (see L{_CheckFilter})
-FILTER_DETECTION_CHARS = frozenset("()=/!~'\"\\" + string.whitespace)
+FILTER_DETECTION_CHARS = frozenset("()=/!~'\"\\<>" + string.whitespace)
#: Characters used to detect globbing filters (see L{_CheckGlobbing})
GLOB_DETECTION_CHARS = frozenset("*?")
binopstbl = {
"==": OP_EQUAL,
"!=": OP_NOT_EQUAL,
+ "<": OP_LT,
+ "<=": OP_LE,
+ ">": OP_GT,
+ ">=": OP_GE,
}
binary_cond = (field_name + pyp.oneOf(binopstbl.keys()) + rval)
qlang.OP_NOT_EQUAL:
(_OPTYPE_BINARY, [(flags, compat.partial(_WrapNot, fn), valprepfn)
for (flags, fn, valprepfn) in _EQUALITY_CHECKS]),
+ qlang.OP_LT: (_OPTYPE_BINARY, [
+ (None, operator.lt, None),
+ ]),
+ qlang.OP_GT: (_OPTYPE_BINARY, [
+ (None, operator.gt, None),
+ ]),
+ qlang.OP_LE: (_OPTYPE_BINARY, [
+ (None, operator.le, None),
+ ]),
+ qlang.OP_GE: (_OPTYPE_BINARY, [
+ (None, operator.ge, None),
+ ]),
qlang.OP_REGEXP: (_OPTYPE_BINARY, [
(None, lambda lhs, rhs: rhs.search(lhs), _PrepareRegex),
]),
<condition> ::=
{ /* Value comparison */
- <field> { == | != } <value>
+ <field> { == | != | < | <= | >= | > } <value>
/* Collection membership */
| <value> [ not ] in <field>
Equality
*!=*
Inequality
+*<*
+ Less than
+*<=*
+ Less than or equal
+*>*
+ Greater than
+*>=*
+ Greater than or equal
*=~*
Pattern match using regular expression
*!~*
[qlang.OP_NOT, [qlang.OP_REGEXP, "field",
utils.DnsNameGlobPattern("*.example.*")]])
+ self._Test("ctime < 1234", [qlang.OP_LT, "ctime", 1234])
+ self._Test("ctime > 1234", [qlang.OP_GT, "ctime", 1234])
+ self._Test("mtime <= 9999", [qlang.OP_LE, "mtime", 9999])
+ self._Test("mtime >= 9999", [qlang.OP_GE, "mtime", 9999])
+
def testAllFields(self):
for name in frozenset(i for d in query.ALL_FIELD_LISTS for i in d.keys()):
self._Test("%s == \"value\"" % name, [qlang.OP_EQUAL, name, "value"])
# Non-matching regexp delimiters
tests.append("name =~ /foobarbaz#")
+ # Invalid operators
+ tests.append("name <> value")
+ tests.append("name => value")
+ tests.append("name =< value")
+
for qfilter in tests:
try:
qlang.ParseFilter(qfilter, parser=self.parser)
self.assertRaises(errors.ParameterError, query.Query, fielddefs, ["name"],
qfilter=["=~", "name", r"["])
+ def testFilterLessGreater(self):
+ fielddefs = query._PrepareFieldList([
+ (query._MakeField("value", "Value", constants.QFT_NUMBER, "Value"),
+ None, 0, lambda ctx, item: item),
+ ], [])
+
+ data = range(100)
+
+ q = query.Query(fielddefs, ["value"],
+ qfilter=["<", "value", 20])
+ self.assertTrue(q.RequestedNames() is None)
+ self.assertEqual(q.Query(data),
+ [[(constants.RS_NORMAL, i)] for i in range(20)])
+
+ q = query.Query(fielddefs, ["value"],
+ qfilter=["<=", "value", 30])
+ self.assertTrue(q.RequestedNames() is None)
+ self.assertEqual(q.Query(data),
+ [[(constants.RS_NORMAL, i)] for i in range(31)])
+
+ q = query.Query(fielddefs, ["value"],
+ qfilter=[">", "value", 40])
+ self.assertTrue(q.RequestedNames() is None)
+ self.assertEqual(q.Query(data),
+ [[(constants.RS_NORMAL, i)] for i in range(41, 100)])
+
+ q = query.Query(fielddefs, ["value"],
+ qfilter=[">=", "value", 50])
+ self.assertTrue(q.RequestedNames() is None)
+ self.assertEqual(q.Query(data),
+ [[(constants.RS_NORMAL, i)] for i in range(50, 100)])
+
if __name__ == "__main__":
testutils.GanetiTestProgram()