9744: Tidy up iterators
Remove order_by parameter. Add unit tests.
This commit is contained in:
parent
1905d417be
commit
9fc316abdf
@ -50,35 +50,6 @@ from .exceptions import DbTransactionCancel
|
|||||||
|
|
||||||
_LOG = logging.getLogger(DBLOGNAME)
|
_LOG = logging.getLogger(DBLOGNAME)
|
||||||
|
|
||||||
def eval_order_by(order_by, obj, db):
|
|
||||||
"""
|
|
||||||
Given a list of [[field, DIRECTION], ...]
|
|
||||||
return the list of values of the fields
|
|
||||||
"""
|
|
||||||
values = []
|
|
||||||
for (field, direction) in order_by:
|
|
||||||
values.append(obj.get_field(field, db, ignore_errors=True))
|
|
||||||
return values
|
|
||||||
|
|
||||||
def sort_objects(objects, order_by, db):
|
|
||||||
"""
|
|
||||||
Python-based sorting.
|
|
||||||
"""
|
|
||||||
# first build sort order:
|
|
||||||
sorted_items = []
|
|
||||||
map_items = {}
|
|
||||||
for obj in objects:
|
|
||||||
# just use values and handle to keep small:
|
|
||||||
sorted_items.append((eval_order_by(order_by, obj, db), obj.handle))
|
|
||||||
map_items[obj.handle] = obj
|
|
||||||
# next we sort by fields and direction
|
|
||||||
pos = len(order_by) - 1
|
|
||||||
for (field, order) in reversed(order_by): # sort the lasts parts first
|
|
||||||
sorted_items.sort(key=itemgetter(pos), reverse=(order=="DESC"))
|
|
||||||
pos -= 1
|
|
||||||
for (order_by_values, handle) in sorted_items:
|
|
||||||
yield map_items[handle]
|
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
# Gramps libraries
|
# Gramps libraries
|
||||||
@ -953,7 +924,7 @@ class DbReadBase:
|
|||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def iter_citations(self, order_by=None):
|
def iter_citations(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over objects for Citations in the database
|
Return an iterator over objects for Citations in the database
|
||||||
"""
|
"""
|
||||||
@ -965,13 +936,13 @@ class DbReadBase:
|
|||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def iter_events(self, order_by=None):
|
def iter_events(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over objects for Events in the database
|
Return an iterator over objects for Events in the database
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def iter_families(self, order_by=None):
|
def iter_families(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over objects for Families in the database
|
Return an iterator over objects for Families in the database
|
||||||
"""
|
"""
|
||||||
@ -989,7 +960,7 @@ class DbReadBase:
|
|||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def iter_media(self, order_by=None):
|
def iter_media(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over objects for Medias in the database
|
Return an iterator over objects for Medias in the database
|
||||||
"""
|
"""
|
||||||
@ -1001,13 +972,13 @@ class DbReadBase:
|
|||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def iter_notes(self, order_by=None):
|
def iter_notes(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over objects for Notes in the database
|
Return an iterator over objects for Notes in the database
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def iter_people(self, order_by=None):
|
def iter_people(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over objects for Persons in the database
|
Return an iterator over objects for Persons in the database
|
||||||
"""
|
"""
|
||||||
@ -1025,13 +996,13 @@ class DbReadBase:
|
|||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def iter_places(self, order_by=None):
|
def iter_places(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over objects for Places in the database
|
Return an iterator over objects for Places in the database
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def iter_repositories(self, order_by=None):
|
def iter_repositories(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over objects for Repositories in the database
|
Return an iterator over objects for Repositories in the database
|
||||||
"""
|
"""
|
||||||
@ -1049,7 +1020,7 @@ class DbReadBase:
|
|||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def iter_sources(self, order_by=None):
|
def iter_sources(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over objects for Sources in the database
|
Return an iterator over objects for Sources in the database
|
||||||
"""
|
"""
|
||||||
@ -1061,7 +1032,7 @@ class DbReadBase:
|
|||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def iter_tags(self, order_by=None):
|
def iter_tags(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over objects for Tags in the database
|
Return an iterator over objects for Tags in the database
|
||||||
"""
|
"""
|
||||||
|
@ -51,8 +51,7 @@ from gramps.gen.db import (DbReadBase, DbWriteBase, DbTxn, DbUndo,
|
|||||||
CLASS_TO_KEY_MAP, TXNADD, TXNUPD, TXNDEL,
|
CLASS_TO_KEY_MAP, TXNADD, TXNUPD, TXNDEL,
|
||||||
PERSON_KEY, FAMILY_KEY, CITATION_KEY,
|
PERSON_KEY, FAMILY_KEY, CITATION_KEY,
|
||||||
SOURCE_KEY, EVENT_KEY, MEDIA_KEY,
|
SOURCE_KEY, EVENT_KEY, MEDIA_KEY,
|
||||||
PLACE_KEY, REPOSITORY_KEY, NOTE_KEY,
|
PLACE_KEY, REPOSITORY_KEY, NOTE_KEY, TAG_KEY)
|
||||||
TAG_KEY, eval_order_by)
|
|
||||||
from gramps.gen.errors import HandleError
|
from gramps.gen.errors import HandleError
|
||||||
from gramps.gen.utils.callback import Callback
|
from gramps.gen.utils.callback import Callback
|
||||||
from gramps.gen.updatecallback import UpdateCallback
|
from gramps.gen.updatecallback import UpdateCallback
|
||||||
@ -1217,47 +1216,43 @@ class DbGeneric(DbWriteBase, DbReadBase, UpdateCallback, Callback):
|
|||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def iter_items(self, order_by, class_):
|
def _iter_objects(self, class_):
|
||||||
"""
|
"""
|
||||||
Iterate over items in a class, possibly ordered by
|
Iterate over items in a class.
|
||||||
a list of field names and direction ("ASC" or "DESC").
|
|
||||||
"""
|
"""
|
||||||
cursor = self.get_table_func(class_.__name__,"cursor_func")
|
cursor = self.get_table_func(class_.__name__,"cursor_func")
|
||||||
if order_by is None:
|
for data in cursor():
|
||||||
for data in cursor():
|
yield class_.create(data[1])
|
||||||
yield class_.create(data[1])
|
|
||||||
else:
|
|
||||||
# first build sort order:
|
|
||||||
sorted_items = []
|
|
||||||
for data in cursor():
|
|
||||||
obj = class_.create(data[1])
|
|
||||||
# just use values and handle to keep small:
|
|
||||||
sorted_items.append((eval_order_by(order_by, obj, self), obj.handle))
|
|
||||||
# next we sort by fields and direction
|
|
||||||
def getitem(item, pos):
|
|
||||||
sort_items = item[0]
|
|
||||||
if isinstance(sort_items[pos], str):
|
|
||||||
return sort_items[pos]
|
|
||||||
elif sort_items[pos] is None:
|
|
||||||
return ""
|
|
||||||
else:
|
|
||||||
# FIXME: should do something clever/recurive to
|
|
||||||
# sort these meaningfully, and return a string:
|
|
||||||
return str(sort_items[pos])
|
|
||||||
pos = len(order_by) - 1
|
|
||||||
for (field, order) in reversed(order_by): # sort the lasts parts first
|
|
||||||
sorted_items.sort(key=lambda item: getitem(item, pos),
|
|
||||||
reverse=(order=="DESC"))
|
|
||||||
pos -= 1
|
|
||||||
# now we will look them up again:
|
|
||||||
for (order_by_values, handle) in sorted_items:
|
|
||||||
yield self.get_table_func(class_.__name__,"handle_func")(handle)
|
|
||||||
|
|
||||||
def iter_people(self, order_by=None):
|
def iter_people(self):
|
||||||
return self.iter_items(order_by, Person)
|
return self._iter_objects(Person)
|
||||||
|
|
||||||
def iter_families(self, order_by=None):
|
def iter_families(self):
|
||||||
return self.iter_items(order_by, Family)
|
return self._iter_objects(Family)
|
||||||
|
|
||||||
|
def iter_citations(self):
|
||||||
|
return self._iter_objects(Citation)
|
||||||
|
|
||||||
|
def iter_events(self):
|
||||||
|
return self._iter_objects(Event)
|
||||||
|
|
||||||
|
def iter_media(self):
|
||||||
|
return self._iter_objects(Media)
|
||||||
|
|
||||||
|
def iter_notes(self):
|
||||||
|
return self._iter_objects(Note)
|
||||||
|
|
||||||
|
def iter_places(self):
|
||||||
|
return self._iter_objects(Place)
|
||||||
|
|
||||||
|
def iter_repositories(self):
|
||||||
|
return self._iter_objects(Repository)
|
||||||
|
|
||||||
|
def iter_sources(self):
|
||||||
|
return self._iter_objects(Source)
|
||||||
|
|
||||||
|
def iter_tags(self):
|
||||||
|
return self._iter_objects(Tag)
|
||||||
|
|
||||||
def get_person_from_gramps_id(self, gramps_id):
|
def get_person_from_gramps_id(self, gramps_id):
|
||||||
data = self._get_raw_person_from_id_data(gramps_id)
|
data = self._get_raw_person_from_id_data(gramps_id)
|
||||||
@ -1838,30 +1833,6 @@ class DbGeneric(DbWriteBase, DbReadBase, UpdateCallback, Callback):
|
|||||||
def is_open(self):
|
def is_open(self):
|
||||||
return self.db_is_open
|
return self.db_is_open
|
||||||
|
|
||||||
def iter_citations(self, order_by=None):
|
|
||||||
return self.iter_items(order_by, Citation)
|
|
||||||
|
|
||||||
def iter_events(self, order_by=None):
|
|
||||||
return self.iter_items(order_by, Event)
|
|
||||||
|
|
||||||
def iter_media(self, order_by=None):
|
|
||||||
return self.iter_items(order_by, Media)
|
|
||||||
|
|
||||||
def iter_notes(self, order_by=None):
|
|
||||||
return self.iter_items(order_by, Note)
|
|
||||||
|
|
||||||
def iter_places(self, order_by=None):
|
|
||||||
return self.iter_items(order_by, Place)
|
|
||||||
|
|
||||||
def iter_repositories(self, order_by=None):
|
|
||||||
return self.iter_items(order_by, Repository)
|
|
||||||
|
|
||||||
def iter_sources(self, order_by=None):
|
|
||||||
return self.iter_items(order_by, Source)
|
|
||||||
|
|
||||||
def iter_tags(self, order_by=None):
|
|
||||||
return self.iter_items(order_by, Tag)
|
|
||||||
|
|
||||||
def set_prefixes(self, person, media, family, source, citation,
|
def set_prefixes(self, person, media, family, source, citation,
|
||||||
place, event, repository, note):
|
place, event, repository, note):
|
||||||
self.set_person_id_prefix(person)
|
self.set_person_id_prefix(person)
|
||||||
|
@ -30,7 +30,6 @@ Proxy class for the Gramps databases. Apply filter
|
|||||||
# Gramps libraries
|
# Gramps libraries
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
from gramps.gen.db.base import sort_objects
|
|
||||||
from .proxybase import ProxyDbBase
|
from .proxybase import ProxyDbBase
|
||||||
from ..lib import (Date, Person, Name, Surname, NameOriginType, Family, Source,
|
from ..lib import (Date, Person, Name, Surname, NameOriginType, Family, Source,
|
||||||
Citation, Event, Media, Place, Repository, Note, Tag)
|
Citation, Event, Media, Place, Repository, Note, Tag)
|
||||||
@ -516,14 +515,11 @@ class FilterProxyDb(ProxyDbBase):
|
|||||||
"""
|
"""
|
||||||
return self.plist
|
return self.plist
|
||||||
|
|
||||||
def iter_people(self, order_by=None):
|
def iter_people(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over objects for Persons in the database
|
Return an iterator over objects for Persons in the database
|
||||||
"""
|
"""
|
||||||
if order_by:
|
return map(self.get_person_from_handle, self.plist)
|
||||||
return sort_objects(map(self.get_person_from_handle, self.plist), order_by, self)
|
|
||||||
else:
|
|
||||||
return map(self.get_person_from_handle, self.plist)
|
|
||||||
|
|
||||||
def get_event_handles(self):
|
def get_event_handles(self):
|
||||||
"""
|
"""
|
||||||
@ -539,14 +535,11 @@ class FilterProxyDb(ProxyDbBase):
|
|||||||
"""
|
"""
|
||||||
return self.elist
|
return self.elist
|
||||||
|
|
||||||
def iter_events(self, order_by=None):
|
def iter_events(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over objects for Events in the database
|
Return an iterator over objects for Events in the database
|
||||||
"""
|
"""
|
||||||
if order_by:
|
return map(self.get_event_from_handle, self.elist)
|
||||||
return sort_objects(map(self.get_event_from_handle, self.elist), order_by, self)
|
|
||||||
else:
|
|
||||||
return map(self.get_event_from_handle, self.elist)
|
|
||||||
|
|
||||||
def get_family_handles(self, sort_handles=False):
|
def get_family_handles(self, sort_handles=False):
|
||||||
"""
|
"""
|
||||||
@ -563,14 +556,11 @@ class FilterProxyDb(ProxyDbBase):
|
|||||||
"""
|
"""
|
||||||
return self.flist
|
return self.flist
|
||||||
|
|
||||||
def iter_families(self, order_by=None):
|
def iter_families(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over objects for Families in the database
|
Return an iterator over objects for Families in the database
|
||||||
"""
|
"""
|
||||||
if order_by:
|
return map(self.get_family_from_handle, self.flist)
|
||||||
return sort_objects(map(self.get_family_from_handle, self.flist), order_by, self)
|
|
||||||
else:
|
|
||||||
return map(self.get_family_from_handle, self.flist)
|
|
||||||
|
|
||||||
def get_note_handles(self):
|
def get_note_handles(self):
|
||||||
"""
|
"""
|
||||||
@ -586,14 +576,11 @@ class FilterProxyDb(ProxyDbBase):
|
|||||||
"""
|
"""
|
||||||
return self.nlist
|
return self.nlist
|
||||||
|
|
||||||
def iter_notes(self, order_by=None):
|
def iter_notes(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over objects for Notes in the database
|
Return an iterator over objects for Notes in the database
|
||||||
"""
|
"""
|
||||||
if order_by:
|
return map(self.get_note_from_handle, self.nlist)
|
||||||
return sort_objects(map(self.get_note_from_handle, self.nlist), order_by, self)
|
|
||||||
else:
|
|
||||||
return map(self.get_note_from_handle, self.nlist)
|
|
||||||
|
|
||||||
def get_default_person(self):
|
def get_default_person(self):
|
||||||
"""returns the default Person of the database"""
|
"""returns the default Person of the database"""
|
||||||
|
@ -33,7 +33,6 @@ from ..lib import (Date, Person, Name, Surname, NameOriginType, Family, Source,
|
|||||||
Citation, Event, Media, Place, Repository, Note, Tag)
|
Citation, Event, Media, Place, Repository, Note, Tag)
|
||||||
from ..utils.alive import probably_alive
|
from ..utils.alive import probably_alive
|
||||||
from ..config import config
|
from ..config import config
|
||||||
from gramps.gen.db.base import sort_objects
|
|
||||||
from gramps.gen.const import GRAMPS_LOCALE as glocale
|
from gramps.gen.const import GRAMPS_LOCALE as glocale
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
@ -234,32 +233,18 @@ class LivingProxyDb(ProxyDbBase):
|
|||||||
family = self.__remove_living_from_family(family)
|
family = self.__remove_living_from_family(family)
|
||||||
return family
|
return family
|
||||||
|
|
||||||
def iter_people(self, order_by=None):
|
def iter_people(self):
|
||||||
"""
|
"""
|
||||||
Protected version of iter_people
|
Protected version of iter_people
|
||||||
"""
|
"""
|
||||||
if order_by:
|
for person in filter(None, self.db.iter_people()):
|
||||||
retval = []
|
if self.__is_living(person):
|
||||||
for person in filter(None, self.db.iter_people()):
|
if self.mode == self.MODE_EXCLUDE_ALL:
|
||||||
if self.__is_living(person):
|
continue
|
||||||
if self.mode == self.MODE_EXCLUDE_ALL:
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
retval.append(self.__restrict_person(person))
|
|
||||||
else:
|
else:
|
||||||
retval.append(person)
|
yield self.__restrict_person(person)
|
||||||
retval = sort_objects(retval, order_by, self)
|
else:
|
||||||
for item in retval:
|
yield person
|
||||||
yield item
|
|
||||||
else:
|
|
||||||
for person in filter(None, self.db.iter_people()):
|
|
||||||
if self.__is_living(person):
|
|
||||||
if self.mode == self.MODE_EXCLUDE_ALL:
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
yield self.__restrict_person(person)
|
|
||||||
else:
|
|
||||||
yield person
|
|
||||||
|
|
||||||
def get_person_from_gramps_id(self, val):
|
def get_person_from_gramps_id(self, val):
|
||||||
"""
|
"""
|
||||||
|
@ -35,7 +35,7 @@ import types
|
|||||||
# Gramps libraries
|
# Gramps libraries
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
from ..db.base import DbReadBase, DbWriteBase, sort_objects
|
from ..db.base import DbReadBase, DbWriteBase
|
||||||
from ..lib import (Citation, Event, Family, Media, Note, Person, Place,
|
from ..lib import (Citation, Event, Family, Media, Note, Person, Place,
|
||||||
Repository, Source, Tag)
|
Repository, Source, Tag)
|
||||||
|
|
||||||
@ -498,85 +498,82 @@ class ProxyDbBase(DbReadBase):
|
|||||||
"""
|
"""
|
||||||
return filter(self.include_tag, self.db.iter_tag_handles())
|
return filter(self.include_tag, self.db.iter_tag_handles())
|
||||||
|
|
||||||
def __iter_object(self, selector, method, order_by=None):
|
def __iter_object(self, selector, method):
|
||||||
""" Helper function to return an iterator over an object class """
|
""" Helper function to return an iterator over an object class """
|
||||||
retval = filter(lambda obj:
|
retval = filter(lambda obj:
|
||||||
((selector is None) or selector(obj.handle)),
|
((selector is None) or selector(obj.handle)),
|
||||||
method())
|
method())
|
||||||
if order_by:
|
return retval
|
||||||
return sort_objects([item for item in retval], order_by, self)
|
|
||||||
else:
|
|
||||||
return retval
|
|
||||||
|
|
||||||
def iter_people(self, order_by=None):
|
def iter_people(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over Person objects in the database
|
Return an iterator over Person objects in the database
|
||||||
"""
|
"""
|
||||||
return self.__iter_object(self.include_person,
|
return self.__iter_object(self.include_person,
|
||||||
self.db.iter_people, order_by)
|
self.db.iter_people)
|
||||||
|
|
||||||
def iter_families(self, order_by=None):
|
def iter_families(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over Family objects in the database
|
Return an iterator over Family objects in the database
|
||||||
"""
|
"""
|
||||||
return self.__iter_object(self.include_family,
|
return self.__iter_object(self.include_family,
|
||||||
self.db.iter_families, order_by)
|
self.db.iter_families)
|
||||||
|
|
||||||
def iter_events(self, order_by=None):
|
def iter_events(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over Event objects in the database
|
Return an iterator over Event objects in the database
|
||||||
"""
|
"""
|
||||||
return self.__iter_object(self.include_event,
|
return self.__iter_object(self.include_event,
|
||||||
self.db.iter_events, order_by)
|
self.db.iter_events)
|
||||||
|
|
||||||
def iter_places(self, order_by=None):
|
def iter_places(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over Place objects in the database
|
Return an iterator over Place objects in the database
|
||||||
"""
|
"""
|
||||||
return self.__iter_object(self.include_place,
|
return self.__iter_object(self.include_place,
|
||||||
self.db.iter_places, order_by)
|
self.db.iter_places)
|
||||||
|
|
||||||
def iter_sources(self, order_by=None):
|
def iter_sources(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over Source objects in the database
|
Return an iterator over Source objects in the database
|
||||||
"""
|
"""
|
||||||
return self.__iter_object(self.include_source,
|
return self.__iter_object(self.include_source,
|
||||||
self.db.iter_sources, order_by)
|
self.db.iter_sources)
|
||||||
|
|
||||||
def iter_citations(self, order_by=None):
|
def iter_citations(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over Citation objects in the database
|
Return an iterator over Citation objects in the database
|
||||||
"""
|
"""
|
||||||
return self.__iter_object(self.include_citation,
|
return self.__iter_object(self.include_citation,
|
||||||
self.db.iter_citations, order_by)
|
self.db.iter_citations)
|
||||||
|
|
||||||
def iter_media(self, order_by=None):
|
def iter_media(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over Media objects in the database
|
Return an iterator over Media objects in the database
|
||||||
"""
|
"""
|
||||||
return self.__iter_object(self.include_media,
|
return self.__iter_object(self.include_media,
|
||||||
self.db.iter_media, order_by)
|
self.db.iter_media)
|
||||||
|
|
||||||
def iter_repositories(self, order_by=None):
|
def iter_repositories(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over Repositories objects in the database
|
Return an iterator over Repositories objects in the database
|
||||||
"""
|
"""
|
||||||
return self.__iter_object(self.include_repository,
|
return self.__iter_object(self.include_repository,
|
||||||
self.db.iter_repositories, order_by)
|
self.db.iter_repositories)
|
||||||
|
|
||||||
def iter_notes(self, order_by=None):
|
def iter_notes(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over Note objects in the database
|
Return an iterator over Note objects in the database
|
||||||
"""
|
"""
|
||||||
return self.__iter_object(self.include_note,
|
return self.__iter_object(self.include_note,
|
||||||
self.db.iter_notes, order_by)
|
self.db.iter_notes)
|
||||||
|
|
||||||
def iter_tags(self, order_by=None):
|
def iter_tags(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over Tag objects in the database
|
Return an iterator over Tag objects in the database
|
||||||
"""
|
"""
|
||||||
return self.__iter_object(self.include_tag,
|
return self.__iter_object(self.include_tag,
|
||||||
self.db.iter_tags, order_by)
|
self.db.iter_tags)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def gfilter(predicate, obj):
|
def gfilter(predicate, obj):
|
||||||
|
@ -71,7 +71,7 @@ from gramps.gen.lib.nameorigintype import NameOriginType
|
|||||||
|
|
||||||
from gramps.gen.utils.callback import Callback
|
from gramps.gen.utils.callback import Callback
|
||||||
from . import BsddbBaseCursor
|
from . import BsddbBaseCursor
|
||||||
from gramps.gen.db.base import DbReadBase, eval_order_by
|
from gramps.gen.db.base import DbReadBase
|
||||||
from gramps.gen.utils.id import create_id
|
from gramps.gen.utils.id import create_id
|
||||||
from gramps.gen.errors import DbError, HandleError
|
from gramps.gen.errors import DbError, HandleError
|
||||||
from gramps.gen.constfunc import get_env_var
|
from gramps.gen.constfunc import get_env_var
|
||||||
@ -1260,34 +1260,12 @@ class DbBsddbRead(DbReadBase, Callback):
|
|||||||
"""
|
"""
|
||||||
Closure that returns an iterator over objects in the database.
|
Closure that returns an iterator over objects in the database.
|
||||||
"""
|
"""
|
||||||
def g(self, order_by=None):
|
def g(self):
|
||||||
"""
|
with curs_(self) as cursor:
|
||||||
order_by - [[field, DIRECTION], ...]
|
for key, data in cursor:
|
||||||
DIRECTION is "ASC" or "DESC"
|
obj = obj_()
|
||||||
"""
|
obj.unserialize(data)
|
||||||
if order_by is None:
|
yield obj
|
||||||
with curs_(self) as cursor:
|
|
||||||
for key, data in cursor:
|
|
||||||
obj = obj_()
|
|
||||||
obj.unserialize(data)
|
|
||||||
yield obj
|
|
||||||
else:
|
|
||||||
# first build sort order:
|
|
||||||
sorted_items = []
|
|
||||||
with curs_(self) as cursor:
|
|
||||||
for key, data in cursor:
|
|
||||||
obj = obj_()
|
|
||||||
obj.unserialize(data)
|
|
||||||
# just use values and handle to keep small:
|
|
||||||
sorted_items.append((eval_order_by(order_by, obj, self), obj.handle))
|
|
||||||
# next we sort by fields and direction
|
|
||||||
pos = len(order_by) - 1
|
|
||||||
for (field, order) in reversed(order_by): # sort the lasts parts first
|
|
||||||
sorted_items.sort(key=itemgetter(pos), reverse=(order=="DESC"))
|
|
||||||
pos -= 1
|
|
||||||
# now we will look them up again:
|
|
||||||
for (order_by_values, handle) in sorted_items:
|
|
||||||
yield self.get_table_func(obj_.__name__,"handle_func")(handle)
|
|
||||||
return g
|
return g
|
||||||
|
|
||||||
# Use closure to define iterators for each primary object type
|
# Use closure to define iterators for each primary object type
|
||||||
|
@ -37,7 +37,6 @@ import logging
|
|||||||
# Gramps Modules
|
# Gramps Modules
|
||||||
#
|
#
|
||||||
#------------------------------------------------------------------------
|
#------------------------------------------------------------------------
|
||||||
from gramps.gen.db.base import eval_order_by
|
|
||||||
from gramps.gen.db.dbconst import (DBLOGNAME, DBBACKEND, KEY_TO_NAME_MAP,
|
from gramps.gen.db.dbconst import (DBLOGNAME, DBBACKEND, KEY_TO_NAME_MAP,
|
||||||
TXNADD, TXNUPD, TXNDEL,
|
TXNADD, TXNUPD, TXNDEL,
|
||||||
PERSON_KEY, FAMILY_KEY, SOURCE_KEY,
|
PERSON_KEY, FAMILY_KEY, SOURCE_KEY,
|
||||||
@ -1014,152 +1013,77 @@ class DBAPI(DbGeneric):
|
|||||||
if row:
|
if row:
|
||||||
return self.get_person_from_handle(row[0])
|
return self.get_person_from_handle(row[0])
|
||||||
|
|
||||||
def iter_items_order_by_python(self, order_by, class_):
|
def _iter_handles(self, obj_key):
|
||||||
"""
|
"""
|
||||||
This method is for those iter_items with a order_by, but
|
Return an iterator over handles in the database
|
||||||
can't be done with secondary fields.
|
|
||||||
"""
|
"""
|
||||||
# first build sort order:
|
table = KEY_TO_NAME_MAP[obj_key]
|
||||||
sorted_items = []
|
sql = "SELECT handle FROM %s" % table
|
||||||
query = "SELECT blob_data FROM %s;" % class_.__name__.lower()
|
self.dbapi.execute(sql)
|
||||||
self.dbapi.execute(query)
|
|
||||||
rows = self.dbapi.fetchall()
|
rows = self.dbapi.fetchall()
|
||||||
for row in rows:
|
for row in rows:
|
||||||
obj = self.get_table_func(class_.__name__,
|
yield row[0]
|
||||||
"class_func").create(pickle.loads(row[0]))
|
|
||||||
# just use values and handle to keep small:
|
|
||||||
sorted_items.append((eval_order_by(order_by, obj, self),
|
|
||||||
obj.handle))
|
|
||||||
# next we sort by fields and direction
|
|
||||||
pos = len(order_by) - 1
|
|
||||||
for (field, order) in reversed(order_by): # sort the lasts parts first
|
|
||||||
sorted_items.sort(key=itemgetter(pos), reverse=(order == "DESC"))
|
|
||||||
pos -= 1
|
|
||||||
# now we will look them up again:
|
|
||||||
for (order_by_values, handle) in sorted_items:
|
|
||||||
yield self.get_table_func(class_.__name__, "handle_func")(handle)
|
|
||||||
|
|
||||||
def iter_items(self, order_by, class_):
|
|
||||||
"""
|
|
||||||
Iterate over items in a class, possibly ordered by
|
|
||||||
a list of field names and direction ("ASC" or "DESC").
|
|
||||||
"""
|
|
||||||
# check if order_by fields are secondary
|
|
||||||
# if so, fine
|
|
||||||
# else, use Python sorts
|
|
||||||
if order_by:
|
|
||||||
secondary_fields = class_.get_secondary_fields()
|
|
||||||
if not self._check_order_by_fields(class_.__name__,
|
|
||||||
order_by, secondary_fields):
|
|
||||||
for item in self.iter_items_order_by_python(order_by, class_):
|
|
||||||
yield item
|
|
||||||
return
|
|
||||||
## Continue with dbapi select
|
|
||||||
if order_by is None:
|
|
||||||
query = "SELECT blob_data FROM %s;" % class_.__name__.lower()
|
|
||||||
else:
|
|
||||||
order_phrases = [
|
|
||||||
"%s %s" % (self._hash_name(class_.__name__,
|
|
||||||
class_.get_field_alias(field)),
|
|
||||||
direction)
|
|
||||||
for (field, direction) in order_by]
|
|
||||||
query = "SELECT blob_data FROM %s ORDER BY %s;" % (
|
|
||||||
class_.__name__.lower(), ", ".join(order_phrases))
|
|
||||||
self.dbapi.execute(query)
|
|
||||||
rows = self.dbapi.fetchall()
|
|
||||||
for row in rows:
|
|
||||||
yield class_.create(pickle.loads(row[0]))
|
|
||||||
|
|
||||||
def iter_person_handles(self):
|
def iter_person_handles(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over handles for Persons in the database
|
Return an iterator over handles for Persons in the database
|
||||||
"""
|
"""
|
||||||
self.dbapi.execute("SELECT handle FROM person;")
|
return self._iter_handles(PERSON_KEY)
|
||||||
rows = self.dbapi.fetchall()
|
|
||||||
for row in rows:
|
|
||||||
yield row[0]
|
|
||||||
|
|
||||||
def iter_family_handles(self):
|
def iter_family_handles(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over handles for Families in the database
|
Return an iterator over handles for Families in the database
|
||||||
"""
|
"""
|
||||||
self.dbapi.execute("SELECT handle FROM family;")
|
return self._iter_handles(FAMILY_KEY)
|
||||||
rows = self.dbapi.fetchall()
|
|
||||||
for row in rows:
|
|
||||||
yield row[0]
|
|
||||||
|
|
||||||
def iter_citation_handles(self):
|
def iter_citation_handles(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over database handles, one handle for each Citation
|
Return an iterator over database handles, one handle for each Citation
|
||||||
in the database.
|
in the database.
|
||||||
"""
|
"""
|
||||||
self.dbapi.execute("SELECT handle FROM citation;")
|
return self._iter_handles(CITATION_KEY)
|
||||||
rows = self.dbapi.fetchall()
|
|
||||||
for row in rows:
|
|
||||||
yield row[0]
|
|
||||||
|
|
||||||
def iter_event_handles(self):
|
def iter_event_handles(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over handles for Events in the database
|
Return an iterator over handles for Events in the database
|
||||||
"""
|
"""
|
||||||
self.dbapi.execute("SELECT handle FROM event;")
|
return self._iter_handles(EVENT_KEY)
|
||||||
rows = self.dbapi.fetchall()
|
|
||||||
for row in rows:
|
|
||||||
yield row[0]
|
|
||||||
|
|
||||||
def iter_media_handles(self):
|
def iter_media_handles(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over handles for Media in the database
|
Return an iterator over handles for Media in the database
|
||||||
"""
|
"""
|
||||||
self.dbapi.execute("SELECT handle FROM media;")
|
return self._iter_handles(MEDIA_KEY)
|
||||||
rows = self.dbapi.fetchall()
|
|
||||||
for row in rows:
|
|
||||||
yield row[0]
|
|
||||||
|
|
||||||
def iter_note_handles(self):
|
def iter_note_handles(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over handles for Notes in the database
|
Return an iterator over handles for Notes in the database
|
||||||
"""
|
"""
|
||||||
self.dbapi.execute("SELECT handle FROM note;")
|
return self._iter_handles(NOTE_KEY)
|
||||||
rows = self.dbapi.fetchall()
|
|
||||||
for row in rows:
|
|
||||||
yield row[0]
|
|
||||||
|
|
||||||
def iter_place_handles(self):
|
def iter_place_handles(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over handles for Places in the database
|
Return an iterator over handles for Places in the database
|
||||||
"""
|
"""
|
||||||
self.dbapi.execute("SELECT handle FROM place;")
|
return self._iter_handles(PLACE_KEY)
|
||||||
rows = self.dbapi.fetchall()
|
|
||||||
for row in rows:
|
|
||||||
yield row[0]
|
|
||||||
|
|
||||||
def iter_repository_handles(self):
|
def iter_repository_handles(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over handles for Repositories in the database
|
Return an iterator over handles for Repositories in the database
|
||||||
"""
|
"""
|
||||||
self.dbapi.execute("SELECT handle FROM repository;")
|
return self._iter_handles(REPOSITORY_KEY)
|
||||||
rows = self.dbapi.fetchall()
|
|
||||||
for row in rows:
|
|
||||||
yield row[0]
|
|
||||||
|
|
||||||
def iter_source_handles(self):
|
def iter_source_handles(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over handles for Sources in the database
|
Return an iterator over handles for Sources in the database
|
||||||
"""
|
"""
|
||||||
self.dbapi.execute("SELECT handle FROM source;")
|
return self._iter_handles(SOURCE_KEY)
|
||||||
rows = self.dbapi.fetchall()
|
|
||||||
for row in rows:
|
|
||||||
yield row[0]
|
|
||||||
|
|
||||||
def iter_tag_handles(self):
|
def iter_tag_handles(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over handles for Tags in the database
|
Return an iterator over handles for Tags in the database
|
||||||
"""
|
"""
|
||||||
self.dbapi.execute("SELECT handle FROM tag;")
|
return self._iter_handles(TAG_KEY)
|
||||||
rows = self.dbapi.fetchall()
|
|
||||||
for row in rows:
|
|
||||||
yield row[0]
|
|
||||||
|
|
||||||
def _iter_raw_data(self, obj_key):
|
def _iter_raw_data(self, obj_key):
|
||||||
"""
|
"""
|
||||||
@ -1725,19 +1649,6 @@ class DBAPI(DbGeneric):
|
|||||||
else:
|
else:
|
||||||
return repr(value)
|
return repr(value)
|
||||||
|
|
||||||
def _check_order_by_fields(self, table, order_by, secondary_fields):
|
|
||||||
"""
|
|
||||||
Check to make sure all order_by fields are defined. If not, then
|
|
||||||
we need to do the Python-based order.
|
|
||||||
|
|
||||||
secondary_fields are hashed.
|
|
||||||
"""
|
|
||||||
if order_by:
|
|
||||||
for (field, directory) in order_by:
|
|
||||||
if self._hash_name(table, field) not in secondary_fields:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def get_summary(self):
|
def get_summary(self):
|
||||||
"""
|
"""
|
||||||
Returns dictionary of summary item.
|
Returns dictionary of summary item.
|
||||||
|
@ -506,6 +506,106 @@ class DbTest(unittest.TestCase):
|
|||||||
self.__get_cursor_test(self.db.get_tag_cursor,
|
self.__get_cursor_test(self.db.get_tag_cursor,
|
||||||
self.db.get_raw_tag_data)
|
self.db.get_raw_tag_data)
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
#
|
||||||
|
# Test iter_*_handles methods
|
||||||
|
#
|
||||||
|
################################################################
|
||||||
|
|
||||||
|
def __iter_handles_test(self, obj_type, iter_func):
|
||||||
|
for handle in iter_func():
|
||||||
|
self.assertIn(handle, self.handles[obj_type])
|
||||||
|
|
||||||
|
def test_iter_person_handles(self):
|
||||||
|
self.__iter_handles_test('Person',
|
||||||
|
self.db.iter_person_handles)
|
||||||
|
|
||||||
|
def test_iter_family_handles(self):
|
||||||
|
self.__iter_handles_test('Family',
|
||||||
|
self.db.iter_family_handles)
|
||||||
|
|
||||||
|
def test_iter_event_handles(self):
|
||||||
|
self.__iter_handles_test('Event',
|
||||||
|
self.db.iter_event_handles)
|
||||||
|
|
||||||
|
def test_iter_place_handles(self):
|
||||||
|
self.__iter_handles_test('Place',
|
||||||
|
self.db.iter_place_handles)
|
||||||
|
|
||||||
|
def test_iter_repository_handles(self):
|
||||||
|
self.__iter_handles_test('Repository',
|
||||||
|
self.db.iter_repository_handles)
|
||||||
|
|
||||||
|
def test_iter_source_handles(self):
|
||||||
|
self.__iter_handles_test('Source',
|
||||||
|
self.db.iter_source_handles)
|
||||||
|
|
||||||
|
def test_iter_citation_handles(self):
|
||||||
|
self.__iter_handles_test('Citation',
|
||||||
|
self.db.iter_citation_handles)
|
||||||
|
|
||||||
|
def test_iter_media_handles(self):
|
||||||
|
self.__iter_handles_test('Media',
|
||||||
|
self.db.iter_media_handles)
|
||||||
|
|
||||||
|
def test_iter_note_handles(self):
|
||||||
|
self.__iter_handles_test('Note',
|
||||||
|
self.db.iter_note_handles)
|
||||||
|
|
||||||
|
def test_iter_tag_handles(self):
|
||||||
|
self.__iter_handles_test('Tag',
|
||||||
|
self.db.iter_tag_handles)
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
#
|
||||||
|
# Test iter_* methods
|
||||||
|
#
|
||||||
|
################################################################
|
||||||
|
|
||||||
|
def __iter_objects_test(self, obj_class, iter_func):
|
||||||
|
for obj in iter_func():
|
||||||
|
self.assertIsInstance(obj, obj_class)
|
||||||
|
|
||||||
|
def test_iter_people(self):
|
||||||
|
self.__iter_objects_test(Person,
|
||||||
|
self.db.iter_people)
|
||||||
|
|
||||||
|
def test_iter_families(self):
|
||||||
|
self.__iter_objects_test(Family,
|
||||||
|
self.db.iter_families)
|
||||||
|
|
||||||
|
def test_iter_events(self):
|
||||||
|
self.__iter_objects_test(Event,
|
||||||
|
self.db.iter_events)
|
||||||
|
|
||||||
|
def test_iter_places(self):
|
||||||
|
self.__iter_objects_test(Place,
|
||||||
|
self.db.iter_places)
|
||||||
|
|
||||||
|
def test_iter_repositories(self):
|
||||||
|
self.__iter_objects_test(Repository,
|
||||||
|
self.db.iter_repositories)
|
||||||
|
|
||||||
|
def test_iter_sources(self):
|
||||||
|
self.__iter_objects_test(Source,
|
||||||
|
self.db.iter_sources)
|
||||||
|
|
||||||
|
def test_iter_citations(self):
|
||||||
|
self.__iter_objects_test(Citation,
|
||||||
|
self.db.iter_citations)
|
||||||
|
|
||||||
|
def test_iter_media(self):
|
||||||
|
self.__iter_objects_test(Media,
|
||||||
|
self.db.iter_media)
|
||||||
|
|
||||||
|
def test_iter_notes(self):
|
||||||
|
self.__iter_objects_test(Note,
|
||||||
|
self.db.iter_notes)
|
||||||
|
|
||||||
|
def test_iter_tags(self):
|
||||||
|
self.__iter_objects_test(Tag,
|
||||||
|
self.db.iter_tags)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
@ -1341,7 +1341,7 @@ class DummyDb(M_A_M_B("NewBaseClass", (DbReadBase, Callback, object,), {})):
|
|||||||
"""
|
"""
|
||||||
return self.db_is_open
|
return self.db_is_open
|
||||||
|
|
||||||
def iter_citations(self, order_by=None):
|
def iter_citations(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over objects for Citations in the database
|
Return an iterator over objects for Citations in the database
|
||||||
"""
|
"""
|
||||||
@ -1357,7 +1357,7 @@ class DummyDb(M_A_M_B("NewBaseClass", (DbReadBase, Callback, object,), {})):
|
|||||||
LOG.warning("database is closed")
|
LOG.warning("database is closed")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def iter_events(self, order_by=None):
|
def iter_events(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over objects for Events in the database
|
Return an iterator over objects for Events in the database
|
||||||
"""
|
"""
|
||||||
@ -1365,7 +1365,7 @@ class DummyDb(M_A_M_B("NewBaseClass", (DbReadBase, Callback, object,), {})):
|
|||||||
LOG.warning("database is closed")
|
LOG.warning("database is closed")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def iter_families(self, order_by=None):
|
def iter_families(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over objects for Families in the database
|
Return an iterator over objects for Families in the database
|
||||||
"""
|
"""
|
||||||
@ -1389,7 +1389,7 @@ class DummyDb(M_A_M_B("NewBaseClass", (DbReadBase, Callback, object,), {})):
|
|||||||
LOG.warning("database is closed")
|
LOG.warning("database is closed")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def iter_media(self, order_by=None):
|
def iter_media(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over objects for Medias in the database
|
Return an iterator over objects for Medias in the database
|
||||||
"""
|
"""
|
||||||
@ -1405,7 +1405,7 @@ class DummyDb(M_A_M_B("NewBaseClass", (DbReadBase, Callback, object,), {})):
|
|||||||
LOG.warning("database is closed")
|
LOG.warning("database is closed")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def iter_notes(self, order_by=None):
|
def iter_notes(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over objects for Notes in the database
|
Return an iterator over objects for Notes in the database
|
||||||
"""
|
"""
|
||||||
@ -1413,7 +1413,7 @@ class DummyDb(M_A_M_B("NewBaseClass", (DbReadBase, Callback, object,), {})):
|
|||||||
LOG.warning("database is closed")
|
LOG.warning("database is closed")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def iter_people(self, order_by=None):
|
def iter_people(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over objects for Persons in the database
|
Return an iterator over objects for Persons in the database
|
||||||
"""
|
"""
|
||||||
@ -1437,7 +1437,7 @@ class DummyDb(M_A_M_B("NewBaseClass", (DbReadBase, Callback, object,), {})):
|
|||||||
LOG.warning("database is closed")
|
LOG.warning("database is closed")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def iter_places(self, order_by=None):
|
def iter_places(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over objects for Places in the database
|
Return an iterator over objects for Places in the database
|
||||||
"""
|
"""
|
||||||
@ -1445,7 +1445,7 @@ class DummyDb(M_A_M_B("NewBaseClass", (DbReadBase, Callback, object,), {})):
|
|||||||
LOG.warning("database is closed")
|
LOG.warning("database is closed")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def iter_repositories(self, order_by=None):
|
def iter_repositories(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over objects for Repositories in the database
|
Return an iterator over objects for Repositories in the database
|
||||||
"""
|
"""
|
||||||
@ -1469,7 +1469,7 @@ class DummyDb(M_A_M_B("NewBaseClass", (DbReadBase, Callback, object,), {})):
|
|||||||
LOG.warning("database is closed")
|
LOG.warning("database is closed")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def iter_sources(self, order_by=None):
|
def iter_sources(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over objects for Sources in the database
|
Return an iterator over objects for Sources in the database
|
||||||
"""
|
"""
|
||||||
@ -1485,7 +1485,7 @@ class DummyDb(M_A_M_B("NewBaseClass", (DbReadBase, Callback, object,), {})):
|
|||||||
LOG.warning("database is closed")
|
LOG.warning("database is closed")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def iter_tags(self, order_by=None):
|
def iter_tags(self):
|
||||||
"""
|
"""
|
||||||
Return an iterator over objects for Tags in the database
|
Return an iterator over objects for Tags in the database
|
||||||
"""
|
"""
|
||||||
|
Loading…
Reference in New Issue
Block a user