diff --git a/gramps/plugins/database/dictionarydb.py b/gramps/plugins/database/dictionarydb.py index a3dbd9586..621425e2d 100644 --- a/gramps/plugins/database/dictionarydb.py +++ b/gramps/plugins/database/dictionarydb.py @@ -29,6 +29,8 @@ import base64 import time import re from gramps.gen.db import DbReadBase, DbWriteBase, DbTxn +from gramps.gen.utils.callback import Callback +from gramps.gen.updatecallback import UpdateCallback from gramps.gen.db import (PERSON_KEY, FAMILY_KEY, CITATION_KEY, @@ -53,33 +55,101 @@ from gramps.gen.lib.repo import Repository from gramps.gen.lib.note import Note from gramps.gen.lib.tag import Tag +class Environment(object): + """ + Implements the Environment API. + """ + def __init__(self, db): + self.db = db + + def txn_begin(self): + return DictionaryTxn("DictionaryDb Transaction", self.db) + +class Table(object): + """ + Implements Table interface. + """ + def __init__(self, funcs): + self.funcs = funcs + + def cursor(self): + """ + Returns a Cursor for this Table. + """ + return self.funcs["cursor_func"]() + + def put(key, data, txn=None): + self[key] = data + +class Map(dict): + """ + Implements the map API for person_map, etc. + + Takes a Table() as argument. + """ + def __init__(self, tbl, *args, **kwargs): + super().__init__(*args, **kwargs) + self.db = tbl + +class MetaCursor(object): + def __init__(self): + pass + def __enter__(self): + return self + def __iter__(self): + return self.__next__() + def __next__(self): + yield None + def __exit__(self, *args, **kwargs): + pass + def iter(self): + yield None + def first(self): + self._iter = self.__iter__() + return self.next() + def next(self): + try: + return next(self._iter) + except: + return None + def close(self): + pass + class Cursor(object): - """ - Iterates through model returning (handle, raw_data)... - """ - def __init__(self, model, func): - self.model = model + def __init__(self, map, func): + self.map = map self.func = func def __enter__(self): return self def __iter__(self): - return self + return self.__next__() def __next__(self): - for handle in self.model.keys(): - return (handle, self.func(handle)) - def next(self): - for handle in self.model.keys(): - return (handle, self.func(handle)) + for item in self.map.keys(): + yield (bytes(item, "utf-8"), self.func(item)) def __exit__(self, *args, **kwargs): pass + def iter(self): + for item in self.map.keys(): + yield (bytes(item, "utf-8"), self.func(item)) + yield None + def first(self): + self._iter = self.__iter__() + return self.next() + def next(self): + try: + return next(self._iter) + except: + return None def close(self): pass -class Bookmarks: +class Bookmarks(object): + def __init__(self): + self.handles = [] def get(self): - return [] # handles + return self.handles def append(self, handle): - pass + self.handles.append(handle) class DictionaryTxn(DbTxn): def __init__(self, message, db, batch=False): @@ -99,13 +169,38 @@ class DictionaryTxn(DbTxn): """ txn[handle] = new_data -class DictionaryDb(DbWriteBase, DbReadBase): +class DictionaryDb(DbWriteBase, DbReadBase, UpdateCallback, Callback): """ A Gramps Database Backend. This replicates the grampsdb functions. """ + __signals__ = dict((obj+'-'+op, signal) + for obj in + ['person', 'family', 'event', 'place', + 'source', 'citation', 'media', 'note', 'repository', 'tag'] + for op, signal in zip( + ['add', 'update', 'delete', 'rebuild'], + [(list,), (list,), (list,), None] + ) + ) + + # 2. Signals for long operations + __signals__.update(('long-op-'+op, signal) for op, signal in zip( + ['start', 'heartbeat', 'end'], + [(object,), None, None] + )) + + # 3. Special signal for change in home person + __signals__['home-person-changed'] = None + + # 4. Signal for change in person group name, parameters are + __signals__['person-groupname-rebuild'] = (str, str) + + __callback_map = {} + def __init__(self, *args, **kwargs): DbReadBase.__init__(self) DbWriteBase.__init__(self) + Callback.__init__(self) self._tables['Person'].update( { "handle_func": self.get_person_from_handle, @@ -115,6 +210,7 @@ class DictionaryDb(DbWriteBase, DbReadBase): "handles_func": self.get_person_handles, "add_func": self.add_person, "commit_func": self.commit_person, + "iter_func": self.iter_people, }) self._tables['Family'].update( { @@ -125,6 +221,7 @@ class DictionaryDb(DbWriteBase, DbReadBase): "handles_func": self.get_family_handles, "add_func": self.add_family, "commit_func": self.commit_family, + "iter_func": self.iter_families, }) self._tables['Source'].update( { @@ -135,6 +232,7 @@ class DictionaryDb(DbWriteBase, DbReadBase): "handles_func": self.get_source_handles, "add_func": self.add_source, "commit_func": self.commit_source, + "iter_func": self.iter_sources, }) self._tables['Citation'].update( { @@ -145,6 +243,7 @@ class DictionaryDb(DbWriteBase, DbReadBase): "handles_func": self.get_citation_handles, "add_func": self.add_citation, "commit_func": self.commit_citation, + "iter_func": self.iter_citations, }) self._tables['Event'].update( { @@ -155,6 +254,7 @@ class DictionaryDb(DbWriteBase, DbReadBase): "handles_func": self.get_event_handles, "add_func": self.add_event, "commit_func": self.commit_event, + "iter_func": self.iter_events, }) self._tables['Media'].update( { @@ -165,6 +265,7 @@ class DictionaryDb(DbWriteBase, DbReadBase): "handles_func": self.get_media_object_handles, "add_func": self.add_object, "commit_func": self.commit_media_object, + "iter_func": self.iter_media_objects, }) self._tables['Place'].update( { @@ -175,6 +276,7 @@ class DictionaryDb(DbWriteBase, DbReadBase): "handles_func": self.get_place_handles, "add_func": self.add_place, "commit_func": self.commit_place, + "iter_func": self.iter_places, }) self._tables['Repository'].update( { @@ -185,6 +287,7 @@ class DictionaryDb(DbWriteBase, DbReadBase): "handles_func": self.get_repository_handles, "add_func": self.add_repository, "commit_func": self.commit_repository, + "iter_func": self.iter_repositories, }) self._tables['Note'].update( { @@ -195,6 +298,7 @@ class DictionaryDb(DbWriteBase, DbReadBase): "handles_func": self.get_note_handles, "add_func": self.add_note, "commit_func": self.commit_note, + "iter_func": self.iter_notes, }) self._tables['Tag'].update( { @@ -205,6 +309,7 @@ class DictionaryDb(DbWriteBase, DbReadBase): "handles_func": self.get_tag_handles, "add_func": self.add_tag, "commit_func": self.commit_tag, + "iter_func": self.iter_tags, }) # skip GEDCOM cross-ref check for now: self.set_feature("skip-check-xref", True) @@ -218,7 +323,7 @@ class DictionaryDb(DbWriteBase, DbReadBase): self.place_bookmarks = Bookmarks() self.citation_bookmarks = Bookmarks() self.source_bookmarks = Bookmarks() - self.repo_bookmarks = Bookmarks() + self.repository_bookmarks = Bookmarks() self.media_bookmarks = Bookmarks() self.note_bookmarks = Bookmarks() self.set_person_id_prefix('I%04d') @@ -249,18 +354,18 @@ class DictionaryDb(DbWriteBase, DbReadBase): self.omap_index = 0 self.rmap_index = 0 self.nmap_index = 0 - self.env = None - self.person_map = {} - self.family_map = {} - self.place_map = {} - self.citation_map = {} - self.source_map = {} - self.repository_map = {} - self.note_map = {} - self.media_map = {} - self.event_map = {} - self.tag_map = {} - self.metadata = {} + self.env = Environment(self) + self.person_map = Map(Table(self._tables["Person"])) + self.family_map = Map(Table(self._tables["Family"])) + self.place_map = Map(Table(self._tables["Place"])) + self.citation_map = Map(Table(self._tables["Citation"])) + self.source_map = Map(Table(self._tables["Source"])) + self.repository_map = Map(Table(self._tables["Repository"])) + self.note_map = Map(Table(self._tables["Note"])) + self.media_map = Map(Table(self._tables["Media"])) + self.event_map = Map(Table(self._tables["Event"])) + self.tag_map = Map(Table(self._tables["Tag"])) + self.metadata = Map(Table({"cursor_func": lambda: MetaCursor()})) self.name_group = {} self.undo_callback = None self.redo_callback = None @@ -286,9 +391,6 @@ class DictionaryDb(DbWriteBase, DbReadBase): def transaction_commit(self, txn): pass - def enable_signals(self): - pass - def get_undodb(self): return None @@ -546,91 +648,107 @@ class DictionaryDb(DbWriteBase, DbReadBase): return obj def get_person_handles(self, sort_handles=False): - if sort_handles: - raise Exception("Implement!") - else: - return self.person_map.keys() + ## Fixme: implement sort + return self.person_map.keys() def get_family_handles(self): return self.family_map.keys() - def get_event_handles(self): + def get_event_handles(self, sort_handles=False): return self.event_map.keys() def get_citation_handles(self, sort_handles=False): - if sort_handles: - raise Exception("Implement!") - else: - return self.citation_map.keys() + ## Fixme: implement sort + return self.citation_map.keys() def get_source_handles(self, sort_handles=False): - if sort_handles: - raise Exception("Implement!") - else: - return self.source_map.keys() + ## Fixme: implement sort + return self.source_map.keys() def get_place_handles(self, sort_handles=False): - if sort_handles: - raise Exception("Implement!") - else: - return self.place_map.keys() + ## Fixme: implement sort + return self.place_map.keys() def get_repository_handles(self): return self.repository_map.keys() def get_media_object_handles(self, sort_handles=False): - if sort_handles: - raise Exception("Implement!") - else: - return self.media_map.keys() + ## Fixme: implement sort + return self.media_map.keys() def get_note_handles(self): return self.note_map.keys() def get_tag_handles(self, sort_handles=False): - if sort_handles: - raise Exception("Implement!") - else: - return self.tag_map.keys() + # FIXME: sort + return self.tag_map.keys() def get_event_from_handle(self, handle): - return self.event_map[handle] + event = None + if handle in self.event_map: + event = self.event_map[handle] + return event def get_family_from_handle(self, handle): - return self.family_map[handle] + family = None + if handle in self.family_map: + family = self.family_map[handle] + return family def get_repository_from_handle(self, handle): - return self.repository_map[handle] + repository = None + if handle in self.repository_map: + repository = self.repository_map[handle] + return repository def get_person_from_handle(self, handle): - return self.person_map[handle] + person = None + if handle in self.person_map: + person = self.person_map[handle] + return person def get_place_from_handle(self, handle): - place = self.place_map[handle] + place = None + if handle in self.place_map: + place = self.place_map[handle] return place def get_citation_from_handle(self, handle): - citation = self.citation_map[handle] + citation = None + if handle in self.citation_map: + citation = self.citation_map[handle] return citation def get_source_from_handle(self, handle): - source = self.source_map[handle] + source = None + if handle in self.source_map: + source = self.source_map[handle] return source def get_note_from_handle(self, handle): - note = self.note_map[handle] + note = None + if handle in self.note_map: + note = self.note_map[handle] return note def get_object_from_handle(self, handle): - media = self.media_map[handle] + media = None + if handle in self.media_map: + media = self.media_map[handle] return media def get_tag_from_handle(self, handle): - tag = self.tag_map[handle] + tag = None + if handle in self.tag_map: + tag = self.tag_map[handle] return tag def get_default_person(self): - return None + handle = self.get_default_handle() + if handle: + return self.get_person_from_handle(handle) + else: + return None def iter_people(self): return (person for person in self.person_map.values()) @@ -1203,3 +1321,205 @@ class DictionaryDb(DbWriteBase, DbReadBase): transaction.add(REFERENCE_KEY, TXNDEL, key, old_data, None) #transaction.reference_del.append(str(key)) self.reference_map.delete(key, txn=txn) + + ## Missing: + + def backup(self): + pass + + def close(self): + pass + + def find_backlink_handles(self, handle, include_classes=None): + return [] + + def find_initial_person(self): + items = self.person_map.keys() + if len(items) > 0: + return self.get_person_from_handle(list(items)[0]) + return None + + def find_place_child_handles(self, handle): + return [] + + def get_bookmarks(self): + return self.bookmarks + + def get_child_reference_types(self): + return [] + + def get_citation_bookmarks(self): + return self.citation_bookmarks + + def get_cursor(self, table, txn=None, update=False, commit=False): + pass + + def get_dbname(self): + return "DictionaryDb" + + def get_default_handle(self): + items = self.person_map.keys() + if len(items) > 0: + return list(items)[0] + return None + + def get_event_attribute_types(self): + return [] + + def get_event_bookmarks(self): + return self.event_bookmarks + + def get_event_roles(self): + return [] + + def get_event_types(self): + return [] + + def get_family_attribute_types(self): + return [] + + def get_family_bookmarks(self): + return self.family_bookmarks + + def get_family_event_types(self): + return [] + + def get_family_relation_types(self): + return [] + + def get_media_attribute_types(self): + return [] + + def get_media_bookmarks(self): + return self.media_bookmarks + + def get_name_types(self): + return [] + + def get_note_bookmarks(self): + return self.note_bookmarks + + def get_note_types(self): + return [] + + def get_number_of_records(self, table): + return 0 + + def get_origin_types(self): + return [] + + def get_person_attribute_types(self): + return [] + + def get_person_event_types(self): + return [] + + def get_place_bookmarks(self): + return self.place_bookmarks + + def get_place_tree_cursor(self): + return [] + + def get_place_types(self): + return [] + + def get_repo_bookmarks(self): + return self.repository_bookmarks + + def get_repository_types(self): + return [] + + def get_save_path(self): + return self._directory + + def get_source_attribute_types(self): + return [] + + def get_source_bookmarks(self): + return self.source_bookmarks + + def get_source_media_types(self): + return [] + + def get_surname_list(self): + return [] + + def get_url_types(self): + return [] + + def has_changed(self): + return True + + def is_open(self): + return True + + def iter_citation_handles(self): + return (key for key in self.citation_map.keys()) + + def iter_citations(self): + return (key for key in self.citation_map.values()) + + def iter_event_handles(self): + return (key for key in self.event_map.keys()) + + def iter_events(self): + return (key for key in self.event_map.values()) + + def iter_media_objects(self): + return (key for key in self.media_map.values()) + + def iter_note_handles(self): + return (key for key in self.note_map.keys()) + + def iter_notes(self): + return (key for key in self.note_map.values()) + + def iter_place_handles(self): + return (key for key in self.place_map.keys()) + + def iter_places(self): + return (key for key in self.place_map.values()) + + def iter_repositories(self): + return (key for key in self.repositories_map.values()) + + def iter_repository_handles(self): + return (key for key in self.repositories_map.keys()) + + def iter_source_handles(self): + return (key for key in self.source_map.keys()) + + def iter_sources(self): + return (key for key in self.source_map.values()) + + def iter_tag_handles(self): + return (key for key in self.tag_map.keys()) + + def iter_tags(self): + return (key for key in self.tag_map.values()) + + def load(self, directory, pulse_progress, mode, + force_schema_upgrade, + force_bsddb_upgrade, + force_bsddb_downgrade, + force_python_upgrade): + self._directory = directory + + def prepare_import(self): + pass + + def redo(self, update_history=True): + pass + + def restore(self): + pass + + def set_prefixes(self, person, media, family, source, citation, + place, event, repository, note): + pass + + def set_save_path(self, directory): + self._directory = directory + + def undo(self, update_history=True): + pass diff --git a/gramps/plugins/database/djangodb.py b/gramps/plugins/database/djangodb.py index e0d8c043a..ee6d4162d 100644 --- a/gramps/plugins/database/djangodb.py +++ b/gramps/plugins/database/djangodb.py @@ -68,7 +68,7 @@ class Environment(object): self.db = db def txn_begin(self): - return DjangoTxn("DbDjango Transaction", self.db) + return DjangoTxn("DjangoDb Transaction", self.db) class Table(object): """ @@ -210,6 +210,8 @@ class DbDjango(DbWriteBase, DbReadBase, UpdateCallback, Callback): # 4. Signal for change in person group name, parameters are __signals__['person-groupname-rebuild'] = (str, str) + __callback_map = {} + def __init__(self, directory=None): DbReadBase.__init__(self) DbWriteBase.__init__(self) @@ -1745,8 +1747,6 @@ class DbDjango(DbWriteBase, DbReadBase, UpdateCallback, Callback): self.get_number_of_media_objects() == 0 and self.get_number_of_repositories() == 0) - __callback_map = {} - def set_prefixes(self, person, media, family, source, citation, place, event, repository, note): self.set_person_id_prefix(person) diff --git a/gramps/webapp/utils.py b/gramps/webapp/utils.py index 07eddd341..10e0aaf38 100644 --- a/gramps/webapp/utils.py +++ b/gramps/webapp/utils.py @@ -143,8 +143,12 @@ def get_person_from_handle(db, handle): return None def probably_alive(handle): + ## FIXME: need to call after save? person = db.get_person_from_handle(handle) - return alive(person, db) + if person: + return alive(person, db) + else: + return True def format_number(number, with_grouping=True): if number != "":