33package Data::ObjectDriver::SQL ;
44use strict;
55use warnings;
6+ use Scalar::Util ' blessed' ;
67
78use base qw( Class::Accessor::Fast ) ;
89
910__PACKAGE__ -> mk_accessors(qw(
1011 select distinct select_map select_map_reverse
1112 from joins where bind limit offset group order
1213 having where_values column_mutator index_hint
13- comment
14+ comment as
1415) );
1516
1617sub new {
@@ -33,10 +34,16 @@ sub new {
3334sub add_select {
3435 my $stmt = shift ;
3536 my ($term , $col ) = @_ ;
36- $col ||= $term ;
3737 push @{ $stmt -> select }, $term ;
38- $stmt -> select_map-> {$term } = $col ;
39- $stmt -> select_map_reverse-> {$col } = $term ;
38+ if (blessed($term ) && $term -> isa(' Data::ObjectDriver::SQL' )) {
39+ my $alias = $col || $term -> as || $term -> as_sql;
40+ $stmt -> select_map-> {$term } = $alias ;
41+ $stmt -> select_map_reverse-> {$alias } = $term ;
42+ } else {
43+ $col ||= $term ;
44+ $stmt -> select_map-> {$term } = $col ;
45+ $stmt -> select_map_reverse-> {$col } = $term ;
46+ }
4047}
4148
4249sub add_join {
@@ -60,12 +67,26 @@ sub add_index_hint {
6067sub as_sql {
6168 my $stmt = shift ;
6269 my $sql = ' ' ;
70+ my @bind_for_select ;
71+
6372 if (@{ $stmt -> select }) {
6473 $sql .= ' SELECT ' ;
6574 $sql .= ' DISTINCT ' if $stmt -> distinct;
75+ my $select_map = $stmt -> select_map;
6676 $sql .= join (' , ' , map {
67- my $alias = $stmt -> select_map-> {$_ };
68- $alias && / (?:^|\. )\Q $alias \E $ / ? $_ : " $_ $alias " ;
77+ my $col = $_ ;
78+ my $alias = $select_map -> {$col };
79+ if (blessed($col ) && $col -> isa(' Data::ObjectDriver::SQL' )) {
80+ push @bind_for_select , @{ $col -> {bind } };
81+ @{ $col -> {bind } } = ();
82+ $col -> as_subquery($alias );
83+ } else {
84+ if ($alias ) {
85+ / (?:^|\. )\Q $alias \E $ / ? $col : " $col $alias " ;
86+ } else {
87+ $col ;
88+ }
89+ }
6990 } @{ $stmt -> select }) . " \n " ;
7091 }
7192 $sql .= ' FROM ' ;
@@ -91,8 +112,19 @@ sub as_sql {
91112 $sql .= ' , ' if @from ;
92113 }
93114
115+ my @bind_for_from ;
116+
94117 if (@from ) {
95- $sql .= join ' , ' , map { $stmt -> _add_index_hint($_ ) } @from ;
118+ $sql .= join ' , ' , map {
119+ my $from = $_ ;
120+ if (blessed($from ) && $from -> isa(' Data::ObjectDriver::SQL' )) {
121+ push @bind_for_from , @{$from -> {bind }};
122+ @{$from -> {bind }} = ();
123+ $from -> as_subquery;
124+ } else {
125+ $stmt -> _add_index_hint($from );
126+ }
127+ } @from ;
96128 }
97129
98130 $sql .= " \n " ;
@@ -107,9 +139,22 @@ sub as_sql {
107139 if ($comment && $comment =~ / ([ 0-9a-zA-Z.:;()_#&,]+)/ ) {
108140 $sql .= " -- $1 " if $1 ;
109141 }
142+
143+ @{ $stmt -> {bind } } = (@bind_for_select , @bind_for_from , @{ $stmt -> {bind } });
144+
110145 return $sql ;
111146}
112147
148+ sub as_subquery {
149+ my ($stmt , $alias ) = @_ ;
150+ my $subquery = ' (' . $stmt -> as_sql . ' )' ;
151+ $alias ||= $stmt -> as ;
152+ if ($alias ) {
153+ $subquery .= ' AS ' . $alias ;
154+ }
155+ $subquery ;
156+ }
157+
113158sub as_limit {
114159 my $stmt = shift ;
115160 my $n = $stmt -> limit or
@@ -231,7 +276,11 @@ sub add_having {
231276# Carp::croak("Invalid/unsafe column name $col") unless $col =~ /^[\w\.]+$/;
232277
233278 if (my $orig = $stmt -> select_map_reverse-> {$col }) {
234- $col = $orig ;
279+ if (blessed($orig ) && $orig -> isa(' Data::ObjectDriver::SQL' )) {
280+ # do nothins
281+ } else {
282+ $col = $orig ;
283+ }
235284 }
236285
237286 my ($term , $bind ) = $stmt -> _mk_term($col , $val );
@@ -281,12 +330,17 @@ sub _mk_term {
281330 $term = " $c $op ? AND ?" ;
282331 push @bind , @{$val -> {value }};
283332 } else {
284- if (ref $val -> {value } eq ' SCALAR' ) {
285- $term = " $c $val ->{op} " . ${$val -> {value }};
333+ my $value = $val -> {value };
334+ if (ref $value eq ' SCALAR' ) {
335+ $term = " $c $val ->{op} " . $$value ;
336+ } elsif (blessed($value ) && $value -> isa(' Data::ObjectDriver::SQL' )) {
337+ local $value -> {as } = undef ;
338+ $term = " $c $val ->{op} " . $value -> as_subquery;
339+ push @bind , @{$value -> {bind }};
286340 } else {
287341 $term = " $c $val ->{op} ?" ;
288342 $term .= $stmt -> as_escape($val -> {escape }) if $val -> {escape } && $op =~ / ^(?:NOT\s +)?I?LIKE$ / ;
289- push @bind , $val -> { value } ;
343+ push @bind , $value ;
290344 }
291345 }
292346 } elsif (ref ($val ) eq ' SCALAR' ) {
0 commit comments