Author
JimFulton?
Status
IsProposal?
Problem
Changes in object implementations often require converting existing objects in a database. This can range from something as simple as renaming or moving a class to complex changes to object representation. When doing this conversion, accesses is needed to stored objects. Often these objects can be found by traversing an object tree, but sometimes this isn't possible or convenient. Often one wants to convert all objects of a given class, no matter where in the database the objects occur.
Proposal
I propose 2 new APIs?. A database API and a storage API:
class IConversionSupport(zope.interface.Interface):
"""Provide access to 'old' objects
This interface is provided to support the use case of
updating existing objects to reflect new data structures or
class locations.
This interface uses the concept of "old" objects. This is to
emphasize the fact that there are no guarentees that data are
current. The emphasis is on converting old data. There is
an assumption that any new data written does not need to be
converted.
This interface is intended for infrequent use. It is likely
that the operations provided are inefficient. If any attempt
is made toward optimization, it will aimed at precenting
excessive load on a ZEO server.
"""
def old_global_names():
"""Return an iterable of global names used in the database.
Globals are objects, most notably classes, that are
referenced by the database but that are stored in Python
modules. Their names consist of module-name, class-name pairs
(2-item iterables).
Data are obtained without loading objects into memory.
Therefore, names returned could include globals not
importable by the calling application.
Globals that were newly referenced after the start of the
operation may be excluded.
"""
def rename(changes, retry=0):
"""Rename one or more global objects
An iterable of old-new global pairs is provided as an
argument. For example, if class C is moved from M1, to
M2, the database can be updated with::
db.rename([[(M1, C), (M2, C)]])
or with::
db.rename({(M1, C): (M2, C)}.iteritems()]
Updates are made without loading objects into memory.
This allows updates even when the named globals cannot be
imported.
Only records containing references to the old globals are
updated. Each record is updated in a separate transaction.
This method can raise write-conflict errors. A retry
argument can be provided to cause the method to retry
updates the given number of times.
"""
def old_oids():
"""Return an interable of "old" database object ids
Ids for objects added after the start of the operation
may be excluded. Ids may be included for objects that
have been deleted.
The resulting object ids can be passed to the connection get
methods to try to get the objects. Because an object may
have been removed, code calling get should catch key errors:
conn = db.open()
for oid in db.old_oids():
try:
ob = conn.get(oid)
except KeyError:
continue
if isonstance(ob, class_I_care_about):
transaction.begin()
... convert ob
transaction.commit()
"""
def rename(changes):
class IOldRecordIterableStorage(zope.interface.Interface):
"""Provide low-level iteration over current object records
Records are required to be current at approximately
"""
def record_iternext(next=None):
"""Get the mext database record.
Ordering is storage dependent. If the argument is
ommitted or passed as None, then the first record is returned.
Each record is a tuple consisting of:
oid -- The record object id
serial -- The revision serial (transaction id) for the record
data -- The raw data for the record
next -- The next value to pass to record_iternext or
None, if this is the last record,
The next argument must be None or a string. This means
also that the return value for next must be None or a string.
"""
`IConversionSupport?' will be provided by databases. `IRecordIterableStorage?` will be provided by storages that play, including `FileStorage` and `ClientStorage?`.
Implementation Status
`IRecordIterableStorage?` has been implemented for `FileStorage`. It needs to be implemented for `ClientStorage?`. `IConversionSupport?' needs to be implemented for databases.