OLD | NEW |
| (Empty) |
1 # -*- test-case-name: twisted.test.test_enterprise -*- | |
2 # Copyright (c) 2001-2008 Twisted Matrix Laboratories. | |
3 # See LICENSE for details. | |
4 | |
5 | |
6 import warnings, types | |
7 | |
8 from twisted.python.versions import Version, getVersionString | |
9 from twisted.python.deprecate import deprecated | |
10 from twisted.enterprise.adbapi import _safe | |
11 | |
12 # Common deprecation decorator used for all deprecations. | |
13 _deprecatedVersion = Version("Twisted", 8, 0, 0) | |
14 _releasedDeprecation = deprecated(_deprecatedVersion) | |
15 | |
16 warnings.warn( | |
17 "twisted.enterprise.util is deprecated since %s." % ( | |
18 getVersionString(_deprecatedVersion),), | |
19 category=DeprecationWarning) | |
20 | |
21 NOQUOTE = 1 | |
22 USEQUOTE = 2 | |
23 | |
24 dbTypeMap = { | |
25 "bigint": NOQUOTE, | |
26 "bool": USEQUOTE, | |
27 "boolean": USEQUOTE, | |
28 "bytea": USEQUOTE, | |
29 "date": USEQUOTE, | |
30 "int2": NOQUOTE, | |
31 "int4": NOQUOTE, | |
32 "int8": NOQUOTE, | |
33 "int": NOQUOTE, | |
34 "integer": NOQUOTE, | |
35 "float4": NOQUOTE, | |
36 "float8": NOQUOTE, | |
37 "numeric": NOQUOTE, | |
38 "real": NOQUOTE, | |
39 "smallint": NOQUOTE, | |
40 "char": USEQUOTE, | |
41 "text": USEQUOTE, | |
42 "time": USEQUOTE, | |
43 "timestamp": USEQUOTE, | |
44 "varchar": USEQUOTE | |
45 } | |
46 | |
47 class DBError(Exception): | |
48 pass | |
49 | |
50 | |
51 | |
52 ### Utility functions | |
53 | |
54 def getKeyColumn(rowClass, name): | |
55 lcname = name.lower() | |
56 for keyColumn, type in rowClass.rowKeyColumns: | |
57 if lcname == keyColumn.lower(): | |
58 return name | |
59 return None | |
60 getKeyColumn = _releasedDeprecation(getKeyColumn) | |
61 | |
62 | |
63 | |
64 def quote(value, typeCode, string_escaper=_safe): | |
65 """Add quotes for text types and no quotes for integer types. | |
66 NOTE: uses Postgresql type codes. | |
67 """ | |
68 q = dbTypeMap.get(typeCode, None) | |
69 if q is None: | |
70 raise DBError("Type %s not known" % typeCode) | |
71 if value is None: | |
72 return 'null' | |
73 if q == NOQUOTE: | |
74 return str(value) | |
75 elif q == USEQUOTE: | |
76 if typeCode.startswith('bool'): | |
77 if value: | |
78 value = '1' | |
79 else: | |
80 value = '0' | |
81 if typeCode == "bytea": | |
82 l = ["'"] | |
83 for c in value: | |
84 i = ord(c) | |
85 if i == 0: | |
86 l.append("\\\\000") | |
87 elif i == 92: | |
88 l.append(c * 4) | |
89 elif 32 <= i <= 126: | |
90 l.append(c) | |
91 else: | |
92 l.append("\\%03o" % i) | |
93 l.append("'") | |
94 return "".join(l) | |
95 if not isinstance(value, types.StringType) and \ | |
96 not isinstance(value, types.UnicodeType): | |
97 value = str(value) | |
98 return "'%s'" % string_escaper(value) | |
99 quote = _releasedDeprecation(quote) | |
100 | |
101 | |
102 def safe(text): | |
103 """ | |
104 Make a string safe to include in an SQL statement. | |
105 """ | |
106 return _safe(text) | |
107 | |
108 safe = _releasedDeprecation(safe) | |
109 | |
110 | |
111 def makeKW(rowClass, args): | |
112 """Utility method to construct a dictionary for the attributes | |
113 of an object from set of args. This also fixes the case of column names. | |
114 """ | |
115 kw = {} | |
116 for i in range(0,len(args)): | |
117 columnName = rowClass.dbColumns[i][0].lower() | |
118 for attr in rowClass.rowColumns: | |
119 if attr.lower() == columnName: | |
120 kw[attr] = args[i] | |
121 break | |
122 return kw | |
123 makeKW = _releasedDeprecation(makeKW) | |
124 | |
125 | |
126 def defaultFactoryMethod(rowClass, data, kw): | |
127 """Used by loadObjects to create rowObject instances. | |
128 """ | |
129 newObject = rowClass() | |
130 newObject.__dict__.update(kw) | |
131 return newObject | |
132 defaultFactoryMethod = _releasedDeprecation(defaultFactoryMethod) | |
133 | |
134 ### utility classes | |
135 | |
136 class _TableInfo: | |
137 """(internal) | |
138 | |
139 Info about a table/class and it's relationships. Also serves as a container
for | |
140 generated SQL. | |
141 """ | |
142 def __init__(self, rc): | |
143 self.rowClass = rc | |
144 self.rowTableName = rc.rowTableName | |
145 self.rowKeyColumns = rc.rowKeyColumns | |
146 self.rowColumns = rc.rowColumns | |
147 | |
148 if hasattr(rc, "rowForeignKeys"): | |
149 self.rowForeignKeys = rc.rowForeignKeys | |
150 else: | |
151 self.rowForeignKeys = [] | |
152 | |
153 if hasattr(rc, "rowFactoryMethod"): | |
154 if rc.rowFactoryMethod: | |
155 self.rowFactoryMethod = rc.rowFactoryMethod | |
156 else: | |
157 self.rowFactoryMethod = [defaultFactoryMethod] | |
158 else: | |
159 self.rowFactoryMethod = [defaultFactoryMethod] | |
160 | |
161 self.updateSQL = None | |
162 self.deleteSQL = None | |
163 self.insertSQL = None | |
164 self.relationships = [] | |
165 self.dbColumns = [] | |
166 | |
167 def addForeignKey(self, childColumns, parentColumns, childRowClass, containe
rMethod, autoLoad): | |
168 """This information is attached to the "parent" table | |
169 childColumns - columns of the "child" table | |
170 parentColumns - columns of the "parent" table, the one being joi
ned to... the "foreign" table | |
171 """ | |
172 self.relationships.append( _TableRelationship(childColumns, parentColumn
s, | |
173 childRowClass, containerMe
thod, autoLoad) ) | |
174 | |
175 def getRelationshipFor(self, tableName): | |
176 for relationship in self.relationships: | |
177 if relationship.childRowClass.rowTableName == tableName: | |
178 return relationship | |
179 return None | |
180 | |
181 class _TableRelationship: | |
182 """(Internal) | |
183 | |
184 A foreign key relationship between two tables. | |
185 """ | |
186 def __init__(self, | |
187 childColumns, | |
188 parentColumns, | |
189 childRowClass, | |
190 containerMethod, | |
191 autoLoad): | |
192 self.childColumns = childColumns | |
193 self.parentColumns = parentColumns | |
194 self.childRowClass = childRowClass | |
195 self.containerMethod = containerMethod | |
196 self.autoLoad = autoLoad | |
197 | |
198 | |
199 __all__ = ['NOQUOTE', 'USEQUOTE', 'dbTypeMap', 'DBError', 'getKeyColumn', | |
200 'safe', 'quote'] | |
OLD | NEW |