9465: DB-API: duplicate note ID
This commit is contained in:
@ -81,6 +81,27 @@ def touch(fname, mode=0o666, dir_fd=None, **kwargs):
|
|||||||
os.utime(f.fileno() if os.utime in os.supports_fd else fname,
|
os.utime(f.fileno() if os.utime in os.supports_fd else fname,
|
||||||
dir_fd=None if os.supports_fd else dir_fd, **kwargs)
|
dir_fd=None if os.supports_fd else dir_fd, **kwargs)
|
||||||
|
|
||||||
|
class IDMapTransaction:
|
||||||
|
"""
|
||||||
|
Provide compatibility with BSDDB. A class to provide a lookup
|
||||||
|
to see if a gramps_id has been inserted.
|
||||||
|
"""
|
||||||
|
def __init__(self, table_name, database):
|
||||||
|
"""
|
||||||
|
Takes a table_name and database.
|
||||||
|
Provides .get(b"gramps_id")
|
||||||
|
"""
|
||||||
|
self.table_name = table_name
|
||||||
|
self.database = database
|
||||||
|
|
||||||
|
def get(self, bkey, default=None, txn=None, **kwargs):
|
||||||
|
"""
|
||||||
|
Returns True if bkey (binary gramps_id) is in database.
|
||||||
|
"""
|
||||||
|
skey = bkey.decode("utf-8")
|
||||||
|
return self.database.get_table_func(self.table_name,
|
||||||
|
"has_gramps_id_func")(skey)
|
||||||
|
|
||||||
class DbGenericUndo(DbUndo):
|
class DbGenericUndo(DbUndo):
|
||||||
def __init__(self, grampsdb, path):
|
def __init__(self, grampsdb, path):
|
||||||
super(DbGenericUndo, self).__init__(grampsdb)
|
super(DbGenericUndo, self).__init__(grampsdb)
|
||||||
@ -259,7 +280,8 @@ class Map:
|
|||||||
self.keys_func = keys_func
|
self.keys_func = keys_func
|
||||||
self.contains_func = contains_func
|
self.contains_func = contains_func
|
||||||
self.raw_func = raw_func
|
self.raw_func = raw_func
|
||||||
self.txn = DbGenericTxn("Dummy transaction", db=self.table.db, batch=True)
|
self.txn = DbGenericTxn("Dummy transaction",
|
||||||
|
db=self.table.db, batch=True)
|
||||||
|
|
||||||
def keys(self):
|
def keys(self):
|
||||||
return self.table.funcs[self.keys_func]()
|
return self.table.funcs[self.keys_func]()
|
||||||
@ -393,25 +415,17 @@ class Bookmarks:
|
|||||||
def close(self):
|
def close(self):
|
||||||
del self.handles
|
del self.handles
|
||||||
|
|
||||||
|
|
||||||
class DbGenericTxn(DbTxn):
|
class DbGenericTxn(DbTxn):
|
||||||
|
"""
|
||||||
|
Generic Transaction.
|
||||||
|
"""
|
||||||
def __init__(self, message, db, batch=False):
|
def __init__(self, message, db, batch=False):
|
||||||
|
"""
|
||||||
|
Placeholder. This can probably be removed once it is
|
||||||
|
known that it is not needed.
|
||||||
|
"""
|
||||||
DbTxn.__init__(self, message, db, batch)
|
DbTxn.__init__(self, message, db, batch)
|
||||||
|
|
||||||
def get(self, key, default=None, txn=None, **kwargs):
|
|
||||||
"""
|
|
||||||
Returns the data object associated with key
|
|
||||||
"""
|
|
||||||
if txn and key in txn:
|
|
||||||
return txn[key]
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def put(self, handle, new_data, txn):
|
|
||||||
"""
|
|
||||||
"""
|
|
||||||
txn[handle] = new_data
|
|
||||||
|
|
||||||
class DbGeneric(DbWriteBase, DbReadBase, UpdateCallback, Callback):
|
class DbGeneric(DbWriteBase, DbReadBase, UpdateCallback, Callback):
|
||||||
"""
|
"""
|
||||||
A Gramps Database Backend. This replicates the grampsdb functions.
|
A Gramps Database Backend. This replicates the grampsdb functions.
|
||||||
@ -653,15 +667,15 @@ class DbGeneric(DbWriteBase, DbReadBase, UpdateCallback, Callback):
|
|||||||
self.set_note_id_prefix('N%04d')
|
self.set_note_id_prefix('N%04d')
|
||||||
# ----------------------------------
|
# ----------------------------------
|
||||||
self.undodb = None
|
self.undodb = None
|
||||||
self.id_trans = DbGenericTxn("ID Transaction", self)
|
self.id_trans = IDMapTransaction("Person", self)
|
||||||
self.fid_trans = DbGenericTxn("FID Transaction", self)
|
self.fid_trans = IDMapTransaction("Family", self)
|
||||||
self.pid_trans = DbGenericTxn("PID Transaction", self)
|
self.pid_trans = IDMapTransaction("Place", self)
|
||||||
self.cid_trans = DbGenericTxn("CID Transaction", self)
|
self.cid_trans = IDMapTransaction("Citation", self)
|
||||||
self.sid_trans = DbGenericTxn("SID Transaction", self)
|
self.sid_trans = IDMapTransaction("Source", self)
|
||||||
self.oid_trans = DbGenericTxn("OID Transaction", self)
|
self.oid_trans = IDMapTransaction("Media", self)
|
||||||
self.rid_trans = DbGenericTxn("RID Transaction", self)
|
self.rid_trans = IDMapTransaction("Repository", self)
|
||||||
self.nid_trans = DbGenericTxn("NID Transaction", self)
|
self.nid_trans = IDMapTransaction("Note", self)
|
||||||
self.eid_trans = DbGenericTxn("EID Transaction", self)
|
self.eid_trans = IDMapTransaction("Event", self)
|
||||||
self.cmap_index = 0
|
self.cmap_index = 0
|
||||||
self.smap_index = 0
|
self.smap_index = 0
|
||||||
self.emap_index = 0
|
self.emap_index = 0
|
||||||
@ -2185,4 +2199,3 @@ class DbGeneric(DbWriteBase, DbReadBase, UpdateCallback, Callback):
|
|||||||
return ast.literal_eval(version)
|
return ast.literal_eval(version)
|
||||||
else:
|
else:
|
||||||
return (0, 0, 0)
|
return (0, 0, 0)
|
||||||
|
|
||||||
|
@ -179,70 +179,3 @@ class DbTxn(defaultdict):
|
|||||||
if self.first is None or self.last is None:
|
if self.first is None or self.last is None:
|
||||||
return 0
|
return 0
|
||||||
return self.last - self.first + 1
|
return self.last - self.first + 1
|
||||||
|
|
||||||
# Test functions
|
|
||||||
|
|
||||||
def testtxn():
|
|
||||||
"""
|
|
||||||
Test suite
|
|
||||||
"""
|
|
||||||
class FakeMap(dict):
|
|
||||||
"""Fake database map with just two methods"""
|
|
||||||
def put(self, key, data):
|
|
||||||
"""Set a property"""
|
|
||||||
super(FakeMap, self).__setitem__(key, data)
|
|
||||||
def delete(self, key):
|
|
||||||
"""Delete a proptery"""
|
|
||||||
super(FakeMap, self).__delitem__(key)
|
|
||||||
|
|
||||||
class FakeDb:
|
|
||||||
"""Fake gramps database"""
|
|
||||||
def __init__(self):
|
|
||||||
self.person_map = FakeMap()
|
|
||||||
self.family_map = FakeMap()
|
|
||||||
self.event_map = FakeMap()
|
|
||||||
self.reference_map = FakeMap()
|
|
||||||
self.readonly = False
|
|
||||||
self.env = None
|
|
||||||
self.undodb = FakeCommitDb()
|
|
||||||
def transaction_commit(self, transaction):
|
|
||||||
"""Commit the transaction to the undo database and cleanup."""
|
|
||||||
transaction.clear()
|
|
||||||
self.undodb.commit(transaction)
|
|
||||||
def emit(self, obj, value):
|
|
||||||
"""send signal"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
class FakeCommitDb(list):
|
|
||||||
""" Fake commit database"""
|
|
||||||
def commit(self, transaction):
|
|
||||||
"""commit transaction to undo db"""
|
|
||||||
pass
|
|
||||||
def undo(self):
|
|
||||||
"""undo last transaction"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
grampsdb = FakeDb()
|
|
||||||
commitdb = grampsdb.undodb
|
|
||||||
trans = DbTxn("Test Transaction", commitdb, grampsdb, batch=False)
|
|
||||||
grampsdb.person_map.put('1', "data1")
|
|
||||||
trans.add(0, TXNADD, '1', None, "data1")
|
|
||||||
grampsdb.person_map.put('2', "data2")
|
|
||||||
trans.add(0, TXNADD, '2', None, "data2")
|
|
||||||
grampsdb.person_map.put('2', "data3")
|
|
||||||
trans.add(0, TXNUPD, '2', None, "data3")
|
|
||||||
grampsdb.person_map.delete('1')
|
|
||||||
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)))
|
|
||||||
print(grampsdb.person_map)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
testtxn()
|
|
||||||
|
Reference in New Issue
Block a user