1import re 2 3__all__ = ["Style", "MixedCaseUnderscoreStyle", "DefaultStyle", 4 "MixedCaseStyle"] 5 6class Style(object): 7 8 """ 9 The base Style class, and also the simplest implementation. No 10 translation occurs -- column names and attribute names match, 11 as do class names and table names (when using auto class or 12 schema generation). 13 """ 14 15 def __init__(self, pythonAttrToDBColumn=None, 16 dbColumnToPythonAttr=None, 17 pythonClassToDBTable=None, 18 dbTableToPythonClass=None, 19 idForTable=None, 20 longID=False): 21 if pythonAttrToDBColumn: 22 self.pythonAttrToDBColumn = lambda a, s=self: pythonAttrToDBColumn(s, a) 23 if dbColumnToPythonAttr: 24 self.dbColumnToPythonAttr = lambda a, s=self: dbColumnToPythonAttr(s, a) 25 if pythonClassToDBTable: 26 self.pythonClassToDBTable = lambda a, s=self: pythonClassToDBTable(s, a) 27 if dbTableToPythonClass: 28 self.dbTableToPythonClass = lambda a, s=self: dbTableToPythonClass(s, a) 29 if idForTable: 30 self.idForTable = lambda a, s=self: idForTable(s, a) 31 self.longID = longID 32 33 def pythonAttrToDBColumn(self, attr): 34 return attr 35 36 def dbColumnToPythonAttr(self, col): 37 return col 38 39 def pythonClassToDBTable(self, className): 40 return className 41 42 def dbTableToPythonClass(self, table): 43 return table 44 45 def idForTable(self, table): 46 if self.longID: 47 return self.tableReference(table) 48 else: 49 return 'id' 50 51 def pythonClassToAttr(self, className): 52 return lowerword(className) 53 54 def instanceAttrToIDAttr(self, attr): 55 return attr + "ID" 56 57 def instanceIDAttrToAttr(self, attr): 58 return attr[:-2] 59 60 def tableReference(self, table): 61 return table + "_id" 62 63class MixedCaseUnderscoreStyle(Style): 64 65 """ 66 This is the default style. Python attributes use mixedCase, 67 while database columns use underscore_separated. 68 """ 69 70 def pythonAttrToDBColumn(self, attr): 71 return mixedToUnder(attr) 72 73 def dbColumnToPythonAttr(self, col): 74 return underToMixed(col) 75 76 def pythonClassToDBTable(self, className): 77 return className[0].lower() \ 78 + mixedToUnder(className[1:]) 79 80 def dbTableToPythonClass(self, table): 81 return table[0].upper() \ 82 + underToMixed(table[1:]) 83 84 def pythonClassToDBTableReference(self, className): 85 return self.tableReference(self.pythonClassToDBTable(className)) 86 87 def tableReference(self, table): 88 return table + "_id" 89 90DefaultStyle = MixedCaseUnderscoreStyle 91 92class MixedCaseStyle(Style): 93 94 """ 95 This style leaves columns as mixed-case, and uses long 96 ID names (like ProductID instead of simply id). 97 """ 98 99 def pythonAttrToDBColumn(self, attr): 100 return capword(attr) 101 102 def dbColumnToPythonAttr(self, col): 103 return lowerword(col) 104 105 def dbTableToPythonClass(self, table): 106 return capword(table) 107 108 def tableReference(self, table): 109 return table + "ID" 110 111defaultStyle = DefaultStyle() 112 113def getStyle(soClass, dbConnection=None): 114 if dbConnection is None: 115 if hasattr(soClass, '_connection'): 116 dbConnection = soClass._connection 117 if hasattr(soClass.sqlmeta, 'style') and soClass.sqlmeta.style: 118 return soClass.sqlmeta.style 119 elif dbConnection and dbConnection.style: 120 return dbConnection.style 121 else: 122 return defaultStyle 123 124############################################################ 125## Text utilities 126############################################################ 127_mixedToUnderRE = re.compile(r'[A-Z]+') 128def mixedToUnder(s): 129 if s.endswith('ID'): 130 return mixedToUnder(s[:-2] + "_id") 131 trans = _mixedToUnderRE.sub(mixedToUnderSub, s) 132 if trans.startswith('_'): 133 trans = trans[1:] 134 return trans 135 136def mixedToUnderSub(match): 137 m = match.group(0).lower() 138 if len(m) > 1: 139 return '_%s_%s' % (m[:-1], m[-1]) 140 else: 141 return '_%s' % m 142 143def capword(s): 144 return s[0].upper() + s[1:] 145 146def lowerword(s): 147 return s[0].lower() + s[1:] 148 149_underToMixedRE = re.compile('_.') 150def underToMixed(name): 151 if name.endswith('_id'): 152 return underToMixed(name[:-3] + "ID") 153 return _underToMixedRE.sub(lambda m: m.group(0)[1].upper(), 154 name) 155