iter_OBJECTS can take an order_by field list

This commit is contained in:
Doug Blank 2016-01-24 08:56:23 -05:00
parent f7e8f04121
commit 1de7bb5ebc
3 changed files with 86 additions and 27 deletions

View File

@ -1892,6 +1892,7 @@ class DbWriteBase(DbReadBase):
["AND", [filter, filter, ...]] |
["OR", [filter, filter, ...]] |
["NOT", filter]
order_by - [[fieldname, "ASC" | "DESC"], ...]
"""
class Result(list):
"""
@ -1993,9 +1994,7 @@ class DbWriteBase(DbReadBase):
if "*" in fields:
fields.remove("*")
fields.extend(self._tables[table]["class_func"].get_schema().keys())
#FIXME: add order_by to iter_funcs
#data = self._tables[table]["iter_func"](order_by=order_by)
data = self._tables[table]["iter_func"]()
data = self._tables[table]["iter_func"](order_by=order_by)
position = 0
selected = 0
result = Result()
@ -2041,3 +2040,14 @@ class DbWriteBase(DbReadBase):
"""
name = self._tables[table]["class_func"].get_field_alias(name)
return name.replace(".", "__")
def eval_order_by(self, order_by, obj):
"""
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))
return values

View File

@ -33,6 +33,7 @@ import logging
import shutil
import bisect
import ast
from operator import itemgetter
#------------------------------------------------------------------------
#
@ -1143,11 +1144,36 @@ class DbGeneric(DbWriteBase, DbReadBase, UpdateCallback, Callback):
else:
return None
def iter_people(self):
return (Person.create(data[1]) for data in self.get_person_cursor())
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").
"""
cursor = self._tables[class_.__name__]["cursor_func"]
if order_by is None:
for data in cursor():
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((self.eval_order_by(order_by, obj), 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._tables[class_.__name__]["handle_func"](handle)
def iter_families(self):
return (Family.create(data[1]) for data in self.get_family_cursor())
def iter_people(self, order_by=None):
return self.iter_items(order_by, Person)
def iter_families(self, order_by=None):
return self.iter_items(order_by, Family)
def get_person_from_gramps_id(self, gramps_id):
return Person.create(self.person_id_map[gramps_id])
@ -1817,26 +1843,26 @@ class DbGeneric(DbWriteBase, DbReadBase, UpdateCallback, Callback):
def is_open(self):
return self.db_is_open
def iter_citations(self):
return (Citation.create(data[1]) for data in self.get_citation_cursor())
def iter_citations(self, order_by=None):
return self.iter_items(order_by, Citation)
def iter_events(self):
return (Event.create(data[1]) for data in self.get_event_cursor())
def iter_events(self, order_by=None):
return self.iter_items(order_by, Event)
def iter_media(self):
return (Media.create(data[1]) for data in self.get_media_cursor())
def iter_media(self, order_by=None):
return self.iter_items(order_by, Media)
def iter_notes(self):
return (Note.create(data[1]) for data in self.get_note_cursor())
def iter_notes(self, order_by=None):
return self.iter_items(order_by, Note)
def iter_places(self):
return (Place.create(data[1]) for data in self.get_place_cursor())
def iter_places(self, order_by=None):
return self.iter_items(order_by, Place)
def iter_repositories(self):
return (Repository.create(data[1]) for data in self.get_repository_cursor())
def iter_repositories(self, order_by=None):
return self.iter_items(order_by, Repository)
def iter_sources(self):
return (Source.create(data[1]) for data in self.get_source_cursor())
def iter_sources(self, order_by=None):
return self.iter_items(order_by, Source)
def iter_tags(self):
return (Tag.create(data[1]) for data in self.get_tag_cursor())

View File

@ -34,6 +34,7 @@ import time
import random
import os
from sys import maxsize
from operator import itemgetter
try:
from bsddb3 import db
@ -1203,12 +1204,34 @@ class DbBsddbRead(DbReadBase, Callback):
"""
Closure that returns an iterator over objects in the database.
"""
def g(self):
with curs_(self) as cursor:
for key, data in cursor:
obj = obj_()
obj.unserialize(data)
yield obj
def g(self, order_by=None):
"""
order_by - [[field, DIRECTION], ...]
DIRECTION is "ASC" or "DESC"
"""
if order_by is None:
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((self.eval_order_by(order_by, obj), 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._tables[obj_.__class__.__name__]["handle_func"](handle)
return g
# Use closure to define iterators for each primary object type