is => 'rw',
isa => LogicEnum,
default => 'AND',
- coerce => 1
+ coerce => 1,
+ required => 1,
);
has visitor => (
builder => '_build_visitor',
);
+ has cmp => (
+ is => 'rw',
+ isa => 'Str',
+ default => '=',
+ required => 1,
+ );
+
+ our %CMP_MAP = (
+ '=' => '==',
+ );
+
+ has convert => (
+ is => 'rw',
+ isa => 'Str',
+ predicate => 'has_field_convertor'
+ );
method select(Str|ArrayRef|ScalarRef $from, ArrayRef|Str $fields,
WhereType $where?,
WhereType $order?)
{
+ my $ast = $self->select_ast($from,$fields,$where,$order);
+
+ return ($self->visitor->dispatch($ast), $self->visitor->binds);
+ }
+ method select_ast(Str|ArrayRef|ScalarRef $from, ArrayRef|Str $fields,
+ WhereType $where?,
+ WhereType $order?)
+ {
my $ast = {
-type => 'select',
columns => [
map {
- $self->mk_name($_)
+ $self->mk_name(0, $_)
} ( is_Str($fields) ? $fields : @$fields )
],
tablespec => $self->tablespec($from)
$ast->{where} = $self->recurse_where($where)
if defined $where;
-
- return ($self->visitor->dispatch($ast), $self->visitor->binds);
+ return $ast;
}
method where(WhereType $where,
}
sub mk_name {
- shift;
- return { -type => 'name', args => [ @_ ] };
+ my ($self, $use_convert) = (shift,shift);
+ my $ast = { -type => 'name', args => [ @_ ] };
+
+ return $ast
+ unless $use_convert && $self->has_field_convertor;
+
+ return $self->apply_convert($ast);
}
method tablespec(Str|ArrayRef|ScalarRef $from) {
- return $self->mk_name($from)
+ return $self->mk_name(0, $from)
if is_Str($from);
}
}
method field(Str $key, $value) returns (AST) {
+ my $op = $CMP_MAP{$self->cmp} || $self->cmp;
my $ret = {
-type => 'expr',
- op => '==',
+ op => $op,
args => [
- { -type => 'name', args => [$key] }
+ $self->mk_name(1, $key)
],
};
my ($op, @rest) = keys %$value;
confess "Don't know how to handle " . dump($value) . " (too many keys)"
if @rest;
+ $value = $value->{$op};
# TODO: Validate the op?
- if ($op =~ /^-([a-z_]+)$/i) {
- $ret->{op} = lc $1;
+ if ($op =~ /^-?(?:(not)[_ ])?([a-z_]+)$/i) {
+ $ret->{op} = lc $2;
+ $ret->{op} = "not_" . $ret->{op} if $1;
- if (is_ArrayRef($value->{$op})) {
+ if (is_ArrayRef($value)) {
push @{$ret->{args}}, $self->value($_)
- for @{$value->{$op}};
+ for @{$value};
return $ret;
}
}
else {
$ret->{op} = $op;
}
-
- push @{$ret->{args}}, $self->value($value->{$op});
+
+ if (is_ArrayRef($value)) {
+ local $self->{cmp} = $op;
+
+ my $ast = {
+ -type => 'expr',
+ # Handle e => { '!=', [qw(f g)] }.
+ # SQLA treats this as a 'DWIM'
+ op => $op eq '!=' ? 'or' : 'and',
+ args => [ map {
+ $self->field($key, $_)
+ } @{$value} ]
+ };
+ return $ast;
+ }
+ push @{$ret->{args}}, $self->value($value);
}
elsif (is_ArrayRef($value)) {
-type => 'expr',
op => 'or',
args => [ map {
- {
- -type => 'expr',
- op => '==',
- args => [
- { -type => 'name', args => [$key] },
- $self->value($_)
- ],
- }
+ $self->field($key, $_)
} @$value ]
};
}
}
method value($value) returns (AST) {
- return { -type => 'value', value => $value }
+ return $self->apply_convert( { -type => 'value', value => $value })
if is_Str($value);
confess "Don't know how to handle terminal value " . dump($value);
}
+ method apply_convert(AST $ast) {
+ return $ast unless $self->has_field_convertor;
+
+ return {
+ -type => 'expr',
+ op => $self->convert,
+ args => [ $ast ]
+ };
+ }
+
}