~landscape/zope3/newer-from-ztk

« back to all changes in this revision

Viewing changes to src/twisted/enterprise/reflector.py

  • Committer: Thomas Hervé
  • Date: 2009-07-08 13:52:04 UTC
  • Revision ID: thomas@canonical.com-20090708135204-df5eesrthifpylf8
Remove twisted copy

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# -*- test-case-name: twisted.test.test_reflector -*-
2
 
# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
3
 
# See LICENSE for details.
4
 
 
5
 
 
6
 
import weakref
7
 
 
8
 
from twisted.enterprise.util import DBError
9
 
 
10
 
class Reflector:
11
 
    """Base class for enterprise reflectors. This implements row caching.
12
 
    """
13
 
    populated = 0
14
 
 
15
 
    def __init__(self, rowClasses):
16
 
        """
17
 
        Initialize me against a database.
18
 
 
19
 
        @param rowClasses: a list of row class objects that describe the
20
 
            database schema.
21
 
        """
22
 
 
23
 
        self.rowCache = weakref.WeakValueDictionary() # does not hold references to cached rows.
24
 
        self.rowClasses = rowClasses
25
 
        self.schema = {}
26
 
        self._populate()
27
 
 
28
 
    def __getstate__(self):
29
 
        d = self.__dict__.copy()
30
 
        del d['rowCache']
31
 
        return d
32
 
 
33
 
    def __setstate__(self, state):
34
 
        self.__dict__ = state
35
 
        self.rowCache = weakref.WeakValueDictionary()
36
 
        self._populate()
37
 
 
38
 
    def _populate(self):
39
 
        """Implement me to populate schema information for the reflector.
40
 
        """
41
 
        raise DBError("not implemented")
42
 
 
43
 
    def populateSchemaFor(self, tableInfo):
44
 
        """This is called once for each registered rowClass to add it
45
 
        and its foreign key relationships for that rowClass to the
46
 
        schema."""
47
 
 
48
 
        self.schema[ tableInfo.rowTableName ] = tableInfo
49
 
 
50
 
        # add the foreign key to the foreign table.
51
 
        for foreignTableName, childColumns, parentColumns, containerMethod, autoLoad in tableInfo.rowForeignKeys:
52
 
            self.schema[foreignTableName].addForeignKey(childColumns,
53
 
                                                        parentColumns, tableInfo.rowClass,
54
 
                                                        containerMethod, autoLoad)
55
 
 
56
 
    def getTableInfo(self, rowObject):
57
 
        """Get a TableInfo record about a particular instance.
58
 
 
59
 
        This record contains various information about the instance's
60
 
        class as registered with this reflector.
61
 
 
62
 
        @param rowObject: a L{RowObject} instance of a class previously
63
 
            registered with me.
64
 
        @raises twisted.enterprise.row.DBError: raised if this class was not
65
 
            previously registered.
66
 
        """
67
 
        try:
68
 
            return self.schema[rowObject.rowTableName]
69
 
        except KeyError:
70
 
            raise DBError("class %s was not registered with %s" % (
71
 
                rowObject.__class__, self))
72
 
 
73
 
    def buildWhereClause(self, relationship, row):
74
 
        """util method used by reflectors. builds a where clause to link a row to another table.
75
 
        """
76
 
        whereClause = []
77
 
        for i in range(0,len(relationship.childColumns)):
78
 
            value = getattr(row, relationship.parentColumns[i][0])
79
 
            whereClause.append( [relationship.childColumns[i][0], EQUAL, value] )
80
 
        return whereClause
81
 
 
82
 
    def addToParent(self, parentRow, rows, tableName):
83
 
        """util method used by reflectors. adds these rows to the parent row object.
84
 
        If a rowClass does not have a containerMethod, then a list attribute "childRows"
85
 
        will be used.
86
 
        """
87
 
        parentInfo = self.getTableInfo(parentRow)
88
 
        relationship = parentInfo.getRelationshipFor(tableName)
89
 
        if not relationship:
90
 
            raise DBError("no relationship from %s to %s" % ( parentRow.rowTableName, tableName) )
91
 
 
92
 
        if not relationship.containerMethod:
93
 
            if hasattr(parentRow, "childRows"):
94
 
                for row in rows:
95
 
                    if row not in parentRow.childRows:
96
 
                        parentRow.childRows.append(row)
97
 
            else:
98
 
                parentRow.childRows = rows
99
 
            return
100
 
 
101
 
        if not hasattr(parentRow, relationship.containerMethod):
102
 
            raise DBError("parent row (%s) doesnt have container method <%s>!" % (parentRow, relationship.containerMethod))
103
 
 
104
 
        meth = getattr(parentRow, relationship.containerMethod)
105
 
        for row in rows:
106
 
            meth(row)
107
 
 
108
 
    ####### Row Cache ########
109
 
 
110
 
    def addToCache(self, rowObject):
111
 
        """NOTE: Should this be recursive?! requires better container knowledge..."""
112
 
        self.rowCache[ rowObject.getKeyTuple() ] = rowObject
113
 
 
114
 
    def findInCache(self, rowClass, kw):
115
 
        keys = []
116
 
        keys.append(rowClass.rowTableName)
117
 
        for keyName, keyType in rowClass.rowKeyColumns:
118
 
            keys.append( kw[keyName] )
119
 
        keyTuple = tuple(keys)
120
 
        return self.rowCache.get(keyTuple)
121
 
 
122
 
    def removeFromCache(self, rowObject):
123
 
        """NOTE: should this be recursive!??"""
124
 
        key = rowObject.getKeyTuple()
125
 
        if self.rowCache.has_key(key):
126
 
            del self.rowCache[key]
127
 
 
128
 
    ####### Row Operations ########
129
 
 
130
 
    def loadObjectsFrom(self, tableName, parent=None, data=None,
131
 
                        whereClause=[], loadChildren=1):
132
 
        """Implement me to load objects from the database.
133
 
 
134
 
        @param whereClause: a list of tuples of (columnName, conditional, value)
135
 
            so it can be parsed by all types of reflectors. eg.::
136
 
              whereClause = [("name", EQUALS, "fred"), ("age", GREATERTHAN, 18)]
137
 
        """
138
 
        raise DBError("not implemented")
139
 
 
140
 
    def updateRow(self, rowObject):
141
 
        """update this rowObject to the database.
142
 
        """
143
 
        raise DBError("not implemented")
144
 
 
145
 
    def insertRow(self, rowObject):
146
 
        """insert a new row for this object instance.
147
 
        """
148
 
        raise DBError("not implemented")
149
 
 
150
 
    def deleteRow(self, rowObject):
151
 
        """delete the row for this object from the database.
152
 
        """
153
 
        raise DBError("not implemented")
154
 
 
155
 
# conditionals
156
 
EQUAL       = 0
157
 
LESSTHAN    = 1
158
 
GREATERTHAN = 2
159
 
LIKE        = 3
160
 
 
161
 
 
162
 
__all__ = ['Reflector', 'EQUAL', 'LESSTHAN', 'GREATERTHAN', 'LIKE']