# -*- 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.
#-----------------------------------------------------------------------------
"""
ClassDescription API
Decrire + notez les champs suivants::
# Join semantic: for later use
INNER_JOIN = 0
FULL_OUTER_JOIN = 1
LEFT_OUTER_JOIN = 2
RIGHT_OUTER_JOIN = 3
# Relationships props
from EntityClassDescription import DELETE_NULLIFY, DELETE_DENY, DELETE_CASCADE
Flattened relationships
A flattened relationship is characterized by its definition
(e.g. "department.company" defined for the entity 'Employee').
The definition is a keypath in which every part (relationship) *must*
be a plain relationship (non flattened).
The following fields are constants for any flattened relationship:
- the set of join is empty
- (to be continued)
CVS information
$Id: Relationship.py 978 2006-02-26 17:50:15Z sbigaret $
"""
__version__='$Revision: 978 $'[11:-2]
try:
from Interface import Base
except:
class Base:
pass
class RelationshipErrorInterface(Exception):
"..."
pass
class RelationshipInterface(Base):
"""
Responsible for class descriptions
class Relationship(Persistent, XMLCapability):
Describes a relationship
Implementation notes:
- join semantic is not used for the moment being, and defaults to INNER_JOIN
Features added to the EOF standard API:
- cardinality of the relationship
[Tableau suivant verifier avec le Modeler]::
SimpleRel. FlattenedRel.
definition get y:None Y
set N Y
deleteRule get Y Y
set Y Y
displayLabel get Y Y
set Y Y
entity get Y Y
set Y Y
isClassProp. get Y Y
set Y Y
joins get Y y:()
set Y N
joinSemantic get Y N
set Y N
name get Y Y
set Y Y
mult.Lower get Y Y?
set Y Y?
mult.Upper get Y Y?
set Y Y?
propagatesPK get Y y:false
set Y N
ownsDestinat.get Y ?
set Y ?
funcs.:
componentRelationship y:() Y
destinationAttributes Y y?
destinationEntity Y Y
inverseRelationship Y Y
isCompound Y N? (see isSimple)
isFlattened Y Y
isMandatory Y Y? (see 'Y?' for multiplicities)
isSimple Y N? (see isCompound)
isToOne Y Y? (|see
isToMany Y Y? (| 'Y?' for multiplicities)
"""
# _TBD + public/private ?...
def __init__(self, aName=''):
"""
Initializes a relationship. A name **must** be provided.
Default value is a non-flattened, to-one relationship with no joins,
deleteRule: Nullify, joinSemantic: INNER_JOIN,
"""
# Check
def checkRelationshipValidity(self):
"""
Checks the relationship validity. This includes the following tests:
- cardinality > 0
- len(joins) > 0
- name
- source and destinationEntity are not None
- joins' sources are identical (idem for destinations)
Raises the relation is invalid.
"""
# Not implemented for the moment being
# multiplicty bounds cannot be wrong, thus they do not need to be checked
def addJoin(self, aJoin):
"""
Adds a join to the relationship
Raises ValueError if aJoin's source attribute does not belong to receiver's
entity, if either aJoin's source or destination attribute is already
registered in an other relationship's join, or if aJoin's destination
entity does not equal to 'self.destinationEntity()' (if this one is not
'None').
"""
def componentRelationships(self):
"""
Returns the sequence of (non flattened) relationships involved in the
flattened relationship, or 'None' if the receiver is not flattened
See also: definition
"""
def definition(self):
"""
Returns the definition (keypath) for the flattened relationship, or
'None' if the relationship is not flattened
See also: componentRelationships
"""
def deleteRule(self):
"""
Returns the delete rule applicable to this relationship. Possible values
are module's integer constants DELETE_CASCADE, DELETE_NULLIFY and
DELETE_DENY
"""
def destinationAttributes(self):
"""
Simply returns the list of joins' destination attributes
"""
def destinationEntity(self):
"""
Returns the destination entity, or 'None' if the relationship has no joins
yet
"""
def destinationEntityName(self):
"Return the destination entity, or None"
def displayLabel(self):
"Returns the display label for the relationship"
def inverseRelationship(self):
"""
Returns the inverse relationship in the destination entity,
or None if it does not exist.
The notion of inverse relationship is very precise: an inverse relationship
has the same number of joins, and there is a bijective relation defined
by 'Join.isReciprocicalTo' between both sets of joins.
"""
def isClassProperty(self):
"Indicates whether the attribute belongs to the class properties/fields"
def isCompound(self):
"""
Simply indicates whether the relationship has one or more joins
Returns true iff relationship has one join, false otherwise.
Raises if relationship has no joins.
"""
def isFlattened(self):
"""
Returns true (integer '1') if the receiver is flattened, false ('0')
otherwise
See also: definition, componentRelationships
"""
def isMandatory(self):
"""
Indicates whether the relationship requires at least a destination
entity to be bound. This is a computed attribute, equivalent to:
'self.multiplicityLowerBound()>0'.
"""
def isSimple(self):
"""
Indicates whether the relation holds one join.
Note that this method return also 'true' when the relationship
is invalid (i.e. it holds no joins)
"""
def isToMany(self):
"""
Indicates whether the relationship has a maximum cardinality > 1.
This is the contrary of method isToOne.
"""
def isToOne(self):
"""
Indicates whether the relationship has a maximim cardinality = 1.
This is the contrary of method isToMany.
"""
def joins(self):
"Return the whole set of joins registered in this relationship"
def multiplicityLowerBound(self):
"Returns the lower bound of the relationship's multiplicity"
def multiplicityUpperBound(self):
"""
Returns the upper bound of the relationship's multiplicity.
Returned value is a strictly positive integer, or -1 if there is no upper
bound.
"""
def name(self):
"Returns the relationship's name"
def ownsDestination(self): # strict equival. toUML aggregate ?
"""
Returns true if the relationship owns the destinationEntity.
See also: setOwnsDestination()
When a relationship owns its destination, the related entity object
cannot exist without the source object. Thus, as a side-effect, this
sets the delete rule to 'cascade'.
"""
def propagatesPrimaryKey(self):
"""
Returns true if the relationship propagates PK value, false otherwise
_TBD should be explained
"""
def removeJoin(self, aJoin):
"""
Removes the supplied join from the relation's join.
Parameter 'aJoin' must be a 'Join' instance.
Raises 'ValueError' if 'aJoin' cannot be found.
"""
def setDefinition(self):
"""
Sets the definition for the receiver, making it a flattened relationship
"""
def setDeleteRule(self, rule):
"""
Sets the delete rule. Accepted values are module's constants:
DELETE_NULLIFY, DELETE_CASCADE and DELETE_DENY
"""
def setDisplayLabel(self, aLabel):
"Sets the display label (string) for the relationship"
def setIsClassProperty(self, aBool):
"Tells the receiver whether it belongs to the class properties/fields"
def setMultiplicityLowerBound(self, lowerBound):
"""
Sets the lower bound of the relationship's multiplicity
Parameter lowerBound must be an positive integer.
"""
def setMultiplicityUpperBound(self, upperBound):
"""
Sets the upper bound of the relationship's multiplicity.
Parameter 'upperBound' must be a strictly positive integer, or -1 for a
non constrained to-many relationship.
"""
def setMultiplicity(self, lowerBound, upperBound):
"""
Sets the lower and upper bounds for the relationship's multiplicity.
See also: setMultiplicityLowerBound, setMultiplicityUpperBound.
"""
def setIsMandatory(self, aBool):
"""
Tells the relationship whether it is mandatory. This method has the
following side-effects: if set to 'true' and the multiplicity lower bound
was '0' (zero) it is set to '1' (one) ; if set to 'false', the multiplicity
lower bound is set to 'zero'.
"""
def setName(self, aName):
"Sets the relationship's name"
def setEntity(self, anEntity):
"Sets the source entity"
def setOwnsDestination(self, boolean):
"""
Tells the receiver whether it owns its destination objects.
When a relationship owns its destination, the related object(s)
cannot exist without the source object. Thus, as a side-effect, this
sets the delete rule to 'cascade' when it is set to true.
"""
def setPropagatesPrimaryKey(self, aBool):
"""
Tells the relationship whether it propagates PK value
_TBD should be explained
"""
def sourceAttributes(self):
"""
Simply returns the list of joins' source attributes
"""
def entity(self):
"Return the relationship's source entity"
sourceEntity = entity # Compatibility w/ old API, _TBD should be removed
def validateRelationship(self):
"""Validates the relationship against general model consistency:
- relationship should have a source and a destination entity
-
Unimplemented
"""
def validateValue(self, value, object=None):
"""
Checks whether the supplied value is valid, i.e. the following tests are
made:
1. value cannot be *void* ('not value' equals to 1) if the relationship
is mandatory
2. Value has a method 'entityName' (i.e. it is 'model-powered'), or if it
is a tuple each item has a persistentID
3. 'value' matches the multiplicity bounds
4. Value's entity is the relationship's destination entity (same for
'value' 's items if 'value' is a tuple)
Parameter 'value' is required, and 'object' is optional --it is
only used to make the error message clearer in case of failure.
Silently returns if it suceeds.
In case of failure, it raises 'Modeling.Validation.Exception' ;
in this case, exception's *value* ('sys.exc_info[1]') consists in a set
of lines, describing line per line the different tests which failed.
"""
# special
def __eq__(self, aRelationship):
"Tests whether both relationship are equal"
# XML
def initWithXMLDOMNode(self, aNode, encoding='iso-8859-1'):
"""
Initializes a relationship with the supplied xml.dom.node.
Also take care of initializing joins
"""
def getXMLDOM(self, doc=None, parentNode=None, encoding='iso-8859-1'):
"""
Returns the (DOM) DocumentObject for the receiver.
Parameters 'doc' and 'parentDoc' should be both omitted or supplied.
If they are omitted, a new DocumentObject is created.
If they are supplied, elements are added to the parentNode.
Returns: the (possibly new) DocumentObject.
"""
def xmlAttributesDict(self):
"."
|