Author: phd
Date: 2005-01-12 17:39:30 +0000 (Wed, 12 Jan 2005)
New Revision: 537
Modified:
home/phd/SQLObject/inheritance/sqlobject/col.py
home/phd/SQLObject/inheritance/sqlobject/converters.py
home/phd/SQLObject/inheritance/sqlobject/dbconnection.py
home/phd/SQLObject/inheritance/sqlobject/mysql/mysqlconnection.py
home/phd/SQLObject/inheritance/sqlobject/postgres/pgconnection.py
home/phd/SQLObject/inheritance/tests/test_sqlobject.py
Log:
Merged patches from revision 536:
added BLOB column type (for PostgreSQL and MySQL),
BinaryValidator and a test for them.
Modified: home/phd/SQLObject/inheritance/sqlobject/col.py
===================================================================
--- home/phd/SQLObject/inheritance/sqlobject/col.py 2005-01-12 17:36:14 UTC (rev 536)
+++ home/phd/SQLObject/inheritance/sqlobject/col.py 2005-01-12 17:39:30 UTC (rev 537)
@@ -845,6 +845,46 @@
class CurrencyCol(DecimalCol):
baseClass = SOCurrencyCol
+
+class BinaryValidator(validators.Validator):
+ """
+ Validator for binary types.
+
+ We're assuming that the per-database modules provide some form
+ of wrapper type for binary conversion.
+ """
+
+ def fromPython(self, value, state):
+ return state.soObject._connection.createBinary(value)
+
+class SOBLOBCol(SOStringCol):
+ validatorClass = BinaryValidator # can be overriden in descendants
+
+ def __init__(self, **kw):
+ SOStringCol.__init__(self, **kw)
+ self.validator = validators.All.join(self.createValidator(), self.validator)
+
+ def createValidator(self):
+ return self.validatorClass()
+
+ def _mysqlType(self):
+ length = self.length
+ varchar = self.varchar
+ if length >= 2**24:
+ return varchar and "LONGTEXT" or "LONGBLOB"
+ if length >= 2**16:
+ return varchar and "MEDIUMTEXT" or "MEDIUMBLOB"
+ if length >= 2**8:
+ return varchar and "TEXT" or "BLOB"
+ return varchar and "TINYTEXT" or "TINYBLOB"
+
+ def _postgresType(self):
+ return 'BYTEA'
+
+class BLOBCol(StringCol):
+ baseClass = SOBLOBCol
+
+
def popKey(kw, name, default=None):
if not kw.has_key(name):
return default
Modified: home/phd/SQLObject/inheritance/sqlobject/converters.py
===================================================================
--- home/phd/SQLObject/inheritance/sqlobject/converters.py 2005-01-12 17:36:14 UTC (rev 536)
+++ home/phd/SQLObject/inheritance/sqlobject/converters.py 2005-01-12 17:39:30 UTC (rev 537)
@@ -188,4 +188,3 @@
else:
return reprFunc(db)
-
Modified: home/phd/SQLObject/inheritance/sqlobject/dbconnection.py
===================================================================
--- home/phd/SQLObject/inheritance/sqlobject/dbconnection.py 2005-01-12 17:36:14 UTC (rev 536)
+++ home/phd/SQLObject/inheritance/sqlobject/dbconnection.py 2005-01-12 17:39:30 UTC (rev 537)
@@ -375,6 +375,13 @@
# that.
self.query("DELETE FROM %s" % tableName)
+ def createBinary(self, value):
+ """
+ Create a binary object wrapper for the given database.
+ """
+ # Default is Binary() function from the connection driver.
+ return self.module.Binary(value)
+
# The _SO_* series of methods are sorts of "friend" methods
# with SQLObject. They grab values from the SQLObject instances
# or classes freely, but keep the SQLObject class from accessing
Modified: home/phd/SQLObject/inheritance/sqlobject/mysql/mysqlconnection.py
===================================================================
--- home/phd/SQLObject/inheritance/sqlobject/mysql/mysqlconnection.py 2005-01-12 17:36:14 UTC (rev 536)
+++ home/phd/SQLObject/inheritance/sqlobject/mysql/mysqlconnection.py 2005-01-12 17:39:30 UTC (rev 537)
@@ -120,6 +120,21 @@
return col.DateTimeCol, {}
elif t.startswith('bool'):
return col.BoolCol, {}
+ elif t.startswith('tinyblob'):
+ return col.BLOBCol, {"length": 2**8-1}
+ elif t.startswith('tinytext'):
+ return col.BLOBCol, {"length": 2**8-1, "varchar": True}
+ elif t.startswith('blob'):
+ return col.BLOBCol, {"length": 2**16-1}
+ elif t.startswith('text'):
+ return col.BLOBCol, {"length": 2**16-1, "varchar": True}
+ elif t.startswith('mediumblob'):
+ return col.BLOBCol, {"length": 2**24-1}
+ elif t.startswith('mediumtext'):
+ return col.BLOBCol, {"length": 2**24-1, "varchar": True}
+ elif t.startswith('longblob'):
+ return col.BLOBCol, {"length": 2**32}
+ elif t.startswith('longtext'):
+ return col.BLOBCol, {"length": 2**32, "varchar": True}
else:
return col.Col, {}
-
Modified: home/phd/SQLObject/inheritance/sqlobject/postgres/pgconnection.py
===================================================================
--- home/phd/SQLObject/inheritance/sqlobject/postgres/pgconnection.py 2005-01-12 17:36:14 UTC (rev 536)
+++ home/phd/SQLObject/inheritance/sqlobject/postgres/pgconnection.py 2005-01-12 17:39:30 UTC (rev 537)
@@ -2,6 +2,7 @@
import re
from sqlobject import col
from sqlobject import sqlbuilder
+from sqlobject.converters import registerConverter
psycopg = None
pgdb = None
@@ -24,6 +25,10 @@
import psycopg
self.module = psycopg
+ # Register a converter for psycopg Binary type.
+ registerConverter(type(psycopg.Binary('')),
+ PsycoBinaryConverter)
+
if dsn is None:
dsn = []
if db:
@@ -49,7 +54,9 @@
connectionFromURI = classmethod(connectionFromURI)
def _setAutoCommit(self, conn, auto):
- conn.autocommit(auto)
+ # psycopg2 does not have an autocommit method.
+ if hasattr(conn, 'autocommit'):
+ conn.autocommit(auto)
def makeConnection(self):
try:
@@ -57,7 +64,9 @@
except self.module.OperationalError, e:
raise self.module.OperationalError("%s; used connection string %r" % (e, self.dsn))
if self.autoCommit:
- conn.autocommit(1)
+ # psycopg2 does not have an autocommit method.
+ if hasattr(conn, 'autocommit'):
+ conn.autocommit(1)
return conn
def _queryInsertID(self, conn, soInstance, id, names, values):
@@ -199,6 +208,8 @@
return col.DateTimeCol, {}
elif t.startswith('bool'):
return col.BoolCol, {}
+ elif t.startswith('bytea'):
+ return col.BLOBCol, {}
else:
return col.Col, {}
@@ -210,3 +221,9 @@
self._server_version = server_version.split()[1]
return self._server_version
server_version = property(server_version)
+
+
+# Converter for psycopg Binary type.
+def PsycoBinaryConverter(value, db):
+ assert db == 'postgres'
+ return str(value)
Modified: home/phd/SQLObject/inheritance/tests/test_sqlobject.py
===================================================================
--- home/phd/SQLObject/inheritance/tests/test_sqlobject.py 2005-01-12 17:36:14 UTC (rev 536)
+++ home/phd/SQLObject/inheritance/tests/test_sqlobject.py 2005-01-12 17:39:30 UTC (rev 537)
@@ -1339,6 +1339,28 @@
self.assertEqual(str(dt2.col2), now_str)
########################################
+## BLOB columns
+########################################
+
+class Profile(SQLObject):
+ image = BLOBCol(default='emptydata', length=65535)
+
+class BLOBColTest(SQLObjectTest):
+ classes = [Profile]
+
+ def testBLOBCol(self):
+ data = ''.join([chr(x) for x in range(256)])
+
+ prof = Profile()
+ prof.image = data
+ iid = prof.id
+
+ connection().cache.clear()
+
+ prof2 = Profile.get(iid)
+ assert prof2.image == data
+
+########################################
## Run from command-line:
########################################
|