Skip to content
100644 104 lines (77 sloc) 3.85 KB
d1b5cd8 @kgaughan Swap the readme files.
authored Apr 20, 2012
1 =====
2 dbkit
3 =====
5 :Author:
6 Keith Gaughan (
8 :Repo:
12 **dbkit** is intended to be a library to abstract away at least part of
13 the pain involved in dealing with `DB-API 2`_ compatible database
14 drivers.
17 Overview
18 ========
20 *dbkit* is intended to be used in circumstances where it is impractical
21 or overkill to use an ORM such as `SQLObject`_ or `SQLAlchemy`_, but it
22 would be useful to at least abstract away some of the pain involved in
23 dealing with the database.
25 Aims:
27 - Minimise and/or remove the need to pass around connection objects.
28 - Make exception handling easier by removing hardwiring of exception
29 handling code to specific drivers. Unfortunately, not all drivers
30 support exceptions on the connection object, making this particular
31 feature more useful than I'd like!
32 - Easier to use transaction handling.
33 - Easier iteration over resultsets.
35 Non-aims:
37 - Abstraction of SQL statements. The idea is to get rid of the more
38 annoying but necessary boilerplate code involved in dealing with
39 DB-API 2 drivers, not to totally abstract away SQL itself.
41 Open questions:
43 - Connection pooling: implement it, or interoperate with `DBUtils`_?
44 - Query logging: this would be a useful feature. The question is, how
45 should it be implemented?
48 Design Notes
49 ============
51 *dbkit* will make heavy use of `context managers`_. The primary context
52 manager used is a *database context*. This wraps a database connection.
53 Database contexts are not created directly, but are exposed via the
54 module's ``connect()`` function, which will work something like this:
56 ::
58 def connect(module, *args, **kwargs):
59 conn = module.connect(*args, **kwargs)
60 return _DatabaseContext(module, conn)
62 A database context contains little or no actual information that's
63 useful or usable to anything outside of *dbkit* itself; it simply
64 maintains a reference to the driver module and the connection, provides
65 a ``close()`` method for use with *contextlib*'s ``closing()`` context
66 manager, and the magic methods necessary for implementing a context
67 manager. It contains very little intelligence.
69 The module maintains a per-thread stack of database contexts. When you
70 use a database context with the ``with`` statement, that context is
71 pushed onto the stack for the duration. Whichever database context is at
72 the head of the stack defines how the rest of the library works.
74 This method of doing things has several key advantages:
76 - Driver-specific exceptions can be exposed in a uniform manner [1]_.
77 - Modules containing any of the SQL statements you want to run against
78 the database don't need to have a reference to the connection as
79 they're totally decoupled from the connection.
81 Additionally, the module will have a context manager function called
82 ``transaction()`` for enclosing statements to be ran in a single
83 transaction. It will also have functions exposing the DB-API cursor
84 method ``execute()``. Additionally, it will have a number of query
85 helper methods such as ``query_row()`` (returns the first row only),
86 ``query_value()`` (returns the first field of the first row),
87 ``query_column()`` (returns an iterable of the values in the first column
88 of the resultset). Cursors will be abstracted away behind some form of
89 iterable object that will expose whatever functionality is needed.
91 .. [1]
92 While the ideal way would be to expose these using something akin to
93 `descriptors`_, descriptors only work with classes, not modules, to
94 the best of my knowledge. I could very easily be wrong here, and
95 rather hope I am!
98 .. _DB-API 2:
99 .. _SQLObject:
100 .. _SQLAlchemy:
101 .. _DBUtils:
102 .. _context managers:
103 .. _descriptors:
Something went wrong with that request. Please try again.