Changeset 3442

Show
Ignore:
Timestamp:
08/10/07 19:59:01 (1 year ago)
Author:
pobrien
Message:

A mostly working implementation of database-aware transactions and field database resolving when using entity references from other databases.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/Schevo/schevo/field.py

    r3439 r3442  
    11031103        if instance is None: 
    11041104            return Field.convert(self, value, db) 
    1105         else: 
    1106             if value is UNASSIGNED: 
    1107                 return value 
    1108             if isinstance(value, basestring): 
    1109                 if value == '': 
     1105        if value is UNASSIGNED: 
     1106            return value 
     1107        if isinstance(value, basestring): 
     1108            if value == '': 
     1109                return UNASSIGNED 
     1110            else: 
     1111                try: 
     1112                    name, oid = value.split('-') 
     1113                    oid = int(oid) 
     1114                    return db.extent(name)[oid] 
     1115                except (AttributeError, KeyError, IndexError, ValueError): 
    11101116                    return UNASSIGNED 
    1111                 else: 
    1112                     try: 
    1113                         name, oid = value.split('-') 
    1114                         oid = int(oid) 
    1115                         return db.extent(name)[oid] 
    1116                     except (AttributeError, KeyError, IndexError, ValueError): 
    1117                         return UNASSIGNED 
    1118             else: 
    1119                 return value 
     1117        if isinstance(self._instance, base.Transaction): 
     1118            msg = ('"%s" field of "%s" cannot be resolved to ' 
     1119                   'the current database') 
     1120            error_msg = msg % (self._name, value) 
     1121            return self._db_resolve(self._instance._db, value, error_msg) 
     1122        return value 
     1123 
     1124    def _db_resolve(self, db, value, error_msg): 
     1125        """Resolve entity references originating in a different 
     1126        database.""" 
     1127        if isinstance(value, base.Entity) and value._db is not db: 
     1128            entity = value 
     1129            if entity._default_key is not None: 
     1130                extent_name = entity.sys.extent.name 
     1131                if hasattr(db, extent_name): 
     1132                    extent = getattr(db, extent_name) 
     1133                    criteria = dict( 
     1134                        [(name, self._db_resolve(db, getattr(entity, name), 
     1135                                                 error_msg)) 
     1136                         for name in entity._default_key]) 
     1137                    value = extent.findone(**criteria) 
     1138                    if value is not None: 
     1139                        return value 
     1140            raise schevo.error.DatabaseMismatch(error_msg) 
     1141        else: 
     1142            return value 
    11201143 
    11211144    def _dump(self): 
     
    12471270 
    12481271    def convert(self, value, db=None): 
    1249         if isinstance(value, list): 
     1272        if isinstance(value, (list, tuple)): 
    12501273            new_values = [] 
    12511274            for item in value: 
  • trunk/Schevo/schevo/schema.py

    r3404 r3442  
    169169        for FieldClass in EntityClass._field_spec.itervalues(): 
    170170            FieldClass.readonly = True 
     171    # Decorate all Transaction classes with the current database. 
     172    for transaction_name in schema_def.T: 
     173        TransactionClass = schema_def.T[transaction_name] 
     174        TransactionClass._db = db 
     175    # Decorate all Entity transaction classes with the current database. 
     176    for entity_name in schema_def.E: 
     177        EntityClass = schema_def.E[entity_name] 
     178        for v in EntityClass.__dict__.itervalues(): 
     179            if (inspect.isclass(v) 
     180                and issubclass(v, schevo.transaction.Transaction)): 
     181                v._db = db 
     182    # Decorate all View transaction classes with the current database. 
     183    for view_name in schema_def.V: 
     184        ViewClass = schema_def.V[view_name] 
     185        for v in ViewClass.__dict__.itervalues(): 
     186            if (inspect.isclass(v) 
     187                and issubclass(v, schevo.transaction.Transaction)): 
     188                v._db = db 
    171189    # Add relationship metadata to each Entity class. 
    172190    for parent, spec in schema_def.relationships.iteritems(): 
  • trunk/Schevo/schevo/test/test_transaction.py

    r3382 r3442  
    585585        gender = db.Gender.findone(code='M') 
    586586        db.execute(gender.t.delete()) 
    587         tx = db.Person.t.create(john, name='Other Guy') 
    588         assert raises(error.DatabaseMismatch, db.execute, tx
     587        assert raises(error.DatabaseMismatch, 
     588                      db.Person.t.create, john, name='Other Guy'
    589589 
    590590    def test_create_with_fget(self): 
  • trunk/Schevo/schevo/transaction.py

    r3437 r3442  
    1212                             UNASSIGN, UNASSIGNED) 
    1313from schevo.error import ( 
    14     DatabaseMismatch, 
    1514    DeleteRestricted, 
    1615    KeyCollision, 
     
    5251    __metaclass__ = TransactionMeta 
    5352 
     53    _db = None 
     54 
    5455    _field_spec = FieldSpecMap() 
    5556 
     
    184185            results.append(db.execute(tx)) 
    185186        return results 
    186  
    187  
    188 def _resolve(db, value, error_msg): 
    189     """Support function for Create transactions to resolve entity 
    190     references originating in a different database.""" 
    191     if isinstance(value, base.Entity) and value._db is not db: 
    192         entity = value 
    193         if entity._default_key is not None: 
    194             extent_name = entity.sys.extent.name 
    195             if hasattr(db, extent_name): 
    196                 extent = getattr(db, extent_name) 
    197                 criteria = dict( 
    198                     [(name, _resolve(db, getattr(entity, name), error_msg)) 
    199                      for name in entity._default_key]) 
    200                 value = extent.findone(**criteria) 
    201                 if value is not None: 
    202                     return value 
    203         raise DatabaseMismatch(error_msg) 
    204     else: 
    205         return value 
    206187 
    207188 
     
    254235    def _execute(self, db): 
    255236        field_map = self._field_map 
    256         # If any fields contain values that are entities not in `db`, 
    257         # attempt to find each equivalent entity in `db` based on the 
    258         # information contained in the foreign entity. 
    259         msg = '"%s" field of "%s" cannot be resolved to the current database' 
    260         for field_name, field in field_map.iteritems(): 
    261             field_value = field._value 
    262             error_msg = msg % (field_name, field_value) 
    263             field._value = _resolve(db, field_value, error_msg) 
    264237        # Before execute callback. 
    265238        self._before_execute(db)