[Jifty-commit] r5724 - Jifty-DBI/branches/tisql/lib/Jifty/DBI
Jifty commits
jifty-commit at lists.jifty.org
Thu Aug 14 20:59:17 EDT 2008
Author: ruz
Date: Thu Aug 14 20:59:14 2008
New Revision: 5724
Modified:
Jifty-DBI/branches/tisql/lib/Jifty/DBI/Tisql.pm
Log:
* fix all failing tisql tests
* a lot changes here and there, so even `svk ci -i` doesn't
help, I hope nobody follows diffs. Otherwise sorry, guys.
Modified: Jifty-DBI/branches/tisql/lib/Jifty/DBI/Tisql.pm
==============================================================================
--- Jifty-DBI/branches/tisql/lib/Jifty/DBI/Tisql.pm (original)
+++ Jifty-DBI/branches/tisql/lib/Jifty/DBI/Tisql.pm Thu Aug 14 20:59:14 2008
@@ -104,30 +104,86 @@
die "wrong query tree";
}
+ $self->apply_query_condition( $collection, $ea, $element, $join );
+ }
+ $collection->close_paren('tisql', $join);
+}
+
+sub apply_query_condition {
+ my ($self, $collection, $ea, $condition, $join) = @_;
+
+ die "left hand side must be always column specififcation"
+ unless ref $condition->{'lhs'};
+
+ my $prefix = $condition->{'prefix'};
+ my $op = $condition->{'op'};
+ my $long = do {
+ my @tmp = split /\./, $condition->{'lhs'}{'string'};
+ @tmp > 2 ? 1 : 0
+ };
+ if ( $long && !$prefix && $op =~ $re_negative_op ) {
+ $prefix = 'has no';
+ $op = $invert_op{ lc $op };
+ }
+ elsif ( $prefix && !$long ) {
+ die "'has no' and 'has' prefixes are only applicable on columns of related records";
+ }
+ $prefix ||= 'has';
+
+ if ( $prefix eq 'has' ) {
my %limit = (
subclause => 'tisql',
leftjoin => $join,
entry_aggregator => $ea,
- operator => $element->{'op'},
+ alias => $self->resolve_join( $condition->{'lhs'} ),
+ column => $condition->{'lhs'}{'chain'}[-1]->name,
+ operator => $op,
);
- if ( ref $element->{'lhs'} ) {
- $limit{'alias'} = $self->resolve_join( $element->{'lhs'} );
- $limit{'column'} = $element->{'lhs'}{'chain'}[-1]->name;
+ if ( ref $condition->{'rhs'} ) {
+ $limit{'quote_value'} = 0;
+ $limit{'value'} =
+ $self->resolve_join( $condition->{'rhs'} )
+ .'.'. $condition->{'rhs'}{'chain'}[-1]->name;
} else {
- die "left hand side must be always column specififcation";
+ $limit{'value'} = $condition->{'rhs'};
}
- if ( ref $element->{'rhs'} ) {
+
+ $collection->limit( %limit );
+ }
+ else {
+ die "not yet implemented: it's a join" if $join;
+
+ my %limit = (
+ subclause => 'tisql',
+ alias => $self->resolve_join( $condition->{'lhs'} ),
+ column => $condition->{'lhs'}{'chain'}[-1]->name,
+ operator => $op,
+ );
+ if ( ref $condition->{'rhs'} ) {
$limit{'quote_value'} = 0;
$limit{'value'} =
- $self->resolve_join( $element->{'rhs'} )
- .'.'. $element->{'rhs'}{'chain'}[-1]->name;
+ $self->resolve_join( $condition->{'rhs'} )
+ .'.'. $condition->{'rhs'}{'chain'}[-1]->name;
} else {
- $limit{'value'} = $element->{'rhs'};
+ $limit{'value'} = $condition->{'rhs'};
}
- $collection->limit( %limit );
+ $collection->limit(
+ %limit,
+ entry_aggregator => 'AND',
+ leftjoin => $limit{'alias'},
+ );
+
+ $collection->limit(
+ subclause => 'tisql',
+ entry_aggregator => $ea,
+ alias => $limit{'alias'},
+ column => 'id',
+ operator => 'IS',
+ value => 'NULL',
+ quote_value => 0,
+ );
}
- $collection->close_paren('tisql', $join);
}
sub resolve_join {
@@ -138,22 +194,26 @@
my $collection = $self->{'collection'};
- my $last_alias = 'main';
+ my ($last_alias) = ('main');
if ( my $prev = $meta->{'previous'} ) {
$last_alias = $self->resolve_join( $prev );
}
my @chain = @{ $meta->{'chain'} };
+ if ( @chain == 1 && !$chain[0]->virtual ) {
+ return $last_alias;
+ }
+
while( my $column = shift @chain ) {
my $name = $column->name;
+ return $last_alias unless @chain;
+
my $classname = $column->refers_to;
unless ( $classname ) {
die "column '$name' is not a reference when there are still items in the chain"
if @chain;
- return $meta->{'sql_alias'} = $last_alias;
- } elsif ( !@chain && !$column->virtual ) {
- return $meta->{'sql_alias'} = $last_alias;
+ return $last_alias;
}
if ( UNIVERSAL::isa( $classname, 'Jifty::DBI::Collection' ) ) {
@@ -161,9 +221,10 @@
my $right_alias;
if ( my $tisql = $column->tisql ) {
$right_alias = $self->resolve_tisql_join(
- alias => $last_alias,
+ chain => $meta->{'previous'},
+ alias => $last_alias,
collection => $collection,
- column => $column,
+ column => $column,
);
} else {
$right_alias = $collection->new_alias( $item );
@@ -194,32 +255,42 @@
else {
die "Column '$name' refers to '$classname' which is not record or collection";
}
+
+ $meta->{'previous'} = {
+ chain => [$column],
+ previous => $meta->{'previous'},
+ string => ($meta->{'previous'}? $meta->{'previous'}{'string'} : '') .'.'. $name,
+ sql_alias => $last_alias,
+ };
+ $meta->{'chain'} = [ @chain ];
}
- $meta->{'sql_alias'} = $last_alias;
- return $last_alias;
+ return $meta->{'sql_alias'} = $last_alias;
}
sub resolve_tisql_join {
my $self = shift;
my %args = (@_);
-
+
my $collection = $args{'collection'};
- my $left_alias = $args{'alias'};
my $query = $args{'column'}->tisql;
- my $classname = $args{'column'}->refers_to;
- my $right_alias = $collection->new_alias( $classname->new( handle => $collection->_handle )->new_item );
+ my $right_alias = $collection->new_alias(
+ $args{'column'}->refers_to->new( handle => $collection->_handle )->new_item
+ );
my $tree = $self->as_array(
$query,
operand_cb => sub { return $self->parse_condition(
$_[0], sub { return $self->find_column(
$_[0],
- { $args{'column'}->name => {
- chain => [ $args{'column'} ],
- string => '',
- sql_alias => $right_alias,
- } },
+ {
+ '' => $args{'chain'},
+ $args{'column'}->name => {
+ chain => [ $args{'column'} ],
+ string => '',
+ sql_alias => $right_alias,
+ }
+ },
) }
) },
);
@@ -234,21 +305,39 @@
my $string = shift;
my $cb = shift;
- if ( $string =~ /^($re_column)\s*($re_sql_op_bin)\s*($re_value)$/o ) {
- my ($lhs, $op, $rhs) = ($cb->($1), $2, $3);
+ if ( $string =~ /^(has(\s+no)?\s+)?($re_column)\s*($re_sql_op_bin)\s*($re_value)$/io ) {
+ my ($lhs, $op, $rhs) = ($cb->($3), $4, $5);
+ my $prefix;
+ $prefix = 'has' if $1;
+ $prefix .= ' no' if $2;
if ( $rhs =~ /^$re_delim$/ ) {
$rhs =~ s/^["']//g;
$rhs =~ s/["']$//g;
}
- return { lhs => $lhs, op => $op, rhs => $rhs };
+ die "Last column in '". $lhs->{'string'} ."' is virtual and can not be used in condition '$string'"
+ if $lhs->{'chain'}[-1]->virtual;
+ return { string => $string, prefix => $prefix, lhs => $lhs, op => $op, rhs => $rhs };
}
elsif ( $string =~ /^($re_column)\s*($re_sql_op_un)$/o ) {
my ($lhs, $op, $rhs) = ($cb->($1), $2, $3);
($op, $rhs) = split /\s*(?=null)/i, $op;
- return { lhs => $lhs, op => $op, rhs => $rhs };
+ die "Last column in '". $lhs->{'string'} ."' is virtual and can not be used in condition '$string'"
+ if $lhs->{'chain'}[-1]->virtual;
+ return { string => $string, lhs => $lhs, op => $op, rhs => $rhs };
+ }
+ elsif ( $string =~ /^(has(\s+no)?\s+)?($re_column)\s*($re_sql_op_bin)\s*($re_column)$/o ) {
+ my ($lhs, $op, $rhs) = ($cb->($3), $4, $cb->($5));
+ my $prefix;
+ $prefix = 'has' if $1;
+ $prefix .= ' no' if $2;
+ die "Last column in '". $lhs->{'string'} ."' is virtual and can not be used in condition '$string'"
+ if $lhs->{'chain'}[-1]->virtual;
+ die "Last column in '". $rhs->{'string'} ."' is virtual and can not be used in condition '$string'"
+ if $rhs->{'chain'}[-1]->virtual;
+ return { string => $string, prefix => $prefix, lhs => $lhs, op => $op, rhs => $rhs };
}
- elsif ( $string =~ /^($re_column)\s*($re_sql_op_bin)\s*($re_column)$/o ) {
- return { lhs => $cb->($1), op => $2, rhs => $cb->($3) };
+ elsif ( $string =~ /^has(\s+no)?\s+($re_column)$/o ) {
+ return { string => $string, lhs => $cb->( $2 .'.id' ), op => $1? 'IS NOT': 'IS', rhs => 'NULL' };
}
else {
die "$string is not a tisql condition";
@@ -269,10 +358,10 @@
my ($start_from, @names) = split /\./, $string;
my $item;
- unless ( $start_from ) {
+ if ( !$start_from && !$aliases->{''} ) {
$item = $collection->new_item;
} else {
- my $alias = $aliases->{ $start_from }
+ my $alias = $aliases->{ $start_from || '' }
|| die "$start_from alias is not declared in from clause";
$res{'previous'} = $alias;
my $classname = $alias->{'chain'}[-1]->refers_to; # ->new( handle => $collection->_handle );
More information about the Jifty-commit
mailing list