Created
March 7, 2019 23:36
-
-
Save erickpeirson/a078b369dfa1ec9bd001261227ffe954 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class astr(str): | |
def __or__(self, other): | |
return astr(f'({self} | {other})') | |
def __and__(self, other): | |
return astr(f'({self} & {other})') | |
def __invert__(self): | |
return astr(f'~{self}') | |
def _grouped_terms_to_q(term_pair: tuple): | |
"""Generate a :class:`.Q` from grouped terms.""" | |
term_a_raw, operator, term_b_raw = term_pair | |
if type(term_a_raw) is tuple and len(term_a_raw) == 3: | |
term_a = _grouped_terms_to_q(term_a_raw) | |
else: | |
term_a = astr(term_a_raw[1]) | |
if type(term_b_raw) is tuple and len(term_b_raw) == 3: | |
term_b = _grouped_terms_to_q(term_b_raw) | |
else: | |
term_b = astr(term_b_raw[1]) | |
if operator == 'OR': | |
return term_a | term_b | |
elif operator == 'AND': | |
return term_a & term_b | |
elif operator == 'NOT': | |
return term_a & ~term_b | |
else: | |
# TODO: Confirm proper exception. | |
raise TypeError("Invalid operator for terms") | |
def _get_operator(obj) -> str: | |
if type(obj) is tuple and len(obj) == 3: | |
return _get_operator(obj[0]) | |
return obj[0] # type: ignore | |
def _group_terms(terms) -> tuple: | |
"""Group fielded search terms into a set of nested tuples.""" | |
for operator in ['NOT', 'AND', 'OR']: | |
i = 0 | |
while i < len(terms) - 1: | |
if _get_operator(terms[i+1]) == operator: | |
terms[i] = (terms[i], operator, terms[i+1]) | |
terms.pop(i+1) | |
i -= 1 | |
i += 1 | |
assert len(terms) == 1 | |
return terms[0] # type: ignore | |
_grouped_terms_to_q( | |
_group_terms([ | |
('AND', '1'), | |
('OR', '2'), | |
('AND', '3'), | |
('OR', '4'), | |
('OR', '5'), | |
('NOT', '6'), | |
('AND', '7'), | |
]) | |
) | |
# '(((1 | (2 & 3)) | 4) | ((5 & ~6) & 7))' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment