Hatena::Groupasakura

浅倉卓司@blog風味? このページをアンテナに追加 RSSフィード

Error : RSSが取得できませんでした。

2007-04-05(Thu)

SQL::Abstract::Fulltext::MySQLを書いてみた。

| 12:54 |  SQL::Abstract::Fulltext::MySQLを書いてみた。 - 浅倉卓司@blog風味? を含むブックマーク  SQL::Abstract::Fulltext::MySQLを書いてみた。 - 浅倉卓司@blog風味? のブックマークコメント

 ちゃんと動作確認はしてないけど。

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

*1CDBI:Sweetのsearchだとうまく動かない。あとで調べる……。調べた。_bindcol()をちゃんと使わなかったのがまずいっぽい。_convert()とか_sqlcase()も使うべきのような気がするけど。

*2:その場合は-fulltextに渡すパラメータ(HASH_REF)をどうするのか考えないといけないけど。

トラックバック - http://asakura.g.hatena.ne.jp/asakura-t/20070405
2004 | 01 | 02 | 03 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2005 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2006 | 01 | 02 | 03 | 04 | 05 | 06 | 08 | 09 | 10 | 11 | 12 |
2007 | 02 | 03 | 04 | 05 | 06 | 07 | 10 | 11 | 12 |
2008 | 02 | 03 | 04 | 06 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2012 | 02 | 03 | 04 | 05 | 07 | 08 | 10 | 11 | 12 |
2013 | 01 | 05 | 07 |
2014 | 01 | 02 |
2016 | 01 |
2017 | 01 |