Adobe AIR の SQL 機能を試してみるためにデモアプリを作ってみた

January 30, 2009

AIR には Flex(MXML/ActionScript) と Ajax(HTML/JavaScript) の二つの作成方法があるが、今回は後者を選んだ。

  1. http://help.adobe.com/ja_JP/AIR/1.5/devappshtml/
  2. http://www.adobe.com/jp/devnet/air/ajax/

開発環境は Aptana Studio を使った。
デモアプリはテキストエリアに SQL 文を書いて実行すると、結果が表示されるというもの。SELECT であればテーブルに結果が表示される。テーブルの表示は、Adobe だけに Spry のデータセット機能を使ってみることにした。

Aptana Studio でプロジェクトを作成

  1. File -> New.. -> Project -> Adobe AIR Project を選択する。
  2. プロジェクトに「AirSQLiteTest」を設定する。
  3. Import JavaScript Library までそのまま [Next] をクリック。
  4. Adobe Spry 1.6 にチェックを入れて [Finish] をクリック。

ソースコード

AirSQLiteTest.html が AIR 本体を構成する。ソースコードは以下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
<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 が入っている。
f:id:tilfin:20090130215150p:image
データをインサート。
f:id:tilfin:20090130215151p:image
SELECT でテーブルを表示。
f:id:tilfin:20090130215152p:image

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 を使うと列ソート機能を簡単に追加できる。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<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 の内容が更新される。

tilfin freelance software engineer