@nqounetです。
今回から「PerlとMooで作るSQLクエリビルダー」シリーズを始めます。SQLクエリビルダーを自作しながら、GoFデザインパターンの1つ「Builderパターン」を学んでいきます。
「え、SQL文なんて文字列結合で作ればいいじゃん」と思ったあなた。その素朴なアプローチがどんな地獄への入り口なのか、これから一緒に体験していきましょう(そして華麗に脱出します)。
このシリーズでは、以下のことを学べます:
- SQLクエリを段階的に構築する技法
- Fluent Interface(メソッドチェーン)の実装
- SQLインジェクション対策の基本(第3回でちょっと危険な実験もします)
- Builderパターンの本質的な価値
まずは最もシンプルなSELECTクエリから始めましょう。
シリーズの前提
このシリーズでは以下の環境を想定しています:
- Perl v5.36以上
- Moo(オブジェクト指向フレームワーク)
- SQLite(ローカルでの実験用)
「Mooによるオブジェクト指向Perl」入門連載を修了していることを前提としています。
文字列結合でSQLを組み立てる
最初のアプローチとして、シンプルな文字列結合でSQLクエリを組み立ててみます。
Query.pm(文字列結合版)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| # 言語: perl
# バージョン: 5.36以上
# 依存: Moo
package Query;
use v5.36;
use Moo;
has table => (is => 'ro', required => 1);
sub to_sql ($self) {
return "SELECT * FROM " . $self->table;
}
1;
|
このクラスはとてもシンプルです。table属性を受け取り、to_sqlメソッドでSQLクエリを生成します。
使ってみる
1
2
3
4
5
6
7
8
9
10
11
12
| #!/usr/bin/env perl
# 言語: perl
# バージョン: 5.36以上
# 依存: Moo
use v5.36;
use lib 'lib';
use Query;
my $query = Query->new(table => 'users');
say $query->to_sql;
# 出力: SELECT * FROM users
|
たった数行で動くSQLクエリビルダーができました。
実行してみる
実際にSQLiteで動作を確認してみましょう。
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
| #!/usr/bin/env perl
# 言語: perl
# バージョン: 5.36以上
# 依存: Moo, DBI, DBD::SQLite
use v5.36;
use lib 'lib';
use Query;
use DBI;
# SQLiteデータベース接続
my $dbh = DBI->connect('dbi:SQLite:dbname=:memory:', '', '', {
RaiseError => 1,
PrintError => 0,
});
# テストテーブル作成
$dbh->do('CREATE TABLE users (id INTEGER, name TEXT)');
$dbh->do("INSERT INTO users VALUES (1, 'Alice')");
$dbh->do("INSERT INTO users VALUES (2, 'Bob')");
# クエリビルダーを使用
my $query = Query->new(table => 'users');
my $sql = $query->to_sql;
say "SQL: $sql";
# 実行
my $rows = $dbh->selectall_arrayref($sql, { Slice => {} });
for my $row ($rows->@*) {
say "ID: $row->{id}, Name: $row->{name}";
}
|
実行結果:
1
2
3
| SQL: SELECT * FROM users
ID: 1, Name: Alice
ID: 2, Name: Bob
|
ちゃんと動いていますね。
今回のまとめ
今回は最もシンプルなSQLクエリビルダーを作りました。
Queryクラスでテーブル名を受け取り、SELECT * FROM テーブル名を生成- 文字列結合による素朴な実装
- SQLiteで実際に動作確認
しかし、このアプローチには問題があります。WHERE条件を追加したい場合はどうなるでしょうか?ORDER BYは?LIMITは?
次回は「WHERE条件を追加したい」という要望に応えようとして、パラメータ地獄に陥る様子を体験します。