Personal tools

simplemapper.py

Click here to get the file

Size 5.1 kB - File type text/python-source

File contents

#!/usr/bin/env python
# coding: utf-8
import sqlite3

class BaseMapper(object):
    """
    シンプルな機能を持つO/Rマッパーのベースクラス
    """
    rows=()

    connection=sqlite3.connect(':memory:')

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

    @classmethod
    def getconnection(cls):
        return cls.connection

    def __init__(self, **kws):
        """
        クラスを初期化する
        idを引数に渡された場合は,既存データをSELECTして返す
        その他のキーワード引数を渡された場合は,データをDBにInsertする
        """
        if 'id' in kws.keys():
            rownames=[v[0] for v in self.__class__.rows]
            rownamestr=', '.join(rownames)
            cn=self.__class__.__name__
            sql="""SELECT %s FROM %s WHERE id=?"""%(rownamestr, cn)
            cur=self.getconnection().cursor()
            cur.execute(sql, (kws['id'],))
            for rowname, v in zip(rownames, cur.fetchone()):
                setattr(self, rowname, v)
            self.id=kws['id']
            cur.close()
        elif kws:
            self.id=self.insert(**kws)
            rownames=[v[0] for v in self.__class__.rows]
            for k in kws.keys():
                if k in rownames:
                    setattr(self, k, kws[k])

    def __repr__(self):
        """
        オブジェクトの文字列表記を定義
        """
        rep=str(self.__class__.__name__)+':'
        rownames=[v[0] for v in self.__class__.rows]
        rep+=', '.join(["%s=%s"%(x, repr(getattr(self, x))) for x in rownames])
        return "<%s>"%rep

    def update(self):
        """
        データを更新する
        """
        sql="""UPDATE %s SET %s WHERE id=?"""
        rownames=[v[0] for v in self.__class__.rows]
        holders=', '.join(['%s=?'%v for v in rownames])
        sql=sql%(self.__class__.__name__, holders)
        values=[getattr(self, n) for n in rownames]
        values.append(self.id)
        cur=self.getconnection().cursor()
        cur.execute(sql, values)
        self.getconnection().commit()
        cur.close()

    @classmethod
    def insert(cls, **kws):
        """
        データを追加し,IDを返す
        """
        sql="""INSERT INTO %s(%s) VALUES(%s)"""
        rownames=', '.join([v[0] for v in cls.rows])
        holders=', '.join(['?' for v in cls.rows])
        sql=sql%(cls.__name__,rownames, holders)
        values=[kws[v[0]] for v in cls.rows]
        cur=cls.getconnection().cursor()
        cur.execute(sql, values)
        cur.execute("SELECT max(id) FROM %s"%cls.__name__)
        newid=cur.fetchone()[0]
        cls.getconnection().commit()
        cur.close()
        return newid

    where_conditions={
        '_gt':'>', '_lt':'<',
        '_gte':'>=', '_lte':'<=',
        '_like':'LIKE' }

    @classmethod
    def select(cls, **kws):
        """
        テーブルからデータをSELECTする
        """
        order=''
        if "order_by" in kws.keys():
            order=" ORDER BY "+kws['order_by']
            del kws['order_by']
        where=[]
        values=[]
        for key in kws.keys():
            ct='='
            kwkeys=cls.where_conditions.keys()
            for ckey in kwkeys:
                if key.endswith(ckey):
                    ct=cls.where_conditions[ckey]
                    kws[key.replace(ckey, '')]=kws[key]
                    del kws[key]
                    key=key.replace(ckey, '')
                    break
            where.append(' '.join((key, ct, '? ')))
            values.append(kws[key])
        wherestr="AND ".join(where)
        sql="SELECT id FROM "+cls.__name__
        if wherestr:
            sql+=" WHERE "+wherestr
        sql+=order
        cur=cls.getconnection().cursor()
        cur.execute(sql, values)
        for item in cur.fetchall():
            ins= cls(id=item[0])
            yield ins
        cur.close()

    @classmethod
    def createtable(cls, ignore_error=False):
        """
        定義に基づいてテーブルを作る
        """
        sql="""CREATE TABLE %s (
               id INTEGER PRIMARY KEY, %s );"""
        columns=', '.join(["%s %s"%(k, v) for k, v in cls.rows])
        sql=sql%(cls.__name__, columns)
        cur=cls.getconnection().cursor()
        try:
            cur.execute(sql)
        except Exception, e:
            if not ignore_error:
                raise e
        cur.close()
        cls.getconnection().commit()


def main():
    class TestMapper(BaseMapper):
        rows=(('foo', 'int'), ('bar', 'text'))

    TestMapper.createtable(True)
    for i in range(10):
        TestMapper(foo=1, bar='abcde')
    ins= TestMapper(id=10)
    ins.foo+=1
    ins.update()
    print ins.foo, ins.bar
    print [x for x in TestMapper.select()]
    print [x for x in TestMapper.select(foo=1, bar_gte='code')]
    print [x for x in TestMapper.select(bar_lte='code',order_by='foo')]
    d=TestMapper(foo=5, bar='abcdefg')
    print d, d.id
    cur=BaseMapper.connection.cursor()


if __name__=='__main__':
    """
    import pdb
    pdb.run('main()')
    """
    main()
    
Pythonな求人
r = urlopen("http://www.webcore.co.jp/recruit")
About this blog
■Author
atsこと柴田淳です。Atsushiはガイジンにうまく発音して頂けないので,これからはJunというペンネームで行こうと思っていましたがあんまり使ってません。
Webcore株式会社 代表取締役
■TRIVIAL TECHNOLOGIES 2.0
トリビアル・テクノロジー 2.0,「トリテク 2.0」と呼んでください。
Blog(ブログ)サイトです。Plone上で動く,オープンソースのBlog Product - COREBlog2を使っています。
 
最近書いた本,Mook
みんなのPython Webアプリ編
Pythonの基礎から,Webアプリやフレームワークの仕組みまで,つまることなく一気に学べる書籍です。「みんなのPython」と一緒に読んでください:-)。
みんなのPython
Pythonの入門書です。基本的なことから分かりやすく解説するよう勤めました。Pythonをはじめたいと思っている人,JavaやC++,PerlやRubyを学ぼうと思って躓いてしまった人はぜひ読んで下さい。
 

Powered by Plone, the Open Source Content Management System