package DBIx::Custom::Where; use strict; use warnings; use base 'Object::Simple'; use overload 'bool' => sub {1}, fallback => 1; use overload '""' => sub { shift->to_string }, fallback => 1; use Carp 'croak'; __PACKAGE__->attr(clause => sub { [] }); __PACKAGE__->attr(param => sub { {} }); __PACKAGE__->attr(sql_builder => sub { {} }); sub to_string { my ($self, $param, $clause) = @_; local $self->{_where} = ''; local $self->{_count} = {}; local $self->{_op_stack} = []; local $self->{_param} = $param; $clause = ['and', $clause] unless ref $clause eq 'ARRAY'; $self->_forward($clause); return $self->{_where}; } our %VALID_OPERATIONS = map { $_ => 1 } qw/and or or_repeat/; sub _forward { my ($self, $clause) = @_; if (ref $clause eq 'ARRAY') { $self->{_where} .= '( '; my $op = $clause->[0] || ''; croak qq{"$op" is invalid operation} unless $VALID_OPERATIONS{$op}; push @{$self->{_op_stack}}, $op; for (my $i = 1; $i < @$clause; $i++) { $self->_forword($clause->[$i]); } pop @{$self->{_op_stack}}; if ($self->{_where} =~ /\( $/) { $self->{_where} =~ s/\( $//; $self->{_where} .= ' '; } $self->{_where} =~ s/ $op $//; $self->{_where} .= ' ) '; } else { my $op = $self->{_op_stack}->[-1]; my $columns = $self->sql_builder->build_query($clause)->columns; croak qq{each tag contains one column name: tag "$clause"} unless @$columns == 1; my $column = $columns->[0]; my $ccount = ++$self->{_count}->{$column}; my $param = $self->{_param}; if (exists $param->{$column}) { if ($op eq 'and' || $op eq 'or') { if (ref $param->{$column} eq 'ARRAY') { $self->{_where} .= $clause . " $op " if exists $param->{$column}->[$ccount]; } else { $self->{_where} .= $clause . " $op " if $ccount == 1; } } elsif ($op eq 'or_repeat') { if (ref $param->{$column} eq 'ARRAY') { $self->{_where} .= $clause . " or " for (1 .. @{$param->{$column}}); } else { $self->{_where} .= $clause; } } } } } 1; =head1 NAME DBIx::Custom::Where - Where clause =head1 SYNOPSYS $where = DBIx::Custom::Where->new; my $sql = "select * from book $where"; =head1 ATTRIBUTES =head2 C my $param = $where->param; $where = $where->param({title => 'Perl', date => ['2010-11-11', '2011-03-05']}, name => ['Ken', 'Taro']); =head1 METHODS =head2 C $where->clause(title => '{= title}', date => ['{< date}', '{> date}']); Where clause. These clauses is joined by ' and ' at C if corresponding parameter name is exists in C. =head2 C $where->to_string;