mirror of
https://github.com/beetbox/beets.git
synced 2026-01-14 20:24:36 +01:00
Move SmartArtistSort to library (#953)
Models can now have a dict of special sort classes.
This commit is contained in:
parent
e2b3fafefa
commit
f9c6dd6d67
5 changed files with 44 additions and 24 deletions
|
|
@ -124,6 +124,11 @@ class Model(object):
|
|||
"""Optional Types for non-fixed (i.e., flexible and computed) fields.
|
||||
"""
|
||||
|
||||
_sorts = {}
|
||||
"""Optional named sort criteria. The keys are strings and the values
|
||||
are subclasses of `Sort`.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def _getters(cls):
|
||||
"""Return a mapping from field names to getter functions.
|
||||
|
|
|
|||
|
|
@ -619,25 +619,6 @@ class FixedFieldSort(FieldSort):
|
|||
return "{0} {1}".format(self.field, order)
|
||||
|
||||
|
||||
class SmartArtistSort(Sort):
|
||||
"""Sort by artist (either album artist or track artist),
|
||||
prioritizing the sort field over the raw field.
|
||||
"""
|
||||
def __init__(self, model_cls, is_ascending=True):
|
||||
self.model_cls = model_cls
|
||||
self.is_ascending = is_ascending
|
||||
|
||||
def order_clause(self):
|
||||
order = "ASC" if self.is_ascending else "DESC"
|
||||
if 'albumartist' in self.model_cls._fields:
|
||||
field = 'albumartist'
|
||||
else:
|
||||
field = 'artist'
|
||||
return ('(CASE {0}_sort WHEN NULL THEN {0} '
|
||||
'WHEN "" THEN {0} '
|
||||
'ELSE {0}_sort END) {1}').format(field, order)
|
||||
|
||||
|
||||
class SlowFieldSort(FieldSort):
|
||||
"""A sort criterion by some model field other than a fixed field:
|
||||
i.e., a computed or flexible field.
|
||||
|
|
|
|||
|
|
@ -136,11 +136,10 @@ def construct_sort_part(model_cls, part):
|
|||
assert direction in ('+', '-'), "part must end with + or -"
|
||||
is_ascending = direction == '+'
|
||||
|
||||
if field in model_cls._fields:
|
||||
if field in model_cls._sorts:
|
||||
sort = model_cls._sorts[field](model_cls, is_ascending)
|
||||
elif field in model_cls._fields:
|
||||
sort = query.FixedFieldSort(field, is_ascending)
|
||||
elif field == 'smartartist':
|
||||
# Special case for smart artist sort.
|
||||
sort = query.SmartArtistSort(model_cls, is_ascending)
|
||||
else:
|
||||
# Flexible or computed.
|
||||
sort = query.SlowFieldSort(field, is_ascending)
|
||||
|
|
|
|||
|
|
@ -60,7 +60,6 @@ class PathQuery(dbcore.FieldQuery):
|
|||
|
||||
# Library-specific field types.
|
||||
|
||||
|
||||
class DateType(types.Float):
|
||||
# TODO representation should be `datetime` object
|
||||
# TODO distinguish beetween date and time types
|
||||
|
|
@ -144,6 +143,27 @@ class MusicalKey(types.String):
|
|||
return self.parse(key)
|
||||
|
||||
|
||||
# Library-specific sort types.
|
||||
|
||||
class SmartArtistSort(dbcore.query.Sort):
|
||||
"""Sort by artist (either album artist or track artist),
|
||||
prioritizing the sort field over the raw field.
|
||||
"""
|
||||
def __init__(self, model_cls, is_ascending=True):
|
||||
self.model_cls = model_cls
|
||||
self.is_ascending = is_ascending
|
||||
|
||||
def order_clause(self):
|
||||
order = "ASC" if self.is_ascending else "DESC"
|
||||
if 'albumartist' in self.model_cls._fields:
|
||||
field = 'albumartist'
|
||||
else:
|
||||
field = 'artist'
|
||||
return ('(CASE {0}_sort WHEN NULL THEN {0} '
|
||||
'WHEN "" THEN {0} '
|
||||
'ELSE {0}_sort END) {1}').format(field, order)
|
||||
|
||||
|
||||
# Special path format key.
|
||||
PF_KEY_DEFAULT = 'default'
|
||||
|
||||
|
|
@ -347,6 +367,8 @@ class Item(LibModel):
|
|||
|
||||
_formatter = FormattedItemMapping
|
||||
|
||||
_sorts = {'smartartist': SmartArtistSort}
|
||||
|
||||
@classmethod
|
||||
def _getters(cls):
|
||||
getters = plugins.item_field_getters()
|
||||
|
|
@ -710,6 +732,8 @@ class Album(LibModel):
|
|||
|
||||
_search_fields = ('album', 'albumartist', 'genre')
|
||||
|
||||
_sorts = {'smartartist': SmartArtistSort}
|
||||
|
||||
item_keys = [
|
||||
'added',
|
||||
'albumartist',
|
||||
|
|
|
|||
|
|
@ -25,6 +25,10 @@ from tempfile import mkstemp
|
|||
# Fixture: concrete database and model classes. For migration tests, we
|
||||
# have multiple models with different numbers of fields.
|
||||
|
||||
class TestSort(dbcore.query.FieldSort):
|
||||
pass
|
||||
|
||||
|
||||
class TestModel1(dbcore.Model):
|
||||
_table = 'test'
|
||||
_flex_table = 'testflex'
|
||||
|
|
@ -35,6 +39,9 @@ class TestModel1(dbcore.Model):
|
|||
_types = {
|
||||
'some_float_field': dbcore.types.FLOAT,
|
||||
}
|
||||
_sorts = {
|
||||
'some_sort': TestSort,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def _getters(cls):
|
||||
|
|
@ -455,6 +462,10 @@ class SortFromStringsTest(unittest.TestCase):
|
|||
self.assertIsInstance(s, dbcore.query.MultipleSort)
|
||||
self.assertIsInstance(s.sorts[0], dbcore.query.SlowFieldSort)
|
||||
|
||||
def test_special_sort(self):
|
||||
s = self.sfs(['some_sort+'])
|
||||
self.assertIsInstance(s.sorts[0], TestSort)
|
||||
|
||||
|
||||
def suite():
|
||||
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||
|
|
|
|||
Loading…
Reference in a new issue