[Jifty-commit] r5966 - in Jifty-DBI/branches/tisql: lib/Jifty/DBI t/tisql

Jifty commits jifty-commit at lists.jifty.org
Wed Oct 29 10:18:17 EDT 2008


Author: ruz
Date: Wed Oct 29 10:18:13 2008
New Revision: 5966

Added:
   Jifty-DBI/branches/tisql/t/tisql/searches_placeholders.t
Modified:
   Jifty-DBI/branches/tisql/Makefile.PL
   Jifty-DBI/branches/tisql/lib/Jifty/DBI/Tisql.pm

Log:
* add initial simple support for bind values to avoid escaping:
1) <column> <op> "?"
2) <field.field{?}>...
* query method takes bindings as well after query string

Modified: Jifty-DBI/branches/tisql/Makefile.PL
==============================================================================
--- Jifty-DBI/branches/tisql/Makefile.PL	(original)
+++ Jifty-DBI/branches/tisql/Makefile.PL	Wed Oct 29 10:18:13 2008
@@ -48,5 +48,6 @@
     ],
 );
 auto_install();
+tests("t/*.t t/*/*.t");
 &WriteAll;
 

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	Wed Oct 29 10:18:13 2008
@@ -13,11 +13,13 @@
 my $re_field      = qr{[a-zA-Z][a-zA-Z0-9_]*};
 my $re_alias_name = $re_field;
 my $re_ph         = qr{%[1-9][0-9]*};
+my $re_binding    = qr{\?};
 
 my $re_value      = qr{$re_delim|[0-9.]+};
 my $re_value_ph   = qr{$re_value|$re_ph};
+my $re_value_ph_b = qr{$re_value_ph|$re_binding};
 my $re_cs_values  = qr{$re_value(?:\s*,\s*$re_value)*};
-my $re_ph_access  = qr{{\s*(?:$re_cs_values|$re_ph)?\s*}};
+my $re_ph_access  = qr{{\s*(?:$re_cs_values|$re_ph|$re_binding)?\s*}};
 my $re_column     = qr{$re_alias_name?(?:\.$re_field$re_ph_access*)+};
 my $re_alias      = qr{$re_column\s+AS\s+$re_alias_name}i;
 
@@ -39,6 +41,19 @@
     '<=' => '>',
 );
 
+sub enq {
+    if ( defined wantarray ) {
+        my $s = $_[0];
+        $s =~ s/'/\\'/g;
+        return "'$s'";
+    } else {
+        $_[0] =~ s/'/\\'/g;
+        substr($_[0], 0, 0) = "'";
+        $_[0] .= "'";
+        return;
+    }
+}
+
 sub dq {
     my $s = $_[0];
     return $s unless $s =~ /^$re_delim$/o;
@@ -71,8 +86,9 @@
 }
 
 sub query {
-    my $self = shift;
+    my $self   = shift;
     my $string = shift;
+    my @binds  = @_;
 
     my $tree = {
         aliases => {},
@@ -92,10 +108,11 @@
             $_[0], sub { $self->find_column( $_[0], $tree->{'aliases'} ) }
         );
     };
-
+    $self->{'bindings'} = \@binds;
     $tree->{'conditions'} = $self->as_array(
         $string, operand_cb => $operand_cb,
     );
+    $self->{'bindings'} = undef;
     $self->{'tisql'}{'conditions'} = $tree->{'conditions'};
     $self->apply_query_tree( $tree->{'conditions'} );
     return $self;
@@ -362,8 +379,9 @@
     my $string = shift;
     my $cb = shift;
 
-    if ( $string =~ /^(has(\s+no)?\s+)?($re_column)\s*($re_sql_op_bin)\s*($re_value_ph)$/io ) {
+    if ( $string =~ /^(has(\s+no)?\s+)?($re_column)\s*($re_sql_op_bin)\s*($re_value_ph_b)$/io ) {
         my ($lhs, $op, $rhs) = ($cb->($3), $4, $5);
+        enq( $rhs = shift @{ $self->{'bindings'} } ) if $rhs eq '?';
         my $prefix;
         $prefix = 'has' if $1;
         $prefix .= ' no' if $2;
@@ -420,6 +438,9 @@
             if ( $ph =~ /^%([0-9]+)$/ ) {
                 $ph = $1;
             }
+            elsif ( $ph eq '?' ) {
+                enq( $ph = shift @{ $self->{'bindings'} } );
+            }
             else {
                 my @values;
                 while ( $ph =~ s/^($re_value)\s*,?\s*// ) {

Added: Jifty-DBI/branches/tisql/t/tisql/searches_placeholders.t
==============================================================================
--- (empty file)
+++ Jifty-DBI/branches/tisql/t/tisql/searches_placeholders.t	Wed Oct 29 10:18:13 2008
@@ -0,0 +1,165 @@
+#!/usr/bin/env perl -w
+
+use strict;
+use warnings;
+
+use File::Spec;
+use Test::More;
+
+BEGIN { require "t/utils.pl" }
+our (@available_drivers);
+
+use constant TESTS_PER_DRIVER => 8;
+
+my $total = scalar(@available_drivers) * TESTS_PER_DRIVER;
+plan tests => $total;
+
+use Data::Dumper;
+
+foreach my $d ( @available_drivers ) {
+SKIP: {
+    unless( has_schema( 'TestApp', $d ) ) {
+        skip "No schema for '$d' driver", TESTS_PER_DRIVER;
+    }
+    unless( should_test( $d ) ) {
+        skip "ENV is not defined for driver '$d'", TESTS_PER_DRIVER;
+    }
+
+    my $handle = get_handle( $d );
+    connect_handle( $handle );
+    isa_ok($handle->dbh, 'DBI::db');
+
+    my $ret = init_schema( 'TestApp', $handle );
+    isa_ok($ret, 'DBI::st', "Inserted the schema. got a statement handle back");
+
+    my $count_users = init_data( 'TestApp::User', $handle );
+    ok( $count_users,  "init users data" );
+
+    my $clean_obj = TestApp::UserCollection->new( handle => $handle );
+    my $users_obj = $clean_obj->clone;
+    is_deeply( $users_obj, $clean_obj, 'after Clone looks the same');
+
+    run_our_cool_tests(
+        $users_obj,
+        [".login = ?", 'a'] => { 'aa' => 1, 'ab' => 1, 'ac' => 1 },
+        [".login != ?", 'a'] => { 'ba' => 1, 'bb' => 1, 'bc' => 1, 'ca' => 1, 'cb' => 1, 'cc' => 1 },
+
+    );
+
+    cleanup_schema( 'TestApp', $handle );
+
+}} # SKIP, foreach blocks
+
+
+sub run_our_cool_tests {
+    my $collection = shift;
+    my @tests = @_;
+    while (@tests) {
+        my ($q, $check) = splice( @tests, 0, 2 );
+        $collection->clean_slate;
+        $collection->tisql->query( @$q );
+        my $expected_count = scalar grep $_, values %$check;
+        is($collection->count, $expected_count, "count is correct for ". $q->[0])
+            or diag "wrong count query: ". $collection->build_select_count_query;
+       
+        my @not_expected;
+        while (my $item = $collection->next ) {
+            my $t = $item->test;
+            push @not_expected, $t unless $check->{ $t };
+            delete $check->{ $t };
+        }
+        ok !@not_expected, 'didnt find additionals'
+            or diag "wrong query: ". $collection->build_select_query;
+    }
+}
+1;
+
+
+package TestApp;
+sub schema_sqlite {
+[
+q{
+CREATE table users (
+    id integer primary key,
+    test varchar(36),
+    login varchar(36),
+    name varchar(36)
+) },
+]
+}
+
+sub schema_mysql {
+[
+q{
+CREATE TEMPORARY table users (
+    id integer primary key AUTO_INCREMENT,
+    login varchar(36)
+) },
+]
+}
+
+sub schema_pg {
+[
+q{
+CREATE TEMPORARY table users (
+    id serial primary key,
+    login varchar(36)
+) },
+]
+}
+
+sub schema_oracle { [
+    "CREATE SEQUENCE users_seq",
+    "CREATE table users (
+        id integer CONSTRAINT users_Key PRIMARY KEY,
+        login varchar(36)
+    )",
+] }
+
+sub cleanup_schema_oracle { [
+    "DROP SEQUENCE users_seq",
+    "DROP table users", 
+] }
+
+package TestApp::User;
+
+use base qw/Jifty::DBI::Record/;
+our $VERSION = '0.01';
+
+BEGIN {
+use Jifty::DBI::Schema;
+use Jifty::DBI::Record schema {
+    column test => type is 'varchar(36)';
+    column login => type is 'varchar(36)';
+    column name => type is 'varchar(36)';
+};
+}
+
+sub init_data {
+    return (
+    [ 'test', 'login', 'name' ],
+
+    [ 'aa', 'a', 'a' ],
+    [ 'ab', 'a', 'b' ],
+    [ 'ac', 'a', 'c' ],
+    [ 'ba', 'b', 'a' ],
+    [ 'bb', 'b', 'b' ],
+    [ 'bc', 'b', 'c' ],
+    [ 'ca', 'c', 'a' ],
+    [ 'cb', 'c', 'b' ],
+    [ 'cc', 'c', 'c' ],
+    );
+}
+
+package TestApp::UserCollection;
+
+use base qw/Jifty::DBI::Collection/;
+our $VERSION = '0.01';
+
+sub _init {
+    my $self = shift;
+    $self->table('users');
+    return $self->SUPER::_init( @_ );
+}
+
+1;


More information about the Jifty-commit mailing list