勉強用にO/R Mapperを自作中

PyDumpFSをwin32対応にするための過程でsqliteを使うことにしたのでそれようのO/R Mapperを勉強がてら作っている。
実用に耐えるものが欲しいならSQLObjectとかSQLAlchemyとか使ったほうが良いんだろうけど、sqlite3モジュールを使うのは初めてだしO/R Mapperの動作の理解のためにも自分で一から書いてみると決めた。

使用するデーターベースエンジンはsqlite3決め打ち。sqliteが対応しない機能は対応しない。

O/R MapperとしてDjangoのそれしか使ったことがないので種類的にはActiveRecordになるのかな。Djangoのものは十分使いやすいので出来る限り構文は似せていきたい。

とりあえず今の段階で書けてるのはここまで:

#!/usr/bin/python
# -*- coding: utf8 -*-

import sqlite3

class DBField:
    """DBのフィールドを表すクラスの基底"""
    def __init__(self, unique=False, null=False, db_index=False, rel=None,
            default=None):
        """初期化"""
        self.unique = unique
        self.null = null
        self.db_index = db_index
        self.rel = rel
        self.default = default
        self.name = None

    def set_name(self,name):
        """フィールド名の設定"""
        self.name = name

    def getsql(self):
        """SQLの生成"""
        if self.name:
            ret = self.name + "text"
            return ret

class DBTable:
    """
    sqlite3決め打ちのO/R Mapper.
    クラス変数
    connection : データベースへのコネクション
    """

    connection = sqlite3.connect(":memory:") #サンプルとしてin-memory

    @classmethod
    def get_conection(cls):
        return cls.conection

    @classmethod
    def set_connection(cls, con):
        cls.connection = con

    @classmethod
    def get_table_sql(cls):
        """SQLの生成"""
        rownames = set(dir(cls)) ^ set(dir(DBTable))
        columns = ""
        for rowname in rownames:
            row = getattr(cls, rowname)
            if hasattr(row, "getsql"):
                columns += row.getsql() + ",\n\t"
        sql = "create table if not exist %s (\n\tid INTEGR PRIMARY KEY," + \
              "\t%s\n);"
        sql = sql%(cls.__name__, columns)
        return sql

    @classmethod
    def create_table(cls):
        """テーブルの生成"""
        cur = cls.get_connection().cursor()
        sql = cls.get_table_sql()
        cur.execute(sql)
        cur.close()
        cls.get_connection().commit()

    def __init__(self, **kw):
        rownames = set(dir(cls)) ^ set(dir(DBTable))
        if "id" in kw.keys():
            rownamess = ", ".join(rownames)
            tablename = self.__class__.__name__
            sql = "select %s from %s where id=?"%(rownamess,tablename)
            cur = self.getconnection().cursor()
            cur.execute(sql, (kw["id"],))
            for rowname, value in zip(rownames, cur.fetchone()):
                setattr(self, rowname, value)
            cur.close()
        elif kw:
            self.id=None
        for rowname in set(rownames) & set(kw.keys()):
            setattr(self, rowname, kw[rowname])