--- /dev/null
+use MooseX::Declare;
+
+class SQL::Abstract::AST::Compat {
+
+ use MooseX::Types::Moose qw/ArrayRef HashRef Str ScalarRef/;
+ use SQL::Abstract::Types qw/AST/;
+ use SQL::Abstract::Types::Compat ':all';
+ use Devel::PartialDump qw/dump/;
+ use Carp qw/croak/;
+
+ clean;
+
+ has logic => (
+ is => 'rw',
+ isa => LogicEnum,
+ default => 'AND'
+ );
+
+ method generate(WhereType $ast) returns (AST) {
+ return $self->recurse_where($ast);
+ }
+
+ method recurse_where(WhereType $ast, LogicEnum $logic?) returns (AST) {
+ return $self->recurse_where_hash($logic || 'AND', $ast) if is_HashRef($ast);
+ return $self->recurse_where_array($logic || 'OR', $ast) if is_ArrayRef($ast);
+ croak "Unknown where clause type " . dump($ast);
+ }
+
+ method recurse_where_hash(LogicEnum $logic, HashRef $ast) returns (AST) {
+ my @args;
+ my $ret = {
+ -type => 'expr',
+ op => lc $logic,
+ args => \@args
+ };
+
+ while (my ($key,$value) = each %$ast) {
+ if ($key =~ /^-(or|and)$/) {
+ my $val = $self->recurse_where($value, uc $1);
+ if ($val->{op} eq $ret->{op}) {
+ push @args, @{$val->{args}};
+ }
+ else {
+ push @args, $val;
+ }
+ next;
+ }
+
+ push @args, $self->field($key, $value);
+ }
+
+ return $args[0] if @args == 1;
+
+ return $ret;
+ }
+
+ method recurse_where_array(LogicEnum $logic, ArrayRef $ast) returns (AST) {
+ my @args;
+ my $ret = {
+ -type => 'expr',
+ op => lc $logic,
+ args => \@args
+ };
+ my @nodes = @$ast;
+
+ while (my $key = shift @nodes) {
+ if ($key =~ /^-(or|and)$/) {
+ my $value = shift @nodes
+ or confess "missing value after $key at " . dump($ast);
+
+ my $val = $self->recurse_where($value, uc $1);
+ if ($val->{op} eq $ret->{op}) {
+ push @args, @{$val->{args}};
+ }
+ else {
+ push @args, $val;
+ }
+ next;
+ }
+
+ push @args, $self->recurse_where($key);
+ }
+
+ return $args[0] if @args == 1;
+
+ return $ret;
+ }
+
+ method field(Str $key, $value) returns (AST) {
+ my $ret = {
+ -type => 'expr',
+ op => '==',
+ args => [
+ { -type => 'name', args => [$key] }
+ ],
+ };
+
+ if (is_Str($value)) {
+ push @{$ret->{args}}, { -type => 'value', value => $value };
+ }
+
+ return $ret;
+ }
+
+
+};
+
+1;
+
+=head1 NAME
+
+SQL::Abstract::AST::Compat - v1.xx AST -> v2 AST visitor
+
+=head1 DESCRIPTION
+
+The purpose of this module is to take the where clause arguments from version
+1.x of SQL::Abstract, and turn it into a proper, explicit AST, suitable for use
+in the rest of the code.
+
+Please note that this module does not have the same interface as other
+SQL::Abstract ASTs.
+
+=head1 AUTHOR
+
+Ash Berlin C<< <ash@cpan.org> >>
+
+=cut
--- /dev/null
+use strict;
+use warnings;
+
+use SQL::Abstract::AST::Compat;
+
+use Test::More tests => 6;
+use Test::Differences;
+
+ok(my $visitor = SQL::Abstract::AST::Compat->new);
+
+my $foo_eq_1 = {
+ -type => 'expr',
+ op => '==',
+ args => [
+ { -type => 'name', args => [qw/foo/] },
+ { -type => 'value', value => 1 }
+ ]
+};
+
+eq_or_diff
+ $visitor->generate({ foo => 1 }),
+ $foo_eq_1,
+ "Single value hash";
+
+
+my $bar_eq_str = {
+ -type => 'expr',
+ op => '==',
+ args => [
+ { -type => 'name', args => [qw/bar/] },
+ { -type => 'value', value => 'some str' }
+ ]
+};
+
+eq_or_diff
+ $visitor->generate({ foo => 1, bar => 'some str' }),
+ { -type => 'expr',
+ op => 'and',
+ args => [
+ $bar_eq_str,
+ $foo_eq_1,
+ ]
+ },
+ "two keys in hash";
+
+eq_or_diff
+ $visitor->generate({ -or => { foo => 1, bar => 'some str' } }),
+ { -type => 'expr',
+ op => 'or',
+ args => [
+ $bar_eq_str,
+ $foo_eq_1,
+ ]
+ },
+ "-or key in hash";
+
+
+eq_or_diff
+ $visitor->generate([ -and => { foo => 1, bar => 'some str' } ]),
+ { -type => 'expr',
+ op => 'and',
+ args => [
+ $bar_eq_str,
+ $foo_eq_1,
+ ]
+ },
+ "-and as first element of array";
+
+
+eq_or_diff
+ $visitor->generate([ -and => { foo => 1, bar => 'some str' }, { foo => 1} ]),
+ { -type => 'expr',
+ op => 'or',
+ args => [
+ { -type => 'expr',
+ op => 'and',
+ args => [
+ $bar_eq_str,
+ $foo_eq_1,
+ ]
+ },
+ $foo_eq_1,
+ ]
+ },
+ "-and as first element of array";