SQL::Abstract::Fulltext::MySQLを書いてみた。
SQL::Abstract::Fulltext::MySQLを書いてみた。
ちゃんと動作確認はしてないけど。
package SQL::Abstract::Fulltext::MySQL; use strict; use warnings; use Carp; my $org_recurse_where = main->can('SQL::Abstract::_recurse_where'); sub import { croak "must be require SQL::Abstract" unless $org_recurse_where; no warnings 'redefine'; *SQL::Abstract::_recurse_where = \&_recurse_where if $org_recurse_where != \&_recurse_where; } sub _recurse_where { my $self = shift; return $org_recurse_where->($self, @_) unless uc($_[1]) eq 'FULLTEXT'; _make_fulltext_where($self, @_); } sub _make_fulltext_where { my $self = shift; my $where = SQL::Abstract::_anoncopy($_[0]); # prevent destroying original my $ref = ref $where || ''; my $bind_col; my $match; my $against; my $boolean; while (my($k, $v) = each %$where) { my $k = uc $k; if ($k eq '-MATCH') { if (ref $v eq 'ARRAY') { $bind_col = $v->[0]; $match = join ', ', map +$self->_quote($_), @$v; } else { $bind_col = $v; $match = $self->_quote($v); } } elsif ($k eq '-AGAINST') { $against = $v; } elsif ($k =~ /-BOOLEAN(_MODE)?/) { $boolean = $v; } } my $where_sql = sprintf "MATCH ( %s ) AGAINST ( ? %s)", $match, ($boolean? 'IN BOOLEAN MODE': '') ; return $where_sql, $self->_bindtype($bind_col, $against); } 1; __END__
使い方としては、
package CDBI::Foo; use base qw/Class::DBI/; use Class::DBI::AbstractSearch; use SQL::Abstract::Fulltext::MySQL; # 以下略 package main; # WHERE MATCH ( description ) AGAINST ('+foo +bar' IN BOOLEAN MODE) my @rows = CDBI::Foo->search_where({ -fulltext => { -match => 'description', -against => '+foo +bar', -boolean => 1, }, });
――みたいな。Class::DBIの場合はClass::DBI::AbstractSearchを使うかClass::DBI::Sweetを*1使っているときに利用できます。
DBIx:ClassはSQL::Abstractを使っているので(確か)、useすれば-fulltextが使えるようになります(未確認動くのを確認しました)。
どこかでuse SQL::Abstract::Fulltext::MySQLしちゃうとSQL::Abstractを書き換えちゃうのでアレだけど。特定クラスだけ変更するのは面倒だから気にしてない。
本当はSQL::Abstract::Limitみたいに各種RDBMS互換にしたいけど、MySQL以外は知らないもので。。。
対応しやすくしてる(つもりな)ので、そのうちなんとかしたいなぁ*2。