import re from szurubooru import errors from szurubooru.search import criteria, tokens from szurubooru.search.query import SearchQuery from szurubooru.search.configs import util def _create_criterion( original_value: str, value: str) -> criteria.BaseCriterion: if re.search(r'(? tokens.AnonymousToken: criterion = _create_criterion(value, value) return tokens.AnonymousToken(criterion, negated) def _parse_named(key: str, value: str, negated: bool) -> tokens.NamedToken: original_value = value if key.endswith('-min'): key = key[:-4] value += '..' elif key.endswith('-max'): key = key[:-4] value = '..' + value criterion = _create_criterion(original_value, value) return tokens.NamedToken(key, criterion, negated) def _parse_special(value: str, negated: bool) -> tokens.SpecialToken: return tokens.SpecialToken(value, negated) def _parse_sort(value: str, negated: bool) -> tokens.SortToken: if value.count(',') == 0: order_str = None elif value.count(',') == 1: value, order_str = value.split(',') else: raise errors.SearchError('Too many commas in sort style token.') try: order = { 'asc': tokens.SortToken.SORT_ASC, 'desc': tokens.SortToken.SORT_DESC, '': tokens.SortToken.SORT_DEFAULT, None: tokens.SortToken.SORT_DEFAULT, }[order_str] except KeyError: raise errors.SearchError( 'Unknown search direction: %r.' % order_str) if negated: order = { tokens.SortToken.SORT_ASC: tokens.SortToken.SORT_DESC, tokens.SortToken.SORT_DESC: tokens.SortToken.SORT_ASC, tokens.SortToken.SORT_DEFAULT: tokens.SortToken.SORT_NEGATED_DEFAULT, tokens.SortToken.SORT_NEGATED_DEFAULT: tokens.SortToken.SORT_DEFAULT, }[order] return tokens.SortToken(value, order) class Parser: def parse(self, query_text: str) -> SearchQuery: query = SearchQuery() for chunk in re.split(r'\s+', (query_text or '').lower()): if not chunk: continue negated = False if chunk[0] == '-': chunk = chunk[1:] negated = True if not chunk: raise errors.SearchError('Empty negated token.') match = re.match(r'^(.*?)(?