Thread: [SQL-CVS] r145 - trunk/SQLObject
SQLObject is a Python ORM.
Brought to you by:
ianbicking,
phd
From: <sub...@co...> - 2004-06-14 12:51:02
|
Author: ahmedmo Date: 2004-06-14 04:48:23 -0400 (Mon, 14 Jun 2004) New Revision: 145 Removed: trunk/SQLObject/col.py Log: Removed file/folder Deleted: trunk/SQLObject/col.py =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- trunk/SQLObject/col.py 2004-06-14 08:47:01 UTC (rev 144) +++ trunk/SQLObject/col.py 2004-06-14 08:48:23 UTC (rev 145) @@ -1,608 +0,0 @@ -""" -Col -""" - -import sqlbuilder -import re -# Sadly the name "constraints" conflicts with many of the function -# arguments in this module, so we rename it: -import constraints as consts -from include import validators - -NoDefault =3D sqlbuilder.NoDefault -True, False =3D 1=3D=3D1, 0=3D=3D1 - =20 - -######################################## -## Columns -######################################## - -# Col is essentially a column definition, it doesn't have -# much logic to it. -class SOCol(object): - - def __init__(self, - name, - soClass, - dbName=3DNone, - default=3DNoDefault, - foreignKey=3DNone, - alternateID=3DFalse, - alternateMethodName=3DNone, - constraints=3DNone, - notNull=3DNoDefault, - notNone=3DNoDefault, - unique=3DNoDefault, - sqlType=3DNone, - columnDef=3DNone, - validator=3DNone, - immutable=3DFalse, - cascade=3DNone, - lazy=3DFalse, - noCache=3DFalse): - - # This isn't strictly true, since we *could* use backquotes or - # " or something (database-specific) around column names, but - # why would anyone *want* to use a name like that? - # @@: I suppose we could actually add backquotes to the - # dbName if we needed to... - assert sqlbuilder.sqlIdentifier(name), 'Name must be SQL-safe (l= etters, numbers, underscores): %s' \ - % repr(name) - assert name !=3D 'id', 'The column name "id" is reserved for SQL= Object use (and is implicitly created).' - assert name, "You must provide a name for all columns" - - self.columnDef =3D columnDef - - self.immutable =3D immutable - - # cascade can be one of: - # None: no constraint is generated - # True: a CASCADE constraint is generated - # False: a RESTRICT constraint is generated - self.cascade =3D cascade - - if type(constraints) not in (type([]), type(())): - constraints =3D [constraints] - self.constraints =3D self.autoConstraints() + constraints - - self.notNone =3D False - if notNull is not NoDefault: - self.notNone =3D notNull - assert notNone is NoDefault or \ - (not notNone) =3D=3D (not notNull), \ - "The notNull and notNone arguments are aliases, and m= ust not conflict. You gave notNull=3D%r, notNone=3D%r" % (notNull, notNo= ne) - elif notNone is not NoDefault: - self.notNone =3D notNone - if self.notNone: - self.constraints =3D [consts.notNull] + self.constraints - - self.name =3D name - self.soClass =3D None - self._default =3D default - self.customSQLType =3D sqlType - - self.foreignKey =3D foreignKey - if self.foreignKey: - #assert self.name.upper().endswith('ID'), "All foreign key c= olumns must end with 'ID' (%s)" % repr(self.name) - if not self.name.upper().endswith('ID'): - self.foreignName =3D self.name - self.name =3D self.name + "ID" - else: - self.foreignName =3D self.name[:-2] - else: - self.foreignName =3D None - - # if they don't give us a specific database name for - # the column, we separate the mixedCase into mixed_case - # and assume that. - if dbName is None: - self.dbName =3D soClass._style.pythonAttrToDBColumn(self.nam= e) - else: - self.dbName =3D dbName - - # alternateID means that this is a unique column that - # can be used to identify rows - self.alternateID =3D alternateID - if self.alternateID and alternateMethodName is None: - self.alternateMethodName =3D 'by' + self.name[0].capitalize(= ) + self.name[1:] - else: - self.alternateMethodName =3D alternateMethodName - - if unique is NoDefault: - self.unique =3D alternateID - else: - self.unique =3D unique - - self.validator =3D validator - self.noCache =3D noCache - self.lazy =3D lazy - - def _set_validator(self, value): - self._validator =3D value - if self._validator: - self.toPython =3D self._validator.toPython - self.fromPython =3D self._validator.fromPython - else: - self.toPython =3D None - self.fromPython =3D None - - def _get_validator(self): - return self._validator - - validator =3D property(_get_validator, _set_validator) - - def autoConstraints(self): - return [] - - def _get_default(self): - # A default can be a callback or a plain value, - # here we resolve the callback - if self._default is NoDefault: - return NoDefault - elif hasattr(self._default, '__sqlrepr__'): - return self._default - elif callable(self._default): - return self._default() - else: - return self._default - default =3D property(_get_default, None, None) - - def _get_joinName(self): - assert self.name[-2:] =3D=3D 'ID' - return self.name[:-2] - joinName =3D property(_get_joinName, None, None) - - def __repr__(self): - r =3D '<%s %s' % (self.__class__.__name__, self.name) - if self.default is not NoDefault: - r +=3D ' default=3D%s' % repr(self.default) - if self.foreignKey: - r +=3D ' connected to %s' % self.foreignKey - if self.alternateID: - r +=3D ' alternate ID' - if self.notNone: - r +=3D ' not null' - return r + '>' - - def createSQL(self): - return ' '.join([self._sqlType() + self._extraSQL()]) - - def _extraSQL(self): - result =3D [] - if self.notNone or self.alternateID: - result.append('NOT NULL') - if self.unique or self.alternateID: - result.append('UNIQUE') - return result - - def _sqlType(self): - if self.customSQLType is None: - raise ValueError, ("Col %s (%s) cannot be used for automatic= " - "schema creation (too abstract)" % - (self.name, self.__class__)) - else: - return self.customSQLType - - def _mysqlType(self): - return self._sqlType() - - def _postgresType(self): - return self._sqlType() - - def _sqliteType(self): - # SQLite is naturally typeless, so as a fallback it uses - # no type. - try: - return self._sqlType() - except ValueError: - return '' - - def _sybaseType(self): - return self._sqlType() - - def _firebirdType(self): - return self._sqlType() - =20 - def _maxdbType(self): - return self._sqlType() - - def mysqlCreateSQL(self): - return ' '.join([self.dbName, self._mysqlType()] + self._extraSQ= L()) - - def postgresCreateSQL(self): - return ' '.join([self.dbName, self._postgresType()] + self._extr= aSQL()) - - def sqliteCreateSQL(self): - return ' '.join([self.dbName, self._sqliteType()] + self._extraS= QL()) - - def sybaseCreateSQL(self): - return ' '.join([self.dbName, self._sybaseType()] + self._extraS= QL()) - - def firebirdCreateSQL(self): - # Ian Sparks pointed out that fb is picky about the order - # of the NOT NULL clause in a create statement. So, we handle - # them differently for Enum columns. - if not isinstance(self, SOEnumCol): - return ' '.join([self.dbName, self._firebirdType()] + self._= extraSQL()) - else: - return ' '.join([self.dbName] + [self._firebirdType()[0]] + = self._extraSQL() + [self._firebirdType()[1]]) -=09 - def maxdbCreateSQL(self): - return ' '.join([self.dbName, self._maxdbType()] + self._extraSQL= ()) - - def __get__(self, obj, type=3DNone): - if obj is None: - # class attribute, return the descriptor itself - return self - if obj.sqlmeta.obsolete: - raise '@@: figure out the exception for a delete' - if obj.sqlmeta.cacheColumns: - columns =3D obj.sqlmeta._columnCache - if columns is None: - obj.sqlmeta.loadValues() - try: - return columns[name] - except KeyError: - return obj.sqlmeta.loadColumn(self) - else: - return obj.sqlmeta.loadColumn(self) - - def __set__(self, obj, value): - if self.immutable: - raise AttributeError("The column %s.%s is immutable" % - (obj.__class__.__name__, - self.name)) - obj.sqlmeta.setColumn(self, value) - - def __delete__(self, obj): - raise AttributeError("I can't be deleted from %r" % obj) - - -class Col(object): - - baseClass =3D SOCol - - def __init__(self, name=3DNone, **kw): - kw['name'] =3D name - kw['columnDef'] =3D self - self.kw =3D kw - - def setName(self, value): - assert self.kw['name'] is None, "You cannot change a name after = it has already been set (from %s to %s)" % (self.kw['name'], value) - self.kw['name'] =3D value - - def withClass(self, soClass): - return self.baseClass(soClass=3DsoClass, **self.kw) - -class SOStringCol(SOCol): - - # 3-03 @@: What about BLOB? - - def __init__(self, **kw): - self.length =3D popKey(kw, 'length') - self.varchar =3D popKey(kw, 'varchar', 'auto') - if not self.length: - assert self.varchar =3D=3D 'auto' or not self.varchar, \ - "Without a length strings are treated as TEXT, not va= rchar" - self.varchar =3D False - elif self.varchar =3D=3D 'auto': - self.varchar =3D True - - SOCol.__init__(self, **kw) - - def autoConstraints(self): - constraints =3D [consts.isString] - if self.length is not None: - constraints +=3D [consts.MaxLength(self.length)] - return constraints - - def _sqlType(self): - if not self.length: - return 'TEXT' - elif self.varchar: - return 'VARCHAR(%i)' % self.length - else: - return 'CHAR(%i)' % self.length - - def _firebirdType(self): - if not self.length: - return 'BLOB SUB_TYPE TEXT' - else: - return self._sqlType() - =20 - def _maxdbType(self): - if not self.length: - return 'LONG ASCII' - else: - return self._sqlType() - -class StringCol(Col): - baseClass =3D SOStringCol - -class SOIntCol(SOCol): - - # 3-03 @@: support precision, maybe max and min directly - - def autoConstraints(self): - return [consts.isInt] - - def _sqlType(self): - return 'INT' - -class IntCol(Col): - baseClass =3D SOIntCol - -class BoolValidator(validators.Validator): - - def fromPython(self, value, state): - if value: - return sqlbuilder.TRUE - else: - return sqlbuilder.FALSE - - def toPython(self, value, state): - if not value or not int(value): - return sqlbuilder.FALSE - else: - return sqlbuilder.TRUE - -class SOBoolCol(SOCol): - - def __init__(self, **kw): - SOCol.__init__(self, **kw) - self.validator =3D validators.All.join(BoolValidator(), self.val= idator) - - def autoConstraints(self): - return [consts.isBool] - - def _postgresType(self): - return 'BOOL' - - def _mysqlType(self): - return "TINYINT" - - def _sybaseType(self): - return "BIT" - - def _firebirdType(self): - return 'INT' - =20 - def _maxdbType(self): - return "BOOLEAN" - -class BoolCol(Col): - baseClass =3D SOBoolCol - -class SOFloatCol(SOCol): - - # 3-03 @@: support precision (e.g., DECIMAL) - - def autoConstraints(self): - return [consts.isFloat] - - def _sqlType(self): - return 'FLOAT' - -class FloatCol(Col): - baseClass =3D SOFloatCol - -class SOKeyCol(SOCol): - - # 3-03 @@: this should have a simplified constructor - # Should provide foreign key information for other DBs. - - def _mysqlType(self): - return 'INT' - - def _sqliteType(self): - return 'INT' - - def _postgresType(self): - return 'INT' - - def _sybaseType(self): - return 'INT' - - def _firebirdType(self): - return 'INT' - =20 - def _maxdbType(self): - return 'INT' - -class KeyCol(Col): - - baseClass =3D SOKeyCol - -class SOForeignKey(SOKeyCol): - - def __init__(self, **kw): - foreignKey =3D kw['foreignKey'] - style =3D kw['soClass']._style - if not kw.get('name'): - kw['name'] =3D style.instanceAttrToIDAttr(style.pythonClassT= oAttr(foreignKey)) - else: - if not kw['name'].upper().endswith('ID'): - kw['name'] =3D style.instanceAttrToIDAttr(kw['name']) - SOKeyCol.__init__(self, **kw) - - def postgresCreateSQL(self): - from main import findClass - sql =3D SOKeyCol.postgresCreateSQL(self) - if self.cascade is not None: - other =3D findClass(self.foreignKey) - tName =3D other._table - idName =3D other._idName - action =3D self.cascade and 'CASCADE' or 'RESTRICT' - constraint =3D ('CONSTRAINT %(tName)s_exists ' - 'FOREIGN KEY(%(colName)s) ' - 'REFERENCES %(tName)s(%(idName)s) ' - 'ON DELETE %(action)s' % - {'tName':tName, - 'colName':self.dbName, - 'idName':idName, - 'action':action}) - sql =3D ', '.join([sql, constraint]) - return sql - - def sybaseCreateSQL(self): - from SQLObject import findClass - sql =3D SOKeyCol.sybaseCreateSQL(self) - other =3D findClass(self.foreignKey) - tName =3D other._table - idName =3D other._idName - reference =3D ('REFERENCES %(tName)s(%(idName)s) ' % - {'tName':tName, - 'idName':idName}) - sql =3D ' '.join([sql, reference]) - return sql - =20 - def maxdbCreateSQL(self): - from main import findClass - other =3D findClass(self.foreignKey) - fidName =3D self.dbName - #I assume that foreign key name is identical to the id of the referen= ce table =09 - sql =3D ' '.join([fidName, self._maxdbType()]) - tName =3D other._table - idName =3D other._idName - sql=3Dsql + ',' + '\n'=20 - sql=3Dsql + 'FOREIGN KEY (%s) REFERENCES %s(%s)'%(fidName,tName,idNam= e) - return sql - -class ForeignKey(KeyCol): - - baseClass =3D SOForeignKey - - def __init__(self, foreignKey=3DNone, **kw): - KeyCol.__init__(self, foreignKey=3DforeignKey, **kw) - -class SOEnumCol(SOCol): - - def __init__(self, **kw): - self.enumValues =3D popKey(kw, 'enumValues', None) - assert self.enumValues is not None, \ - 'You must provide an enumValues keyword argument' - SOCol.__init__(self, **kw) - - def autoConstraints(self): - return [consts.isString, consts.InList(self.enumValues)] - - def _mysqlType(self): - return "ENUM(%s)" % ', '.join([sqlbuilder.sqlrepr(v, 'mysql') fo= r v in self.enumValues]) - - def _postgresType(self): - length =3D max(map(len, self.enumValues)) - enumValues =3D ', '.join([sqlbuilder.sqlrepr(v, 'postgres') for = v in self.enumValues]) - checkConstraint =3D "CHECK (%s in (%s))" % (self.dbName, enumVal= ues) - return "VARCHAR(%i) %s" % (length, checkConstraint) - - def _sqliteType(self): - return self._postgresType() - - def _sybaseType(self): - return self._postgresType() - - def _firebirdType(self): - length =3D max(map(len, self.enumValues)) - enumValues =3D ', '.join([sqlbuilder.sqlrepr(v, 'firebird') for = v in self.enumValues]) - checkConstraint =3D "CHECK (%s in (%s))" % (self.dbName, enumVal= ues) - #NB. Return a tuple, not a string here - return "VARCHAR(%i)" % (length), checkConstraint -=20 - def _maxdbType(self): - raise "Enum type is not supported" - -class EnumCol(Col): - baseClass =3D SOEnumCol - -class SODateTimeCol(SOCol): - - # 3-03 @@: provide constraints; right now we let the database - # do any parsing and checking. And DATE and TIME? - - def _mysqlType(self): - return 'DATETIME' - - def _postgresType(self): - return 'TIMESTAMP' - - def _sybaseType(self): - return 'DATETIME' - - def _sqliteType(self): - return 'TIMESTAMP' - - def _firebirdType(self): - return 'TIMESTAMP' - =20 - def _maxdbType(self): - return 'TIMESTAMP' - -class DateTimeCol(Col): - baseClass =3D SODateTimeCol - -class SODateCol(SOCol): - - # 3-03 @@: provide constraints; right now we let the database - # do any parsing and checking. And DATE and TIME? - - def _mysqlType(self): - return 'DATE' - - def _postgresType(self): - return 'DATE' - - def _sybaseType(self): - return self._postgresType() - - def _firebirdType(self): - return 'DATE' - =20 - def _maxdbType(self): - return 'DATE' - -class DateCol(Col): - baseClass =3D SODateCol - -class SODecimalCol(SOCol): - - def __init__(self, **kw): - self.size =3D popKey(kw, 'size', NoDefault) - assert self.size is not NoDefault, \ - "You must give a size argument" - self.precision =3D popKey(kw, 'precision', NoDefault) - assert self.precision is not NoDefault, \ - "You must give a precision argument" - SOCol.__init__(self, **kw) - - def _sqlType(self): - return 'DECIMAL(%i, %i)' % (self.size, self.precision) - -class DecimalCol(Col): - baseClass =3D SODecimalCol - -class SOCurrencyCol(SODecimalCol): - - def __init__(self, **kw): - pushKey(kw, 'size', 10) - pushKey(kw, 'precision', 2) - SODecimalCol.__init__(self, **kw) - -class CurrencyCol(DecimalCol): - baseClass =3D SOCurrencyCol - -def popKey(kw, name, default=3DNone): - if not kw.has_key(name): - return default - value =3D kw[name] - del kw[name] - return value - -def pushKey(kw, name, value): - if not kw.has_key(name): - kw[name] =3D value - -all =3D [] -for key, value in globals().items(): - if isinstance(value, type) and issubclass(value, Col): - all.append(key) -__all__ =3D all |