split FieldQuery into base and registered versions

This commit is contained in:
Adrian Sampson 2013-03-14 10:00:30 -07:00
parent a4fb44ab1b
commit f474f3aed2
3 changed files with 26 additions and 19 deletions

View file

@ -456,9 +456,8 @@ class FieldQuery(Query):
"""An abstract query that searches in a specific field for a
pattern. Subclasses must provide a `value_match` class method, which
determines whether a certain pattern string matches a certain value
string. They may then either override the `clause` method to use
native SQLite functionality or get registered to use a callback into
Python.
string. Subclasses also need to provide `clause` to implement the
same matching functionality in SQLite.
"""
def __init__(self, field, pattern):
self.field = field
@ -481,6 +480,11 @@ class FieldQuery(Query):
def match(self, item):
return self._raw_value_match(self.pattern, getattr(item, self.field))
class RegisteredFieldQuery(FieldQuery):
"""A FieldQuery that uses a registered SQLite callback function.
Before it can be used to execute queries, the `register` method must
be called.
"""
def clause(self):
# Invoke the registered SQLite function.
clause = "{name}(?, {field})".format(name=self.__class__.__name__,
@ -522,7 +526,7 @@ class SubstringQuery(FieldQuery):
def value_match(cls, pattern, value):
return pattern.lower() in value.lower()
class RegexpQuery(FieldQuery):
class RegexpQuery(RegisteredFieldQuery):
"""A query that matches a regular expression in a specific item
field.
"""
@ -1112,7 +1116,8 @@ class Library(BaseLibrary):
# Register plugin queries.
RegexpQuery.register(conn)
for prefix, query_class in plugins.queries().items():
query_class.register(conn)
if issubclass(query_class, RegisteredFieldQuery):
query_class.register(conn)
self._connections[thread_id] = conn
return conn

View file

@ -16,12 +16,12 @@
"""
from beets.plugins import BeetsPlugin
from beets.library import FieldQuery
from beets.library import RegisteredFieldQuery
import beets
import difflib
class FuzzyQuery(FieldQuery):
class FuzzyQuery(RegisteredFieldQuery):
@classmethod
def value_match(self, pattern, val):
# smartcase

View file

@ -334,26 +334,28 @@ You can add new kinds of queries to beets' :doc:`query syntax
supports regular expression queries, which are indicated by a colon
prefix---plugins can do the same.
To do so, define a subclass of the ``FieldQuery`` type from the
``beets.library`` module. In this subclass, you should override the
``value_match`` class method. (Remember the ``@classmethod`` decorator!) Then,
in the ``queries`` method of your plugin class, return a dictionary mapping
prefix strings to query classes.
To do so, define a subclass of the ``Query`` type from the ``beets.library``
module. Then, in the ``queries`` method of your plugin class, return a
dictionary mapping prefix strings to query classes.
The following example plugins declares a query using the ``@`` prefix. So the
plugin will be called if we issue a command like ``beet ls @something`` or
``beet ls artist:@something``::
One simple kind of query you can extend is the ``RegisteredFieldQuery``, which
implements string comparisons. To use it, create a subclass inheriting from
that class and override the ``value_match`` class method. (Remember the
``@classmethod`` decorator!) The following example plugin declares a query
using the ``@`` prefix to delimit exact string matches. The plugin will be
used if we issue a command like ``beet ls @something`` or ``beet ls
artist:@something``::
from beets.plugins import BeetsPlugin
from beets.library import PluginQuery
class ExampleQuery(PluginQuery):
class ExactMatchQuery(PluginQuery):
@classmethod
def value_match(self, pattern, val):
return True # This will just match everything.
return pattern == val
class ExamplePlugin(BeetsPlugin):
class ExactMatchPlugin(BeetsPlugin):
def queries():
return {
'@': ExampleQuery
'@': ExactMatchQuery
}