Add new modules to support restructured database objects
bsddbtxn.py -- Wrapper for BSDDB DBTxn to support context manager protocol txn.py -- GrampsDbTxn class to manage atomic transactions write.py -- GrampsDbWrite class for read/write databases read.py -- GrampsDbRead class for read-only databases undoredo.py -- GrampsDbUndo class to manage the undo database upgrade.py -- Helper module for upgrading a database at open time svn: r13078
This commit is contained in:
parent
fa05e52a04
commit
c8f7bf0c69
210
src/gen/db/bsddbtxn.py
Normal file
210
src/gen/db/bsddbtxn.py
Normal file
@ -0,0 +1,210 @@
|
||||
#
|
||||
# Gramps - a GTK+/GNOME based genealogy program
|
||||
#
|
||||
# Copyright (C) 2009 Gerald W. Britton
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
# $Id: bsddbtxn.py 12786 2009-07-11 15:32:37Z gbritton $
|
||||
|
||||
"""
|
||||
BSDDBTxn class: Wrapper for BSDDB transaction-oriented methods
|
||||
"""
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# BSDDBTxn
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
class BSDDBTxn(object):
|
||||
"""
|
||||
Wrapper for BSDDB methods that set up and manage transactions. Implements
|
||||
context management functionality allowing constructs like:
|
||||
|
||||
with BSDDBTxn(env) as txn:
|
||||
DB.get(txn=txn)
|
||||
DB.put(txn=txn)
|
||||
DB.delete(txn=txn)
|
||||
|
||||
and other transaction-oriented DB access methods, where "env" is a
|
||||
BSDDB DBEnv object and "DB" is a BSDDB database object.
|
||||
|
||||
Transactions are automatically begun when the "with" statement is executed
|
||||
and automatically committed when control flows off the end of the "with"
|
||||
statement context, either implicitly by reaching the end of the indentation
|
||||
level or explicity if a "return" statement is encountered or an exception
|
||||
is raised.
|
||||
"""
|
||||
|
||||
__slots__ = ['env', 'db', 'txn', 'parent']
|
||||
|
||||
def __init__(self, env, db=None):
|
||||
"""
|
||||
Initialize transaction instance
|
||||
"""
|
||||
self.env = env
|
||||
self.db = db
|
||||
self.txn = None
|
||||
|
||||
# Context manager methods
|
||||
|
||||
def __enter__(self, parent=None, **kwargs):
|
||||
"""
|
||||
Context manager entry method
|
||||
|
||||
Begin the transaction
|
||||
"""
|
||||
self.txn = self.begin(parent, **kwargs)
|
||||
self.parent = parent
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
"""
|
||||
Context manager exit function
|
||||
|
||||
Commit the transaction if no exception occurred
|
||||
"""
|
||||
if exc_type is not None:
|
||||
return False
|
||||
if self.txn:
|
||||
self.commit()
|
||||
return True
|
||||
|
||||
# Methods implementing txn_ methods in DBEnv
|
||||
|
||||
def begin(self, *args, **kwargs):
|
||||
"""
|
||||
Create and begin a new transaction. A DBTxn object is returned
|
||||
"""
|
||||
self.txn = self.env.txn_begin(*args, **kwargs)
|
||||
return self.txn
|
||||
|
||||
def checkpoint(self, *args, **kwargs):
|
||||
"""
|
||||
Flush the underlying memory pool, write a checkpoint record to the
|
||||
log and then flush the log
|
||||
"""
|
||||
if self.env:
|
||||
self.env.txn_checkpoint(*args, **kwargs)
|
||||
|
||||
def stat(self):
|
||||
"""
|
||||
Return a dictionary of transaction statistics
|
||||
"""
|
||||
if self.env:
|
||||
return self.env.txn_stat()
|
||||
|
||||
def recover(self):
|
||||
"""
|
||||
Returns a list of tuples (GID, TXN) of transactions prepared but
|
||||
still unresolved
|
||||
"""
|
||||
if self.env:
|
||||
return self.env.txn_recover()
|
||||
|
||||
# Methods implementing DBTxn methods
|
||||
|
||||
def abort(self):
|
||||
"""
|
||||
Abort the transaction
|
||||
"""
|
||||
if self.txn:
|
||||
self.txn.abort()
|
||||
self.txn = None
|
||||
|
||||
def commit(self, flags=0):
|
||||
"""
|
||||
End the transaction, committing any changes to the databases
|
||||
"""
|
||||
if self.txn:
|
||||
self.txn.commit(flags)
|
||||
self.txn = None
|
||||
|
||||
def id(self):
|
||||
"""
|
||||
Return the unique transaction id associated with the specified
|
||||
transaction
|
||||
"""
|
||||
if self.txn:
|
||||
return self.txn.id()
|
||||
|
||||
def prepare(self, gid):
|
||||
"""
|
||||
Initiate the beginning of a two-phase commit
|
||||
"""
|
||||
if self.txn:
|
||||
self.txn.prepare(gid)
|
||||
|
||||
def discard(self):
|
||||
"""
|
||||
Release all the per-process resources associated with the specified
|
||||
transaction, neither committing nor aborting the transaction
|
||||
"""
|
||||
if self.txn:
|
||||
self.txn.discard()
|
||||
self.txn = None
|
||||
|
||||
# Methods implementing DB methods within the transaction context
|
||||
|
||||
def get(self, key, default=None, txn=None, **kwargs):
|
||||
"""
|
||||
Returns the data object associated with key
|
||||
"""
|
||||
if txn == None: txn = self.txn
|
||||
return self.db.get(key, default, txn, **kwargs)
|
||||
|
||||
def pget(self, key, default=None, txn=None, **kwargs):
|
||||
"""
|
||||
Returns the primary key, given the secondary one, and associated data
|
||||
"""
|
||||
if txn == None: txn = self.txn
|
||||
return self.db.pget(key, default, txn, **kwargs)
|
||||
|
||||
def put(self, key, data, txn=None, **kwargs):
|
||||
"""
|
||||
Stores the key/data pair in the database
|
||||
"""
|
||||
if txn == None: txn = self.txn
|
||||
return self.db.put(key, data, txn, **kwargs)
|
||||
|
||||
def delete(self, key, txn=None, **kwargs):
|
||||
"""
|
||||
Removes a key/data pair from the database
|
||||
"""
|
||||
if txn == None: txn = self.txn
|
||||
self.db.delete(key, txn, **kwargs)
|
||||
|
||||
# test code
|
||||
if __name__ == "__main__":
|
||||
print "1"
|
||||
from bsddb import db, dbshelve
|
||||
print "2"
|
||||
x = db.DBEnv()
|
||||
print "3"
|
||||
x.open('/tmp', db.DB_CREATE | db.DB_PRIVATE |\
|
||||
db.DB_INIT_MPOOL | db.DB_INIT_LOCK |\
|
||||
db.DB_INIT_LOG | db.DB_INIT_TXN | db.DB_THREAD)
|
||||
print "4"
|
||||
d = dbshelve.DBShelf(x)
|
||||
print "5"
|
||||
#from tran import BSDDBTxn as T
|
||||
print "6"
|
||||
T = BSDDBTxn
|
||||
with T(x) as tx:
|
||||
print "stat", tx.stat()
|
||||
print "id", tx.id()
|
||||
tx.checkpoint()
|
1566
src/gen/db/read.py
Normal file
1566
src/gen/db/read.py
Normal file
File diff suppressed because it is too large
Load Diff
335
src/gen/db/txn.py
Normal file
335
src/gen/db/txn.py
Normal file
@ -0,0 +1,335 @@
|
||||
#
|
||||
# Gramps - a GTK+/GNOME based genealogy program
|
||||
#
|
||||
# Copyright (C) 2004-2006 Donald N. Allingham
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
# $Id: txn.py 12672 2009-06-16 15:49:17Z gbritton $
|
||||
|
||||
"""
|
||||
Exports the GrampsDbTxn class for managing Gramps transactions and the undo
|
||||
database.
|
||||
"""
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Standard python modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from __future__ import with_statement
|
||||
import cPickle as pickle
|
||||
from bsddb import dbshelve, db
|
||||
import logging
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Gramps modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from gen.db.dbconst import *
|
||||
from gen.db import BSDDBTxn
|
||||
import Errors
|
||||
|
||||
_LOG = logging.getLogger(DBLOGNAME)
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Gramps transaction class
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
class GrampsDbTxn(dict):
|
||||
"""
|
||||
Define a group of database commits that define a single logical operation.
|
||||
This class should not be used directly, but subclassed to reference a real
|
||||
database
|
||||
"""
|
||||
|
||||
__slots__ = ('msg', 'commitdb', 'db', 'first',
|
||||
'last', 'timestamp', 'db_maps')
|
||||
|
||||
def get_db_txn(self, value):
|
||||
"""
|
||||
Return a transaction object from the database
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def __enter__(self):
|
||||
"""
|
||||
Context manager entry method
|
||||
"""
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
"""
|
||||
Context manager exit method
|
||||
"""
|
||||
if exc_type is None:
|
||||
self.commit()
|
||||
return exc_type is None
|
||||
|
||||
def __init__(self, msg, commitdb, grampsdb):
|
||||
"""
|
||||
Create a new transaction.
|
||||
|
||||
A Transaction instance should not be created directly, but by the
|
||||
GrampsDbBase class or classes derived from GrampsDbBase. The commitdb
|
||||
parameter is a list-like interface that stores the commit data. This
|
||||
could be a simple list, or a RECNO-style database object. The grampsdb
|
||||
parameter is a reference to the GrampsDbWrite object to which this
|
||||
transaction will be applied.
|
||||
|
||||
The data structure used to handle the transactions is a Python
|
||||
dictionary where:
|
||||
|
||||
key = (object type, transaction type) where:
|
||||
object type = the numeric type of an object. These are
|
||||
defined as PERSON_KEY = 0, FAMILY_KEY = 1, etc.
|
||||
as imported from dbconst.
|
||||
transaction type = a numeric representation of the type of
|
||||
transaction: TXNADD = 0, TXNUPD = 1, TXNDEL = 2
|
||||
|
||||
data = Python list where:
|
||||
list element = (handle, data) where:
|
||||
handle = handle (database key) of the object in the transaction
|
||||
data = pickled representation of the object
|
||||
"""
|
||||
|
||||
super(GrampsDbTxn, self).__init__({})
|
||||
|
||||
self.msg = msg
|
||||
self.commitdb = commitdb
|
||||
self.db = grampsdb
|
||||
self.first = None
|
||||
self.last = None
|
||||
self.timestamp = 0
|
||||
|
||||
# Dictionary to enable table-driven logic in the class
|
||||
self.db_maps = {
|
||||
PERSON_KEY: (self.db.person_map, 'person'),
|
||||
FAMILY_KEY: (self.db.family_map, 'family'),
|
||||
EVENT_KEY: (self.db.event_map, 'event'),
|
||||
SOURCE_KEY: (self.db.source_map, 'source'),
|
||||
PLACE_KEY: (self.db.place_map, 'place'),
|
||||
MEDIA_KEY: (self.db.media_map, 'media'),
|
||||
REPOSITORY_KEY: (self.db.repository_map, 'repository'),
|
||||
#REFERENCE_KEY: (self.db.reference_map, 'reference'),
|
||||
NOTE_KEY: (self.db.note_map, 'note'),
|
||||
}
|
||||
|
||||
def get_description(self):
|
||||
"""
|
||||
Return the text string that describes the logical operation performed
|
||||
by the Transaction.
|
||||
"""
|
||||
return self.msg
|
||||
|
||||
def set_description(self, msg):
|
||||
"""
|
||||
Set the text string that describes the logical operation performed by
|
||||
the Transaction.
|
||||
"""
|
||||
self.msg = msg
|
||||
|
||||
def add(self, obj_type, trans_type, handle, old_data, new_data):
|
||||
"""
|
||||
Add a commit operation to the Transaction.
|
||||
|
||||
The obj_type is a constant that indicates what type of PrimaryObject
|
||||
is being added. The handle is the object's database handle, and the
|
||||
data is the tuple returned by the object's serialize method.
|
||||
"""
|
||||
self.last = self.commitdb.append(
|
||||
pickle.dumps((obj_type, trans_type, handle, old_data, new_data), 1))
|
||||
if self.last is None:
|
||||
self.last = len(self.commitdb) -1
|
||||
if self.first is None:
|
||||
self.first = self.last
|
||||
if (obj_type, trans_type) in self:
|
||||
self[(obj_type, trans_type)] += [(handle, new_data)]
|
||||
else:
|
||||
self[(obj_type, trans_type)] = [(handle, new_data)]
|
||||
|
||||
def get_recnos(self, reverse=False):
|
||||
"""
|
||||
Return a list of record numbers associated with the transaction.
|
||||
|
||||
While the list is an arbitrary index of integers, it can be used
|
||||
to indicate record numbers for a database.
|
||||
"""
|
||||
if not reverse:
|
||||
return xrange(self.first, self.last+1)
|
||||
else:
|
||||
return xrange(self.last, self.first-1, -1)
|
||||
|
||||
def get_record(self, recno):
|
||||
"""
|
||||
Return a tuple representing the PrimaryObject type, database handle
|
||||
for the PrimaryObject, and a tuple representing the data created by
|
||||
the object's serialize method.
|
||||
"""
|
||||
return pickle.loads(self.commitdb[recno])
|
||||
|
||||
def __len__(self):
|
||||
"""
|
||||
Return the number of commits associated with the Transaction.
|
||||
"""
|
||||
if self.first is None or self.last is None:
|
||||
return 0
|
||||
return self.last - self.first + 1
|
||||
|
||||
def commit(self, msg=None):
|
||||
"""
|
||||
Commit the transaction to the assocated commit database.
|
||||
"""
|
||||
if msg is not None:
|
||||
self.msg = msg
|
||||
|
||||
if not len(self) or self.db.readonly:
|
||||
return
|
||||
|
||||
# Begin new database transaction
|
||||
txn = self.get_db_txn(self.db.env)
|
||||
self.db.txn = txn.begin()
|
||||
|
||||
# Commit all add transactions to the database
|
||||
db_map = lambda key: self.db_maps[key][0]
|
||||
for (obj_type, trans_type), data in self.iteritems():
|
||||
if trans_type == TXNADD and obj_type in self.db_maps:
|
||||
for handle, new_data in data:
|
||||
assert handle == str(handle)
|
||||
db_map(obj_type).put(handle, new_data, txn=txn.txn)
|
||||
|
||||
# Commit all update transactions to the database
|
||||
for (obj_type, trans_type), data in self.iteritems():
|
||||
if trans_type == TXNUPD and obj_type in self.db_maps:
|
||||
for handle, new_data in data:
|
||||
assert handle == str(handle)
|
||||
db_map(obj_type).put(handle, new_data, txn=txn.txn)
|
||||
|
||||
# Before we commit delete transactions, emit signals as required
|
||||
|
||||
# Loop through the data maps, emitting signals as required
|
||||
emit = self.__emit
|
||||
for obj_type, (m_, obj_name) in self.db_maps.iteritems():
|
||||
# Do an emit for each object and transaction type as required
|
||||
emit(obj_type, TXNADD, obj_name, '-add')
|
||||
emit(obj_type, TXNUPD, obj_name, '-update')
|
||||
emit(obj_type, TXNDEL, obj_name, '-delete')
|
||||
|
||||
# Commit all delete transactions to the database
|
||||
for (obj_type, trans_type), data in self.iteritems():
|
||||
if trans_type == TXNDEL and obj_type in self.db_maps:
|
||||
for handle, n_ in data:
|
||||
assert handle == str(handle)
|
||||
db_map(obj_type).delete(handle, txn=txn.txn)
|
||||
|
||||
# Add new reference keys as required
|
||||
db_map = self.db.reference_map
|
||||
if (REFERENCE_KEY, TXNADD) in self:
|
||||
for handle, new_data in self[(REFERENCE_KEY, TXNADD)]:
|
||||
assert handle == str(handle)
|
||||
db_map.put(handle, new_data, txn=txn.txn)
|
||||
|
||||
# Delete old reference keys as required
|
||||
if (REFERENCE_KEY, TXNDEL) in self:
|
||||
for handle, none_ in self[(REFERENCE_KEY, TXNDEL)]:
|
||||
assert handle == str(handle)
|
||||
db_map.delete(handle, txn=txn.txn)
|
||||
|
||||
# Commit database transaction
|
||||
txn.commit()
|
||||
self.db.txn = None
|
||||
self.clear()
|
||||
return
|
||||
|
||||
# Define helper function to do the actual emits
|
||||
def __emit(self,obj_type, trans_type, obj, suffix):
|
||||
if (obj_type, trans_type) in self:
|
||||
handles = [handle for handle, data in
|
||||
self[(obj_type, trans_type)]]
|
||||
if handles:
|
||||
self.db.emit(obj + suffix, (handles, ))
|
||||
|
||||
# Test functions
|
||||
|
||||
def testtxn():
|
||||
"""
|
||||
Test suite
|
||||
"""
|
||||
class M(dict):
|
||||
"""Fake database map with just two methods"""
|
||||
def put(self, key, data, txn=None):
|
||||
super(M, self).__setitem__(key, data)
|
||||
def delete(self, key, txn=None):
|
||||
super(M, self).__delitem__(key)
|
||||
|
||||
class D:
|
||||
"""Fake gramps database"""
|
||||
def __init__(self):
|
||||
self.person_map = M()
|
||||
self.family_map = M()
|
||||
self.source_map = M()
|
||||
self.event_map = M()
|
||||
self.media_map = M()
|
||||
self.place_map = M()
|
||||
self.note_map = M()
|
||||
self.repository_map = M()
|
||||
self.reference_map = M()
|
||||
self.readonly = False
|
||||
self.env = None
|
||||
def emit(self, obj, value):
|
||||
pass
|
||||
|
||||
class C(list):
|
||||
""" Fake commit database"""
|
||||
pass
|
||||
|
||||
class G(GrampsDbTxn):
|
||||
"""Derived transacton class"""
|
||||
def get_db_txn(self, env):
|
||||
return T()
|
||||
|
||||
class T():
|
||||
"""Fake DBMS transaction class"""
|
||||
def __init__(self):
|
||||
self.txn = None
|
||||
def begin(self):
|
||||
return self
|
||||
def commit(self):
|
||||
pass
|
||||
|
||||
commitdb = C()
|
||||
grampsdb = D()
|
||||
trans = G("Test Transaction", commitdb, grampsdb)
|
||||
trans.add(0, TXNADD, '1', None, "data1")
|
||||
trans.add(0, TXNADD, '2', None, "data2")
|
||||
trans.add(0, TXNUPD, '2', None, "data3")
|
||||
trans.add(0, TXNDEL, '1', None, None)
|
||||
|
||||
print trans
|
||||
print trans.get_description()
|
||||
print trans.set_description("new text")
|
||||
print trans.get_description()
|
||||
for i in trans.get_recnos():
|
||||
print trans.get_record(i)
|
||||
print list(trans.get_recnos())
|
||||
print list(trans.get_recnos(reverse=True))
|
||||
trans.commit("test")
|
||||
print grampsdb.person_map
|
||||
|
||||
if __name__ == '__main__':
|
||||
testtxn()
|
509
src/gen/db/undoredo.py
Normal file
509
src/gen/db/undoredo.py
Normal file
@ -0,0 +1,509 @@
|
||||
#
|
||||
# Gramps - a GTK+/GNOME based genealogy program
|
||||
#
|
||||
# Copyright (C) 2004-2006 Donald N. Allingham
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
# $Id: undoredo.py 12672 2009-06-16 15:49:17Z gbritton $
|
||||
|
||||
"""
|
||||
Exports the GrampsDbUndo class for managing Gramps transactions
|
||||
undos and redos.
|
||||
"""
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Standard python modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import time, os
|
||||
import cPickle as pickle
|
||||
from bsddb import db
|
||||
from gettext import gettext as _
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Gramps modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from gen.db.dbconst import *
|
||||
from gen.db import BSDDBTxn
|
||||
import Errors
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Local Constants
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
DBERRS = (db.DBRunRecoveryError, db.DBAccessError,
|
||||
db.DBPageNotFoundError, db.DBInvalidArgError)
|
||||
|
||||
_SIGBASE = ('person', 'family', 'source', 'event', 'media',
|
||||
'place', 'repository', 'reference', 'note')
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# GrampsDbUndo class
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
class GrampsDbUndo(object):
|
||||
"""
|
||||
Base class for the gramps undo/redo manager. Needs to be subclassed
|
||||
for use with a real backend.
|
||||
"""
|
||||
|
||||
__slots__ = ['undodb', 'db', 'mapbase', 'translist', 'undoindex',
|
||||
'undo_history_timestamp', 'txn']
|
||||
|
||||
def __init__(self, grampsdb):
|
||||
"""
|
||||
Class constructor. Set up main instance variables
|
||||
"""
|
||||
self.db = grampsdb
|
||||
self.clear()
|
||||
self.mapbase = (
|
||||
self.db.person_map,
|
||||
self.db.family_map,
|
||||
self.db.source_map,
|
||||
self.db.event_map,
|
||||
self.db.media_map,
|
||||
self.db.place_map,
|
||||
self.db.repository_map,
|
||||
self.db.reference_map,
|
||||
self.db.note_map,
|
||||
)
|
||||
|
||||
def clear(self):
|
||||
"""
|
||||
Clear the undo/redo list (but not the backing storage)
|
||||
"""
|
||||
self.translist = []
|
||||
self.undoindex = -1
|
||||
self.undo_history_timestamp = time.time()
|
||||
self.txn = None
|
||||
|
||||
def __enter__(self, value):
|
||||
"""
|
||||
Context manager method to establish the context
|
||||
"""
|
||||
self.open(value)
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
"""
|
||||
Context manager method to finish the context
|
||||
"""
|
||||
if exc_type is None:
|
||||
self.close()
|
||||
return exc_type is None
|
||||
|
||||
def open(self, value):
|
||||
"""
|
||||
Open the backing storage. Needs to be overridden in the derived
|
||||
class.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def close(self):
|
||||
"""
|
||||
Close the backing storage. Needs to be overridden in the derived
|
||||
class.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def append(self, value):
|
||||
"""
|
||||
Add a new entry on the end. Needs to be overridden in the derived
|
||||
class.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def __getitem__(self, index):
|
||||
"""
|
||||
Returns an entry by index number. Needs to be overridden in the
|
||||
derived class.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def __setitem__(self, index, value):
|
||||
"""
|
||||
Set an entry to a value. Needs to be overridden in the derived class.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def __len__(self):
|
||||
"""
|
||||
Returns the number of entries. Needs to be overridden in the derived
|
||||
class.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def commit(self, txn, msg):
|
||||
"""
|
||||
Commit the transaction to the undo/redo database. "txn" should be
|
||||
an instance of gramps gramps transaction class
|
||||
"""
|
||||
txn.set_description(msg)
|
||||
txn.timestamp = time.time()
|
||||
|
||||
# If we're within our undo limit, add this transaction
|
||||
self.undoindex += 1
|
||||
if self.undoindex < DBUNDO:
|
||||
if self.undoindex >= len(self.translist):
|
||||
self.translist.append(txn)
|
||||
else:
|
||||
self.translist[self.undoindex] = txn
|
||||
del self.translist[self.undoindex+1:]
|
||||
|
||||
# Otherwise, we've exceeded our undo limit
|
||||
else:
|
||||
self.db.abort_possible = False
|
||||
self.undo_history_timestamp = time.time()
|
||||
self.translist[-1] = txn
|
||||
|
||||
def undo_available(self):
|
||||
"""
|
||||
Return boolean of whether or not there's a possibility of undo.
|
||||
"""
|
||||
if 0 <= self.undoindex < len(self.translist):
|
||||
return True
|
||||
return False
|
||||
|
||||
def redo_available(self):
|
||||
"""
|
||||
Return boolean of whether or not there's a possibility of redo.
|
||||
"""
|
||||
if 0 <= self.undoindex+1 < len(self.translist):
|
||||
return True
|
||||
return False
|
||||
|
||||
def undo(self, update_history=True):
|
||||
"""
|
||||
Undo a previously committed transaction
|
||||
"""
|
||||
if self.db.readonly or not self.undo_available():
|
||||
return False
|
||||
return self.__undoredo(update_history, self.__undo)
|
||||
|
||||
def redo(self, update_history=True):
|
||||
"""
|
||||
Redo a previously committed, then undone, transaction
|
||||
"""
|
||||
if self.db.readonly or not self.redo_available():
|
||||
return False
|
||||
return self.__undoredo(update_history, self.__redo)
|
||||
|
||||
def __undoredo(self, update_history, func):
|
||||
"""
|
||||
Helper method used by both undo and redo methods.
|
||||
"""
|
||||
try:
|
||||
with BSDDBTxn(self.db.env) as txn:
|
||||
self.txn = self.db.txn = txn.txn
|
||||
status = func(update_history)
|
||||
if not status:
|
||||
txn.abort()
|
||||
self.db.txn = None
|
||||
return status
|
||||
|
||||
except DBERRS, msg:
|
||||
self.db._log_error()
|
||||
raise Errors.DbError(msg)
|
||||
|
||||
def __undo(self, update_history=True):
|
||||
"""
|
||||
Access the last committed transaction, and revert the data to the
|
||||
state before the transaction was committed.
|
||||
"""
|
||||
transaction = self.translist[self.undoindex]
|
||||
db = self.db
|
||||
self.undoindex -= 1
|
||||
subitems = transaction.get_recnos(reverse=True)
|
||||
|
||||
# Process all records in the transaction
|
||||
for record_id in subitems:
|
||||
(key, trans_type, handle, old_data, new_data) = \
|
||||
pickle.loads(self.undodb[record_id])
|
||||
|
||||
if key == REFERENCE_KEY:
|
||||
self.undo_reference(old_data, handle, self.mapbase[key])
|
||||
else:
|
||||
self.undo_data(old_data, handle, self.mapbase[key],
|
||||
db.emit, _SIGBASE[key])
|
||||
# Notify listeners
|
||||
if db.undo_callback:
|
||||
if self.undo_available():
|
||||
db.undo_callback(_("_Undo %s")
|
||||
% transaction.get_description())
|
||||
else:
|
||||
db.undo_callback(None)
|
||||
|
||||
if db.redo_callback:
|
||||
db.redo_callback(_("_Redo %s")
|
||||
% transaction.get_description())
|
||||
|
||||
if update_history and db.undo_history_callback:
|
||||
db.undo_history_callback()
|
||||
return True
|
||||
|
||||
def __redo(self, db=None, update_history=True):
|
||||
"""
|
||||
Accesse the last undone transaction, and revert the data to the state
|
||||
before the transaction was undone.
|
||||
"""
|
||||
|
||||
self.undoindex += 1
|
||||
transaction = self.translist[self.undoindex]
|
||||
db = self.db
|
||||
subitems = transaction.get_recnos()
|
||||
|
||||
# Process all records in the transaction
|
||||
for record_id in subitems:
|
||||
(key, trans_type, handle, old_data, new_data) = \
|
||||
pickle.loads(self.undodb[record_id])
|
||||
|
||||
if key == REFERENCE_KEY:
|
||||
self.undo_reference(new_data, handle, self.mapbase[key])
|
||||
else:
|
||||
self.undo_data(new_data, handle, self.mapbase[key],
|
||||
db.emit, _SIGBASE[key])
|
||||
# Notify listeners
|
||||
if db.undo_callback:
|
||||
db.undo_callback(_("_Undo %s")
|
||||
% transaction.get_description())
|
||||
|
||||
if db.redo_callback:
|
||||
if self.redo_available():
|
||||
new_transaction = self.translist[self.undoindex+1]
|
||||
db.redo_callback(_("_Redo %s")
|
||||
% new_transaction.get_description())
|
||||
else:
|
||||
db.redo_callback(None)
|
||||
|
||||
if update_history and db.undo_history_callback:
|
||||
db.undo_history_callback()
|
||||
return True
|
||||
|
||||
def undo_reference(self, data, handle, db_map):
|
||||
"""
|
||||
Helper method to undo a reference map entry
|
||||
"""
|
||||
try:
|
||||
if data is None:
|
||||
db_map.delete(handle, txn=self.txn)
|
||||
else:
|
||||
db_map.put(handle, data, txn=self.txn)
|
||||
|
||||
except DBERRS, msg:
|
||||
self.db._log_error()
|
||||
raise Errors.DbError(msg)
|
||||
|
||||
def undo_data(self, data, handle, db_map, emit, signal_root):
|
||||
"""
|
||||
Helper method to undo/redo the changes made
|
||||
"""
|
||||
try:
|
||||
if data is None:
|
||||
emit(signal_root + '-delete', ([handle],))
|
||||
db_map.delete(handle, txn=self.txn)
|
||||
else:
|
||||
ex_data = db_map.get(handle, txn=self.txn)
|
||||
if ex_data:
|
||||
signal = signal_root + '-update'
|
||||
else:
|
||||
signal = signal_root + '-add'
|
||||
db_map.put(handle, data, txn=self.txn)
|
||||
emit(signal, ([handle],))
|
||||
|
||||
except DBERRS, msg:
|
||||
self.db._log_error()
|
||||
raise Errors.DbError(msg)
|
||||
|
||||
class GrampsDbUndoList(GrampsDbUndo):
|
||||
"""
|
||||
Implementation of the gramps undo database using a Python list
|
||||
"""
|
||||
def __init__(self, grampsdb):
|
||||
"""
|
||||
Class constructor
|
||||
"""
|
||||
super(GrampsDbUndoList, self).__init__(grampsdb)
|
||||
self.undodb = []
|
||||
|
||||
def open(self):
|
||||
"""
|
||||
A list does not need to be opened
|
||||
"""
|
||||
pass
|
||||
|
||||
def close(self):
|
||||
"""
|
||||
Close the list by resetting it to empty
|
||||
"""
|
||||
self.undodb = []
|
||||
self.clear()
|
||||
|
||||
def append(self, value):
|
||||
"""
|
||||
Add an entry on the end of the list
|
||||
"""
|
||||
self.undodb.append(value)
|
||||
return len(self.undodb)-1
|
||||
|
||||
def __getitem__(self, index):
|
||||
"""
|
||||
Return an item at the specified index
|
||||
"""
|
||||
return self.undodb[index]
|
||||
|
||||
def __setitem__(self, index, value):
|
||||
"""
|
||||
Set an item at the speficied index to the given value
|
||||
"""
|
||||
self.undodb[index] = value
|
||||
|
||||
def __iter__(self):
|
||||
"""
|
||||
Iterator
|
||||
"""
|
||||
for item in self.undodb:
|
||||
yield item
|
||||
|
||||
def __len__(self):
|
||||
"""
|
||||
Return number of entries in the list
|
||||
"""
|
||||
return len(self.undodb)
|
||||
|
||||
class GrampsDbUndoBSDDB(GrampsDbUndo):
|
||||
"""
|
||||
Class constructor for gramps undo/redo database using a bsddb recno
|
||||
database as the backing store.
|
||||
"""
|
||||
|
||||
def __init__(self, grampsdb, path):
|
||||
"""
|
||||
Class constructor
|
||||
"""
|
||||
super(GrampsDbUndoBSDDB, self).__init__(grampsdb)
|
||||
self.undodb = db.DB()
|
||||
self.path = path
|
||||
|
||||
def open(self):
|
||||
"""
|
||||
Open the undo/redo database
|
||||
"""
|
||||
self.undodb.open(self.path, db.DB_RECNO, db.DB_CREATE)
|
||||
|
||||
def close(self):
|
||||
"""
|
||||
Close the undo/redo database
|
||||
"""
|
||||
self.undodb.close()
|
||||
try:
|
||||
os.remove(self.path)
|
||||
except OSError:
|
||||
pass
|
||||
self.clear()
|
||||
|
||||
def append(self, value):
|
||||
"""
|
||||
Add an entry on the end of the database
|
||||
"""
|
||||
return self.undodb.append(value)
|
||||
|
||||
def __len__(self):
|
||||
"""
|
||||
Returns the number of entries in the database
|
||||
"""
|
||||
x = self.undodb.stat()['nkeys']
|
||||
y = len(self.undodb)
|
||||
assert x == y
|
||||
return x
|
||||
|
||||
def __getitem__(self, index):
|
||||
"""
|
||||
Returns the entry stored at the specified index
|
||||
"""
|
||||
return self.undodb.get(index)
|
||||
|
||||
def __setitem__(self, index, value):
|
||||
"""
|
||||
Sets the entry stored at the specified index to the value given.
|
||||
"""
|
||||
self.undodb.put(index, value)
|
||||
|
||||
def __iter__(self):
|
||||
"""
|
||||
Iterator
|
||||
"""
|
||||
cursor = self.undodb.cursor()
|
||||
data = cursor.first()
|
||||
while data:
|
||||
yield data
|
||||
data = cursor.next()
|
||||
|
||||
def testundo():
|
||||
class T:
|
||||
def __init__(self):
|
||||
self.msg = ''
|
||||
self.timetstamp = 0
|
||||
def set_description(self, msg):
|
||||
self.msg = msg
|
||||
|
||||
class D:
|
||||
def __init__(self):
|
||||
self.person_map = {}
|
||||
self.family_map = {}
|
||||
self.source_map = {}
|
||||
self.event_map = {}
|
||||
self.media_map = {}
|
||||
self.place_map = {}
|
||||
self.note_map = {}
|
||||
self.repository_map = {}
|
||||
self.reference_map = {}
|
||||
|
||||
print "list tests"
|
||||
undo = GrampsDbUndoList(D())
|
||||
print undo.append('foo')
|
||||
print undo.append('bar')
|
||||
print undo[0]
|
||||
undo[0] = 'foobar'
|
||||
print undo[0]
|
||||
print "len", len(undo)
|
||||
print "iter"
|
||||
for data in undo:
|
||||
print data
|
||||
print
|
||||
print "bsddb tests"
|
||||
undo = GrampsDbUndoBSDDB(D(), '/tmp/testundo')
|
||||
undo.open()
|
||||
print undo.append('foo')
|
||||
print undo.append('fo2')
|
||||
print undo.append('fo3')
|
||||
print undo[1]
|
||||
undo[1] = 'bar'
|
||||
print undo[1]
|
||||
for data in undo:
|
||||
print data
|
||||
print "len", len(undo)
|
||||
|
||||
print "test commit"
|
||||
undo.commit(T(), msg="test commit")
|
||||
undo.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
testundo()
|
305
src/gen/db/upgrade.py
Normal file
305
src/gen/db/upgrade.py
Normal file
@ -0,0 +1,305 @@
|
||||
from gen.db import BSDDBTxn
|
||||
def gramps_upgrade_14(self):
|
||||
"""Upgrade database from version 13 to 14."""
|
||||
# This upgrade modifies notes and dates
|
||||
length = (len(self.note_map) + len(self.person_map) +
|
||||
len(self.event_map) + len(self.family_map) +
|
||||
len(self.repository_map) + len(self.media_map) +
|
||||
len(self.place_map) + len(self.source_map))
|
||||
self.set_total(length)
|
||||
|
||||
# ---------------------------------
|
||||
# Modify Notes
|
||||
# ---------------------------------
|
||||
# replace clear text with StyledText in Notes
|
||||
for handle in self.note_map.keys():
|
||||
note = self.note_map[handle]
|
||||
(junk_handle, gramps_id, text, format, note_type,
|
||||
change, marker, private) = note
|
||||
styled_text = (text, [])
|
||||
new_note = (handle, gramps_id, styled_text, format, note_type,
|
||||
change, marker, private)
|
||||
with BSDDBTxn(self.env, self.note_map) as txn:
|
||||
txn.put(str(handle), new_note)
|
||||
self.update()
|
||||
|
||||
# ---------------------------------
|
||||
# Modify Event
|
||||
# ---------------------------------
|
||||
# update dates with newyear
|
||||
for handle in self.event_map.keys():
|
||||
event = self.event_map[handle]
|
||||
(junk_handle, gramps_id, the_type, date, description, place,
|
||||
source_list, note_list, media_list, attribute_list,
|
||||
change, marker, private) = event
|
||||
new_date = convert_date_14(date)
|
||||
new_source_list = new_source_list_14(source_list)
|
||||
new_media_list = new_media_list_14(media_list)
|
||||
new_attribute_list = new_attribute_list_14(attribute_list)
|
||||
new_event = (junk_handle, gramps_id, the_type, new_date,
|
||||
description, place, new_source_list, note_list,
|
||||
new_media_list, new_attribute_list, change,marker,private)
|
||||
with BSDDBTxn(self.env, self.event_map) as txn:
|
||||
txn.put(str(handle), new_event)
|
||||
self.update()
|
||||
|
||||
# ---------------------------------
|
||||
# Modify Person
|
||||
# ---------------------------------
|
||||
# update dates with newyear
|
||||
for handle in self.person_map.keys():
|
||||
person = self.person_map[handle]
|
||||
(junk_handle, # 0
|
||||
gramps_id, # 1
|
||||
gender, # 2
|
||||
primary_name, # 3
|
||||
alternate_names, # 4
|
||||
death_ref_index, # 5
|
||||
birth_ref_index, # 6
|
||||
event_ref_list, # 7
|
||||
family_list, # 8
|
||||
parent_family_list, # 9
|
||||
media_list, # 10
|
||||
address_list, # 11
|
||||
attribute_list, # 12
|
||||
urls, # 13
|
||||
lds_ord_list, # 14
|
||||
psource_list, # 15
|
||||
pnote_list, # 16
|
||||
change, # 17
|
||||
marker, # 18
|
||||
pprivate, # 19
|
||||
person_ref_list, # 20
|
||||
) = person
|
||||
|
||||
new_address_list = []
|
||||
for address in address_list:
|
||||
(privacy, asource_list, anote_list, date, location) = address
|
||||
new_date = convert_date_14(date)
|
||||
new_asource_list = new_source_list_14(asource_list)
|
||||
new_address_list.append((privacy, new_asource_list, anote_list,
|
||||
new_date, location))
|
||||
new_ord_list = []
|
||||
for ldsord in lds_ord_list:
|
||||
(lsource_list, lnote_list, date, type, place,
|
||||
famc, temple, status, lprivate) = ldsord
|
||||
new_date = convert_date_14(date)
|
||||
new_lsource_list = new_source_list_14(lsource_list)
|
||||
new_ord_list.append( (new_lsource_list, lnote_list, new_date, type,
|
||||
place, famc, temple, status, lprivate))
|
||||
|
||||
new_primary_name = convert_name_14(primary_name)
|
||||
|
||||
new_alternate_names = [convert_name_14(name) for name
|
||||
in alternate_names]
|
||||
|
||||
new_media_list = new_media_list_14(media_list)
|
||||
new_psource_list = new_source_list_14(psource_list)
|
||||
new_attribute_list = new_attribute_list_14(attribute_list)
|
||||
new_person_ref_list = new_person_ref_list_14(person_ref_list)
|
||||
|
||||
new_person = (junk_handle, # 0
|
||||
gramps_id, # 1
|
||||
gender, # 2
|
||||
new_primary_name, # 3
|
||||
new_alternate_names, # 4
|
||||
death_ref_index, # 5
|
||||
birth_ref_index, # 6
|
||||
event_ref_list, # 7
|
||||
family_list, # 8
|
||||
parent_family_list, # 9
|
||||
new_media_list, # 10
|
||||
new_address_list, # 11
|
||||
new_attribute_list, # 12
|
||||
urls, # 13
|
||||
new_ord_list, # 14
|
||||
new_psource_list, # 15
|
||||
pnote_list, # 16
|
||||
change, # 17
|
||||
marker, # 18
|
||||
pprivate, # 19
|
||||
new_person_ref_list, # 20
|
||||
)
|
||||
|
||||
with BSDDBTxn(self.env, self.person_map) as txn:
|
||||
txn.put(str(handle), new_person)
|
||||
self.update()
|
||||
|
||||
# ---------------------------------
|
||||
# Modify Family
|
||||
# ---------------------------------
|
||||
# update dates with newyear
|
||||
for handle in self.family_map.keys():
|
||||
family = self.family_map[handle]
|
||||
(junk_handle, gramps_id, father_handle, mother_handle,
|
||||
child_ref_list, the_type, event_ref_list, media_list,
|
||||
attribute_list, lds_seal_list, source_list, note_list,
|
||||
change, marker, private) = family
|
||||
new_child_ref_list = new_child_ref_list_14(child_ref_list)
|
||||
new_media_list = new_media_list_14(media_list)
|
||||
new_source_list = new_source_list_14(source_list)
|
||||
new_attribute_list = new_attribute_list_14(attribute_list)
|
||||
new_seal_list = []
|
||||
for ldsord in lds_seal_list:
|
||||
(lsource_list, lnote_list, date, type, place,
|
||||
famc, temple, status, lprivate) = ldsord
|
||||
new_date = convert_date_14(date)
|
||||
new_lsource_list = new_source_list_14(lsource_list)
|
||||
new_seal_list.append( (new_lsource_list, lnote_list, new_date, type,
|
||||
place, famc, temple, status, lprivate))
|
||||
|
||||
new_family = (junk_handle, gramps_id, father_handle, mother_handle,
|
||||
new_child_ref_list, the_type, event_ref_list, new_media_list,
|
||||
new_attribute_list, new_seal_list, new_source_list, note_list,
|
||||
change, marker, private)
|
||||
|
||||
with BSDDBTxn(self.env, self.family_map) as txn:
|
||||
txn.put(str(handle), new_family)
|
||||
self.update()
|
||||
|
||||
# ---------------------------------
|
||||
# Modify Repository
|
||||
# ---------------------------------
|
||||
# update dates with newyear
|
||||
for handle in self.repository_map.keys():
|
||||
repository = self.repository_map[handle]
|
||||
# address
|
||||
(junk_handle, gramps_id, the_type, name, note_list,
|
||||
address_list, urls, change, marker, private) = repository
|
||||
|
||||
new_address_list = []
|
||||
for address in address_list:
|
||||
(privacy, asource_list, anote_list, date, location) = address
|
||||
new_date = convert_date_14(date)
|
||||
new_asource_list = new_source_list_14(asource_list)
|
||||
new_address_list.append((privacy, new_asource_list, anote_list,
|
||||
new_date, location))
|
||||
|
||||
new_repository = (junk_handle, gramps_id, the_type, name, note_list,
|
||||
new_address_list, urls, change, marker, private)
|
||||
|
||||
with BSDDBTxn(self.env, self.repository_map) as txn:
|
||||
txn.put(str(handle), new_repository)
|
||||
self.update()
|
||||
|
||||
# ---------------------------------
|
||||
# Modify Media
|
||||
# ---------------------------------
|
||||
for media_handle in self.media_map.keys():
|
||||
media = self.media_map[media_handle]
|
||||
(handle, gramps_id, path, mime, desc,
|
||||
attribute_list, source_list, note_list, change,
|
||||
date, marker, private) = media
|
||||
new_source_list = new_source_list_14(source_list)
|
||||
new_date = convert_date_14(date)
|
||||
new_media = (handle, gramps_id, path, mime, desc,
|
||||
attribute_list, new_source_list, note_list, change,
|
||||
new_date, marker, private)
|
||||
|
||||
with BSDDBTxn(self.env, self.media_map) as txn:
|
||||
txn.put(str(handle), new_media)
|
||||
self.update()
|
||||
|
||||
# ---------------------------------
|
||||
# Modify Place
|
||||
# ---------------------------------
|
||||
for place_handle in self.place_map.keys():
|
||||
place = self.place_map[place_handle]
|
||||
(handle, gramps_id, title, long, lat,
|
||||
main_loc, alt_loc, urls, media_list, source_list, note_list,
|
||||
change, marker, private) = place
|
||||
new_media_list = new_media_list_14(media_list)
|
||||
new_source_list = new_source_list_14(source_list)
|
||||
new_place = (handle, gramps_id, title, long, lat,
|
||||
main_loc, alt_loc, urls, new_media_list,
|
||||
new_source_list, note_list, change, marker, private)
|
||||
|
||||
with BSDDBTxn(self.env, self.place_map) as txn:
|
||||
txn.put(str(handle), new_place)
|
||||
self.update()
|
||||
|
||||
# ---------------------------------
|
||||
# Modify Source
|
||||
# ---------------------------------
|
||||
for source_handle in self.source_map.keys():
|
||||
source = self.source_map[source_handle]
|
||||
(handle, gramps_id, title, author,
|
||||
pubinfo, note_list, media_list,
|
||||
abbrev, change, datamap, reporef_list,
|
||||
marker, private) = source
|
||||
new_media_list = new_media_list_14(media_list)
|
||||
new_source = (handle, gramps_id, title, author,
|
||||
pubinfo, note_list, new_media_list,
|
||||
abbrev, change, datamap, reporef_list,
|
||||
marker, private)
|
||||
|
||||
with BSDDBTxn(self.env, self.source_map) as txn:
|
||||
txn.put(str(handle), new_source)
|
||||
self.update()
|
||||
|
||||
# Bump up database version. Separate transaction to save metadata.
|
||||
with BSDDBTxn(self.env, self.metadata) as txn:
|
||||
txn.put('version', 14)
|
||||
|
||||
def new_source_list_14(source_list):
|
||||
new_source_list = []
|
||||
for source in source_list:
|
||||
(date, private, note_list, confidence, ref, page) = source
|
||||
new_date = convert_date_14(date)
|
||||
new_source_list.append((new_date, private, note_list, confidence, ref, page))
|
||||
return new_source_list
|
||||
|
||||
def new_attribute_list_14(attribute_list):
|
||||
new_attribute_list = []
|
||||
for attribute in attribute_list:
|
||||
(private, asource_list, note_list, the_type, value) = attribute
|
||||
new_asource_list = new_source_list_14(asource_list)
|
||||
new_attribute_list.append((private, new_asource_list, note_list, the_type, value))
|
||||
return new_attribute_list
|
||||
|
||||
def new_media_list_14(media_list):
|
||||
# ---------------------------------
|
||||
# Event Media list
|
||||
# ---------------------------------
|
||||
new_media_list = []
|
||||
for media in media_list:
|
||||
(private, source_list, note_list,attribute_list,ref,role) = media
|
||||
new_source_list = new_source_list_14(source_list)
|
||||
new_attribute_list = new_attribute_list_14(attribute_list)
|
||||
new_media_list.append((private, new_source_list, note_list, new_attribute_list, ref, role))
|
||||
return new_media_list
|
||||
|
||||
def new_person_ref_list_14(person_ref_list):
|
||||
new_person_ref_list = []
|
||||
for person_ref in person_ref_list:
|
||||
(private, source_list, note_list, ref, rel) = person_ref
|
||||
new_source_list = new_source_list_14(source_list)
|
||||
new_person_ref_list.append((private, new_source_list, note_list, ref, rel))
|
||||
return new_person_ref_list
|
||||
|
||||
def new_child_ref_list_14(child_ref_list):
|
||||
new_child_ref_list = []
|
||||
for data in child_ref_list:
|
||||
(private, source_list, note_list, ref, frel, mrel) = data
|
||||
new_source_list = new_source_list_14(source_list)
|
||||
new_child_ref_list.append((private, new_source_list, note_list, ref, frel, mrel))
|
||||
return new_child_ref_list
|
||||
|
||||
def convert_date_14(date):
|
||||
if date:
|
||||
(calendar, modifier, quality, dateval, text, sortval) = date
|
||||
return (calendar, modifier, quality, dateval, text, sortval, 0)
|
||||
else:
|
||||
return None
|
||||
|
||||
def convert_name_14(name):
|
||||
(privacy, source_list, note_list, date,
|
||||
first_name, surname, suffix, title,
|
||||
name_type, prefix, patronymic,
|
||||
group_as, sort_as, display_as, call) = name
|
||||
new_date = convert_date_14(date)
|
||||
new_source_list = new_source_list_14(source_list)
|
||||
return (privacy, new_source_list, note_list, new_date,
|
||||
first_name, surname, suffix, title,
|
||||
name_type, prefix, patronymic,
|
||||
group_as, sort_as, display_as, call)
|
1857
src/gen/db/write.py
Normal file
1857
src/gen/db/write.py
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user