# -*- coding: iso-8859-1 -*-
#-----------------------------------------------------------------------------
# Modeling Framework: an Object-Relational Bridge for python
#
# Copyright (c) 2001-2004 Sbastien Bigaret <sbigaret@users.sourceforge.net>
# All rights reserved.
#
# This file is part of the Modeling Framework.
#
# This code is distributed under a "3-clause BSD"-style license;
# see the LICENSE file for details.
#-----------------------------------------------------------------------------
"""
Allows the generic manipulation of objects in relation by inspecting the
underlying model and taking appropriate actions.
This modules consists of two parts:
- module functions implementing the default behaviour for the API
- a mix-in class using this default implementation
See interfaces.RelationshipManipulating for a full description of the
default implementation.
CVS information
$Id: RelationshipManipulation.py 932 2004-07-20 06:21:57Z sbigaret $
"""
__version__='$Revision: 932 $'[11:-2]
from logging import warn
# Framework
from Modeling.utils import capitalizeFirstLetter
# interfaces
from interfaces.RelationshipManipulation import RelationshipManipulationInterface
def addObjectToBothSidesOfRelationshipWithKey(self, anObject, aKey):
"See interfaces.RelationshipManipulating"
toOnes = self.classDescription().toOneRelationshipKeys()
toManys = self.classDescription().toManyRelationshipKeys()
if aKey not in toOnes+toManys:
raise TypeError, "Key %s is not a relationship's key"%aKey
## First step: update this side
##
if aKey in toManys:
_addObjectToPropertyWithKey(self, anObject, aKey, toOnes, toManys)
else:
# toOne relationship: is it already set?
_selfRelObj=self.valueForKey(aKey)
if _selfRelObj: # Yes: now remove it
_removeObjectFromBothSidesOfRelationshipWithKey(self, _selfRelObj, aKey,
toOnes, toManys)
_addObjectToPropertyWithKey(self, anObject, aKey, toOnes, toManys)
## Second step: update the other side
##
_backRelKey=self.inverseForRelationshipKey(aKey)
if _backRelKey is None: return
otoOnes = anObject.classDescription().toOneRelationshipKeys()
otoManys = anObject.classDescription().toManyRelationshipKeys()
destClassDesc=self.classDescription().\
classDescriptionForDestinationKey(aKey)
if _backRelKey in destClassDesc.toManyRelationshipKeys():
_addObjectToPropertyWithKey(anObject, self, _backRelKey, otoOnes, otoManys)
else:
# toOne relationship: is it already set?
_backRelObj=anObject.valueForKey(_backRelKey)
#if _backRelObj and _backRelObj.persistentID()!=self.persistentID():
if _backRelObj and _backRelObj!=self:
# Yes: now remove it
_removeObjectFromBothSidesOfRelationshipWithKey(anObject, _backRelObj, _backRelKey, otoOnes, otoManys)
_addObjectToPropertyWithKey(anObject, self, _backRelKey, otoOnes, otoManys)
def addObjectToPropertyWithKey(self, anObject, aKey):
"See interfaces.RelationshipManipulating"
toOnes = self.classDescription().toOneRelationshipKeys()
toManys = self.classDescription().toManyRelationshipKeys()
return _addObjectToPropertyWithKey(self, anObject, aKey, toOnes, toManys)
def removeObjectFromBothSidesOfRelationshipWithKey(self, anObject, aKey):
"See interfaces.RelationshipManipulating"
toOnes = self.classDescription().toOneRelationshipKeys()
toManys = self.classDescription().toManyRelationshipKeys()
return _removeObjectFromBothSidesOfRelationshipWithKey(self, anObject, aKey,
toOnes, toManys)
def removeObjectFromPropertyWithKey(self, anObject, aKey):
"See interfaces.RelationshipManipulating"
toOnes = self.classDescription().toOneRelationshipKeys()
toManys = self.classDescription().toManyRelationshipKeys()
return _removeObjectFromPropertyWithKey(self,anObject,aKey,toOnes,toManys)
def _addObjectToPropertyWithKey(self, anObject, aKey, toOnes, toManys):
"""
Private method used by the methods in this module to avoid the
re-computation of to-one and to-many relationships when it is not necessary.
Parameters are the same as for addObjectToPropertyWithKey, with the
additional parameters:
toOnes -- should equal to
self.classDescription().toOneRelationshipKeys()
toManys -- should equal to
self.classDescription().toManyRelationshipKeys()
"""
if aKey not in toOnes+toManys:
raise ValueError, "Key %s is not a relationship's key"%aKey
if aKey in toOnes:
# toOne: Simply uses KVC
self.takeValueForKey(anObject, aKey)
else:
# toMany: search addToKey
Key=capitalizeFirstLetter(aKey)
setter=getattr(self, 'addTo'+Key, None) # addToKey()
if callable(setter):
apply(setter, (anObject,))
return
# addToKey not found: apply changes on the (sequence) variable directly
values=list(self.valueForKey(aKey))
if anObject not in values:
values.append(anObject)
self.takeValueForKey(tuple(values), aKey)
def _removeObjectFromBothSidesOfRelationshipWithKey(self, anObject, aKey,
toOnes, toManys):
"""
Private method used by the methods in this module to avoid the
re-computation of to-one and to-many relationships when it is not necessary.
Parameters are the same as for
removeObjectFromBothSidesOfRelationshipWithKey, with the additional
parameters:
toOnes -- should equal to self.classDescription().toOneRelationshipKeys()
toManys -- should equal to
self.classDescription().toManyRelationshipKeys()
"""
if anObject is None:
warn('removeObjectFromBothSidesOfRelationshipWithKey', \
'called w/ anObject==None')
return
if aKey not in toOnes+toManys:
raise ValueError, "Key %s is not a relationship"%aKey
## First step: update this side
##
if aKey in toManys:
_removeObjectFromPropertyWithKey(self,anObject, aKey, toOnes, toManys)
else:
# toOne: check this is the one!
if self.valueForKey(aKey) != anObject:
raise ValueError, 'anObject %s is not set for key %s'%(repr(anObject),
aKey)
_addObjectToPropertyWithKey(self,None, aKey, toOnes,toManys)
## Second step: update the other side
_backRelKey=self.inverseForRelationshipKey(aKey)
if _backRelKey is None: return
destClassDesc=self.classDescription().\
classDescriptionForDestinationKey(aKey)
if _backRelKey in destClassDesc.toManyRelationshipKeys():
try: # the other side may be unset
anObject.removeObjectFromPropertyWithKey(self, _backRelKey)
except ValueError:
pass
else:
# toOne: do we need to check this is the one??
#assert(anObject.objectForKey(_backRelKey).persistentID()==self.persistentID())
anObject.addObjectToPropertyWithKey(None, _backRelKey)
def _removeObjectFromPropertyWithKey(self, anObject, aKey, toOnes, toManys):
"""
Private method used by the methods in this module to avoid the
re-computation of to-one and to-many relationships when it is not necessary.
Parameters are the same as for removeObjectFromPropertyWithKey(), with the
additional parameters:
toOnes -- should equal to self.classDescription().toOneRelationshipKeys()
toManys -- should equal to
self.classDescription().toManyRelationshipKeys()
"""
if aKey not in toOnes+toManys:
raise ValueError, "Key %s is not a relationship's key"%aKey
if aKey in toOnes:
# toOne: Simply uses KVC
if self.valueForKey(aKey)!=anObject:
raise ValueError, 'anObject %s is not set for key %s'%(repr(anObject),
aKey)
self.takeValueForKey(None, aKey)
else:
# toMany: search removeFromKey
Key=capitalizeFirstLetter(aKey)
setter=getattr(self, 'removeFrom'+Key, None) # removeFromKey()
if callable(setter):
apply(setter, (anObject,))
return
#removeFromKey not found: apply changes on the (sequence) variable directly
values=list(self.valueForKey(aKey))
if anObject not in values:
raise ValueError, 'anObject %s is not set for key %s'%(repr(anObject),
aKey)
values.remove(anObject)
self.takeValueForKey(tuple(values), aKey)
class RelationshipManipulation:
"""
This mix-in class provides the default implementation for
RelationshipManipulation interface to all subclasses.
"""
__implements__=(RelationshipManipulationInterface,)
def addObjectToBothSidesOfRelationshipWithKey(self, anObject, aKey):
"See interfaces.RelationshipManipulating"
addObjectToBothSidesOfRelationshipWithKey(self, anObject, aKey)
def addObjectToPropertyWithKey(self, anObject, aKey):
"See interfaces.RelationshipManipulating"
addObjectToPropertyWithKey(self, anObject, aKey)
def removeObjectFromBothSidesOfRelationshipWithKey(self, anObject, aKey):
"See interfaces.RelationshipManipulating"
removeObjectFromBothSidesOfRelationshipWithKey(self, anObject, aKey)
def removeObjectFromPropertyWithKey(self, anObject, aKey):
"See interfaces.RelationshipManipulating"
removeObjectFromPropertyWithKey(self, anObject, aKey)
|