Firefox拡張入門第6回(Database.jsmライブラリ)

マッチFOXに同梱しているDatabase.jsmライブラリは、SQLite用のORマッパです。tomblooが開発しました。

使用例

// Bookmarkモデルを生成。
var Bookmark = Entity({
    name : 'bookmarks',
    fields : {
        id           : 'INTEGER PRIMARY KEY',
        url          : 'TEXT UNIQUE NOT NULL',
        title        : 'TEXT',
        date         : 'TIMESTAMP NOT NULL',
        last_visited : 'TIMESTAMP',
        comment      : 'TEXT',
    }
})
// データベースのファイル("ProfD/hogehoge/hogehoge.sqlite")を取得。
function dbFile() {
  var pd = DirectoryService.get("ProfD", Ci.nsIFile);
  pd.append("hogehoge");
  if (!pd.exists() || !pd.isDirectory()) {
    pd.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
  }
  pd.append("hogehoge.sqlite");
  return pd;
}
// Databaseインスタンスを生成
var db = new Database(dbFile());
// BookmarkモデルにDatabaseインスタンスをセット
Bookmark.db = db;
// Bookmarkモデルを初期化
Bookmark.initialize();
...
//Bookmark.insert     作成、
//Bookmark.find       検索、
//Bookmark.update     更新、
//Bookmark.deleteById 削除、などなど
...
// データベースを閉じる
db.close();

TIMESTAMP型、LIST型

TIMESTAMP型を指定すると、JavascriptのDateオブジェクトを透過的に読み書きできます。
(SQLiteには日付型がないので実際にはINTEGER型で"Date.getTime()の値"をデータベースに保存しています)
同様に、LIST型を指定すると、JavascriptのArrayオブジェクトを透過的に読み書きできます。
(実際にはTEXT型で"Arrayから作ったCSV的な文字列"を保存しています。)
便利。

findByFoo, findByFooAndBar, countByFoo、countByFooAndBar,

モデルのFooやBarの値で、検索やカウントができます。これは__noSuchMethod__をフックして実現してます。
すごい。

リファレンスマニュアル

Databaseクラス
function: Database aFile
Databaseのインスタンスを生成します。
aFile SQLiteのデータベースファイルの場所。nsIFlieのインスタンス。


getter: version
データベースのバージョンを取得します。
PRAGMAのuser_versionに相当します(schema_versionではない)。


setter: version
データベースのバージョンを設定します。


function: getPragma aName
PRAGMAの値を取得します。
aName PRAGMAの名前。文字列。


function: setPragma aName aVal
PRAGMAの値を設定します。
aName PRAGMAの名前。文字列。
aVal  設定する値。文字列。


function: createStatement aSQL
ステートメントを生成します。mozIStorageStatementWrapperを返します。
aSQL  SQL文。文字列。


function: bindParams aWrapper aParams
ステートメントにパラメーターをバインドします。バインドしたステートメントをmozIStorageStatementWrapperで返します。
aWrapper ステートメント。mozIStorageStatementWrapperのインスタンス。
aParams  パラメーター。
Objectの場合、名前付きパラメーターとみなします。
Arrayの場合、出現順に先頭からバインドします。
単値の場合、先頭のパラメーターにバインドします。
nullの場合、処理を行いません。


function: getParamNames aWrapper
ステートメント内に含まれる名前付きパラメーターのリストを、配列で返します。
aWrapper ステートメント。mozIStorageStatementWrapperのインスタンス。


function: getColumnNames aStatement
ステートメントの列名のリストを、配列で返します。
aStatement ステートメント。mozIStorageStatementかmozIStorageStatementWrapperのインスタンス。


function: getRow aRow aColumnNames
テーブル行をオブジェクトに変換したものを返します。
aRow テーブル行。mozIStorageStatementRowのインスタンス。
aColumnNames 列名のリスト。配列。


function: execute aSQL aParams
SQLを実行します。DDL/DML共に利用できます。
aSQL    SQL文。文字列かmozIStorageStatementWrapper。
aParams SQL文のパラメータ。オブジェクトか配列か文字列。bindParamsと同じです。


function: transaction aProc
トランザクション内で処理を実行します。
パフォーマンスを考慮する必要のある一括追加部分などで用います。
例外が発生した場合は、トランザクションがロールバックします。
それ以外は、自動的にコミットします。
既にトランザクションが始まっていたら新たなトランザクションは開始しません。
aProc   実行する処理。引数なしの関数。


function: beginTransaction
トランザクションを開始します。
トランザクションが既に開始していた場合でも、例外を発生しません。


function: commitTransaction
トランザクションをコミットします。
トランザクションが開始していない場合でも、例外を発生しません。


function: rollbackTransaction
トランザクションをロールバックします。
トランザクションが開始していない場合でも、例外を発生しません。


function: throwException aError
データベースの例外を解釈し再発生します。
aError データベースの例外。


function: close
データベースを閉じます。
閉じないと、ファイルがロックし削除できません。


function: tableExists aName
テーブルが存在するかを確認します。
aName テーブル名。文字列。


function: vacuum
データベースの無駄な領域を除去します。
Modelクラス
function: save
Modelをデータベースに保存します。初回はinsert、次からはupdateで保存します。
特にinsert時には、Modelにidを割り振ります。


function: remove
Modelをデータベースから削除します。内部的にはdeleteByIdです。


property: definitions
ModelのEntityの定義を示したオブジェクトです。


function: initialize
テーブルをCREATEします。内部的には以下のSQLを実行します。
CREATE TABLE IF NOT EXISTS {def.name} (
  {def.fields.join(', ')}
)


function: deinitialize
テーブルをDROPします。内部的には以下のSQLを実行します。
DROP TABLE {def.name}


function: insert
ModelをINSERTします。内部的には以下のSQLを実行します。
INSERT INTO {def.name} (
  {fields.join(', ')}
) VALUES (
  {params.join(', ')}
)


function: update
ModelをUPDATEします。内部的には以下のSQLを実行します。
UPDATE {def.name}
  SET {fields}
  WHERE id = :id


function: deleteById aId
ModelをIDでDELETEします。内部的には以下のSQLを実行します。
aId ModelのID。整数。
DELETE FROM {def.name}
  WHERE id = :id


function: deleteAll
Modelを全てDELETEします。内部的には以下のSQLを実行します。
DELETE FROM {def.name}


function: countAll
Modelの数をカウントします。内部的には以下のSQLを実行します。
SELECT count(*) AS count
  FROM {def.name}


function: findAll
Modelを全て検索します。内部的には以下のSQLを実行します。
SELECT *
  FROM {def.name}


function: findFirst aParams
ModelをパラメータでLIMIT 1で検索します。内部的には以下のSQLを実行します。
aParams パラメータ。Database.executeと同様。
SELECT *
  FROM {def.name}
  ...aParamsの内容...
  LIMIT 1 OFFSET 0


function: find aSQL aParams
Modelをパラメータで検索します。
aSQL    オブジェクトかmozIStorageStatementWrapperのインスタンス。
aParams パラメータ。Database.executeと同様。
aParamsがnullで、aSQLがオブジェクトで、aSQL.whereが文字列のとき、内部的には以下のSQLを実行します。
SELECT *
  FROM {def.name}
  WHERE {sql.where}
aParamsがnullで、aSQLがオブジェクトのとき、内部的には以下のSQLを実行します。
SELECT *
  FROM {def.name}
それ以外のとき、内部的にはDatabase.executeを実行します。
Model.db.execute(sql, params).map(Model.rowToObject);


function: findByFoo aFoo
function: findByFooAndBarAnd... aFoo aBar ...
ModelをFooやBarの値で検索します。__noSuchMethod__をフックして実現しています。
内部的には以下のSQLを実行します。
SELECT *
  FROM {def.name}
  WHERE foo = aFoo and bar = aBar and ...


function: countByFoo aFoo
function: countByFooAndBar... aFoo aBar ...
ModelをFooやBarの値でカウントします。__noSuchMethod__をフックして実現しています。
内部的には以下のSQLを実行します。
SELECT count(id) AS count
  FROM {def.name}
  WHERE foo = aFoo and bar = aBar and ...


function: rowToObject aObject
オブジェクトからModelのインスタンスを生成します。ただし、saveのときupdateが動きます。
aObject Entityの定義に沿った内容のオブジェクト。
Entityクラス
function: Entity aDefinition
エンティティ定義に沿ったModelのインスタンスを生成します。
aDefinition エンティティ定義を示したオブジェクト。
(nameプロパティでテーブル名、fieldsプロパティで、エンティティ名と型の対応。)
例.
var Bookmark = Entity({
    name : 'bookmarks',
    fields : {
        id           : 'INTEGER PRIMARY KEY',
        url          : 'TEXT UNIQUE NOT NULL',
        title        : 'TEXT',
        date         : 'TIMESTAMP NOT NULL',
        last_visited : 'TIMESTAMP',
        comment      : 'TEXT',
    }
})


function: createWhereClause aFields
WHERE節を示した文字列を作ります。
aFields WHEREするパラメータ名をリストにした配列。


function: createInitializeSQL aDefinition
CREATE TABLE IF NOT EXISTS...文を示した文字列を作ります。
aDefinition エンティティ定義を示したオブジェクト。Entityのものと同様。


function: createInsertSQL aDefinition
INSERT INTO...文を示した文字列を作ります。
aDefinition エンティティ定義を示したオブジェクト。Entityのものと同様。


function: createUpdateSQL aDefinition
UPDATE ... 文を示した文字列を作ります。
aDefinition エンティティ定義を示したオブジェクト。Entityのものと同様。


function: compactSQL aSQL
SQL文から不要な空白などを取り除き短く整形したSQL文の文字列を作ります。
表記のぶれを無くし、解析後の文のキャッシュヒットを増やす目的があります。
aSQL SQL文の文字列。