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, ...]] | ["AND", [filter, filter, ...]] |
["OR", [filter, filter, ...]] | ["OR", [filter, filter, ...]] |
["NOT", filter] ["NOT", filter]
order_by - [[fieldname, "ASC" | "DESC"], ...]
""" """
class Result(list): class Result(list):
""" """
@@ -1993,9 +1994,7 @@ class DbWriteBase(DbReadBase):
if "*" in fields: if "*" in fields:
fields.remove("*") fields.remove("*")
fields.extend(self._tables[table]["class_func"].get_schema().keys()) 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"](order_by=order_by)
data = self._tables[table]["iter_func"]()
position = 0 position = 0
selected = 0 selected = 0
result = Result() result = Result()
@@ -2041,3 +2040,14 @@ class DbWriteBase(DbReadBase):
""" """
name = self._tables[table]["class_func"].get_field_alias(name) name = self._tables[table]["class_func"].get_field_alias(name)
return name.replace(".", "__") 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 shutil
import bisect import bisect
import ast import ast
from operator import itemgetter
#------------------------------------------------------------------------ #------------------------------------------------------------------------
# #
@@ -1143,11 +1144,36 @@ class DbGeneric(DbWriteBase, DbReadBase, UpdateCallback, Callback):
else: else:
return None return None
def iter_people(self): def iter_items(self, order_by, class_):
return (Person.create(data[1]) for data in self.get_person_cursor()) """
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): def iter_people(self, order_by=None):
return (Family.create(data[1]) for data in self.get_family_cursor()) 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): def get_person_from_gramps_id(self, gramps_id):
return Person.create(self.person_id_map[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): def is_open(self):
return self.db_is_open return self.db_is_open
def iter_citations(self): def iter_citations(self, order_by=None):
return (Citation.create(data[1]) for data in self.get_citation_cursor()) return self.iter_items(order_by, Citation)
def iter_events(self): def iter_events(self, order_by=None):
return (Event.create(data[1]) for data in self.get_event_cursor()) return self.iter_items(order_by, Event)
def iter_media(self): def iter_media(self, order_by=None):
return (Media.create(data[1]) for data in self.get_media_cursor()) return self.iter_items(order_by, Media)
def iter_notes(self): def iter_notes(self, order_by=None):
return (Note.create(data[1]) for data in self.get_note_cursor()) return self.iter_items(order_by, Note)
def iter_places(self): def iter_places(self, order_by=None):
return (Place.create(data[1]) for data in self.get_place_cursor()) return self.iter_items(order_by, Place)
def iter_repositories(self): def iter_repositories(self, order_by=None):
return (Repository.create(data[1]) for data in self.get_repository_cursor()) return self.iter_items(order_by, Repository)
def iter_sources(self): def iter_sources(self, order_by=None):
return (Source.create(data[1]) for data in self.get_source_cursor()) return self.iter_items(order_by, Source)
def iter_tags(self): def iter_tags(self):
return (Tag.create(data[1]) for data in self.get_tag_cursor()) return (Tag.create(data[1]) for data in self.get_tag_cursor())

View File

@@ -34,6 +34,7 @@ import time
import random import random
import os import os
from sys import maxsize from sys import maxsize
from operator import itemgetter
try: try:
from bsddb3 import db from bsddb3 import db
@@ -1203,12 +1204,34 @@ 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): def g(self, order_by=None):
with curs_(self) as cursor: """
for key, data in cursor: order_by - [[field, DIRECTION], ...]
obj = obj_() DIRECTION is "ASC" or "DESC"
obj.unserialize(data) """
yield obj 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 return g
# Use closure to define iterators for each primary object type # Use closure to define iterators for each primary object type