add support for direct SQL query of directory
Tara L Andrews [Thu, 23 Feb 2012 02:09:18 +0000 (03:09 +0100)]
Makefile.PL
lib/Text/Tradition/Directory.pm
script/strip_punctuation.pl
stemmaweb/lib/stemmaweb/Controller/Root.pm
t/text_tradition_directory.t

index 2ac2f1e..7fdbba7 100644 (file)
@@ -7,6 +7,7 @@ perl_version( '5.012' );
 all_from( 'lib/Text/Tradition.pm' );
 requires( 'Algorithm::Diff' );
 requires( 'Bio::Phylo::IO' );
+requires( 'DBI' );
 requires( 'File::chdir' );
 requires( 'File::Which' );
 requires( 'Graph' );
index 9293d0c..8783b96 100644 (file)
@@ -3,6 +3,7 @@ package Text::Tradition::Directory;
 use strict;
 use warnings;
 use Moose;
+use DBI;
 use KiokuDB::GC::Naive;
 use KiokuDB::TypeMap;
 use KiokuDB::TypeMap::Entry::Naive;
@@ -40,9 +41,9 @@ Text::Tradition::Directory is an interface for storing and retrieving text tradi
 
 Returns a Directory object. 
 
-=head2 tradition_ids
+=head2 traditionlist
 
-Returns the ID of all traditions in the database.
+Returns a hashref mapping of ID => name for all traditions in the directory.
 
 =head2 tradition( $id )
 
@@ -106,11 +107,14 @@ is( ref( $nt ), 'Text::Tradition', "Made new tradition" );
 {
        my $f = Text::Tradition::Directory->new( 'dsn' => $dsn );
        my $scope = $f->new_scope;
-       is( scalar $f->tradition_ids, 1, "Directory index has our tradition" );
+       is( scalar $f->traditionlist, 1, "Directory index has our tradition" );
        my $nuuid = $f->save( $nt );
        ok( $nuuid, "Stored second tradition" );
-       is( scalar $f->tradition_ids, 2, "Directory index has both traditions" );
+       my @tlist = $f->traditionlist;
+       is( scalar @tlist, 2, "Directory index has both traditions" );
        my $tf = $f->tradition( $uuid );
+       my( $tlobj ) = grep { $_->{'id'} eq $uuid } @tlist;
+       is( $tlobj->{'name'}, $tf->name, "Directory index has correct tradition name" );
        is( $tf->name, $t->name, "Retrieved the tradition from a new directory" );
        my $sid = $f->object_to_id( $tf->stemma(0) );
        try {
@@ -129,13 +133,13 @@ is( ref( $nt ), 'Text::Tradition', "Made new tradition" );
        $f->delete( $uuid );
        ok( !$f->exists( $uuid ), "Object is deleted from DB" );
        ok( !$f->exists( $sid ), "Object stemma also deleted from DB" );
-       is( scalar $f->tradition_ids, 1, "Object is deleted from index" );
+       is( scalar $f->traditionlist, 1, "Object is deleted from index" );
 }
 
 {
        my $g = Text::Tradition::Directory->new( 'dsn' => $dsn );
        my $scope = $g->new_scope;
-       is( scalar $g->tradition_ids, 1, "Now one object in new directory index" );
+       is( scalar $g->traditionlist, 1, "Now one object in new directory index" );
 }
 
 =end testing
@@ -155,6 +159,32 @@ has +typemap => (
        },
 );
 
+# Push some columns into the extra_args
+around BUILDARGS => sub {
+       my $orig = shift;
+       my $class = shift;
+       my $args;
+       if( @_ == 1 ) {
+               $args = $_[0];
+       } else {
+               $args = { @_ };
+       }
+       if( $args->{'dsn'} =~ /^dbi/ ) { # We're using Backend::DBI
+               my @column_args = ( 'columns',
+                       [ 'name' => { 'data_type' => 'varchar', 'is_nullable' => 1 } ] );
+               my $ea = $args->{'extra_args'};
+               if( ref( $ea ) eq 'ARRAY' ) {
+                       push( @$ea, @column_args );
+               } elsif( ref( $ea ) eq 'HASH' ) {
+                       $ea = { %$ea, @column_args };
+               } else {
+                       $ea = { @column_args };
+               }
+               $args->{'extra_args'} = $ea;
+       }
+       return $class->$orig( $args );
+};
+
 before [ qw/ store update insert delete / ] => sub {
        my $self = shift;
        my @nontrad;
@@ -196,11 +226,31 @@ sub tradition {
        return $obj;
 }
 
-sub tradition_ids {
+sub traditionlist {
        my $self = shift;
-       my @ids;
-       $self->scan( sub { push( @ids, $self->object_to_id( @_ ) ) } );
-       return @ids;
+       # If we are using DBI, we can do it the easy way; if not, the hard way.
+       # Easy way still involves making a separate DBI connection. Ew.
+       my @tlist;
+       if( $self->dsn =~ /^dbi/ ) {
+               $DB::single = 1;
+               my @connection = @{$self->directory->backend->connect_info};
+               # Get rid of KiokuDB-specific arg
+               pop @connection if scalar @connection > 4;
+               $connection[3]->{'sqlite_unicode'} = 1 if $connection[0] =~ /^dbi:SQLite/;
+               $connection[3]->{'mysql_enable_utf8'} = 1 if $connection[0] =~ /^dbi:mysql/;
+               $connection[3]->{'pg_enable_utf8'} = 1 if $connection[0] =~ /^dbi:Pg/;
+               my $dbh = DBI->connect( @connection );
+               my $q = $dbh->prepare( 'SELECT id, name from entries WHERE class = "Text::Tradition"' );
+               $q->execute();
+               while( my @row = $q->fetchrow_array ) {
+                       push( @tlist, { 'id' => $row[0], 'name' => $row[1] } );
+               }
+       } else {
+               $self->scan( sub { my $o = shift; 
+                                                  push( @tlist, { 'id' => $self->object_to_id( $o ), 
+                                                                                  'name' => $o->name } ) } );
+       }
+       return @tlist;
 }
 
 sub throw {
index fceb484..db1189d 100755 (executable)
@@ -14,7 +14,8 @@ $connect_args->{'extra_args'} = { user => $user, password => $pass }
        if $user && $pass;
 my $dir = Text::Tradition::Directory->new( $connect_args );
 
-foreach my $id ( $dir->tradition_ids ) {
+foreach my $text ( $dir->traditionlist ) {
+       my $id = $text->{'id'};
        my $scope = $dir->new_scope;
        my $tradition = $dir->lookup( $id );
        print STDERR "Processing tradition " . $tradition->name . "\n";
index cd6cb76..c33b9f0 100644 (file)
@@ -49,12 +49,7 @@ sub directory :Local :Args(0) {
     my $m = $c->model('Directory');
     # TODO not used yet, will load user texts later
     my $user = $c->request->param( 'user' ) || 'ALL';
-    my @textlist;
-    $m->scan( sub { 
-       push( @textlist, {
-               'id' => $m->object_to_id( @_ ),
-               'name' => $_[0]->name } ) 
-       } );    
+    my @textlist = $m->traditionlist();
     $c->stash->{texts} = \@textlist;
        $c->stash->{template} = 'directory.tt';
 }
index dd8eeec..5ca1a3e 100644 (file)
@@ -55,11 +55,14 @@ is( ref( $nt ), 'Text::Tradition', "Made new tradition" );
 {
        my $f = Text::Tradition::Directory->new( 'dsn' => $dsn );
        my $scope = $f->new_scope;
-       is( scalar $f->tradition_ids, 1, "Directory index has our tradition" );
+       is( scalar $f->traditionlist, 1, "Directory index has our tradition" );
        my $nuuid = $f->save( $nt );
        ok( $nuuid, "Stored second tradition" );
-       is( scalar $f->tradition_ids, 2, "Directory index has both traditions" );
+       my @tlist = $f->traditionlist;
+       is( scalar @tlist, 2, "Directory index has both traditions" );
        my $tf = $f->tradition( $uuid );
+       my( $tlobj ) = grep { $_->{'id'} eq $uuid } @tlist;
+       is( $tlobj->{'name'}, $tf->name, "Directory index has correct tradition name" );
        is( $tf->name, $t->name, "Retrieved the tradition from a new directory" );
        my $sid = $f->object_to_id( $tf->stemma(0) );
        try {
@@ -78,13 +81,13 @@ is( ref( $nt ), 'Text::Tradition', "Made new tradition" );
        $f->delete( $uuid );
        ok( !$f->exists( $uuid ), "Object is deleted from DB" );
        ok( !$f->exists( $sid ), "Object stemma also deleted from DB" );
-       is( scalar $f->tradition_ids, 1, "Object is deleted from index" );
+       is( scalar $f->traditionlist, 1, "Object is deleted from index" );
 }
 
 {
        my $g = Text::Tradition::Directory->new( 'dsn' => $dsn );
        my $scope = $g->new_scope;
-       is( scalar $g->tradition_ids, 1, "Now one object in new directory index" );
+       is( scalar $g->traditionlist, 1, "Now one object in new directory index" );
 }
 }