3 class SQL::Abstract::Compat {
5 use Moose::Util::TypeConstraints;
6 use MooseX::Types::Moose qw/Str ScalarRef ArrayRef HashRef/;
7 use SQL::Abstract::Types::Compat ':all';
8 use SQL::Abstract::Types qw/AST/;
9 use SQL::Abstract::AST::v1;
10 use Data::Dump qw/pp/;
11 use Devel::PartialDump qw/dump/;
14 class_type 'SQL::Abstract';
27 isa => 'SQL::Abstract',
28 clearer => 'clear_visitor',
30 builder => '_build_visitor',
47 predicate => 'has_field_convertor'
50 method select(Str|ArrayRef|ScalarRef $from, ArrayRef|Str $fields,
54 my $ast = $self->select_ast($from,$fields,$where,$order);
56 return ($self->visitor->dispatch($ast), $self->visitor->binds);
58 method select_ast(Str|ArrayRef|ScalarRef $from, ArrayRef|Str $fields,
67 } ( is_Str($fields) ? $fields : @$fields )
69 tablespec => $self->tablespec($from)
73 $ast->{where} = $self->recurse_where($where)
78 method where(WhereType $where,
84 my $ast = $self->recurse_where($where);
85 $ret .= "WHERE " . $self->visitor->_expr($ast);
91 method _build_visitor() {
92 return SQL::Abstract->create(1);
96 my ($self, $use_convert) = (shift,shift);
97 my $ast = { -type => 'name', args => [ @_ ] };
100 unless $use_convert && $self->has_field_convertor;
102 return $self->apply_convert($ast);
105 method tablespec(Str|ArrayRef|ScalarRef $from) {
106 return $self->mk_name(0, $from)
110 method recurse_where(WhereType $ast, LogicEnum $logic?) returns (AST) {
111 return $self->recurse_where_hash($logic || 'AND', $ast) if is_HashRef($ast);
112 return $self->recurse_where_array($logic || 'OR', $ast) if is_ArrayRef($ast);
113 croak "Unknown where clause type " . dump($ast);
116 method recurse_where_hash(LogicEnum $logic, HashRef $ast) returns (AST) {
124 for my $key ( sort keys %$ast ) {
125 my $value = $ast->{$key};
127 if ($key =~ /^-(or|and)$/) {
128 my $val = $self->recurse_where($value, uc $1);
129 if ($val->{op} eq $ret->{op}) {
130 push @args, @{$val->{args}};
138 push @args, $self->field($key, $value);
141 return $args[0] if @args == 1;
146 method recurse_where_array(LogicEnum $logic, ArrayRef $ast) returns (AST) {
155 while (my $key = shift @nodes) {
156 if ($key =~ /^-(or|and)$/) {
157 my $value = shift @nodes
158 or confess "missing value after $key at " . dump($ast);
160 my $val = $self->recurse_where($value, uc $1);
161 if ($val->{op} eq $ret->{op}) {
162 push @args, @{$val->{args}};
170 push @args, $self->recurse_where($key);
173 return $args[0] if @args == 1;
178 method field_hash(Str $key, HashRef $value) returns (AST) {
179 my ($op, @rest) = keys %$value;
181 confess "Don't know how to handle " . dump($value) . " (too many keys)"
184 $value = $value->{$op};
190 $self->mk_name(1, $key)
195 # TODO: Validate the op?
196 # 'word_like' operator
197 if ($op =~ /^-?(?:(not)[_ ])?([a-z_]+)$/i) {
199 $ret->{op} = "not_" . $ret->{op} if $1;
202 if (is_ArrayRef($value)) {
203 push @{$ret->{args}}, $self->value($_) for @{$value};
209 # field => { '!=' => [ 'a','b','c'] }
210 # field => { '<' => [ 'a','b','c'] }
212 # *not* when op is a work or function operator - basic cmp operator only
213 if (is_ArrayRef($value)) {
214 local $self->{cmp} = $op;
219 # Handle e => { '!=', [qw(f g)] }.
220 # SQLA treats this as a 'DWIM' since e != f AND e != g doesn't make sense
221 op => $op eq '!=' ? 'or' : 'and',
223 $self->field($key, $_)
230 push @{$ret->{args}}, $self->value($value);
234 # Handle [ { ... }, { ... } ]
235 method field_array(Str $key, ArrayRef $value) {
236 # Return an or clause, sort of.
241 $self->field($key, $_)
246 method field(Str $key, $value) returns (AST) {
248 if (is_HashRef($value)) {
249 return $self->field_hash($key, $value);
251 elsif (is_ArrayRef($value)) {
252 return $self->field_array($key, $value);
257 op => $CMP_MAP{$self->cmp} || $self->cmp,
259 $self->mk_name(1, $key),
267 method value($value) returns (AST) {
268 return $self->apply_convert( { -type => 'value', value => $value })
271 confess "Don't know how to handle terminal value " . dump($value);
274 method apply_convert(AST $ast) {
275 return $ast unless $self->has_field_convertor;
279 op => $self->convert,
289 SQL::Abstract::Compant - compatibility layer for SQL::Abstrct v 1.xx
293 This class attempts to maintain the original behaviour of version 1 of
294 SQL::Abstract. It does this by internally converting to an AST and then using
295 the standard AST visitor.
297 If so desired, you can get hold of this transformed AST somehow. This is aimed
298 at libraries such as L<DBIx::Class> that use SQL::Abstract-style arrays or
299 hashes as part of their public interface.
303 Ash Berlin C<< <ash@cpan.org> >>