From: Rafael Kitover Date: Sat, 23 May 2009 07:20:22 +0000 (+0000) Subject: DBIC::Schema - add tests for helper X-Git-Tag: v0.26~28 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=catagits%2FCatalyst-Model-DBIC-Schema.git;a=commitdiff_plain;h=4cbe63e7292ff70058c58e3c80ff11afa2c31cc3 DBIC::Schema - add tests for helper --- diff --git a/lib/Catalyst/Helper/Model/DBIC/Schema.pm b/lib/Catalyst/Helper/Model/DBIC/Schema.pm index 8c8d0f6..c3dadc9 100644 --- a/lib/Catalyst/Helper/Model/DBIC/Schema.pm +++ b/lib/Catalyst/Helper/Model/DBIC/Schema.pm @@ -9,7 +9,10 @@ use Carp; use Tie::IxHash (); use Data::Dumper (); use List::Util 'first'; -use MooseX::Types::Moose qw/Str HashRef Bool/; +use MooseX::Types::Moose qw/Str HashRef Bool ArrayRef/; +use Catalyst::Model::DBIC::Schema::Types 'CreateOption'; +use Moose::Autobox; +use List::MoreUtils 'firstidx'; use namespace::clean -except => 'meta'; @@ -97,7 +100,7 @@ Same, but with extra Schema::Loader args (separate multiple values by commas): script/myapp_create.pl model CatalystModelName DBIC::Schema \ MyApp::SchemaClass create=static db_schema=foodb components=Foo,Bar \ - exclude='^wibble|wobble$' moniker_map='{ foo => "FOO" }' \ + exclude='^(wibble|wobble)$' moniker_map='{ foo => "FOO" }' \ dbi:Pg:dbname=foodb myuname mypass See L for a list of options @@ -121,13 +124,14 @@ in your app config, or [not recommended] in the schema itself). =cut has helper => (is => 'ro', isa => 'Catalyst::Helper', required => 1); - +has create => (is => 'rw', isa => CreateOption); +has args => (is => 'ro', isa => ArrayRef); +has roles => (is => 'rw', isa => ArrayRef); has schema_class => (is => 'ro', isa => Str, required => 1); - has loader_args => (is => 'rw', isa => HashRef); has connect_info => (is => 'rw', isa => HashRef); - has old_schema => (is => 'rw', isa => Bool, lazy_build => 1); +has components => (is => 'rw', isa => ArrayRef); =head1 METHODS @@ -141,46 +145,68 @@ files. sub mk_compclass { my ($package, $helper, $schema_class, @args) = @_; - my $self = $package->new(helper => $helper, schema_class => $schema_class); + my $self = $package->new( + helper => $helper, + schema_class => $schema_class, + args => \@args + ); - $helper->{schema_class} = $schema_class; + $self->run; +} + +sub BUILD { + my $self = shift; + my $helper = $self->helper; + my @args = $self->args->flatten if $self->args; + + $helper->{schema_class} = $self->schema_class; @args = $self->_cleanup_args(\@args); - my $create = ''; - if ($args[0] && $args[0] =~ /^create=(dynamic|static)\z/) { - $create = $1; - shift @args; + my ($roles_idx, $roles); + if (($roles_idx = firstidx { ($roles) = /^roles=(\S*)\z/ } @args) != -1) { + my @roles = split /,/ => $roles; - if ($args[0] && $args[0] =~ /^roles=(.*)\z/) { - $helper->{roles} = '[' - .(join ',' => map { qq{'$_'} } (split /,/ => $1)) - .']'; - shift @args; - } + $self->roles(\@roles); + + $helper->{roles} = '[' + .(join ',' => map { qq{'$_'} } ($self->roles->flatten)) + .']'; + + splice @args, $roles_idx, 1, (); + } + + if ($args[0] && $args[0] =~ /^create=(\S*)\z/) { + $self->create($1); + shift @args; if (@args) { $self->_parse_loader_args(\@args); + $helper->{loader_args} = $self->_build_helper_loader_args; + if (first { /^dbi:/i } @args) { $helper->{setup_connect_info} = 1; $helper->{connect_info} = $self->_build_helper_connect_info(\@args); - $self->_parse_connect_info(\@args) if $create eq 'static'; + $self->_parse_connect_info(\@args); } } } $helper->{generator} = ref $self; $helper->{generator_version} = $VERSION; +} + +sub run { + my $self = shift; - if ($create eq 'dynamic') { + if ($self->create eq 'dynamic') { $self->_print_dynamic_deprecation_warning; - $self->helper->{loader_args} = $self->_build_helper_loader_args; $self->_gen_dynamic_schema; - } elsif ($create eq 'static') { + } elsif ($self->create eq 'static') { $self->_gen_static_schema; } @@ -203,6 +229,8 @@ sub _parse_loader_args { my @components = $self->_build_loader_components(delete $loader_args{components}); + $self->components(\@components); + for my $re_opt (qw/constraint exclude/) { $loader_args{$re_opt} = qr/$loader_args{$re_opt}/ if exists $loader_args{$re_opt}; @@ -234,7 +262,9 @@ sub _read_loader_args { while (@$args && $args->[0] !~ /^dbi:/) { my ($key, $val) = split /=/, shift(@$args), 2; - if ((my @vals = split /,/ => $val) > 1) { + if ($self->_is_struct($val)) { + $loader_args{$key} = $val; + } elsif ((my @vals = split /,/ => $val) > 1) { $loader_args{$key} = \@vals; } else { $loader_args{$key} = $val; @@ -302,7 +332,7 @@ sub _build_helper_connect_info { if (ref $val) { $val = $self->_data_struct_to_string($val); } else { - $val = qq{'$val'}; + $val = 'q{'.$val.'}'; } $helper_connect_info{$key} = $val; @@ -399,10 +429,16 @@ sub _parse_connect_info { \%connect_info } +sub _is_struct { + my ($self, $val) = @_; + + return $val =~ /^\s*[[{]/; +} + sub _quote_unless_struct { my ($self, $val) = @_; - $val = qq{'$val'} if $val !~ /^\s*[[{]/; + $val = 'q{'.$val.'}' if not $self->_is_struct($val); $val; } diff --git a/lib/Catalyst/Model/DBIC/Schema/Types.pm b/lib/Catalyst/Model/DBIC/Schema/Types.pm index 45a523e..88a7a00 100644 --- a/lib/Catalyst/Model/DBIC/Schema/Types.pm +++ b/lib/Catalyst/Model/DBIC/Schema/Types.pm @@ -1,7 +1,9 @@ package Catalyst::Model::DBIC::Schema::Types; -use MooseX::Types - -declare => [qw/ConnectInfo ConnectInfos Replicants SchemaClass CursorClass/]; +use MooseX::Types -declare => [qw/ + ConnectInfo ConnectInfos Replicants SchemaClass CursorClass + CreateOption +/]; use Carp::Clan '^Catalyst::Model::DBIC::Schema'; use MooseX::Types::Moose qw/ArrayRef HashRef Str ClassName/; @@ -56,6 +58,13 @@ coerce ConnectInfos, : die 'invalid connect_info' } @$_ ] }; +# Helper stuff + +subtype CreateOption, + as Str, + where { /^(?:static|dynamic)\z/ }, + message { "Invalid create option, must be one of 'static' or 'dynamic'" }; + sub _coerce_connect_info_from_arrayref { my %connect_info; diff --git a/t/08helper.t b/t/08helper.t new file mode 100644 index 0000000..3f3bd74 --- /dev/null +++ b/t/08helper.t @@ -0,0 +1,148 @@ +use strict; +use warnings; + +use FindBin '$Bin'; +use lib "$Bin/lib"; + +use Test::More tests => 37; +use Test::Exception; +use Catalyst::Helper::Model::DBIC::Schema; +use Catalyst::Helper; +use Storable 'dclone'; + +my $helper = Catalyst::Helper->new; +$helper->{base} = $Bin; +my $static = 'create=static'; +my $dynamic = 'create=dynamic'; +my $sqlite = 'dbi:SQLite:myapp.db'; +my $pg = 'dbi:Pg:dbname=foo'; +my $on_connect_do = 'on_connect_do=["select 1", "select 2"]'; +my $quote_char = 'quote_char="'; +my $name_sep = 'name_sep=.'; +my $i; + +$i = instance(schema_class => 'ASchemaClass'); +is $i->old_schema, 1, '->load_classes detected correctly'; + +$i = instance(args => ['roles=Caching']); +is_deeply $i->roles, ['Caching'], 'one role'; +is $i->helper->{roles}, "['Caching']", 'one role as string'; + +$i = instance(args => ['roles=Caching,Replicated']); +is_deeply $i->roles, ['Caching', 'Replicated'], 'two roles'; +is $i->helper->{roles}, "['Caching','Replicated']", 'two roles as string'; + +$i = instance(args => [$static]); +is $i->create, 'static', 'create=static'; + +$i = instance(args => [$static, + q{moniker_map={ authors => "AUTHORS", books => "BOOKS" }}] +); +is_deeply $i->loader_args->{moniker_map}, + { authors => 'AUTHORS', books => 'BOOKS' }, + 'loader hash arg'; +is $i->helper->{loader_args}{moniker_map}, + q{{authors => "AUTHORS",books => "BOOKS"}}, + 'loader hash arg as string'; + +$i = instance(args => [$static, q{foo=["bar","baz"]}]); +is_deeply $i->loader_args->{foo}, ['bar', 'baz'], 'loader array arg'; +is $i->helper->{loader_args}{foo}, + q{["bar","baz"]}, + 'loader array arg as string'; + +$i = instance(args => [$static, q{components=TimeStamp}]); +is_deeply $i->components, ['InflateColumn::DateTime', 'TimeStamp'], + 'extra component'; +is $i->helper->{loader_args}{components}, + q{["InflateColumn::DateTime","TimeStamp"]}, + 'components as string'; + +$i = instance( + schema_class => 'ASchemaClass', + args => [$static, q{components=TimeStamp}] +); +is_deeply $i->components, ['TimeStamp'], + 'extra component with ->load_classes'; + +$i = instance(args => [$static, q{components=TimeStamp,Foo}]); +is_deeply $i->components, ['InflateColumn::DateTime', 'TimeStamp', 'Foo'], + 'two extra components'; + +$i = instance(args => [$static, q{constraint=^(foo|bar)$}]); +is $i->loader_args->{constraint}, qr/^(foo|bar)$/, + 'constraint loader arg'; +is $i->helper->{loader_args}{constraint}, + q{qr/(?-xism:^(foo|bar)$)/}, + 'constraint loader arg as string'; + +$i = instance(args => [$static, q{exclude=^(foo|bar)$}]); +is $i->loader_args->{exclude}, qr/^(foo|bar)$/, + 'exclude loader arg'; + +$i = instance(args => [ + $static, 'components=TimeStamp', $sqlite, $on_connect_do, + $quote_char, $name_sep +]); + +is_deeply $i->components, ['InflateColumn::DateTime', 'TimeStamp'], + 'extra component'; + +is $i->connect_info->{dsn}, $sqlite, 'connect_info dsn'; +is $i->connect_info->{user}, '', 'sqlite omitted user'; +is $i->connect_info->{password}, '', 'sqlite omitted password'; + +is_deeply $i->connect_info->{on_connect_do}, + ['select 1', 'select 2'], 'connect_info data struct'; + +is $i->helper->{connect_info}{on_connect_do}, + q{["select 1", "select 2"]}, 'connect_info data struct as string'; + +is $i->connect_info->{quote_char}, '"', 'connect_info quote_char'; + +is $i->helper->{connect_info}{quote_char}, 'q{"}', + 'connect_info quote_char as string'; + +is $i->connect_info->{name_sep}, '.', 'connect_info name_sep'; + +is $i->helper->{connect_info}{name_sep}, 'q{.}', + 'connect_info name_sep as string'; + +$i = instance(args => [ + $static, 'components=TimeStamp', $sqlite, '', $on_connect_do, + $quote_char, $name_sep +]); + +is $i->connect_info->{dsn}, $sqlite, 'connect_info dsn'; +is $i->connect_info->{user}, '', 'sqlite user'; +is $i->connect_info->{password}, '', 'sqlite omitted password'; + +$i = instance(args => [ + $static, 'components=TimeStamp', $pg, 'user', 'pass', $on_connect_do, + $quote_char, $name_sep +]); + +is $i->connect_info->{dsn}, $pg, 'connect_info dsn'; +is $i->connect_info->{user}, 'user', 'user'; +is $i->connect_info->{password}, 'pass', 'password'; + +$i = instance(args => [ + $static, 'components=TimeStamp', $sqlite, $on_connect_do, + $quote_char, $name_sep, '{ auto_savepoint => 1, AutoCommit => 0 }' +]); + +is $i->connect_info->{auto_savepoint}, 1, 'connect_info arg from extra hash'; +is $i->connect_info->{AutoCommit}, 0, 'connect_info arg from extra hash'; +is $i->helper->{connect_info}{auto_savepoint}, 'q{1}', + 'connect_info arg from extra hash as string'; +is $i->helper->{connect_info}{AutoCommit}, 'q{0}', + 'connect_info arg from extra hash as string'; + +sub instance { + Catalyst::Helper::Model::DBIC::Schema->new( + schema_class => 'AnotherSchemaClass', + helper => dclone($helper), + args => ['create=static'], + @_ + ) +} diff --git a/t/lib/AnotherSchemaClass.pm b/t/lib/AnotherSchemaClass.pm new file mode 100644 index 0000000..7442a44 --- /dev/null +++ b/t/lib/AnotherSchemaClass.pm @@ -0,0 +1,7 @@ +package AnotherSchemaClass; + +use base 'DBIx::Class::Schema'; + +__PACKAGE__->load_namespaces; + +1; diff --git a/t/lib/AnotherSchemaClass/Result/Users.pm b/t/lib/AnotherSchemaClass/Result/Users.pm new file mode 100644 index 0000000..cced8ce --- /dev/null +++ b/t/lib/AnotherSchemaClass/Result/Users.pm @@ -0,0 +1,13 @@ +package AnotherSchemaClass::Result::Users; + +# empty schemas no longer work + +use strict; +use warnings; + +use base 'DBIx::Class'; + +__PACKAGE__->load_components("Core"); +__PACKAGE__->table("users"); + +1;