X-Git-Url: https://git.decadent.org.uk/gitweb/?a=blobdiff_plain;ds=sidebyside;f=daklib%2Fdbconn.py;h=df38b777831c019abfbd64dd394c3d564cd26d69;hb=8c491e536146ef00491001c68d076830ce963ea8;hp=1fca9839d73baf31787904a6f27cb0415ce51936;hpb=f698f038afdccb07487c104dac7c83d3120b6de3;p=dak.git diff --git a/daklib/dbconn.py b/daklib/dbconn.py index 1fca9839..df38b777 100755 --- a/daklib/dbconn.py +++ b/daklib/dbconn.py @@ -55,7 +55,7 @@ from inspect import getargspec import sqlalchemy from sqlalchemy import create_engine, Table, MetaData, Column, Integer, desc from sqlalchemy.orm import sessionmaker, mapper, relation, object_session, \ - backref, MapperExtension, EXT_CONTINUE + backref, MapperExtension, EXT_CONTINUE, object_mapper from sqlalchemy import types as sqltypes # Don't remove this, we re-export the exceptions to scripts which import us @@ -287,6 +287,42 @@ class ORMObject(object): ''' return session.query(cls).get(primary_key) + def session(self, replace = False): + ''' + Returns the current session that is associated with the object. May + return None is object is in detached state. + ''' + + return object_session(self) + + def clone(self, session = None): + ''' + Clones the current object in a new session and returns the new clone. A + fresh session is created if the optional session parameter is not + provided. + + RATIONALE: SQLAlchemy's session is not thread safe. This method allows + cloning of an existing object to allow several threads to work with + their own instances of an ORMObject. + + WARNING: Only persistent (committed) objects can be cloned. + ''' + + if session is None: + session = DBConn().session() + if self.session() is None: + raise RuntimeError('Method clone() failed for detached object:\n%s' % + self) + self.session().flush() + mapper = object_mapper(self) + primary_key = mapper.primary_key_from_instance(self) + object_class = self.__class__ + new_object = session.query(object_class).get(primary_key) + if new_object is None: + raise RuntimeError( \ + 'Method clone() failed for non-persistent object:\n%s' % self) + return new_object + __all__.append('ORMObject') ################################################################################ @@ -1161,7 +1197,7 @@ class PoolFile(ORMObject): def fullpath(self): return os.path.join(self.location.path, self.filename) - def is_valid(self, filesize = -1, md5sum = None):\ + def is_valid(self, filesize = -1, md5sum = None): return self.filesize == long(filesize) and self.md5sum == md5sum def properties(self): @@ -1575,8 +1611,6 @@ __all__.append('get_dbchange') ################################################################################ -# TODO: Why do we have a separate Location class? Can't it be fully integrated -# into class Component? class Location(ORMObject): def __init__(self, path = None, component = None): self.path = path @@ -1585,7 +1619,8 @@ class Location(ORMObject): self.archive_type = 'pool' def properties(self): - return ['path', 'archive_type', 'component', 'files_count'] + return ['path', 'location_id', 'archive_type', 'component', \ + 'files_count'] def not_null_constraints(self): return ['path', 'archive_type']