commit refactored dbicadmin script and very minor changes to its existing test suite
Gordon Irving [Sat, 12 Dec 2009 21:09:39 +0000 (21:09 +0000)]
script/dbicadmin
t/89dbicadmin.t

index d6c8ecd..356b537 100755 (executable)
-#!/usr/bin/perl
+#!/usr/bin/perl 
+
 use strict;
 use warnings;
 
-use Getopt::Long;
-use Pod::Usage;
-use JSON::Any;
-
-
-my $json = JSON::Any->new(allow_barekey => 1, allow_singlequote => 1);
-
-GetOptions(
-    'schema=s'  => \my $schema_class,
-    'class=s'   => \my $resultset_class,
-    'connect=s' => \my $connect,
-    'op=s'      => \my $op,
-    'set=s'     => \my $set,
-    'where=s'   => \my $where,
-    'attrs=s'   => \my $attrs,
-    'format=s'  => \my $format,
-    'force'     => \my $force,
-    'trace'     => \my $trace,
-    'quiet'     => \my $quiet,
-    'help'      => \my $help,
-    'tlibs'      => \my $t_libs,
+use Getopt::Long::Descriptive;
+
+use FindBin qw($Bin);
+use Path::Class;
+use lib dir($Bin,'..','lib')->stringify;
+
+use DBIx::Class::Admin;
+
+
+my ($opts, $usage) = describe_options(
+       "%c: %o",
+       (
+               ['Actions'],
+               ["action" => hidden => { one_of => [
+                       ['create|c' => 'Create version diffs needs preversion',],
+                       ['upgrade|u' => 'Upgrade the database to the current schema '],
+                       ['install|i' => 'Install the schema to the database',],
+                       ['deploy|d' => 'Deploy the schema to the database',],
+                       ['select|s'   => 'Select data from the schema', ],
+                       ['insert|i'   => 'Insert data into the schema', ],
+                       ['update|u'   => 'Update data in the schema', ], 
+                       ['delete|D'   => 'Delete data from the schema',],
+                       ['help|h' => 'display this help'],
+               ], required=> 1 }],
+               ['Options'],
+               ['schema-class|schema|C:s' => 'The class of the schema to load', { required => 1 } ],
+               ['resultset|resultset_class|class|r:s' => 'The resultset to operate on for data manipulation' ],
+               ['config-stanza|S:s' => 'Where in the config to find the connection_info, supply in form MyApp::Model::DB',],
+               ['config|f:s' => 'Supply the config file for parsing by Config::Any', { depends => 'config_stanza'} ],
+               ['connect-info|n:s%' => 'Supply the connect info as additonal options ie -I dsn=<dsn> user=<user> password=<pass> '],
+               ['connect:s' => 'Supply the connect info as a json string' ],
+               ['sql-dir|q:s' => 'The directory where sql diffs will be created'],
+               ['sql-type|t:s' => 'The RDBMs flavour you wish to use'],
+               ['version|v:i' => 'Supply a version install'],
+               ['preversion|p:s' => 'The previous version to diff against',],
+               ['set:s' => 'JSON data used to perform data operations' ],
+               ['lib|I:s' => 'Additonal library path to search in'], 
+               ['attrs:s' => 'JSON string to be used for the second argument for search'],
+               ['where:s' => 'JSON string to be used for the where clause of search'],
+               ['force' => 'Be forceful with some operations'],
+               ['trace' => 'Turn on DBIx::Class trace output'],
+               ['tlibs' => 'Include test dirs in @INC'],
+               ['quiet' => 'Be less verbose'],
+       )
 );
 
-if ($t_libs) {
-    unshift( @INC, 't/lib', 'lib' );
-}
 
-pod2usage(1) if ($help);
-$ENV{DBIC_TRACE} = 1 if ($trace);
-
-die('No op specified') if(!$op);
-die('Invalid op') if ($op!~/^insert|update|delete|select$/s);
-my $csv_class;
-if ($op eq 'select') {
-    $format ||= 'tsv';
-    die('Invalid format') if ($format!~/^tsv|csv$/s);
-    $csv_class = 'Text::CSV_XS';
-    eval{ require Text::CSV_XS };
-    if ($@) {
-        $csv_class = 'Text::CSV_PP';
-        eval{ require Text::CSV_PP };
-        die('The select op requires either the Text::CSV_XS or the Text::CSV_PP module') if ($@);
-    }
+if ($opts->{help}) {
+       print $usage->text;
+       exit 0;
 }
 
-die('No schema specified') if(!$schema_class);
-eval("require $schema_class");
-die('Unable to load schema') if ($@);
-$connect = $json->jsonToObj( $connect ) if ($connect);
-my $schema = $schema_class->connect(
-    ( $connect ? @$connect : () )
-);
-
-die('No class specified') if(!$resultset_class);
-my $resultset = eval{ $schema->resultset($resultset_class) };
-die('Unable to load the class with the schema') if ($@);
+if ($opts->{tlibs}) {
+    unshift( @INC, 't/lib', 'lib' );
+}
 
-$set = $json->jsonToObj( $set ) if ($set);
-$where = $json->jsonToObj( $where ) if ($where);
-$attrs = $json->jsonToObj( $attrs ) if ($attrs);
+die "please only use one of --config or --connect-info" if ($opts->{config} and $opts->{connect_info});
 
-if ($op eq 'insert') {
-    die('Do not use the where option with the insert op') if ($where);
-    die('Do not use the attrs option with the insert op') if ($attrs);
-    my $obj = $resultset->create( $set );
-    print ''.ref($resultset).' ID: '.join(',',$obj->id())."\n" if (!$quiet);
-}
-elsif ($op eq 'update') {
-    $resultset = $resultset->search( ($where||{}) );
-    my $count = $resultset->count();
-    print "This action will modify $count ".ref($resultset)." records.\n" if (!$quiet);
-    if ( $force || confirm() ) {
-        $resultset->update_all( $set );
-    }
-}
-elsif ($op eq 'delete') {
-    die('Do not use the set option with the delete op') if ($set);
-    $resultset = $resultset->search( ($where||{}), ($attrs||()) );
-    my $count = $resultset->count();
-    print "This action will delete $count ".ref($resultset)." records.\n" if (!$quiet);
-    if ( $force || confirm() ) {
-        $resultset->delete_all();
-    }
-}
-elsif ($op eq 'select') {
-    die('Do not use the set option with the select op') if ($set);
-    my $csv = $csv_class->new({
-        sep_char => ( $format eq 'tsv' ? "\t" : ',' ),
-    });
-    $resultset = $resultset->search( ($where||{}), ($attrs||()) );
-    my @columns = $resultset->result_source->columns();
-    $csv->combine( @columns );
-    print $csv->string()."\n";
-    while (my $row = $resultset->next()) {
-        my @fields;
-        foreach my $column (@columns) {
-            push( @fields, $row->get_column($column) );
-        }
-        $csv->combine( @fields );
-        print $csv->string()."\n";
-    }
+# option compatability mangle
+if($opts->{connect}) {
+       $opts->{connect_info} = delete $opts->{connect};
 }
 
-sub confirm {
-    print "Are you sure you want to do this? (type YES to confirm) ";
-    my $response = <STDIN>;
-    return 1 if ($response=~/^YES/);
-    return;
+my $admin = DBIx::Class::Admin->new( %$opts );
+
+
+my $action = $opts->{action};
+print "going to perform action $action\n";
+my $res = $admin->$action();
+
+if ($action eq 'select') {
+
+       my $csv_class;
+       my $format = $opts->{format} || 'tsv';
+       die('Invalid format') if ($format!~/^tsv|csv$/s);
+       $csv_class = 'Text::CSV_XS';
+       eval{ require Text::CSV_XS };
+       if ($@) {
+               $csv_class = 'Text::CSV_PP';
+               eval{ require Text::CSV_PP };
+               die('The select op requires either the Text::CSV_XS or the Text::CSV_PP module') if ($@);
+       }
+
+       my $csv = $csv_class->new({
+                       sep_char => ( $format eq 'tsv' ? "\t" : ',' ),
+               });
+       foreach my $row (@$res) {
+               $csv->combine( @$row );
+               print $csv->string()."\n";
+       }
 }
 
-__END__
-
-=head1 NAME
-
-dbicadmin - Execute operations upon DBIx::Class objects.
-
-=head1 SYNOPSIS
-
-  dbicadmin --op=insert --schema=My::Schema --class=Class --set=JSON
-  dbicadmin --op=update --schema=My::Schema --class=Class --set=JSON --where=JSON
-  dbicadmin --op=delete --schema=My::Schema --class=Class --where=JSON
-  dbicadmin --op=select --schema=My::Schema --class=Class --where=JSON --format=tsv
-
-=head1 DESCRIPTION
-
-This utility provides the ability to run INSERTs, UPDATEs, 
-DELETEs, and SELECTs on any DBIx::Class object.
-
-=head1 OPTIONS
-
-=head2 op
-
-The type of operation.  Valid values are insert, update, delete, 
-and select.
-
-=head2 schema
-
-The name of your schema class.
-
-=head2 class
-
-The name of the class, within your schema, that you want to run 
-the operation on.
-
-=head2 connect
 
-A JSON array to be passed to your schema class upon connecting.  
-The array will need to be compatible with whatever the DBIC 
-->connect() method requires.
-
-=head2 set
-
-This option must be valid JSON data string and is passed in to 
-the DBIC update() method.  Use this option with the update 
-and insert ops.
-
-=head2 where
-
-This option must be valid JSON data string and is passed in as 
-the first argument to the DBIC search() method.  Use this 
-option with the update, delete, and select ops.
-
-=head2 attrs
-
-This option must be valid JSON data string and is passed in as 
-the second argument to the DBIC search() method.  Use this 
-option with the update, delete, and select ops.
-
-=head2 help
-
-Display this help page.
-
-=head2 force
-
-Suppresses the confirmation dialogues that are usually displayed 
-when someone runs a DELETE or UPDATE action.
-
-=head2 quiet
-
-Do not display status messages.
-
-=head2 trace
-
-Turns on tracing on the DBI storage, thus printing SQL as it is 
-executed.
-
-=head2 tlibs
-
-This option is purely for testing during the DBIC installation.  Do 
-not use it.
-
-=head1 JSON
-
-JSON is a lightweight data-interchange format.  It allows you 
-to express complex data structures for use in the where and 
-set options.
-
-This module turns on L<JSON>'s BareKey and QuotApos options so 
-that your data can look a bit more readable.
-
-  --where={"this":"that"} # generic JSON
-  --where={this:'that'}   # with BareKey and QuoteApos
-
-Consider wrapping your JSON in outer quotes so that you don't 
-have to escape your inner quotes.
-
-  --where={this:\"that\"} # no outer quote
-  --where='{this:"that"}' # outer quoted
 
 =head1 AUTHOR
 
 Aran Deltac <bluefeet@cpan.org>
 
+refactored by 
+Gordon Irving <goraxe@cpan.org>
+
 =head1 LICENSE
 
 You may distribute this code under the same terms as Perl itself.
-
index 1729d2d..0baaacd 100644 (file)
@@ -38,28 +38,30 @@ sub test_dbicadmin {
 
     my $employees = $schema->resultset('Employee');
 
-    system( _prepare_system_args( qw|--op=insert --set={"name":"Matt"}| ) );
+    system( _prepare_system_args( qw|--insert --set={"name":"Matt"}| ) );
     ok( ($employees->count()==1), "$ENV{JSON_ANY_ORDER}: insert count" );
 
     my $employee = $employees->find(1);
     ok( ($employee->name() eq 'Matt'), "$ENV{JSON_ANY_ORDER}: insert valid" );
 
-    system( _prepare_system_args( qw|--op=update --set={"name":"Trout"}| ) );
+    system( _prepare_system_args( qw|--update --set={"name":"Trout"}| ) );
     $employee = $employees->find(1);
     ok( ($employee->name() eq 'Trout'), "$ENV{JSON_ANY_ORDER}: update" );
 
-    system( _prepare_system_args( qw|--op=insert --set={"name":"Aran"}| ) );
+    system( _prepare_system_args( qw|--insert --set={"name":"Aran"}| ) );
 
     SKIP: {
         skip ("MSWin32 doesn't support -| either", 1) if $^O eq 'MSWin32';
 
-        open(my $fh, "-|",  _prepare_system_args( qw|--op=select --attrs={"order_by":"name"}| ) ) or die $!;
+        open(my $fh, "-|",  _prepare_system_args( qw|--select --attrs={"order_by":"name"}| ) ) or die $!;
         my $data = do { local $/; <$fh> };
         close($fh);
-        ok( ($data=~/Aran.*Trout/s), "$ENV{JSON_ANY_ORDER}: select with attrs" );
+        if (!ok( ($data=~/Aran.*Trout/s), "$ENV{JSON_ANY_ORDER}: select with attrs" )) {
+                       diag ("data from select is $data")
+               };
     }
 
-    system( _prepare_system_args( qw|--op=delete --where={"name":"Trout"}| ) );
+    system( _prepare_system_args( qw|--delete --where={"name":"Trout"}| ) );
     ok( ($employees->count()==1), "$ENV{JSON_ANY_ORDER}: delete" );
 }