1 package DBIx::Class::SQL::Abstract;
3 # Many thanks to SQL::Abstract, from which I stole most of this
8 my ($self, $cond, $attrs, $join) = @_;
9 my $ref = ref $cond || '';
10 $join ||= $attrs->{logic} || ($ref eq 'ARRAY' ? 'OR' : 'AND');
11 my $cmp = uc($attrs->{cmp}) || '=';
13 # For assembling SQL fields and values
16 # If an arrayref, then we join each element
17 if ($ref eq 'ARRAY') {
18 # need to use while() so can shift() for arrays
19 while (my $el = shift @$cond) {
22 # skip empty elements, otherwise get invalid trailing AND stuff
23 if (my $ref2 = ref $el) {
24 if ($ref2 eq 'ARRAY') {
26 } elsif ($ref2 eq 'HASH') {
29 } elsif ($ref2 eq 'SCALAR') {
34 $self->_debug("$ref2(*top) means join with $subjoin");
36 # top-level arrayref with scalars, recurse in pairs
37 $self->_debug("NOREF(*top) means join with $subjoin");
38 $el = {$el => shift(@$cond)};
40 push @sqlf, scalar $self->_cond_resolve($el, $attrs, $subjoin);
43 elsif ($ref eq 'HASH') {
44 # Note: during recursion, the last element will always be a hashref,
45 # since it needs to point a column => value. So this be the end.
46 for my $k (sort keys %$cond) {
50 $self->_debug("UNDEF($k) means IS NULL");
51 push @sqlf, $k . ' IS NULL'
52 } elsif (ref $v eq 'ARRAY') {
53 # multiple elements: multiple options
54 $self->_debug("ARRAY($k) means multiple elements: [ @$v ]");
56 # map into an array of hashrefs and recurse
58 push @w, { $k => $_ } for @$v;
59 push @sqlf, scalar $self->_cond_resolve(\@w, $attrs, 'OR');
61 } elsif (ref $v eq 'HASH') {
62 # modified operator { '!=', 'completed' }
63 for my $f (sort keys %$v) {
65 $self->_debug("HASH($k) means modified operator: { $f }");
67 # check for the operator being "IN" or "BETWEEN" or whatever
68 if ($f =~ /^([\s\w]+)$/i && ref $x eq 'ARRAY') {
70 if ($u =~ /BETWEEN/) {
72 $self->throw( "BETWEEN must have exactly two arguments" ) unless @$x == 2;
74 $self->_cond_key($attrs => $k), $u,
75 $self->_cond_value($attrs => $k => $x->[0]),
77 $self->_cond_value($attrs => $k => $x->[1]);
79 push @sqlf, join ' ', $self->_cond_key($attrs, $k), $u, '(',
81 map { $self->_cond_value($attrs, $k, $_) } @$x),
84 } elsif (ref $x eq 'ARRAY') {
85 # multiple elements: multiple options
86 $self->_debug("ARRAY($x) means multiple elements: [ @$x ]");
88 # map into an array of hashrefs and recurse
90 push @w, { $k => { $f => $_ } } for @$x;
91 push @sqlf, scalar $self->_cond_resolve(\@w, $attrs, 'OR');
93 } elsif (! defined($x)) {
95 my $not = ($f eq '!=' || $f eq 'not like') ? ' NOT' : '';
96 push @sqlf, $self->_cond_key($attrs => $k) . " IS${not} NULL";
99 push @sqlf, join ' ', $self->_cond_key($attrs => $k), $f,
100 $self->_cond_value($attrs => $k => $x);
103 } elsif (ref $v eq 'SCALAR') {
105 $self->_debug("SCALAR($k) means literal SQL: $$v");
106 push @sqlf, join ' ', $self->_cond_key($attrs => $k), $$v;
108 # standard key => val
109 $self->_debug("NOREF($k) means simple key=val: $k ${cmp} $v");
110 push @sqlf, join ' ', $self->_cond_key($attrs => $k), $cmp,
111 $self->_cond_value($attrs => $k => $v);
115 elsif ($ref eq 'SCALAR') {
117 $self->_debug("SCALAR(*top) means literal SQL: $$cond");
120 elsif (defined $cond) {
122 $self->_debug("NOREF(*top) means literal SQL: $cond");
126 # assemble and return sql
127 my $wsql = @sqlf ? '( ' . join(" $join ", @sqlf) . ' )' : '1 = 1';
128 return wantarray ? ($wsql, @{$attrs->{bind} || []}) : $wsql;
132 my ($self, $attrs, $key) = @_;
137 my ($self, $attrs, $key, $value) = @_;
138 push(@{$attrs->{bind}}, $value);
146 DBIx::Class::SQL::Abstract - SQL::Abstract customized for DBIC.
152 This is a customized version of L<SQL::Abstract> for use in
153 generating L<DBIx::Searchbuilder> searches.
159 Matt S. Trout <perl-stuff@trout.me.uk>
163 You may distribute this code under the same terms as Perl itself.