~ntt-pf-lab/nova/monkey_patch_notification

« back to all changes in this revision

Viewing changes to vendor/Twisted-10.0.0/twisted/enterprise/sqlreflector.py

  • Committer: Jesse Andrews
  • Date: 2010-05-28 06:05:26 UTC
  • Revision ID: git-v1:bf6e6e718cdc7488e2da87b21e258ccc065fe499
initial commit

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
from twisted.enterprise import reflector
 
7
from twisted.enterprise.util import DBError, getKeyColumn, quote, safe
 
8
from twisted.enterprise.util import _TableInfo
 
9
from twisted.enterprise.row import RowObject
 
10
 
 
11
from twisted.python import reflect
 
12
 
 
13
class SQLReflector(reflector.Reflector):
 
14
    """
 
15
    DEPRECATED.
 
16
    
 
17
    I reflect on a database and load RowObjects from it.
 
18
 
 
19
    In order to do this, I interrogate a relational database to
 
20
    extract schema information and interface with RowObject class
 
21
    objects that can interact with specific tables. 
 
22
    """
 
23
    populated = 0
 
24
    conditionalLabels = {
 
25
        reflector.EQUAL       : "=",
 
26
        reflector.LESSTHAN    : "<",
 
27
        reflector.GREATERTHAN : ">",
 
28
        reflector.LIKE        : "like"
 
29
        }
 
30
 
 
31
    def __init__(self, dbpool, rowClasses):
 
32
        """Initialize me against a database.
 
33
        """
 
34
        reflector.Reflector.__init__(self, rowClasses)
 
35
        self.dbpool = dbpool
 
36
 
 
37
    def _populate(self):
 
38
        self._transPopulateSchema()
 
39
 
 
40
    def _transPopulateSchema(self):
 
41
        """Used to construct the row classes in a single interaction.
 
42
        """
 
43
        for rc in self.rowClasses:
 
44
            if not issubclass(rc, RowObject):
 
45
                raise DBError("Stub class (%s) is not derived from RowObject" % reflect.qual(rc.rowClass))
 
46
 
 
47
            self._populateSchemaFor(rc)
 
48
        self.populated = 1
 
49
 
 
50
    def _populateSchemaFor(self, rc):
 
51
        """Construct all the SQL templates for database operations on
 
52
        <tableName> and populate the class <rowClass> with that info.
 
53
        """
 
54
        attributes = ("rowColumns", "rowKeyColumns", "rowTableName" )
 
55
        for att in attributes:
 
56
            if not hasattr(rc, att):
 
57
                raise DBError("RowClass %s must have class variable: %s" % (rc, att))
 
58
 
 
59
        tableInfo = _TableInfo(rc)
 
60
        tableInfo.updateSQL = self.buildUpdateSQL(tableInfo)
 
61
        tableInfo.insertSQL = self.buildInsertSQL(tableInfo)
 
62
        tableInfo.deleteSQL = self.buildDeleteSQL(tableInfo)
 
63
        self.populateSchemaFor(tableInfo)
 
64
 
 
65
    def escape_string(self, text):
 
66
        """Escape a string for use in an SQL statement. The default
 
67
        implementation escapes ' with '' and \ with \\. Redefine this
 
68
        function in a subclass if your database server uses different
 
69
        escaping rules.
 
70
        """
 
71
        return safe(text)
 
72
 
 
73
    def quote_value(self, value, type):
 
74
        """Format a value for use in an SQL statement.
 
75
 
 
76
        @param value: a value to format as data in SQL.
 
77
        @param type: a key in util.dbTypeMap.
 
78
        """
 
79
        return quote(value, type, string_escaper=self.escape_string)
 
80
 
 
81
    def loadObjectsFrom(self, tableName, parentRow=None, data=None,
 
82
                        whereClause=None, forceChildren=0):
 
83
        """Load a set of RowObjects from a database.
 
84
 
 
85
        Create a set of python objects of <rowClass> from the contents
 
86
        of a table populated with appropriate data members.
 
87
        Example::
 
88
 
 
89
          |  class EmployeeRow(row.RowObject):
 
90
          |      pass
 
91
          |
 
92
          |  def gotEmployees(employees):
 
93
          |      for emp in employees:
 
94
          |          emp.manager = "fred smith"
 
95
          |          manager.updateRow(emp)
 
96
          |
 
97
          |  reflector.loadObjectsFrom("employee",
 
98
          |                          data = userData,
 
99
          |                          whereClause = [("manager" , EQUAL, "fred smith")]
 
100
          |                          ).addCallback(gotEmployees)
 
101
 
 
102
        NOTE: the objects and all children should be loaded in a single transaction.
 
103
        NOTE: can specify a parentRow _OR_ a whereClause.
 
104
 
 
105
        """
 
106
        if parentRow and whereClause:
 
107
            raise DBError("Must specify one of parentRow _OR_ whereClause")
 
108
        if parentRow:
 
109
            info = self.getTableInfo(parentRow)
 
110
            relationship = info.getRelationshipFor(tableName)
 
111
            whereClause = self.buildWhereClause(relationship, parentRow)
 
112
        elif whereClause:
 
113
            pass
 
114
        else:
 
115
            whereClause = []
 
116
        return self.dbpool.runInteraction(self._rowLoader, tableName,
 
117
                                          parentRow, data, whereClause,
 
118
                                          forceChildren)
 
119
 
 
120
    def _rowLoader(self, transaction, tableName, parentRow, data,
 
121
                   whereClause, forceChildren):
 
122
        """immediate loading of rowobjects from the table with the whereClause.
 
123
        """
 
124
        tableInfo = self.schema[tableName]
 
125
        # Build the SQL for the query
 
126
        sql = "SELECT "
 
127
        first = 1
 
128
        for column, type in tableInfo.rowColumns:
 
129
            if first:
 
130
                first = 0
 
131
            else:
 
132
                sql = sql + ","
 
133
            sql = sql + " %s" % column
 
134
        sql = sql + " FROM %s " % (tableName)
 
135
        if whereClause:
 
136
            sql += " WHERE "
 
137
            first = 1
 
138
            for wItem in whereClause:
 
139
                if first:
 
140
                    first = 0
 
141
                else:
 
142
                    sql += " AND "
 
143
                (columnName, cond, value) = wItem
 
144
                t = self.findTypeFor(tableName, columnName)
 
145
                quotedValue = self.quote_value(value, t)
 
146
                sql += "%s %s %s" % (columnName, self.conditionalLabels[cond],
 
147
                                     quotedValue)
 
148
 
 
149
        # execute the query
 
150
        transaction.execute(sql)
 
151
        rows = transaction.fetchall()
 
152
 
 
153
        # construct the row objects
 
154
        results = []
 
155
        newRows = []
 
156
        for args in rows:
 
157
            kw = {}
 
158
            for i in range(0,len(args)):
 
159
                ColumnName = tableInfo.rowColumns[i][0].lower()
 
160
                for attr, type in tableInfo.rowClass.rowColumns:
 
161
                    if attr.lower() == ColumnName:
 
162
                        kw[attr] = args[i]
 
163
                        break
 
164
            # find the row in the cache or add it
 
165
            resultObject = self.findInCache(tableInfo.rowClass, kw)
 
166
            if not resultObject:
 
167
                meth = tableInfo.rowFactoryMethod[0]
 
168
                resultObject = meth(tableInfo.rowClass, data, kw)
 
169
                self.addToCache(resultObject)
 
170
                newRows.append(resultObject)
 
171
            results.append(resultObject)
 
172
 
 
173
        # add these rows to the parentRow if required
 
174
        if parentRow:
 
175
            self.addToParent(parentRow, newRows, tableName)
 
176
 
 
177
        # load children or each of these rows if required
 
178
        for relationship in tableInfo.relationships:
 
179
            if not forceChildren and not relationship.autoLoad:
 
180
                continue
 
181
            for row in results:
 
182
                # build where clause
 
183
                childWhereClause = self.buildWhereClause(relationship, row)
 
184
                # load the children immediately, but do nothing with them
 
185
                self._rowLoader(transaction,
 
186
                                relationship.childRowClass.rowTableName,
 
187
                                row, data, childWhereClause, forceChildren)
 
188
 
 
189
        return results
 
190
 
 
191
    def findTypeFor(self, tableName, columnName):
 
192
        tableInfo = self.schema[tableName]
 
193
        columnName = columnName.lower()
 
194
        for column, type in tableInfo.rowColumns:
 
195
            if column.lower() == columnName:
 
196
                return type
 
197
 
 
198
    def buildUpdateSQL(self, tableInfo):
 
199
        """(Internal) Build SQL template to update a RowObject.
 
200
 
 
201
        Returns: SQL that is used to contruct a rowObject class.
 
202
        """
 
203
        sql = "UPDATE %s SET" % tableInfo.rowTableName
 
204
        # build update attributes
 
205
        first = 1
 
206
        for column, type in tableInfo.rowColumns:
 
207
            if getKeyColumn(tableInfo.rowClass, column):
 
208
                continue
 
209
            if not first:
 
210
                sql = sql + ", "
 
211
            sql = sql + " %s = %s" % (column, "%s")
 
212
            first = 0
 
213
 
 
214
        # build where clause
 
215
        first = 1
 
216
        sql = sql + " WHERE "
 
217
        for keyColumn, type in tableInfo.rowKeyColumns:
 
218
            if not first:
 
219
                sql = sql + " AND "
 
220
            sql = sql + " %s = %s " % (keyColumn, "%s")
 
221
            first = 0
 
222
        return sql
 
223
 
 
224
    def buildInsertSQL(self, tableInfo):
 
225
        """(Internal) Build SQL template to insert a new row.
 
226
 
 
227
        Returns: SQL that is used to insert a new row for a rowObject
 
228
        instance not created from the database.
 
229
        """
 
230
        sql = "INSERT INTO %s (" % tableInfo.rowTableName
 
231
        # build column list
 
232
        first = 1
 
233
        for column, type in tableInfo.rowColumns:
 
234
            if not first:
 
235
                sql = sql + ", "
 
236
            sql = sql + column
 
237
            first = 0
 
238
 
 
239
        sql = sql + " ) VALUES ("
 
240
 
 
241
        # build values list
 
242
        first = 1
 
243
        for column, type in tableInfo.rowColumns:
 
244
            if not first:
 
245
                sql = sql + ", "
 
246
            sql = sql + "%s"
 
247
            first = 0
 
248
 
 
249
        sql = sql + ")"
 
250
        return sql
 
251
 
 
252
    def buildDeleteSQL(self, tableInfo):
 
253
        """Build the SQL template to delete a row from the table.
 
254
        """
 
255
        sql = "DELETE FROM %s " % tableInfo.rowTableName
 
256
        # build where clause
 
257
        first = 1
 
258
        sql = sql + " WHERE "
 
259
        for keyColumn, type in tableInfo.rowKeyColumns:
 
260
            if not first:
 
261
                sql = sql + " AND "
 
262
            sql = sql + " %s = %s " % (keyColumn, "%s")
 
263
            first = 0
 
264
        return sql
 
265
 
 
266
    def updateRowSQL(self, rowObject):
 
267
        """Build SQL to update the contents of rowObject.
 
268
        """
 
269
        args = []
 
270
        tableInfo = self.schema[rowObject.rowTableName]
 
271
        # build update attributes
 
272
        for column, type in tableInfo.rowColumns:
 
273
            if not getKeyColumn(rowObject.__class__, column):
 
274
                args.append(self.quote_value(rowObject.findAttribute(column),
 
275
                                             type))
 
276
        # build where clause
 
277
        for keyColumn, type in tableInfo.rowKeyColumns:
 
278
            args.append(self.quote_value(rowObject.findAttribute(keyColumn),
 
279
                                         type))
 
280
 
 
281
        return self.getTableInfo(rowObject).updateSQL % tuple(args)
 
282
 
 
283
    def updateRow(self, rowObject):
 
284
        """Update the contents of rowObject to the database.
 
285
        """
 
286
        sql = self.updateRowSQL(rowObject)
 
287
        rowObject.setDirty(0)
 
288
        return self.dbpool.runOperation(sql)
 
289
 
 
290
    def insertRowSQL(self, rowObject):
 
291
        """Build SQL to insert the contents of rowObject.
 
292
        """
 
293
        args = []
 
294
        tableInfo = self.schema[rowObject.rowTableName]        
 
295
        # build values
 
296
        for column, type in tableInfo.rowColumns:
 
297
            args.append(self.quote_value(rowObject.findAttribute(column),type))
 
298
        return self.getTableInfo(rowObject).insertSQL % tuple(args)
 
299
 
 
300
    def insertRow(self, rowObject):
 
301
        """Insert a new row for rowObject.
 
302
        """
 
303
        rowObject.setDirty(0)
 
304
        sql = self.insertRowSQL(rowObject)
 
305
        return self.dbpool.runOperation(sql)
 
306
 
 
307
    def deleteRowSQL(self, rowObject):
 
308
        """Build SQL to delete rowObject from the database.
 
309
        """
 
310
        args = []
 
311
        tableInfo = self.schema[rowObject.rowTableName]        
 
312
        # build where clause
 
313
        for keyColumn, type in tableInfo.rowKeyColumns:
 
314
            args.append(self.quote_value(rowObject.findAttribute(keyColumn),
 
315
                                         type))
 
316
 
 
317
        return self.getTableInfo(rowObject).deleteSQL % tuple(args)
 
318
 
 
319
    def deleteRow(self, rowObject):
 
320
        """Delete the row for rowObject from the database.
 
321
        """
 
322
        sql = self.deleteRowSQL(rowObject)
 
323
        self.removeFromCache(rowObject)
 
324
        return self.dbpool.runOperation(sql)
 
325
 
 
326
 
 
327
__all__ = ['SQLReflector']