0001import re
0002
0003__all__ = ["Style", "MixedCaseUnderscoreStyle", "DefaultStyle",
0004 "MixedCaseStyle"]
0005
0006class Style(object):
0007
0008 """
0009 The base Style class, and also the simplest implementation. No
0010 translation occurs -- column names and attribute names match,
0011 as do class names and table names (when using auto class or
0012 schema generation).
0013 """
0014
0015 def __init__(self, pythonAttrToDBColumn=None,
0016 dbColumnToPythonAttr=None,
0017 pythonClassToDBTable=None,
0018 dbTableToPythonClass=None,
0019 idForTable=None,
0020 longID=False):
0021 if pythonAttrToDBColumn:
0022 self.pythonAttrToDBColumn = lambda a, s=self: pythonAttrToDBColumn(s, a)
0023 if dbColumnToPythonAttr:
0024 self.dbColumnToPythonAttr = lambda a, s=self: dbColumnToPythonAttr(s, a)
0025 if pythonClassToDBTable:
0026 self.pythonClassToDBTable = lambda a, s=self: pythonClassToDBTable(s, a)
0027 if dbTableToPythonClass:
0028 self.dbTableToPythonClass = lambda a, s=self: dbTableToPythonClass(s, a)
0029 if idForTable:
0030 self.idForTable = lambda a, s=self: idForTable(s, a)
0031 self.longID = longID
0032
0033 def pythonAttrToDBColumn(self, attr):
0034 return attr
0035
0036 def dbColumnToPythonAttr(self, col):
0037 return col
0038
0039 def pythonClassToDBTable(self, className):
0040 return className
0041
0042 def dbTableToPythonClass(self, table):
0043 return table
0044
0045 def idForTable(self, table):
0046 if self.longID:
0047 return self.tableReference(table)
0048 else:
0049 return 'id'
0050
0051 def pythonClassToAttr(self, className):
0052 return lowerword(className)
0053
0054 def instanceAttrToIDAttr(self, attr):
0055 return attr + "ID"
0056
0057 def instanceIDAttrToAttr(self, attr):
0058 return attr[:-2]
0059
0060 def tableReference(self, table):
0061 return table + "_id"
0062
0063class MixedCaseUnderscoreStyle(Style):
0064
0065 """
0066 This is the default style. Python attributes use mixedCase,
0067 while database columns use underscore_separated.
0068 """
0069
0070 def pythonAttrToDBColumn(self, attr):
0071 return mixedToUnder(attr)
0072
0073 def dbColumnToPythonAttr(self, col):
0074 return underToMixed(col)
0075
0076 def pythonClassToDBTable(self, className):
0077 return className[0].lower() + mixedToUnder(className[1:])
0079
0080 def dbTableToPythonClass(self, table):
0081 return table[0].upper() + underToMixed(table[1:])
0083
0084 def pythonClassToDBTableReference(self, className):
0085 return self.tableReference(self.pythonClassToDBTable(className))
0086
0087 def tableReference(self, table):
0088 return table + "_id"
0089
0090DefaultStyle = MixedCaseUnderscoreStyle
0091
0092class MixedCaseStyle(Style):
0093
0094 """
0095 This style leaves columns as mixed-case, and uses long
0096 ID names (like ProductID instead of simply id).
0097 """
0098
0099 def pythonAttrToDBColumn(self, attr):
0100 return capword(attr)
0101
0102 def dbColumnToPythonAttr(self, col):
0103 return lowerword(col)
0104
0105 def dbTableToPythonClass(self, table):
0106 return capword(table)
0107
0108 def tableReference(self, table):
0109 return table + "ID"
0110
0111defaultStyle = DefaultStyle()
0112
0113def getStyle(soClass, dbConnection=None):
0114 if dbConnection is None:
0115 if hasattr(soClass, '_connection'):
0116 dbConnection = soClass._connection
0117 if hasattr(soClass.sqlmeta, 'style') and soClass.sqlmeta.style:
0118 return soClass.sqlmeta.style
0119 elif dbConnection and dbConnection.style:
0120 return dbConnection.style
0121 else:
0122 return defaultStyle
0123
0124
0125
0126
0127_mixedToUnderRE = re.compile(r'[A-Z]+')
0128def mixedToUnder(s):
0129 if s.endswith('ID'):
0130 return mixedToUnder(s[:-2] + "_id")
0131 trans = _mixedToUnderRE.sub(mixedToUnderSub, s)
0132 if trans.startswith('_'):
0133 trans = trans[1:]
0134 return trans
0135
0136def mixedToUnderSub(match):
0137 m = match.group(0).lower()
0138 if len(m) > 1:
0139 return '_%s_%s' % (m[:-1], m[-1])
0140 else:
0141 return '_%s' % m
0142
0143def capword(s):
0144 return s[0].upper() + s[1:]
0145
0146def lowerword(s):
0147 return s[0].lower() + s[1:]
0148
0149_underToMixedRE = re.compile('_.')
0150def underToMixed(name):
0151 if name.endswith('_id'):
0152 return underToMixed(name[:-3] + "ID")
0153 return _underToMixedRE.sub(lambda m: m.group(0)[1].upper(),
0154 name)