8000 add regex operator by Bodyhealer · Pull Request #74 · ivelum/djangoql · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

add regex operator #74

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ parenthesis. DjangoQL is case-sensitive.
- comparison operators: ``=``, ``!=``, ``<``, ``<=``, ``>``, ``>=``
- work as you expect. ``~`` and ``!~`` - test whether or not a string contains
a substring (translated into ``__icontains``);
- ``regex`` - find based on regular expression (translated into ``__iregex``);
- test a value vs. list: ``in``, ``not in``. Example:
``pk in (2, 3)``.

Expand Down
7 changes: 6 additions & 1 deletion djangoql/lexer.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def find_column(self, t):

re_escaped_char = r'\\[\"\\/bfnrt]'
re_escaped_unicode = r'\\u[0-9A-Fa-f]{4}'
re_string_char = r'[^\"\\' + re_line_terminators + u']'
re_string_char = r'[^\"' + re_line_terminators + u']'

re_int_value = r'(-?0|-?[1-9][0-9]*)'
re_fraction_part = r'\.[0-9]+'
Expand Down Expand Up @@ -84,6 +84,7 @@ def find_column(self, t):
'LESS_EQUAL',
'CONTAINS',
'NOT_CONTAINS',
'REGEX',
]

t_COMMA = ','
Expand Down Expand Up @@ -137,6 +138,10 @@ def t_NOT(self, t):
def t_IN(self, t):
return t

@TOKEN('regex' + not_followed_by_name)
def t_REGEX(self, t):
return t

@TOKEN('True' + not_followed_by_name)
def t_TRUE(self, t):
return t
Expand Down
7 changes: 7 additions & 0 deletions djangoql/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ def p_comparison_string(self, p):
comparison_string : comparison_equality
| comparison_greater_less
| comparison_contains
| comparison_regex
"""
p[0] = p[1]

Expand All @@ -119,6 +120,12 @@ def p_comparison_contains(self, p):
"""
p[0] = Comparison(operator=p[1])

def p_comparison_regex(self, p):
"""
comparison_regex : REGEX
"""
p[0] = Comparison(operator=p[1])

def p_comparison_in_list(self, p):
"""
comparison_in_list : IN
Expand Down
14 changes: 8 additions & 6 deletions djangoql/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ def get_operator(self, operator):
'<': '__lt',
'<=': '__lte',
'~': '__icontains',
'regex': '__iregex',
'in': '__in',
}.get(operator)
if op is not None:
Expand All @@ -124,11 +125,12 @@ def get_lookup(self, path, operator, value):
be ['author', 'groups']. 'name' is not included, because it's the
current field instance itself.
:param operator: a string with comparison operator. It could be one of
the following: '=', '!=', '>', '>=', '<', '<=', '~', '!~', 'in',
'not in'. Depending on the field type, some operators may be
excluded. '~' and '!~' can be applied to StrField only and aren't
allowed for any other fields. BoolField can't be used with less or
greater operators, '>', '>=', '<' and '<=' are excluded for it.
the following: '=', '!=', '>', '>=', '<', '<=', '~', '!~', 'regex',
'in', 'not in'. Depending on the field type, some operators
may be excluded. '~' and '!~' can be applied to StrField only and
aren't allowed for any other fields. BoolField can't be used with
less or greater operators, '>', '>=', '<' and '<=' are excluded
for it.
:param value: value passed for comparison
:return: Q-object
"""
Expand Down Expand Up @@ -277,7 +279,7 @@ def get_lookup(self, path, operator, value):
# and resulting comparison would look like
# 'created LIKE %2017-01-30 00:00:00%'
# which is not what we want for this case.
val = value if operator in ('~', '!~') else self.get_lookup_value(value)
val = value if operator in ('~', '!~', 'regex') else self.get_lookup_value(value)

q = models.Q(**{'%s%s' % (search, op): val})
return ~q if invert else q
Expand Down
2 changes: 1 addition & 1 deletion djangoql/static/djangoql/js/completion.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion djangoql/static/djangoql/js/completion.js.map

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions djangoql/templates/djangoql/syntax_help.html
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,11 @@ <h2 id="comparison-operators">Comparison operators</h2>
<td>does not contain a substring</td>
<td>username !~ "test"</td>
</tr>
<tr>
<td>regex</td>
<td>find based on regular expression</td>
<td>email regex "\w+@\w+\.com"</td>
</tr>
<tr>
<td>&gt;</td>
<td>greater</td>
Expand Down
2 changes: 1 addition & 1 deletion test_project/core/tests/test_lexer.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def test_entity_props(self):
pass

def test_reserved_words(self):
reserved = ('True', 'False', 'None', 'or', 'and', 'in')
reserved = ('True', 'False', 'None', 'or', 'and', 'in', 'regex')
for word in reserved:
self.assert_output(self.lexer.input(word), [(word.upper(), word)])
# A word made of reserved words should be treated as a name
Expand Down
3 changes: 3 additions & 0 deletions test_project/core/tests/test_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,9 @@ def test_invalid_config(self):
def test_validation_pass(self):
samples = [
'first_name = "Lolita"',
'first_name regex "^Lol"',
'first_name regex "ita$"',
r'first_name regex "\w+i\w+a"',
'groups.id < 42',
'groups = None', # that's ok to compare a model to None
'groups != None',
Expand Down
0