X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FSQL%2FAbstract%2FCompat.pm;h=ea74a1a06af7e234140f6828d6e7cb085640a223;hb=e76b9ff712b99ede4137380e6e2c401bd15229b9;hp=5158b32960a8212885d12977c8a75e3701df01a9;hpb=03f6671a68c9b5d8a8ad57fb9a632ca0551928ef;p=dbsrgits%2FSQL-Abstract-2.0-ish.git diff --git a/lib/SQL/Abstract/Compat.pm b/lib/SQL/Abstract/Compat.pm index 5158b32..ea74a1a 100644 --- a/lib/SQL/Abstract/Compat.pm +++ b/lib/SQL/Abstract/Compat.pm @@ -5,7 +5,7 @@ class SQL::Abstract::Compat { use Moose::Util::TypeConstraints; use MooseX::Types::Moose qw/Str ScalarRef ArrayRef HashRef/; use SQL::Abstract::Types::Compat ':all'; - use SQL::Abstract::Types qw/AST/; + use SQL::Abstract::Types qw/AST NameSeparator QuoteChars/; use SQL::Abstract::AST::v1; use Data::Dump qw/pp/; use Devel::PartialDump qw/dump/; @@ -47,14 +47,43 @@ class SQL::Abstract::Compat { predicate => 'has_field_convertor' ); + # TODO: a metaclass trait to automatically use this on vistior construction + has quote_char => ( + is => 'rw', + isa => QuoteChars, + coerce => 1, + predicate => "has_quote_chars" + ); + + has name_sep => ( + is => 'rw', + isa => NameSeparator, + predicate => "has_name_sep" + ); + + method _build_visitor() { + my %args = ( + ast_version => 1 + ); + $args{quote_chars} = $self->quote_char + if $self->has_quote_chars; + $args{name_sep} = $self->name_sep + if $self->has_name_sep; + + # TODO: this needs improving along with SQL::A::create + my $visitor = SQL::Abstract::AST::v1->new(%args); + } + 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); + $DB::single = 1; + return ($self->visitor->dispatch($ast), @{$self->visitor->binds}); } + method select_ast(Str|ArrayRef|ScalarRef $from, ArrayRef|Str $fields, WhereType $where?, WhereType $order?) @@ -72,6 +101,12 @@ class SQL::Abstract::Compat { $ast->{where} = $self->recurse_where($where) if defined $where; + + if (defined $order) { + my @order = is_ArrayRef($order) ? @$order : $order; + $ast->{order_by} = [ map { $self->mk_name(0, $_) } @order ]; + } + return $ast; } @@ -88,13 +123,15 @@ class SQL::Abstract::Compat { return $ret; } - method _build_visitor() { - return SQL::Abstract->create(1); - } + # method mk_name(Bool $use_convert, Str @names) { sub mk_name { - my ($self, $use_convert) = (shift,shift); - my $ast = { -type => 'name', args => [ @_ ] }; + my ($self, $use_convert, @names) = @_; + + @names = split /\Q@{[$self->name_sep]}\E/, $names[0] + if (@names == 1 && $self->has_name_sep); + + my $ast = { -type => 'name', args => [ @names ] }; return $ast unless $use_convert && $self->has_field_convertor; @@ -105,6 +142,13 @@ class SQL::Abstract::Compat { method tablespec(Str|ArrayRef|ScalarRef $from) { return $self->mk_name(0, $from) if is_Str($from); + + return { + -type => 'list', + args => [ map { + $self->mk_name(0, $_) + } @$from ] + }; } method recurse_where(WhereType $ast, LogicEnum $logic?) returns (AST) { @@ -113,6 +157,7 @@ class SQL::Abstract::Compat { croak "Unknown where clause type " . dump($ast); } + # Deals with where({ .... }) case method recurse_where_hash(LogicEnum $logic, HashRef $ast) returns (AST) { my @args; my $ret = { @@ -143,6 +188,7 @@ class SQL::Abstract::Compat { return $ret; } + # Deals with where([ .... ]) case method recurse_where_array(LogicEnum $logic, ArrayRef $ast) returns (AST) { my @args; my $ret = { @@ -175,8 +221,15 @@ class SQL::Abstract::Compat { return $ret; } - method field(Str $key, $value) returns (AST) { - my $op = $CMP_MAP{$self->cmp} || $self->cmp; + # { field => { .... } } case + method field_hash(Str $key, HashRef $value) returns (AST) { + my ($op, @rest) = keys %$value; + + confess "Don't know how to handle " . dump($value) . " (too many keys)" + if @rest; + + $value = $value->{$op}; + my $ret = { -type => 'expr', op => $op, @@ -184,59 +237,74 @@ class SQL::Abstract::Compat { $self->mk_name(1, $key) ], }; + $ret->{op} = $op; + + # TODO: Validate the op? + # 'word_like' operator + if ($op =~ /^-?(?:(not)[_ ])?([a-z_]+)$/i) { + $ret->{op} = lc $2; + $ret->{op} = "not_" . $ret->{op} if $1; + - if (is_HashRef($value)) { - 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 =~ /^-?(?:(not)[_ ])?([a-z_]+)$/i) { - $ret->{op} = lc $2; - $ret->{op} = "not_" . $ret->{op} if $1; - - if (is_ArrayRef($value)) { - push @{$ret->{args}}, $self->value($_) - for @{$value}; - return $ret; - } - } - else { - $ret->{op} = $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($_) for @{$value}; + return $ret; } - push @{$ret->{args}}, $self->value($value); - } - elsif (is_ArrayRef($value)) { - # Return an or clause, sort of. - return { + + # Cases like: + # field => { '!=' => [ 'a','b','c'] } + # field => { '<' => [ 'a','b','c'] } + # + # *not* when op is a work or function operator - basic cmp operator only + if (is_ArrayRef($value)) { + local $self->{cmp} = $op; + + my $ast = { -type => 'expr', op => 'or', args => [ map { - $self->field($key, $_) - } @$value ] + $self->field($key, $_) + } @{$value} ] }; + return $ast; + } + + + push @{$ret->{args}}, $self->value($value); + return $ret; + } + + # Handle [ { ... }, { ... } ] + method field_array(Str $key, ArrayRef $value) { + # Return an or clause, sort of. + return { + -type => 'expr', + op => 'or', + args => [ map { + $self->field($key, $_) + } @$value ] + }; + } + + method field(Str $key, $value) returns (AST) { + + if (is_HashRef($value)) { + return $self->field_hash($key, $value); } - else { - push @{$ret->{args}}, $self->value($value); + elsif (is_ArrayRef($value)) { + return $self->field_array($key, $value); } + my $ret = { + -type => 'expr', + op => $CMP_MAP{$self->cmp} || $self->cmp, + args => [ + $self->mk_name(1, $key), + $self->value($value) + ], + }; + return $ret; }