Friday, October 17, 2008

The turbogears database component

The TurboGears database component is a Python module which allows the framework to connect to some database specified in the project configuration. I'd like to explore some interesting features and implementation details of this component. No particular reason, I just find it interesting since I've built several projects using this framework. The source for this component can be found here (I'm pointing to the 1.0.7 tag because it is the most recent stable release).

The responsibility of this component is to provide database access to the TurboGears project that is being developed. This includes providing support for both SQLAlchemy and SQLObject. The database TurboGears component implements a conditional declaration of various SQLAlchemy and SQLObject classes and functions depending on which one is enabled for the project. This is done by attempting to import both packages. If both the SQLAlchemy and SQLObject packages are installed and importable, all declarations are executed as illustrated below.



I'm going to focus on SQLObject TurboGears support here because the current support for SQLObject is stronger than SQLAlchemy support. There are two classes defined by the TurboGears database component that help carry out SQLObject support. These classes are AutoConnectHub and PackageHub and are illustrated below.



Typically, in a TurboGears project, you'll have several database abstractions using SQLObject. In simple projects, these abstractions are store in model.py. However, you may have enough abstractions to justify spanning them across several modules. Each one of these modules defines a package hub to connect to a database. A package hub is a simple variable that states the name of the project package. Since this is a TurboGears project, it will module likely contain a configuration file which specifies a database connection string. Although, there are other ways to do this.

When TurboGears encounters a package hub, a new PackageHub instance is created. This instance then creates a AutoConnectHub instance by calling the set_hub() method. This AutoConnectHub instance that is now a member of the PackageHub instance is the bridge between your TurboGears project and the database connection.

However, for some reason, the set_hub() method is not invoked in the constructor of the PackageHub instance. It is invoked for all access methods (if needed). Perhaps there is good reasoning for this design but if it is possible, I wonder if it would make more sense to have this instance created in the constructor. If this were the case, it would eliminate the need for checking if the AutoConnectHub instance exists for every other method of the PackageHub instance.

One last improvement I think would make sense for this component is to classify some of the functions defined here. For example, there are several functions that are either SQLObject or SQLAlchemy specific. I think these should at least be class methods. There could be two classes here called SODBTools and SADBTools. The ORM-specific functions could then be moved to these classes accordingly. This is just a minor improvement I feel would have major design perks.