def parse_query_parts(parts, model_cls): """Given a beets query string as a list of components, return the `Query` and `Sort` they represent. Like `dbcore.parse_sorted_query`, with beets query prefixes and special path query detection. """ # Get query types and their prefix characters. prefixes = {':': dbcore.query.RegexpQuery} prefixes.update(plugins.queries()) # Special-case path-like queries, which are non-field queries # containing path separators (/). path_parts = [] non_path_parts = [] for s in parts: if PathQuery.is_path_query(s): path_parts.append(s) else: non_path_parts.append(s) query, sort = dbcore.parse_sorted_query( model_cls, non_path_parts, prefixes ) # Add path queries to aggregate query. # Match field / flexattr depending on whether the model has the path field fast_path_query = 'path' in model_cls._fields query.subqueries += [PathQuery('path', s, fast_path_query) for s in path_parts] return query, sort
def parse_query_parts(parts, model_cls): """Given a beets query string as a list of components, return the `Query` and `Sort` they represent. Like `dbcore.parse_sorted_query`, with beets query prefixes and special path query detection. """ # Get query types and their prefix characters. prefixes = {':': dbcore.query.RegexpQuery} prefixes.update(plugins.queries()) # Special-case path-like queries, which are non-field queries # containing path separators (/). path_parts = [] non_path_parts = [] for s in parts: if PathQuery.is_path_query(s): path_parts.append(s) else: non_path_parts.append(s) query, sort = dbcore.parse_sorted_query(model_cls, non_path_parts, prefixes) # Add path queries to aggregate query. # Match field / flexattr depending on whether the model has the path field fast_path_query = 'path' in model_cls._fields query.subqueries += [ PathQuery('path', s, fast_path_query) for s in path_parts ] return query, sort
def parse_query_parts(parts, model_cls): """Given a beets query string as a list of components, return the `Query` and `Sort` they represent. Like `dbcore.parse_sorted_query`, with beets query prefixes and special path query detection. """ # Get query types and their prefix characters. prefixes = {':': dbcore.query.RegexpQuery} prefixes.update(plugins.queries()) # Special-case path-like queries, which are non-field queries # containing path separators (/). if 'path' in model_cls._fields: path_parts = [] non_path_parts = [] for s in parts: if s.find(os.sep, 0, s.find(':')) != -1: # Separator precedes colon. path_parts.append(s) else: non_path_parts.append(s) else: path_parts = () non_path_parts = parts query, sort = dbcore.parse_sorted_query( model_cls, non_path_parts, prefixes ) # Add path queries to aggregate query. if path_parts: query.subqueries += [PathQuery('path', s) for s in path_parts] return query, sort
def parse_query_parts(parts, model_cls): """Given a beets query string as a list of components, return the `Query` and `Sort` they represent. Like `dbcore.parse_sorted_query`, with beets query prefixes and special path query detection. """ # Get query types and their prefix characters. prefixes = {':': dbcore.query.RegexpQuery} prefixes.update(plugins.queries()) # Special-case path-like queries, which are non-field queries # containing path separators (/). if 'path' in model_cls._fields: path_parts = [] non_path_parts = [] for s in parts: if s.find(os.sep, 0, s.find(':')) != -1: # Separator precedes colon. path_parts.append(s) else: non_path_parts.append(s) else: path_parts = () non_path_parts = parts query, sort = dbcore.parse_sorted_query(model_cls, non_path_parts, prefixes) # Add path queries to aggregate query. if path_parts: query.subqueries += [PathQuery('path', s) for s in path_parts] return query, sort
def construct_query_part(query_part, model_cls): """Create a query from a single query component, `query_part`, for querying instances of `model_cls`. Return a `Query` instance. """ # Shortcut for empty query parts. if not query_part: return dbcore.query.TrueQuery() # Set up and parse the string. query_classes = dict((k, t.query) for (k, t) in model_cls._fields.items()) prefixes = {':': dbcore.query.RegexpQuery} prefixes.update(plugins.queries()) key, pattern, query_class = \ parse_query_part(query_part, query_classes, prefixes) # No key specified. if key is None: if os.sep in pattern and 'path' in model_cls._fields: # This looks like a path. return PathQuery('path', pattern) elif issubclass(query_class, dbcore.FieldQuery): # The query type matches a specific field, but none was # specified. So we use a version of the query that matches # any field. return dbcore.query.AnyFieldQuery(pattern, model_cls._search_fields, query_class) else: # Other query type. return query_class(pattern) key = key.lower() return query_class(key.lower(), pattern, key in model_cls._fields)
def parse_query_part(part): """Takes a query in the form of a key/value pair separated by a colon. The value part is matched against a list of prefixes that can be extended by plugins to add custom query types. For example, the colon prefix denotes a regular expression query. The function returns a tuple of `(key, value, cls)`. `key` may be None, indicating that any field may be matched. `cls` is a subclass of `FieldQuery`. For instance, parse_query('stapler') == (None, 'stapler', None) parse_query('color:red') == ('color', 'red', None) parse_query(':^Quiet') == (None, '^Quiet', RegexpQuery) parse_query('color::b..e') == ('color', 'b..e', RegexpQuery) Prefixes may be 'escaped' with a backslash to disable the keying behavior. """ part = part.strip() match = PARSE_QUERY_PART_REGEX.match(part) prefixes = {':': RegexpQuery} prefixes.update(plugins.queries()) if match: key = match.group(1) term = match.group(2).replace('\:', ':') # Match the search term against the list of prefixes. for pre, query_class in prefixes.items(): if term.startswith(pre): return key, term[len(pre):], query_class if key and NumericQuery.applies_to(key): return key, term, NumericQuery return key, term, SubstringQuery # The default query type.
def get_query(val, model_cls): """Take a value which may be None, a query string, a query string list, or a Query object, and return a suitable Query object. `model_cls` is the subclass of Model indicating which entity this is a query for (i.e., Album or Item) and is used to determine which fields are searched. """ # Get query types and their prefix characters. prefixes = {':': dbcore.query.RegexpQuery} prefixes.update(plugins.queries()) # Convert a single string into a list of space-separated # criteria. if isinstance(val, basestring): # A bug in Python < 2.7.3 prevents correct shlex splitting of # Unicode strings. # http://bugs.python.org/issue6988 if isinstance(val, unicode): val = val.encode('utf8') val = [s.decode('utf8') for s in shlex.split(val)] if val is None: return dbcore.query.TrueQuery() elif isinstance(val, list) or isinstance(val, tuple): # Special-case path-like queries, which are non-field queries # containing path separators (/). if 'path' in model_cls._fields: path_parts = [] non_path_parts = [] for s in val: if s.find(os.sep, 0, s.find(':')) != -1: # Separator precedes colon. path_parts.append(s) else: non_path_parts.append(s) else: path_parts = () non_path_parts = val # Parse remaining parts and construct an AndQuery. query = dbcore.query_from_strings( dbcore.AndQuery, model_cls, prefixes, non_path_parts ) # Add path queries to aggregate query. if path_parts: query.subqueries += [PathQuery('path', s) for s in path_parts] return query elif isinstance(val, dbcore.Query): return val else: raise ValueError('query must be None or have type Query or str')
def get_query(val, model_cls): """Take a value which may be None, a query string, a query string list, or a Query object, and return a suitable Query object. `model_cls` is the subclass of Model indicating which entity this is a query for (i.e., Album or Item) and is used to determine which fields are searched. """ # Get query types and their prefix characters. prefixes = {':': dbcore.query.RegexpQuery} prefixes.update(plugins.queries()) # Convert a single string into a list of space-separated # criteria. if isinstance(val, basestring): # A bug in Python < 2.7.3 prevents correct shlex splitting of # Unicode strings. # http://bugs.python.org/issue6988 if isinstance(val, unicode): val = val.encode('utf8') val = [s.decode('utf8') for s in shlex.split(val)] if val is None: return dbcore.query.TrueQuery() elif isinstance(val, list) or isinstance(val, tuple): # Special-case path-like queries, which are non-field queries # containing path separators (/). if 'path' in model_cls._fields: path_parts = [] non_path_parts = [] for s in val: if s.find(os.sep, 0, s.find(':')) != -1: # Separator precedes colon. path_parts.append(s) else: non_path_parts.append(s) else: path_parts = () non_path_parts = val # Parse remaining parts and construct an AndQuery. query = dbcore.query_from_strings(dbcore.AndQuery, model_cls, prefixes, non_path_parts) # Add path queries to aggregate query. if path_parts: query.subqueries += [PathQuery('path', s) for s in path_parts] return query elif isinstance(val, dbcore.Query): return val else: raise ValueError('query must be None or have type Query or str')
def construct_query_part(query_part, model_cls): """Create a query from a single query component, `query_part`, for querying instances of `model_cls`. Return a `Query` instance or `None` if the value cannot be parsed. """ query_classes = dict((k, t.query) for (k, t) in model_cls._fields.items()) prefixes = {':': dbcore.query.RegexpQuery} prefixes.update(plugins.queries()) parsed = parse_query_part(query_part, query_classes, prefixes) if not parsed: return key, pattern, query_class = parsed # No key specified. if key is None: if os.sep in pattern and 'path' in model_cls._fields: # This looks like a path. return PathQuery('path', pattern) elif issubclass(query_class, dbcore.FieldQuery): # The query type matches a specific field, but none was # specified. So we use a version of the query that matches # any field. return dbcore.query.AnyFieldQuery(pattern, model_cls._search_fields, query_class) else: # Other query type. return query_class(pattern) key = key.lower() # Singleton query (not a real field). if key == 'singleton': return SingletonQuery(util.str2bool(pattern)) # Other field. else: return query_class(key.lower(), pattern, key in model_cls._fields)