Wednesday, May 23, 2007

Generic database proxy that separates the reads and writes based on the caller object

One problem that I faced this days was to pass the proper database connection based on the caller class. The task was to separate the writes and reads to and into the database, to use one database connection for the writes and another for the reads. It wasn't hard but I had to search a little the python documentation . The inspect module can do wonders if you know how to use it. The plan was to get the __class__ of the caller object by getting the previous frame from the caller stack and check the class type.
import inspect


class DatabaseProxy :
__writeConn = None
__readConn = None
__readClass = None
def __init__(self, writeConnection, readConnection, readClass) :
self.__writeConn = writeConnection
self.__readConn = readConnection
self.__readClass = readClass

def getConnection(self):
returnConnection = None
# get the previos frame from the database
frame_dict = inspect.currentframe().f_back.f_locals
try:

if frame_dict.has_key('self') and self.is_write_class(frame_dict['self'], self.__readClass):
# this is the read event
returnConnection = self.__readConn
else:
print 'write'
# this is the write event
returnConnection = self.__writeconn
finally:
del frame_dict
return returnConnection

def is_write_class(self, instance, class_type):

# get the instance's class
instance_class = instance.__class__

# test the instance_class to be the same type as class_type
# or to be a class that extends class_type
if len([object for object in inspect.getmro(instance_class) if (clas is class_type)]) != 0 :
return True

return False

The easy part was that all the read access to the database was done throw one class(QuerySet) or throw a class that extends this QuerySet class.