Thread: [SQL-CVS] r2377 - in home/phd/SQLObject/paramstyles/sqlobject: . mysql
SQLObject is a Python ORM.
Brought to you by:
ianbicking,
phd
From: <sub...@co...> - 2007-03-02 15:48:36
|
Author: phd Date: 2007-03-02 08:48:25 -0700 (Fri, 02 Mar 2007) New Revision: 2377 Modified: home/phd/SQLObject/paramstyles/sqlobject/col.py home/phd/SQLObject/paramstyles/sqlobject/dbconnection.py home/phd/SQLObject/paramstyles/sqlobject/main.py home/phd/SQLObject/paramstyles/sqlobject/mysql/mysqlconnection.py home/phd/SQLObject/paramstyles/sqlobject/sqlbuilder.py Log: Merged patches from the revisions 2360:2376 from the trunk Modified: home/phd/SQLObject/paramstyles/sqlobject/col.py =================================================================== --- home/phd/SQLObject/paramstyles/sqlobject/col.py 2007-03-02 15:42:13 UTC (rev 2376) +++ home/phd/SQLObject/paramstyles/sqlobject/col.py 2007-03-02 15:48:25 UTC (rev 2377) @@ -112,6 +112,7 @@ creationOrder, dbName=None, default=NoDefault, + defaultSQL=None, foreignKey=None, alternateID=False, alternateMethodName=None, @@ -178,6 +179,7 @@ self.name = name self.soClass = soClass self._default = default + self.defaultSQL = defaultSQL self.customSQLType = sqlType # deal with foreign keys @@ -293,6 +295,8 @@ result.append('NOT NULL') if self.unique or self.alternateID: result.append('UNIQUE') + if self.defaultSQL is not None: + result.append("DEFAULT %s" % self.defaultSQL) return result def _sqlType(self): @@ -594,6 +598,11 @@ class SOIntCol(SOCol): # 3-03 @@: support precision, maybe max and min directly + def __init__(self, **kw): + self.length = popKey(kw, 'length') + self.unsigned = bool(popKey(kw, 'unsigned')) + self.zerofill = bool(popKey(kw, 'unsigned')) + SOCol.__init__(self, **kw) def autoConstraints(self): return [consts.isInt] @@ -602,12 +611,54 @@ return [IntValidator(name=self.name)] + \ super(SOIntCol, self).createValidators() + def addSQLAttrs(self, str): + _ret = str + if str is None or len(str) < 1: + return None + + if self.length >= 1: + _ret = "%s(%d)" % (_ret, self.length) + if self.unsigned: + _ret = _ret + " UNSIGNED" + if self.zerofill: + _ret = _reg + " ZEROFILL" + return _ret + def _sqlType(self): - return 'INT' + return self.addSQLAttrs("INT") class IntCol(Col): baseClass = SOIntCol +class SOTinyIntCol(SOIntCol): + def _sqlTyps(self): + return self.addSQLAttrs("TINYINT") + +class TinyIntCol(Col): + baseClass = SOTinyIntCol + +class SOSmallIntCol(SOIntCol): + def _sqlTyps(self): + return self.addSQLAttrs("SMALLINT") + +class SmallIntCol(Col): + baseClass = SOSmallIntCol + +class SOMediumIntCol(SOIntCol): + def _sqlTyps(self): + return self.addSQLAttrs("MEDIUMINT") + +class MediumIntCol(Col): + baseClass = SOMediumIntCol + +class SOBigIntCol(SOIntCol): + def _sqlTyps(self): + return self.addSQLAttrs("BIGINT") + +class BigIntCol(Col): + baseClass = SOBigIntCol + + class BoolValidator(validators.Validator): def to_python(self, value, state): @@ -940,6 +991,43 @@ baseClass = SOEnumCol +class SetValidator(validators.Validator): + """ + Translates Python tuples into SQL comma-delimited SET strings. + """ + + def to_python(self, value, state): + if not isinstance(value, str): + raise validators.Invalid("expected a value string, got % instead" % \ + (value), value, state) + return tuple(value.split(",")) + + def from_python(self, value, state): + if not isinstance(value, tuple): + value = (value,) + return ",".join([v for v in value]) + +class SOSetCol(SOCol): + def __init__(self, **kw): + self.setValues = popKey(kw, 'setValues', None) + assert self.setValues is not None, \ + 'You must provide a setValues keyword argument' + super(SOSetCol, self).__init__(**kw) + + def autoConstraints(self): + return [consts.isString, consts.InList(self.setValues)] + + def createValidators(self): + return [SetValidator(name = self.name, setValues = self.setValues)] + \ + super(SOSetCol, self).createValidators() + + def _mysqlType(self): + return "SET(%s)" % ', '.join([sqlbuilder.sqlrepr(v, 'mysql') for v in self.enumValues]) + +class SetCol(Col): + baseClass = SOSetCol + + if datetime_available: class DateTimeValidator(validators.DateValidator): def to_python(self, value, state): @@ -1063,7 +1151,6 @@ % DATETIME_IMPLEMENTATION) now = staticmethod(now) - if datetime_available: class DateValidator(DateTimeValidator): def to_python(self, value, state): @@ -1180,6 +1267,21 @@ baseClass = SOTimeCol +class SOTimestampCol(SODateTimeCol): + """ + Necessary to support MySQL's use of TIMESTAMP versus DATETIME types + """ + + def __init__(self, **kw): + SOCol.__init__(self, **kw) + + def _mysqlType(self): + return 'TIMESTAMP' + +class TimestampCol(Col): + baseClass = SOTimestampCol + + try: from decimal import Decimal except ImportError: @@ -1355,6 +1457,7 @@ class PickleCol(BLOBCol): baseClass = SOPickleCol + def popKey(kw, name, default=None): if not kw.has_key(name): return default Modified: home/phd/SQLObject/paramstyles/sqlobject/dbconnection.py =================================================================== --- home/phd/SQLObject/paramstyles/sqlobject/dbconnection.py 2007-03-02 15:42:13 UTC (rev 2376) +++ home/phd/SQLObject/paramstyles/sqlobject/dbconnection.py 2007-03-02 15:48:25 UTC (rev 2377) @@ -555,12 +555,13 @@ self.query(self._SO_createJoinTableSQL(join)) def _SO_createJoinTableSQL(self, join): - return ('CREATE TABLE %s (\n%s %s,\n%s %s\n)' % + return ('CREATE TABLE %s (\n%s %s,\n%s %s\n) %s' % (join.intermediateTable, join.joinColumn, self.joinSQLType(join), join.otherColumn, - self.joinSQLType(join))) + self.joinSQLType(join), + self.getDBOptions(join))) def _SO_dropJoinTable(self, join): self.query("DROP TABLE %s" % join.intermediateTable) @@ -606,10 +607,18 @@ def createTableSQL(self, soClass): constraints = self.createReferenceConstraints(soClass) extraSQL = self.createSQL(soClass) - createSql = ('CREATE TABLE %s (\n%s\n)' % - (soClass.sqlmeta.table, self.createColumns(soClass))) + createSql = ('CREATE TABLE %s (\n%s\n) %s' % + (soClass.sqlmeta.table, self.createColumns(soClass), + self.getDBOptions(soClass))) return createSql, constraints + extraSQL + def getDBOptions(self, soClass): + if soClass.sqlmeta.engineSQL is not None and \ + len(soClass.sqlmeta.engineSQL) > 0: + return "ENGINE = %s" % soClass.sqlmeta.engineSQL + else: + return "" + def createColumns(self, soClass): columnDefs = [self.createIDColumn(soClass)] \ + [self.createColumn(soClass, col) Modified: home/phd/SQLObject/paramstyles/sqlobject/main.py =================================================================== --- home/phd/SQLObject/paramstyles/sqlobject/main.py 2007-03-02 15:42:13 UTC (rev 2376) +++ home/phd/SQLObject/paramstyles/sqlobject/main.py 2007-03-02 15:48:25 UTC (rev 2377) @@ -200,6 +200,8 @@ # Default is false, but we set it to true for the *instance* # when necessary: (bad clever? maybe) expired = False + # Engine SQL; currently used for MySQL engine ("MyISAM", "InnoDB", etc.) + engineSQL = None # This is a mapping from column names to SOCol (or subclass) # instances: @@ -1231,7 +1233,8 @@ default = column.default # If we don't get it, it's an error: - if default is NoDefault: + # If we specified an SQL DEFAULT, then we should use that + if default is NoDefault and column.defaultSQL is not None: raise TypeError, "%s() did not get expected keyword argument %s" % (self.__class__.__name__, column.name) # Otherwise we put it in as though they did pass # that keyword: @@ -1453,6 +1456,7 @@ continue if join.soClass.__name__ > join.otherClass.__name__: continue + join.engineSQL = cls.sqlmeta.engineSQL joins.append(join) return joins _getJoinsToCreate = classmethod(_getJoinsToCreate) Modified: home/phd/SQLObject/paramstyles/sqlobject/mysql/mysqlconnection.py =================================================================== --- home/phd/SQLObject/paramstyles/sqlobject/mysql/mysqlconnection.py 2007-03-02 15:42:13 UTC (rev 2376) +++ home/phd/SQLObject/paramstyles/sqlobject/mysql/mysqlconnection.py 2007-03-02 15:48:25 UTC (rev 2377) @@ -236,6 +236,10 @@ 'varchar': False} elif t.startswith('datetime'): return col.DateTimeCol, {} + elif t.startswith('date'): + return col.DateCol, {} + elif t.startswith('timestamp'): + return col.TimestampCol, {} elif t.startswith('bool'): return col.BoolCol, {} elif t.startswith('tinyblob'): Modified: home/phd/SQLObject/paramstyles/sqlobject/sqlbuilder.py =================================================================== --- home/phd/SQLObject/paramstyles/sqlobject/sqlbuilder.py 2007-03-02 15:42:13 UTC (rev 2376) +++ home/phd/SQLObject/paramstyles/sqlobject/sqlbuilder.py 2007-03-02 15:48:25 UTC (rev 2377) @@ -369,10 +369,14 @@ SQLObjectField.__init__(self, tableName, fieldName, original) self.column = column def __eq__(self, other): + if other is None: + return ISNULL(self) if isinstance(other, unicode): other = other.encode(self.column.dbEncoding) return SQLOp('=', self, other) def __ne__(self, other): + if other is None: + return ISNOTNULL(self) if isinstance(other, unicode): other = other.encode(self.column.dbEncoding) return SQLOp('<>', self, other) |