From: Gordon Irving Date: Sat, 12 Dec 2009 21:09:39 +0000 (+0000) Subject: commit refactored dbicadmin script and very minor changes to its existing test suite X-Git-Tag: v0.08119~9^2~41 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=fd27648a069a0e01b9b7369fe9341c02d84c92bd;p=dbsrgits%2FDBIx-Class.git commit refactored dbicadmin script and very minor changes to its existing test suite --- diff --git a/script/dbicadmin b/script/dbicadmin index d6c8ecd..356b537 100755 --- a/script/dbicadmin +++ b/script/dbicadmin @@ -1,221 +1,109 @@ -#!/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= user= password= '], + ['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 = ; - 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'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 +refactored by +Gordon Irving + =head1 LICENSE You may distribute this code under the same terms as Perl itself. - diff --git a/t/89dbicadmin.t b/t/89dbicadmin.t index 1729d2d..0baaacd 100644 --- a/t/89dbicadmin.t +++ b/t/89dbicadmin.t @@ -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" ); }