アーカイブ

Archive for 2013年3月

PythonSQLMapperのMySQLdbへの依存を除去しました

PythonSQLMapperのMySQLdbへの依存を除去しました。
https://github.com/marvelph/PythonSQLMapper

現状、下記の三種類のデータベースモジュールをサポートしています。

また、データベースモジュールには適切に実装されたラッパーも利用できます。
PythonSQLMapperでコネクションプルールが必要な場合は、sqlalchemy.poolの利用を推奨します。
下記のようなコードで、コネクションプルールが有効になります。

import sqlalchemy.pool as pool
import MySQLdb

MySQLdb = pool.manage(MySQLdb)

mapper = SQLMapper.Mapper(driver=MySQLdb, host='127.0.0.1', db='db', user='user', passwd='passwd', charset='utf8')
カテゴリー:開発 タグ: , , ,

PythonSQLMapperを公開しました

iBATIS風味のSQLマッピング、PythonSQLMapperをリリースしました。
https://github.com/marvelph/PythonSQLMapper

現在メインのお仕事ではバックエンド「も」担当しているのですが、データベースのアクセスにSQLAlchemyを使っています。
迷った末の選定でしたが、正直失敗したと思っています。

例えばアトミックな更新を行いたいとすると、1エンティティをロック付きでフェッチして、値を変更してコミットします。
一定条件の複数レコードを同時更新したい場合は、複数エンティティをロック付きでフェッチして、ループで値を変更してコミットです。

生成したばかりのエンティティのオートインクリメント・プライムキーを他のエンティティに保存しようとすると、一旦コミットするか再フェッチしないと値が手に入りません。

複雑なクエリ条件でエンティティを引っ張ろうとすると、フィルタをメソッドのチェーンで表現する必要があるのですが、どうみてもSQLよりも難解になります。
その上、pythonのインタープリタでしか試せません。

バッチ処理などでループ中で利用すると、マネージドエンティティが激増して、猛烈に重くなったりします。

これらはO/Rマッピング全般の傾向ではあると思うんですが、コードが複雑になるだけで良い事が無いというのが実感です。
みんな、そんなにSQLが嫌いなのかと。

iBATISのようなツールも探しまわったのですが、良い物は見つかりませんでした。
そこでCocoaSQLMapperのpythonへの移植を考えていたのですが、新サービス立ち上げのチャンスが回って来たので、土日をつぶして「ガッ」と実装しました。
その後実際に新サービスの開発に使っているのですが、良い感じに使えているので公開する事にしました。

移植と言っても、重要な部分に差異があります。
まずCocoaSQLMapperはSQLite専用であるため、テーブルのフィールド側には「型」がありません。一方、Objective-Cのクラスのプロパティには「型」があります。
そのため、オブジェクトをパラメータとし渡す場合も、クラスを結果セットの入れ物として指定する場合も、Objective-C側の型情報を使ってSQLiteにアクセスする仕組みでした。

一方PythonSQLMapperですが、現状ターゲットにしているMySQLはテーブルのフィールドに型を持ちます。
またpythonのクラスの属性の型は変化できますし、結果セットの受け取り時などに生成前であれば、属性の名前も判りません。
そのため、型情報はデータベース側を当てにする事にしました。
この考え方はパラメータとしてオブジェクトを渡す場合は問題が無いのですが、リザルトタイプにクラスを指定して結果セットを受け取る場合が問題になります。
そこで、「結果セットとクラスのコンストラクタが整合すれば良い」という事にしました。

これは次のようなSQLの結果を、

SELECT name, age FROM person;

こんなクラスであれば受け取れるという事です。

class Person(object):
    def __init__(self, name, age):
        ...

いずれにしても、データベーススキーマを解析したりして、マッピングルールを何らかの方法で与えるという事はしないという考え方は変えていません。
エンティティに対する細工も不要で、特別な親クラスなども導入していません。
マネージドエンティティという考え方を、避けているという事です。

また使い勝手を考えて、パラメータにはdictも利用可能としました。
さらにリザルトタイプは省略が可能で、匿名クラスのオブジェクトに結果セットを属性として取り付けて返します。

dictと匿名クラスだけで使う事も可能という事になりますが、エンティティクラスにはメソッドが使えますから、多くのユースケースでは従来の使い方が有効だと思います。

当面の開発目標としては、次のような事を考えています。

  • PostgreSQLのサポート
  • コネクションプールの実装
  • Flask Extensionの提供

とりあえず、コネクションプールが最優先です。

カテゴリー:開発 タグ: , ,