JSDB日本ユーザー会2007年05月12日 03時56分00秒

リファラ辿ったら、JSDB日本ユーザー会が立ち上がってた。びっくり。

今日の今日立ち上がったばかりみたいだし、ひょっとしたらコメントくれたhiroさんかな。

うあ、このブログにリンク貼ってくださってるよ。ありがたや。

dara-j的には、だいたいがヘソが曲がった使い方ばかりしているのであまりお力になれないかも知れませんが、関係者の方々はぜひがんばってください。陰ながら応援してます。

JSDBでデータベースを触る2007年05月09日 02時58分10秒

このままじゃ使いづらいってば。

本家のCookbookを見て、ちょっと試してみたところ、個人的にちょっと扱いづらかったのでいきなりTableクラスとRecordクラスを拡張することから始めてみた。

使いづらかった部分というのは、

  • Tableクラスで列情報にアクセスするのにtitleメソッド(カラム名の取得)、typeメソッド(型情報の取得)と分かれている
  • RecordクラスのコンストラクタがStringベースでちょっと面倒だった
といったあたりで、また行の抽出でループ処理が必須になるのでEnumerableにしてみることにした。以下はその拡張コード。prototype.jsが必要。
// Tableクラスの拡張
Object.extend( Table.prototype, {
	_each : function(iterator) {
		for(var i = 1; i <= this.count; i++) {
			iterator( this.getRow( i ) );
		}
	},
	// カラム名を配列で取得する
	colNames : function() {
		return this.getColumnInfo().map( function( col ) { return col.name; } );
	},
	// カラム情報の配列を取得する。orderは列位置、nameはカラム名、typeは型情報
	getColumnInfo : function() {
		var result = [];
		for(var i = 1; i <= this.colCount; i++) {
			result.push( {
				order : i,
				name : this.title( i ),
				type : this.type( i - 1 ).toArray().join("")
			} );
		}
		return result;
	}
} );
Object.extend( Table.prototype, Enumerable );

// Recordクラスの拡張
Object.extend( Record.prototype, {
	// 名前:値形式の単純なオブジェクトを返す
	toHash : function() {
		var result = {};
		for(var i = 0; i < this.count; i++) {
			result[ this.name( i ) ] = this.value( i );
		}
		return result;
	}
} );

// オブジェクトをパラメータにとってRecordを作成するファクトリメソッド
Record.fromHash = function(hash) {
	var src = $H( hash ).map( function(entry) {
		return [ entry.key, "=", entry.value == null ? "NULL" : entry.value ].join("");
	} ).join(",");
	return new Record( src );
}

じゃあ使ってみるか

このような拡張をした上で、データベースへアクセスしてみる。ここではmdbを使用してみた。

適当なmdbファイルを「test_db」としてODBCデータソース(ユーザDSNまたはシステムDSN)に登録しておいて、以下のようなコードでテーブルの作成、行の挿入、行の取得を行う。

js>var odbc = new ODBC("DSN=test_db")
js>odbc.exec("create table t_test ( id integer primary key, name text )")
true
js>var updater = new Table("odbc://test_db/t_test");
js>updater.add( Record.fromHash( { id : 1, name : "test 1" } ) )
-1
js>updater.add( Record.fromHash( { id : 2, name : "test 2" } ) )
-1
js>var table = odbc.query( "select * from t_test" );
js>table.each( function(record) {
2:      writeln( $H( record.toHash() ).inspect() )
3: } )
#<Hash:{'id': '1', 'name': 'test 1'}>
#<Hash:{'id': '2', 'name': 'test 2'}>

js>table.close()
true
js>updater.close()
true
js>odbc.close()
true
js>

まずは、「new ODBC()」でODBCオブジェクトを初期化する。この例ではmdbを使用したためユーザID・パスワードはないが、通常のDBMSの場合は「UID=ユーザID;PWD=パスワード」を追加する必要がある。

次のODBC#execでテスト用のテーブルを作成している。insert/delete/updateの場合もexecメソッドで実行する。

次の変数「updater」は今作成したテーブルの更新に使用するTableオブジェクト。この後に説明するODBC#queryメソッドの戻りもTableオブジェクトだが、それは読み取り専用らしく、更新する場合はこの例のようにURIをパラメータにしてTableをnewする必要がある。

その後はTable#addメソッドで行を新規に追加しているが、追加する行の初期化には、このエントリで拡張したRecrd::fromHashメソッドを使用している。このような拡張をしない場合は、
updater.add( new Record( "id=1,name=test 1" ) );
のようになる。

次に、ODBC#queryを使用してupdaterとは別にTableを取得している。この「table」は読み取り専用でaddメソッドは失敗する。

取得したtableをeachで列挙し、Record#toHashをHashにした上でinspectしてダンプしている。

最後に使用したTableとODBCをcloseして終了。

問題がちらほら

上記のサンプル程度では特に問題がないが、とりあえず目に付いた問題点をば。

  • Table#typeの戻り値の型がドキュメントと違う。type(1)のように引数を1つだけの場合はStringが帰ってくるはずだが実際は要素が1つのArrayが帰ってくる。
  • Table#typeで型情報は取得できるが、Record#valueで実際に取得する値は常にString
  • Table#addでレコードを追加すると、日本語のデータが化ける。insertクエリを使用した場合は化けない
  • Table#close、ODBC#closeを実行しても実際は接続が残っているぽい。mdbやSQLiteはjsdbを終了するまでファイル自体がロックされている
といった感じ。まあ、Table#typeはたいした話ではないが、日本語のデータが通らないとなるとこのオブジェクトモデルを利用したデータアクセスはほぼ使えないと思うのだが。

オブジェクトモデルが微妙に使いづらかったり、同じ情報を示すプロパティが複数あったり、あるオブジェクトの生成方法が複数あったり、設計も実装もちょっと中途半端な感じがする。特にODBC#queryで生成したTableでデータを更新できないのはなんだかなぁと思う。

おまけで、TableにRecordを生成するファクトリメソッド(Table#createRow、とかね)がほしかったなぁ。そのほうが新しいレコード挿入するのに勝手がよいんだけど。

JSDB日本語リファレンス2007年05月07日 13時47分06秒

JSDBがらみでちょろちょろ検索かけてたら、シンテック株式会社というCAD製品なんかやっている企業さんに行き着いた。

自社製品のオンラインマニュアルに、JSDBリファレンスの日本語訳版も加えておられる模様。

Cosmos Referenceへ飛ぶと、「分類」フレームに「JSDBライブラリー」のリンクがある。

ざっと見たところ、手持ちのリファレンス(4/27版に付属)のものと若干内容が異なる部分があるみたいなので、バージョンが違うものかもしれないが、dara-jみたいに「英語読むのマンドクセェ」ってな方には助けになるかも。

JSDBのhttp取得・おかわり2007年05月07日 13時14分13秒

しつこいなぁ > 自分

いいかげん誰も興味がないだろうが、JSDBのhttp取得をさらに調べた。

Keep-Aliveかい!?

ローカルホストに環境変数を返すasp設置して試したら、リクエストヘッダに「Connection」の指定がなかった。

ということは、Connection: keep-alive扱いですか。そうですか。

んじゃ、Connection: closeを送りつけたらどうなるかを試そうと思ったが、Streamコンストラクタにhttp://渡した場合はリクエストヘッダのカスタマイズができないぽい。リファレンス確認したら

To simply open a socket to the server and send your own headers, use a = new Stream('net://server.com:80/'); a.writeln('POST /file.cgi/ HTTP/1.1\r\n').
とか書いてあるので以下のようなコードを実行。
js>var stream = new Stream("net://localhost:80")
js>stream.writeln( "GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n" )
52
js>stream.canRead
true
js>writeln( stream.read() )
HTTP/1.1 200 OK
Server: Microsoft-IIS/5.1
Date: Mon, 07 May 2007 04:25:46 GMT
X-Powered-By: ASP.NET
Connection: close
Content-Length: 11519
Content-Type: text/html
Set-Cookie: myCounter=1; path=/
Set-Cookie: ASPSESSIONIDASBRTBDS=PJEHLAFDDOAGKOAIHFNJHMNI; path=/
Cache-control: private
:
(略)
返ってくるじゃん!!

結局

以前のエントリ(これこれ)でハングするだなんだぶつぶついっていたのは、HTTPキープアライブのタイムアウト待ち状態だったということのようだ。実際、IISの設定でHTTPキープアライブのタイムアウトを10秒程度にしたら、待ち時間がそのくらいで制御が帰ってきた。うあ~、このくらいちゃんと調べろよ > 自分

まあ、このことから、「Stream#read()で一括読み込みしようとしたら、長い長いタイムアウト待ちになる可能性がある」ということになるので、webのリソースを単純に引っ張ってくるにはこの方法は向かないってことになる。

さらに恥ずかしいことに(こればっか)、最初のエントリで行単位読み込みのループがうまくいかなかったのはStream#eofを頼りにしていたからと判明。Stream#canReadはちゃんと意図した動作をするので、

while( stream.canRead ) { writeln( stream.readln() ); }
で、最初のリクエストに対する応答を全部読み込み終わった時点でループを脱出する。

まとめ

  • JSDBのStreamをhttpで初期化するとHTTPキープアライブアプリケーションとして動作する
  • リクエストヘッダをカスタマイズするにはnet://で初期化して、いちいちリクエストをwriteln()してやる必要がある
  • 行単位のループ処理をする場合はcanReadプロパティをみるべし
  • Stream#read()なんて不精をするとタイムアウト待ちに巻き込まれる可能性があるので注意
といった感じだろうか。はぁ。

JSDBのhttp取得の件2007年05月05日 22時36分14秒

Streamのhttp取得できます

以前のエントリで、JSDBのStreamを使用したhttp読み込みがハングするといったことを記述しましたが、これ間違いでした。もし信じてしまった方がいましたら、ごめんなさい。おわびします。

なぜ取得できなかった?

前のエントリでのテストはローカルホスト(Win2K Pro + IIS5.0)に対するリクエストだったが、どうもこれがハングの原因だった模様。ローカルに設置したコンテンツは末尾の改行の有無にかかわらず、read()した以降制御を戻してこない。

最初はローカルホストに対する制約かとも思ったが、考えてみたら

while( ! stream.eof ) writeln( readln() );
のコードは最終行前までは出力できていたので、多分、IISが原因。

(2007/05/06 00:30 追記)
いくつかIISなホストを探して試してみたところ、IIS6は問題ないが、IIS5.0はconnectionが切断されない。IIS5.1(XP)はどうだろうか。
(2007/05/07 13:40 追記)
さらに調査したところ、IISうんぬんでないと判明。詳しくはこちら

さらにちょっと恥ずかしいことに

malさんよりいただいたコメントに、「prototypeの本家サイトから1.5.1を読み込ませてもハング」と書いたのだが、これまた恥ずかしいことにしばらく待ってたら受信完了したよ。

これ、「多分ハングするよ」という思い込みと、dara-jの家庭のネットワーク環境が、いまどきなろーばんどなため、状態を確認せずにハングしたと思い込んでいたためのようだった。

というわけで

JSDBでStreamを使用したhttp接続は普通に使えます。エンコード変換はわからんけど。

もう少ししっかり検討して投稿しないとあかんなぁ。コメントくださったmalさんに感謝です。

おまけ

しかしコンソール出力に文字数制限があるみたい。prototype.1.5.1を読み込んでそのままwriteln()すると出力されない。

substr()するとどっかを境に出力される・されないが分かれるみたいだが、これも不定っぽい。

もすこし調査したら別に掲載する予定。