Adobe AIR の SQL 機能を試してみるためにデモアプリを作ってみた
AIR には Flex(MXML/ActionScript) と Ajax(HTML/JavaScript) の二つの作成方法があるが、今回は後者を選んだ。
開発環境は Aptana Studio を使った。
デモアプリはテキストエリアに SQL 文を書いて実行すると、結果が表示されるというもの。SELECT であればテーブルに結果が表示される。テーブルの表示は、Adobe だけに Spry のデータセット機能を使ってみることにした。
Aptana Studio でプロジェクトを作成
- File -> New.. -> Project -> Adobe AIR Project を選択する。
- プロジェクトに「AirSQLiteTest」を設定する。
- Import JavaScript Library までそのまま [Next] をクリック。
- Adobe Spry 1.6 にチェックを入れて [Finish] をクリック。
ソースコード
AirSQLiteTest.html が AIR 本体を構成する。ソースコードは以下。
<html> <head> <title>AIR SQL Test</title> <script type="text/javascript" src="lib/air/AIRAliases.js"></script> <script type="text/javascript" src="lib/spry/includes/SpryData.js"></script> <style type="text/css"> div { margin:16px; } #textSql { width:100%; height:120px; } #textResult { width:100%; height:60px; } p { margin:4px 0; } table th, table td { border:1px solid gray; } th, td { padding:8px } th { cursor: default; } </style> <script type="text/javascript"> /** * AIR SQL を操作する DBClient * * @param {String} dbname データベース名 * @param {Function} closure クロージャ(省略可能) * 指定された場合はクロージャ引数にこのオブジェクトが渡り、 * 処理終了とともに接続が閉じられる。 */ function DBClient(dbname, closure){ if (closure) { var dbc = new DBClient(dbname); closure(dbc); dbc.close(); } else { this.open(dbname); } } DBClient.prototype = { /* * データベースを開く * * @param {String} dbname データベース名 */ open: function(dbname){ try { this.conn = new air.SQLConnection(); var dbfile = null; if (dbname) { dbfile = air.File.applicationStorageDirectory.resolvePath(dbname + ".db"); } this.conn.open(dbfile); } catch (error) { statustext.innerText = "Error opening database"; air.trace("error.message:", error.message); air.trace("error.details:", error.details); return; } }, /* * データベース接続を開じる */ close: function(){ if (this.conn) { this.conn.close(); this.conn = null; } }, /* * SQL文を実行する * * @param {String} sqltext SQL文 * @param {Function} cbsuccess クエリ成功時のコールバック関数 * @param {Function} cberror クエリ失敗時のコールバック関数 */ execute: function(sqltext, cbsuccess, cberror){ try { var stmt = new air.SQLStatement(); stmt.sqlConnection = this.conn; stmt.text = sqltext; stmt.execute(); cbsuccess(stmt.getResult()); return true; } catch (error) { if (cberror) cberror(error); return false; } } } </script> </head> <body> <div> <div> <p>SQL Statement:</p> <textarea id="textSql">CREATE TABLE IF NOT EXISTS sample ( id INTEGER PRIMARY KEY AUTOINCREMENT, content TEXT, score INTEGER )</textarea> </div> <div> <button id="buttonExecute">execute SQL</button> </div> <div> <p>Query Result:</p> <textarea id="textResult"></textarea> </div> <div> <table spry:region="Results"> <caption>Select Result</caption> <thead> <tr> <th spry:sort="{ds_RowNumberPlus1}">#</th> <th spry:sort="id">id</th> <th spry:sort="content">content</th> <th spry:sort="score">score</th> </tr> </thead> <tbody spry:repeatchildren="Results"> <tr> <td>{ds_RowNumberPlus1}</td><td>{id}</td><td>{content}</td><td>{score}</td> </tr> </tbody> </table> </div> </div> <script type="text/javascript"><!-- function $(id) { return document.getElementById(id) }; var Results = new Spry.Data.DataSet(); $("buttonExecute").onclick = function(e){ // SQLを実行する DBClient("sampledb", function(dbh){ dbh.execute($("textSql").value, function(result){ // 成功 $("textResult").value = "QUERY OK, " + result.rowsAffected + " rows affected"; Results.data = result.data ? result.data : {}; Results.loadData(); }, function(error){ // 失敗 $("textResult").value = error.message + "\n" + error.detailID + ": " + error.details; }); }); }; //--> </script> </body> </html>
試してみる
プロジェクトを選択した状態で、Run -> Run...
デフォルトで SQL 文には CREATE TABLE が入っている。
データをインサート。
SELECT でテーブルを表示。
SQL についての解説
AIR SQL では非同期処理も可能だが、SQL 操作をここでは同期処理している。
SQL 機能に用意された SQLConnection や SQLStatement をそのまま使ってもよいのだが、ラッパーを作った方が早かったので DBClient 定義した。
AIR SQL は SQLite3 がベースらしいのだが、CURRENT_TIMESTAMP は認識されないようだった。
参考)
Spry についての解説
今回使用した、Spry の動的な領域はまずデータセットを作成する。
var Results = new Spry.Data.DataSet();
それにマッピングするテーブルを HTML で定義しておく。spry:region にさきほどのオブジェクト名を入れる。この場合は書くテーブルの行となるのは、その Results の各配列要素のため繰り返し項目の親となる tbody にも spry:repeatchildren="Results" を定義する。
あとは、各列名を {column} として定義しておけばいい。spry:sort を使うと列ソート機能を簡単に追加できる。
<table spry:region="Results"> <caption>Select Result</caption> <thead> <tr> <th spry:sort="{ds_RowNumberPlus1}">#</th> <th spry:sort="id">id</th> <th spry:sort="content">content</th> <th spry:sort="score">score</th> </tr> </thead> <tbody spry:repeatchildren="Results"> <tr> <td>{ds_RowNumberPlus1}</td><td>{id}</td><td>{content}</td><td>{score}</td> </tr> </tbody> </table>
あとは、SQL の実行結果の data プロパティの値を Results.data にセットして、Results.loadData() を呼んでやれば自動的に table の内容が更新される。