SQL::Translator

GraphvizでE/Rダイアグラムっぽいものを生成できるという SQL::Translatorをつかってみた。

他にもOracle,Mysql,PostgreSQL,SQLiteなんかの間でsqlを変換したり、テーブルスキーマをYAMLとかXMLにシリアライズできたりする。 (他にもCGIのGUIがくっついてるけど僕は試してない)

taggingで使ったsqlがあったのでそれで試してみる。フィールド名を入れるとなんか汚いので、除くオプション付きで実行

$ sqlt-graph -f SQLite --no-fields tag.sql -o test.png

sqlt

そもそも、SQLiteに外部キー制約使えないので駄目すぎだった。というわけで、なんかないかと探したら、DBDesignerのbookshopというサンプルがちょうどよさそうなので、それを使ってみた。

$ sqlt-graph -f MySQL ex.sql -o mysqlt.png

おーまずまず。

DBDesigner

なかなかヨサゲなものを発見。

MOONGIFT オープンソース - DBDesigner - DBDesigner

本日紹介するオープンソース・ソフトウェアはDBDesigner、各種データベースに対応した構造管理ツールだ。基本はMySQL、Oracleなどだが、ODBCにも対応しているのでPostgreSQLの構造を扱うこともできる(データの編集などではエラーが出てしまったが)。

SQLで吐けるので結構便利かも。

醴泉を楽しむ会

ちょっと前に、酒のいわせ主催の醴泉を楽しむ会にお邪魔してきた。場所は御殿場のたから亭、中華の店。

たから亭 醴泉ラインナップ

発泡酒で乾杯。日本酒の発泡性のやつは久々だ(2年位前に獺祭りの飲んで以来かな)。しかも美味い。続いて蘭奢待(大吟醸)。

発泡酒 蘭奢待

前菜をちびちびつまみながら、大吟やら、純吟をやるのが最高。

前菜 醴泉正宗

野菜中心(百合のつぼみを使った炒め物)だと、意外に日本酒もいける。というか、この頃は大吟醸を燗つけてたような気が。

炒め物

sake meets chineseといった企画だったが、エビチリとか、辛い炒め物(写真には載せてない)とかは、ちょっと日本酒とは合わんような気がした。純米酒とかの燗つけて美味い酒は、濃い目の料理でもいい感じだったかも。

かなり満足。

ちなみに、クイズの景品の手ぬぐい。

手ぬぐい

なかなかいい感じ。前の家だったら和室があったから飾ればいい感じだったのだけど、今の家は和室なしだからナァ。(豆知識だが、和室の畳は転居時に一枚5000くらいとられるので、貸すほう、借りるほう両方から敬遠されるらしい。)

たから亭

ガネー舎

新橋から少し歩いたところにあるガネー舎へスープカレーを食べに。 ちと入り口がわかりづらい。

ガネー舎

とりカリィを注文。

鳥カリィ

鶏は柔らかく、野菜はしゃっきり感があってうまい。
が、スパイシーさがもうちょっと欲しいかも。

graphvizでテーブルスキーマ

地道にそれっぽいのを用意しようとするならば、こんな感じ

digraph sample {
   graph [size = "6, 8"];   
   graph [nodesep = 0.7];
   node [shape = record, height = 0.01,   
         fontname = "Helvetica", fontsize = 9];

   bookmark [label = "{bookmark|id\nname\nuri\ndescription\ntime_created}"];
   tagmap [label = "{tagmap|id\nbookmark_id\ntag_id}"];
   tag [label = "{tag|id\nname}"];

   tagmap -> tag [label = "belongs_to"];
   tagmap -> bookmark [label = "belongs_to"];
   tag -> tagmap [label = "has_many"];
   tag -> tagmap [label = "many_to_many"];
   bookmark -> tagmap [label = "has_many"];
   bookmark -> tagmap [label = "many_to_many"];
}

dotコマンドで実行

$ dot -Tpng db.dot -o db_sample.png

many to many

もう少し、スキーマ図っぽくしたいなぁと色々探したらSQL::Translatorというものをみつけた。

後で試す。

男前マグネット

豆腐好きにはたまらないと評判の男前豆腐にガシャポンがでたと知ってから、密かにチェックしてたんだけど、先週末偶然イトーヨーカドーに立ち寄ったら見つけた。

ガシャポン(当時はガチャガチャ)まわすの、小学校以来だ。湯豆腐野郎とジョニーゲットして、帰って携帯につけようとしたら、ストラップじゃなくてマグネットだった。

残念。仕方ないので、家の冷蔵庫にくっつけておいた。

男前マグネット

イトーヨーカドーに結構設置されてるみたいね。

DBICで多対多

多対多のサンプルとしてTags: Database schemasの“Toxi” solutionをDBICで書いてみる。

関連を表すテーブルに対しては、1対多の関係を設定しておいて、更にmany_to_manyを追加する

図にしてみたらわかりやすくなった。

manytomany

ちなみに、1対多はこちらを、多対多はこちらを参考にしました。

Kzfm::Schema

use 5.008008;
use strict;
use warnings;
use base 'DBIx::Class::Schema';
our $VERSION = '0.01';

__PACKAGE__->load_classes(qw/Tag Bookmark TagMap/);

1;

Kzfm::Schema::Tag

use strict;
use warnings;
use base 'Kzfm::Schema';

__PACKAGE__->load_components(qw/PK::Auto::SQLite Core/);
__PACKAGE__->table('tag');
__PACKAGE__->add_columns(qw/id name/);
__PACKAGE__->set_primary_key('id');
__PACKAGE__->has_many(tagmap => 'Kzfm::Schema::TagMap','tag_id');
__PACKAGE__->many_to_many('bookmarks' => 'tagmap','bookmark_id');

1;

Kzfm::Schema::Bookmark

use strict;
use warnings;
use base 'Kzfm::Schema';

__PACKAGE__->load_components(qw/PK::Auto::SQLite Core/);
__PACKAGE__->table('bookmark');
__PACKAGE__->add_columns(qw/id name uri description time_created/);
__PACKAGE__->set_primary_key('id');
__PACKAGE__->has_many(tagmap => 'Kzfm::Schema::TagMap','bookmark_id');
__PACKAGE__->many_to_many('tags' => 'tagmap','tag_id');

1;

Kzfm::Schema::TagMap

use strict;
use warnings;
use base 'Kzfm::Schema';

__PACKAGE__->load_components(qw/PK::Auto::SQLite Core/);
__PACKAGE__->table('tagmap');
__PACKAGE__->add_columns(qw/id bookmark_id tag_id/);
__PACKAGE__->set_primary_key('id');
__PACKAGE__->belongs_to('bookmark_id' => 'Kzfm::Schema::Bookmark');
__PACKAGE__->belongs_to('tag_id' => 'Kzfm::Schema::Tag');

1;

制約の部分だけ、考えてみる。

__PACKAGE__->belongs_to('カラム名(アクセサ?)' => 'スキーマ(pm)');
__PACKAGE__->has_many(テーブル名 => 'スキーマ(pm)','カラム名(アクセサ?)');
__PACKAGE__->many_to_many('任意のキー名' => 'テーブル名','多対多関係のカラム');
  • belongs_toはまぁわかりやすい。
  • many_to_manyは任意にキー名決められるのにhas_manyはキー値にテーブル名指定しないとエラー吐くのが謎。
  • many_to_manyでテーブル名のとこをKzfm::Schema::TagMapってやるのが駄目な理由がよくわからない。

あと、さらにユーザーを追加する場合に、ユーザーとブックマークも多対多の関係になるけど、こっちも正規化したほうがいいのか、むしろやりすぎないほうがむしろいいのか悩む。

追記 06.12.04

ボケボケだったことに気付いた。

DBICで多対多の設定を

かなりボケボケだった。

こういうことらしい。

DBIx::Class::Relationship - Inter-table relationships - search.cpan.org

PACKAGE>$method_name('relname', 'Foreign::Class', $cond, $attrs);

というわけで、こんな感じの理解で。

__PACKAGE__->belongs_to(アクセサ名(任意) => 
    '従うクラス','従うクラスのIDを持つ属性名');
__PACKAGE__->has_many(アクセサ名(任意) => 
    'クラス','自分のクラスのIDをもつ属性名');
__PACKAGE__->many_to_many(アクセサ名(任意) => 
    'has_manyでのアクセサ名','belongs_toでのアクセサ名');

データベースを指しているのかクラスを属性を指してるのか良く分かってなかった。というかO/RマッパーでDBのカラム名っておかしいよって何で気づかなかったんだろう。

  • many_to_manyは任意にキー名決められるのにhas_manyはキー値にテーブル名指定しないとエラー吐くのが謎。
  • has_many(アクセサ名(任意) => 'クラス','カラム名')でOK
  • many_to_manyでテーブル名のとこをKzfm::Schema::TagMapってやるのが駄目な理由がよくわからない。
  • has_manyで指定したアクセサ名が必要なのでダメ。

なんとなくこんな感じか。

Hyper Estraier

あるとわかっているのに辿りつけないもどかしさというか、

google 検索結果返す 故にエントリ有り

というようなgoogle認識論的なアプローチに依存しすぎるということはちょっとツライことに気付いた。

ちゅうのは、自サイトの検索をgoogleに任せてからそこそこ経つんだけど、googleは被リンク数が少ないと(クローラーはガッツリ持ってくくせに)検索結果の表示対象にならない。そのため、自分で書いたエントリがあるはずなのに探せないという状況が頻発した。

なんで、やっぱ自前で検索エンジン入れる必要があるなぁと、Hyper Estraierを利用して検索できるようにした。

僕のサイトはblosxomで構築されている。これは、データベースでなく普通のテキストファイルでエントリを管理しているので、Hyper Estraierのestcmdでデータディレクトリを検索対象にすればよい。ただし、これだと、タイトル属性がないために、検索結果のタイトルがファイル名になってしまう。

blosxomのエントリデータは先頭行がタイトルのテキストデータなので、ここら辺をちょっといじくるblosxom用のフィルタを作成した。

まずは、フィルタを作成。/usr/local/share/hyperestraier/filterのestfxpdftohtmlをコピーしてフィルタを作成。下はdiffってみたけど、要するにpdftotextのコマンドをblosxom用のコンバートコマンドに書き換えれば良いだけ。僕の使っているestfxblosxomtohtml

--- estfxpdftohtml      2006-12-02 16:09:34.000000000 +0900
+++ estfxblosxomtohtml  2006-12-02 17:47:04.000000000 +0900
@@ -1,14 +1,14 @@
 #! /bin/sh
 #================================================================
-# extfxpdftohtml
+# extfxblosxomtohtml
 # Convert PDF into HTML
 #================================================================

 # set variables
 PATH="$PATH:/usr/local/bin:$HOME/bin:." ; export PATH
-progname="estfxpdftohtml"
+progname="estfxblosxomtohtml"

 # check arguments
@@ -56,7 +56,7 @@

 # output the result
-pdftotext -enc UTF-8 -htmlmeta "$infile" - 2> "/dev/null" | output
+bldata2html "$infile" - 2> "/dev/null" | output

 # exit normally

で、blosxomのデータをhtmlに吐くには先頭行だけtitle属性で囲んで、あとはそのまま出力すればいいんだけど、僕はmarkdown使っているので、フィルタリングしてhtmlに出力するようなスクリプトにした。これがpdftotxtにあたるbldata2htmlで/usr/local/binとかのパスの通ったところに保存する。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/usr/bin/perl

use strict;
use warnings;
use FileHandle;
use Text::Markdown 'markdown';

my $filename = shift;
my ($title,$body) = ();

my $fh = new FileHandle($filename);

$title = <$fh>;
chomp($title);

{
local $/ = undef;
$body = <$fh>;
}
my $html = markdown($body);

print "<title>", $title , "</title>\n", $html;

あとは、実際にインデックスをつくる。txt属性はestfxblosxomtohtmlフィルタをかますようにオプションを指定しておく。最後のextkeysは検索速度向上のため。

PATH=$PATH:/usr/local/share/hyperestraier/filter ; export PATH
estcmd gather -il ja -fx ".txt" "H@estfxblosxomtohtml" -sd casket /var/blosxom/data/
estcmd extkeys casket

で、実際にestseekで検索するといい感じ。後は定期的にインデックスの更新するようにしとけば、自サイトの検索はOK。今のとこ、cronでインデックスの更新するようにしていないので、blosomの検索フォームはgoogleのままだけど、そのうち変更しよう。

あとは、blosxomのエントリに類似エントリ検索をした結果を表示するプラグインを作っておけば便利かな。

markdownでコードを貼り付けるのは

markdownは行の先頭にスペース4文字を入れればcodeブロックになるので、

perl -ne 'print "    " . $_' file

とやった出力をblosxomのエントリにペーストしてるんだが、もうちょい楽な方法はないもんだろうか?
とか思った。