mirror of
https://github.com/beetbox/beets.git
synced 2025-12-06 16:42:42 +01:00
added Query object and friends (from_string is next)
--HG-- extra : convert_revision : svn%3A41726ec3-264d-0410-9c23-a9f1637257cc/trunk%405
This commit is contained in:
parent
2651b1c2b5
commit
932f839bca
1 changed files with 108 additions and 0 deletions
108
beets/library.py
108
beets/library.py
|
|
@ -31,6 +31,10 @@ item_keys = map(operator.itemgetter(0), item_fields)
|
|||
|
||||
class LibraryError(Exception):
|
||||
pass
|
||||
class InvalidFieldError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -179,6 +183,110 @@ class Item(object):
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class QueryElement(object):
|
||||
"""A building block for library queries."""
|
||||
def clause(self):
|
||||
"""Returns (clause, subvals) where clause is a valid sqlite WHERE
|
||||
clause implementing the query element and subvals is a list of items
|
||||
to be substituted for ?s in the clause."""
|
||||
raise NotImplementedError
|
||||
|
||||
class SubstringQueryElement(QueryElement):
|
||||
"""A query element that matches a substring in a specific item field."""
|
||||
|
||||
def __init__(self, field, value):
|
||||
if field not in item_keys:
|
||||
raise InvalidFieldError(field + ' is not an item key')
|
||||
self.field = field
|
||||
self.value = value
|
||||
|
||||
def clause(self):
|
||||
search = '%' + (self.value.replace('\\','\\\\').replace('%','\\%')
|
||||
.replace('_','\\_')) + '%'
|
||||
clause = self.field + " like ? escape '\\'"
|
||||
subvals = [search]
|
||||
return (clause, subvals)
|
||||
|
||||
class AndQueryElement(QueryElement):
|
||||
"""A conjunction of a list of other query elements. Can be indexed like a
|
||||
list to access the sub-elements."""
|
||||
|
||||
def __init__(self, elements = None):
|
||||
if elements is None:
|
||||
self.elements = []
|
||||
else:
|
||||
self.elements = elements
|
||||
|
||||
# is there a better way to do this?
|
||||
def __len__(self): return len(self.elements)
|
||||
def __getitem__(self, key): return self.elements[key]
|
||||
def __setitem__(self, key, value): self.elements[key] = value
|
||||
def __delitem__(self, key): del self.elements[key]
|
||||
def __iter__(self): iter(self.elements)
|
||||
def __contains__(self, item): item in self.elements
|
||||
|
||||
def clause(self):
|
||||
clause_parts = []
|
||||
subvals = []
|
||||
for el in self.elements:
|
||||
el_clause, el_subvals = el.clause()
|
||||
clause_parts.append('(' + el_clause + ')')
|
||||
subvals += el_subvals
|
||||
clause = ' and '.join(clause_parts)
|
||||
return (clause, subvals)
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, matches):
|
||||
"""Construct a query element from a dictionary, matches, whose keys
|
||||
are item field names and whose values are substring patterns."""
|
||||
elements = []
|
||||
for key, pattern in matches.iteritems():
|
||||
elements.append(SubstringQueryElement(key, pattern))
|
||||
return cls(elements)
|
||||
|
||||
class Query(AndQueryElement):
|
||||
"""A query into the item database."""
|
||||
|
||||
def statement(self, columns='*'):
|
||||
"""Returns (query, subvals) where clause is a sqlite SELECT statement
|
||||
to enact this query and subvals is a list of values to substitute in
|
||||
for ?s in the query."""
|
||||
clause, subvals = self.clause()
|
||||
return ('select ' + columns + ' from items where ' + clause, subvals)
|
||||
|
||||
def execute(self, library):
|
||||
"""Runs the query in the specified library, returning an
|
||||
ItemResultIterator."""
|
||||
cursor = library.conn.cursor()
|
||||
cursor.execute(*self.statement())
|
||||
return ItemResultIterator(cursor)
|
||||
|
||||
class ItemResultIterator(object):
|
||||
"""An iterator into an item result set."""
|
||||
|
||||
def __init__(self, cursor):
|
||||
self.cursor = cursor
|
||||
|
||||
def __iter__(self): return self
|
||||
|
||||
def next(self):
|
||||
try:
|
||||
row = self.cursor.next()
|
||||
except StopIteration:
|
||||
self.cursor.close()
|
||||
raise StopIteration
|
||||
return Item(row)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class Library(object):
|
||||
def __init__(self, path='library.blb'):
|
||||
self.path = path
|
||||
|
|
|
|||
Loading…
Reference in a new issue