Brian Phillips <bphillips@cpan.org> <bphillips@digitalriver.com>
David Kamholz <dkamholz@cpan.org> <davekam@pobox.com>
David Schmidt <davewood@gmx.at> <d.schmidt@tripwolf.com>
+David Schmidt <davewood@gmx.at> <dt@univie.ac.at>
Devin Austin <dhoss@cpan.org> <devin.austin@gmail.com>
Felix Antonius Wilhelm Ostmann <sadrak@cpan.org> <ostmann@sadraksaemp.intern4.websuche.de>
Gerda Shank <gshank@cpan.org> <gerda.shank@gmail.com>
#
#
-# Smoke only specific branches to a) not overload the queue and b) not
-# overspam the notification channels
+# Smoke all branches except for blocked* and wip/*
#
-# Furthermore if the branch is ^topic/ - the custom compiled smokes will
-# not run at all, again in order to conserve queue resources
-#
-# Additionally bleadperl tests do not run on master (but do run on smoke/*)
+# Additionally master does not smoke with bleadperl
+# ( implemented in maint/travis-ci_scripts/10_before_install.bash )
#
branches:
- only:
- - master
- - /^smoke\//
- - /^topic\//
+ except:
+ - /^wip\//
+ - /^blocked/
notifications:
irc:
+++ /dev/null
-With DBIx::Class on git now, this is the process for contributing.
-
-1) Clone the DBIx::Class master branch
- > git clone dbsrgits@git.shadowcat.co.uk:DBIx-Class.git
-2) Do your work on your machine. This is git - everything is local!
-3) When you think you're ready, push it back out to the origin as a
- remote branch. See rebasing for what you should do before pushing.
- > git push origin my-branch
-4) Notify the other contributors that you're ready to have your branch
- reviewed.
-5) Another contributor will merge it back into master. See rebasing for
- what you should do before merging.
-
-Rebasing: Please rebase before merging and pushing; we'd rather not have
-commit messages that say, "Oops" and "typo", in master, and furthermore
-fast-forward merges lead to a cleaner history.
-
-Yes, this does mean that DBIx::Class is moving to a formal code review process.
-Yes, this does mean that you will never merge your own code to master.
Revision history for DBIx::Class
+0.08209 2013-03-01 12:56 (UTC)
+ * New Features / Changes
+ - Debugging aid - warn on invalid result objects created by what
+ seems like an invalid inheritance hierarchy
+
+ * Fixes
+ - Fix another embarrassing regression preventing correct refining of
+ the search criteria on a prefetched relation (broken in 0.08205)
+ - Fix incorrect callsite reporting by DBIC::Carp
+
+0.08208 2013-02-20 09:56 (UTC)
+ * New Features / Changes
+ - A bunch of nonsensically named arguments to the SQL::Translator
+ parser have been marked as deprecated (while still fully
+ supported)
+
+ * Fixes
+ - Fix duplicated selected columns when calling 'count' when a same
+ aggregate function is used more than once in a 'having' clause
+ (RT#83305)
+ - Prevent SQL::Translator::Producer::YAML from seeing the $dbh
+ in a potentially connected $schema instance (RT#75394)
+
+ * Misc
+ - Fixup our distbuilding process to stop creating world-writable
+ tarball contents (implicitly fixes RT#83084)
+ - Added strict and warnings tests for all lib and test files
+
0.08241-TRIAL (EXPERIMENTAL BETA RELEASE) 2013-02-20 11:97 (UTC)
* New Features / Changes
- Revert to passing the original (pre-0.08240) arguments to
DBIx::Class - Extensible and flexible object <-> relational mapper.
-=head1 GETTING HELP/SUPPORT
+=head1 WHERE TO START READING
-The community can be found via:
+See L<DBIx::Class::Manual::DocMap> for an overview of the exhaustive documentation.
+To get the most out of DBIx::Class with the least confusion it is strongly
+recommended to read (at the very least) the
+L<Manuals|DBIx::Class::Manual::DocMap/Manuals> in the order presented there.
+
+=head1 HOW TO GET HELP
+
+Due to the complexity of its problem domain, DBIx::Class is a relatively
+complex framework. After you start using DBIx::Class questions will inevitably
+arise. If you are stuck with a problem or have doubts about a particular
+approach do not hesitate to contact the community with your questions. The
+list below is sorted by "fastest response time":
=over
=item * IRC: irc.perl.org#dbix-class
=for html
-<a href="http://chat.mibbit.com/#dbix-class@irc.perl.org">(click for instant chatroom login)</a>
+<a href="https://chat.mibbit.com/#dbix-class@irc.perl.org">(click for instant chatroom login)</a>
=item * Mailing list: L<http://lists.scsys.co.uk/mailman/listinfo/dbix-class>
-=item * Twitter L<http://www.twitter.com/dbix_class>
+=item * RT Bug Tracker: L<https://rt.cpan.org/NoAuth/Bugs.html?Dist=DBIx-Class>
-=item * Web Site: L<http://www.dbix-class.org/>
+=item * Twitter: L<https://www.twitter.com/dbix_class>
-=item * RT Bug Tracker: L<https://rt.cpan.org/Dist/Display.html?Queue=DBIx-Class>
+=item * Web Site: L<http://www.dbix-class.org/>
=back
-The project is maintained in a git repository, accessible from the following sources:
+=head1 HOW TO CONTRIBUTE
+
+Contributions are always welcome, in all usable forms (we especially
+welcome documentation improvements). The delivery methods include git-
+or unified-diff formatted patches, GitHub pull requests, or plain bug
+reports either via RT or the Mailing list. Contributors are generally
+granted full access to the official repository after their first patch
+passes successful review.
+
+=for comment
+FIXME: Getty, frew and jnap need to get off their asses and finish the contrib section so we can link it here ;)
+
+This project is maintained in a git repository. The code and related tools are
+accessible at the following locations:
=over
-=item * git: L<git://git.shadowcat.co.uk/dbsrgits/DBIx-Class.git>
+=item * Official repo: L<git://git.shadowcat.co.uk/dbsrgits/DBIx-Class.git>
-=item * gitweb: L<http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=dbsrgits/DBIx-Class.git>
+=item * Official gitweb: L<http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=dbsrgits/DBIx-Class.git>
-=item * github mirror: L<https://github.com/dbsrgits/DBIx-Class>
+=item * GitHub mirror: L<https://github.com/dbsrgits/DBIx-Class>
-=item * authorized committers: L<ssh://dbsrgits@git.shadowcat.co.uk/DBIx-Class.git>
+=item * Authorized committers: L<ssh://dbsrgits@git.shadowcat.co.uk/DBIx-Class.git>
-=item * Travis-CI log: L<http://travis-ci.org/dbsrgits/dbix-class/builds>
+=item * Travis-CI log: L<https://travis-ci.org/dbsrgits/dbix-class/builds>
=for html
-<img src="https://secure.travis-ci.org/dbsrgits/dbix-class.png?branch=master"></img>
+<br>↪ Stable branch CI status: <img src="https://secure.travis-ci.org/dbsrgits/dbix-class.png?branch=master"></img>
=back
are generally made to CPAN before the branch for the next release is
merged back to trunk for a major release.
-=head1 WHERE TO GO NEXT
-
-L<DBIx::Class::Manual::DocMap> lists each task you might want help on, and
-the modules where you will find documentation.
-
=head1 AUTHOR
mst: Matt S. Trout <mst@shadowcatsystems.co.uk>
da5id: David Jack Olrik <djo@cpan.org>
+davewood: David Schmidt <davewood@gmx.at>
+
debolaz: Anders Nor Berle <berle@cpan.org>
dew: Dan Thomas <dan@godders.org>
milki: Jonathan Chu <milki@rescomp.berkeley.edu>
+mithaldu: Christian Walde <walde.christian@gmail.com>
+
mjemmeson: Michael Jemmeson <michael.jemmeson@gmail.com>
mstratman: Mark A. Stratman <stratman@gmail.com>
package # hide from PAUSE
DBIx::Class::Admin::Types;
+# Workaround for https://rt.cpan.org/Public/Bug/Display.html?id=83336
+use warnings;
+use strict;
+
use MooseX::Types -declare => [qw(
DBICConnectInfo
DBICArrayRef
my $fr_num = 1; # skip us and the calling carp*
my @f;
while (@f = caller($fr_num++)) {
- last unless $f[0] =~ $skip_pattern;
-
if (
$f[0]->can('_skip_namespace_frames')
and
) {
$skip_pattern = qr/$skip_pattern|$extra_skip/;
}
+
+ last if $f[0] !~ $skip_pattern;
}
my ($ln, $calling) = @f # if empty - nothing matched - full stack
my $into = caller;
$skip_pattern = $skip_pattern
- ? qr/ ^ $into $ | $skip_pattern /xo
- : qr/ ^ $into $ /xo
+ ? qr/ ^ $into $ | $skip_pattern /x
+ : qr/ ^ $into $ /x
;
no strict 'refs';
# SELECT cd.*, artist.*, liner_notes.* FROM cd
# JOIN artist ON cd.artist = artist.id
# JOIN liner_notes ON cd.id = liner_notes.cd
- # WHERE artist.name = 'Bob Marley'
+ # WHERE artist.name = 'Bob Marley' AND liner_notes.notes LIKE '%some text%'
# ORDER BY artist.name
=head2 Multi-step joins
=item L<DBIx::Class::Manual::Example> - Full example Schema.
-=item L<DBIx::Class::Manual::SQLHackers::TOC> - How to use DBIx::Class if you know SQL (external, available on CPAN)
+=item L<DBIx::Class::Manual::SQLHackers> - How to use DBIx::Class if you know SQL (external, available on CPAN)
=item L<DBIx::Class::Manual::Glossary> - What do all those terms mean?
=item L<DBIx::Class::Manual::Troubleshooting> - What to do if things go wrong (diagnostics of known error messages).
-=item L<DBIx::Class::Manual::Component> - How to write your own DBIx::Class components.
-
=back
-=head1 Setting up
+=head1 Some essential reference documentation
=over 4
-=item L<DBIx::Class::Schema> - Overall schemas, and connection container.
-
-=item L<DBIx::Class::ResultSource> - Source/Table definition functions.
-
-=item L<DBIx::Class::Relationship> - Simple relationships.
-
-=item L<DBIx::Class::Relationship::Base> - Relationship details.
-
-=item L<DBIx::Class::PK::Auto> - Magically retrieve auto-incrementing fields.
-
-=item L<DBIx::Class::Core> - Set of standard components to load.
-
-=item L<DBIx::Class::InflateColumn> - Making objects out of your columns.
-
-=item L<DBIx::Class::InflateColumn::DateTime> - Magically turn your datetime or timestamp columns into DateTime objects.
+=item L<DBIx::Class::$resultclass (normally based on DBIx::Class::Core)|DBIx::Class::Manual::ResultClass> - Representing a single result (row) from a DB query
-=item L<DBIx::Class::PK> - Dealing with primary keys.
-
-=item L<DBIx::Class::ResultSourceProxy::Table> - Turns the resultsource into a table.
-
-=item L<DBIx::Class::AccessorGroup> - Accessor grouping.
-
-=back
-
-=head1 Retrieving and creating data
+=item L<DBIx::Class::ResultSet> - Selecting and manipulating sets.
-=over 4
+=item L<DBIx::Class::ResultSetColumn> - Perform operations on a single column of a ResultSet.
-=item L<DBIx::Class::ResultSet> - Selecting and manipulating sets.
+=item L<DBIx::Class::ResultSource> - Source/Table definition functions.
-=item L<DBIx::Class::ResultSetColumn> - Perform operations on entire columns of a ResultSet.
+=item L<DBIx::Class::Schema> - Overall sourcess, and connection container.
-=item L<DBIx::Class::Row> - Dealing with actual data.
+=item L<DBIx::Class::Relationship> - Simple relationship declarations.
-=item L<DBIx::Class::Storage> - Basic Storage stuff.
+=item L<DBIx::Class::Relationship::Base> - Relationship declaration details.
-=item L<DBIx::Class::Storage::DBI> - Storage using L<DBI> and L<SQL::Abstract>.
+=item L<DBIx::Class::InflateColumn> - Making objects out of your column values.
=back
};
my $reqs = {
- dist_upload => {
- req => {
- 'CPAN::Uploader' => '0.103001',
- },
- },
-
- dist_podinherit => {
- req => {
- 'Pod::Inherit' => '0.90',
- 'Pod::Tree' => '0',
- }
- },
-
replicated => {
req => $replicated,
pod => {
test_strictures => {
req => {
- 'Test::Strict' => '0.16',
+ 'Test::Strict' => '0.20',
},
},
test_cdbicompat => {
req => {
- 'Class::DBI' => 0,
'Class::DBI::Plugin::DeepAbstractSearch' => '0',
%$datetime_basic,
'Time::Piece::MySQL' => '0',
},
},
+ dist_dir => {
+ req => {
+ 'ExtUtils::MakeMaker' => '6.64',
+ 'Pod::Inherit' => '0.90',
+ 'Pod::Tree' => '0',
+ }
+ },
+
+ dist_upload => {
+ req => {
+ 'CPAN::Uploader' => '0.103001',
+ },
+ },
+
};
+our %req_availability_cache;
sub req_list_for {
my ($class, $group) = @_;
}
-our %req_availability_cache;
+sub die_unless_req_ok_for {
+ my ($class, $group) = @_;
+
+ Carp::croak "die_unless_req_ok_for() expects a requirement group name"
+ unless $group;
+
+ $class->_check_deps($group)->{status}
+ or die sprintf( "Required modules missing, unable to continue: %s\n", $class->_check_deps($group)->{missing} );
+}
+
sub req_ok_for {
my ($class, $group) = @_;
returning the actual error seen by the user.
EOD
+ '=head2 die_unless_req_ok_for',
+ '=over',
+ '=item Arguments: $group_name',
+ '=back',
+ <<'EOD',
+Checks if L</req_ok_for> passes for the supplied C<$group_name>, and
+in case of failure throws an exception including the information
+from L</req_missing_for>.
+EOD
+
'=head2 req_errorlist_for',
'=over',
'=item Arguments: $group_name',
use base qw/DBIx::Class/;
use DBIx::Class::Carp;
use DBIx::Class::ResultSetColumn;
-use Scalar::Util qw/blessed weaken/;
+use Scalar::Util qw/blessed weaken reftype/;
use Try::Tiny;
use Data::Compare (); # no imports!!! guard against insane architecture
'bool' => "_bool",
fallback => 1;
+# this is real - CDBICompat overrides it with insanity
+# yes, prototype won't matter, but that's for now ;)
+sub _bool () { 1 }
+
__PACKAGE__->mk_group_accessors('simple' => qw/_result_class result_source/);
=head1 NAME
my $cache;
my %safe = (alias => 1, cache => 1);
if ( ! List::Util::first { !$safe{$_} } keys %$call_attrs and (
- ! defined $_[0]
+ ! defined $call_cond
or
- ref $_[0] eq 'HASH' && ! keys %{$_[0]}
+ ref $call_cond eq 'HASH' && ! keys %$call_cond
or
- ref $_[0] eq 'ARRAY' && ! @{$_[0]}
+ ref $call_cond eq 'ARRAY' && ! @$call_cond
)) {
$cache = $self->get_cache;
}
->get_column ('count');
}
-sub _bool {
- return 1;
-}
=head2 count_literal
my ($merged_cond, $cols_from_relations) = $self->_merge_with_rscond($values);
- my %new = (
+ my $new = $self->result_class->new({
%$merged_cond,
- @$cols_from_relations
+ ( @$cols_from_relations
? (-cols_from_relations => $cols_from_relations)
- : (),
+ : ()
+ ),
-result_source => $self->result_source, # DO NOT REMOVE THIS, REQUIRED
- );
+ });
+
+ if (
+ reftype($new) eq 'HASH'
+ and
+ ! keys %$new
+ and
+ blessed($new)
+ ) {
+ carp_unique (sprintf (
+ "%s->new returned a blessed empty hashref - a strong indicator something is wrong with its inheritance chain",
+ $self->result_class,
+ ));
+ }
- return $self->result_class->new(\%new);
+ $new;
}
# _merge_with_rscond
SQL_TXN_ISOLATION_OPTION
/
) {
- my $v = $self->_dbh_get_info($inf);
+ # some drivers barf on things they do not know about instead
+ # of returning undef
+ my $v = try { $self->_dbh_get_info($inf) };
next unless defined $v;
#my $key = sprintf( '%s(%s)', $inf, $DBI::Const::GetInfoType::GetInfoType{$inf} );
# DBIx::Class::Storage::DBI::Replicated::Types - Types used internally by
# L<DBIx::Class::Storage::DBI::Replicated>
+# Workaround for https://rt.cpan.org/Public/Bug/Display.html?id=83336
+use warnings;
+use strict;
+
use MooseX::Types
-declare => [qw/BalancerClassNamePart Weight DBICSchema DBICStorageDBI/];
use MooseX::Types::Moose qw/ClassName Str Num/;
sub parse {
my ($tr, $data) = @_;
my $args = $tr->parser_args;
- my $dbicschema = $args->{'DBIx::Class::Schema'} || $args->{"DBIx::Schema"} ||$data;
- $dbicschema ||= $args->{'package'};
- my $limit_sources = $args->{'sources'};
+
+ my $dbicschema = $data || $args->{dbic_schema};
+
+ for (qw(DBIx::Class::Schema DBIx::Schema package)) {
+ if (defined (my $s = delete $args->{$_} )) {
+ carp_unique("Supplying a schema via ... parser_args => { '$_' => \$schema } is deprecated. Please use parser_args => { dbic_schema => \$schema } instead");
+
+ # move it from the deprecated to the proper $args slot
+ unless ($dbicschema) {
+ $args->{dbic_schema} = $dbicschema = $s;
+ }
+ }
+ }
DBIx::Class::Exception->throw('No DBIx::Class::Schema') unless ($dbicschema);
+
if (!ref $dbicschema) {
eval "require $dbicschema"
or DBIx::Class::Exception->throw("Can't load $dbicschema: $@");
}
+ if (
+ ref $args->{dbic_schema}
+ and
+ $args->{dbic_schema}->storage
+ ) {
+ # we have a storage-holding $schema instance in $args
+ # we need to dissociate it from that $storage
+ # otherwise SQLT insanity may ensue due to how some
+ # serializing producers treat $args (crazy crazy shit)
+ local $args->{dbic_schema}{storage};
+ $args->{dbic_schema} = $args->{dbic_schema}->clone;
+ }
+
my $schema = $tr->schema;
my $table_no = 0;
unless ($schema->name);
my @monikers = sort $dbicschema->sources;
- if ($limit_sources) {
+ if (my $limit_sources = $args->{'sources'}) {
my $ref = ref $limit_sources || '';
$dbicschema->throw_exception ("'sources' parameter must be an array or hash ref")
unless( $ref eq 'ARRAY' || ref eq 'HASH' );
my $trans = SQL::Translator->new (
parser => 'SQL::Translator::Parser::DBIx::Class',
parser_args => {
- package => $schema,
+ dbic_schema => $schema,
add_fk_index => 0,
sources => [qw/
Artist
=head1 PARSER OPTIONS
+=head2 dbic_schema
+
+The DBIx::Class schema (either an instance or a class name) to be parsed.
+This argument is in fact optional - instead one can supply it later at
+translation time as an argument to L<SQL::Translator/translate>. In
+other words both of the following invocations are valid and will produce
+conceptually identical output:
+
+ my $yaml = SQL::Translator->new(
+ parser => 'SQL::Translator::Parser::DBIx::Class',
+ parser_args => {
+ dbic_schema => $schema,
+ },
+ producer => 'SQL::Translator::Producer::YAML',
+ )->translate;
+
+ my $yaml = SQL::Translator->new(
+ parser => 'SQL::Translator::Parser::DBIx::Class',
+ producer => 'SQL::Translator::Producer::YAML',
+ )->translate(data => $schema);
+
=head2 add_fk_index
Create an index for each foreign key.
# exclude the rdbms_* groups which are for DBIC users
$opt_testdeps = {
- map { %{$reqs_for_group{$_}} } grep { !/^rdbms_/ } keys %reqs_for_group
+ map { %{$reqs_for_group{$_}} } grep { !/^rdbms_|^dist_/ } keys %reqs_for_group
};
print "Including all optional deps\n";
return <<"EOM";
$snippet
-create_distdir : clonedir_generate_files clonedir_post_generate_files fresh_manifest create_distdir_copy_manifested clonedir_cleanup_generated_files
+create_distdir : check_create_distdir_prereqs clonedir_generate_files clonedir_post_generate_files fresh_manifest create_distdir_copy_manifested clonedir_cleanup_generated_files
\t\$(NOECHO) \$(NOOP)
clonedir_generate_files :
clonedir_cleanup_generated_files :
\t\$(NOECHO) \$(NOOP)
+check_create_distdir_prereqs :
+\t\$(NOECHO) @{[
+ $mm_proto->oneliner("DBIx::Class::Optional::Dependencies->die_unless_req_ok_for(q(dist_dir))", [qw/-Ilib -MDBIx::Class::Optional::Dependencies/])
+]}
+
+EOM
+ }
+}
+
+# M::I inserts its own default postamble, so we can't easily override upload
+# but we can still hook postamble in EU::MM
+{
+ package MY;
+
+ sub postamble {
+ my $snippet = shift->SUPER::postamble(@_);
+ return <<"EOM";
+$snippet
+
+upload :: check_create_distdir_prereqs check_upload_dist_prereqs
+
+check_upload_dist_prereqs :
+\t\$(NOECHO) @{[
+ $mm_proto->oneliner("DBIx::Class::Optional::Dependencies->die_unless_req_ok_for(q(dist_upload))", [qw/-Ilib -MDBIx::Class::Optional::Dependencies/])
+]}
+
EOM
}
}
realclean :: remove_manifest
+manifest : check_manifest_is_lone_target
+
+check_manifest_is_lone_target :
+\t\$(NOECHO) @{[
+ $mm_proto->oneliner('q($(MAKECMDGOALS)) =~ /(\S*manifest\b)/ and q($(MAKECMDGOALS)) ne $1 and die qq(The DBIC build chain does not support mixing the $1 target with others\n)')
+]}
+
EOM
# keep the Makefile.PL eval happy
source maint/travis-ci_scripts/common.bash
if [[ -n "$SHORT_CIRCUIT_SMOKE" ]] ; then return ; fi
-# .travis.yml already restricts branches to master, topic/* and smoke/*
# do some extra short-circuiting here
# when smoking master do not attempt bleadperl (not release-critical)
#
parallel_installdeps_notest ExtUtils::MakeMaker
parallel_installdeps_notest Carp
- parallel_installdeps_notest Module::Build
- parallel_installdeps_notest Module::Runtime ExtUtils::Depends File::Spec Data::Dumper
- parallel_installdeps_notest Test::Exception Encode::Locale HTTP::Status HTTP::Daemon Try::Tiny
- parallel_installdeps_notest Test::Fatal Test::Warn bareword::filehandles B::Hooks::EndOfScope
+ parallel_installdeps_notest Module::Build ExtUtils::Depends
+ parallel_installdeps_notest Module::Runtime File::Spec Data::Dumper
+ parallel_installdeps_notest Test::Exception Encode::Locale Test::Fatal
+ parallel_installdeps_notest Test::Warn bareword::filehandles B::Hooks::EndOfScope Test::Differences HTTP::Status
parallel_installdeps_notest Test::Pod::Coverage Test::EOL Devel::GlobalDestruction Sub::Name MRO::Compat Class::XSAccessor URI::Escape HTML::Entities
- parallel_installdeps_notest YAML LWP Moose Class::Trigger JSON::XS DBI
- parallel_installdeps_notest Moo Class::Accessor::Grouped Module::Install JSON
+ parallel_installdeps_notest YAML LWP Moo Class::Trigger JSON::XS DBI DateTime::Format::Builder
+ parallel_installdeps_notest Moose Class::Accessor::Grouped Module::Install JSON Package::Variant
if [[ -n "DBICTEST_FIREBIRD_DSN" ]] ; then
# the official version is full of 5.10-isms, but works perfectly fine on 5.8
source maint/travis-ci_scripts/common.bash
if [[ -n "$SHORT_CIRCUIT_SMOKE" ]] ; then return ; fi
-[[ "$CLEANTEST" = "true" ]] || run_or_err "Attempt to build a dist with all prereqs present" "make dist"
+if [[ "$CLEANTEST" != "true" ]] ; then
+ parallel_installdeps_notest $(perl -Ilib -MDBIx::Class -e 'print join " ", keys %{DBIx::Class::Optional::Dependencies->req_list_for("dist_dir")}')
+ run_or_err "Attempt to build a dist with all prereqs present" "make dist"
+fi
use warnings;
use Test::More;
+use Test::Warn;
use Test::Exception;
use Scalar::Util ();
my @schemas = (
create_schema ({ schema => $s }),
- create_schema ({ args => { parser_args => { 'DBIx::Class::Schema' => $s } } }),
- create_schema ({ args => { parser_args => { 'DBIx::Schema' => $s } } }),
- create_schema ({ args => { parser_args => { package => $s } } }),
+ create_schema ({ args => { parser_args => { dbic_schema => $s } } }),
);
+ for my $parser_args_key (qw(
+ DBIx::Class::Schema
+ DBIx::Schema
+ package
+ )) {
+ warnings_exist {
+ push @schemas, create_schema({
+ args => { parser_args => { $parser_args_key => $s } }
+ });
+ } qr/\Qparser_args => {\E.+?is deprecated.+\Q@{[__FILE__]}/,
+ "deprecated crazy parser_arg '$parser_args_key' warned";
+ }
+
Scalar::Util::weaken ($s);
ok (!$s, 'Schema not leaked');
# make sure classname-style works
lives_ok { isa_ok (create_schema ({ schema => 'DBICTest::Schema' }), 'SQL::Translator::Schema', 'SQLT schema object produced') };
+# make sure a connected instance passed via $args does not get the $dbh improperly serialized
+SKIP: {
+
+ # YAML is a build_requires dep of SQLT - it may or may not be here
+ eval { require YAML } or skip "Test requires YAML.pm", 1;
+
+ lives_ok {
+
+ my $s = DBICTest->init_schema(no_populate => 1);
+ ok ($s->storage->connected, '$schema instance connected');
+
+ # roundtrip through YAML
+ my $yaml_rt_schema = SQL::Translator->new(
+ parser => 'SQL::Translator::Parser::YAML'
+ )->translate(
+ data => SQL::Translator->new(
+ parser_args => { dbic_schema => $s },
+ parser => 'SQL::Translator::Parser::DBIx::Class',
+ producer => 'SQL::Translator::Producer::YAML',
+ )->translate
+ );
+
+ isa_ok ( $yaml_rt_schema, 'SQL::Translator::Schema', 'SQLT schema object produced after YAML roundtrip');
+
+ ok ($s->storage->connected, '$schema instance still connected');
+ }
+
+ eval <<'EOE' or die $@;
+ END {
+ $^W = 1; # important, otherwise DBI won't trip the next fail()
+ $SIG{__WARN__} = sub {
+ fail "Unexpected global destruction warning"
+ if $_[0] =~ /is not a DBI/;
+ warn @_;
+ };
+ }
+EOE
+
+}
my $schema = DBICTest->init_schema( no_deploy => 1 );
sub create_schema {
my $args = shift;
- my $schema = $args->{schema};
my $additional_sqltargs = $args->{args} || {};
my $sqltargs = {
my $sqlt = SQL::Translator->new( $sqltargs );
$sqlt->parser('SQL::Translator::Parser::DBIx::Class');
- return $sqlt->translate({ data => $schema }) || die $sqlt->error;
+ return $sqlt->translate(
+ $args->{schema} ? ( data => $args->{schema} ) : ()
+ ) || die $sqlt->error;
}
sub get_table {
'using a DateTime object in ->search generates a warning';
{
- local $TODO = "We can't do this yet before 0.09" if DBIx::Class->VERSION < 0.09;
+ local $TODO = "This stuff won't work without a -dt operator of some sort"
+ unless eval { require DBIx::Class::SQLMaker::DateOps };
is(eval { $row->id }, 1, 'DT in search');
sub import {
my $self = shift;
- my $lockpath = DBICTest::RunMode->tmpdir->file('.dbictest_global.lock');
+ my $tmpdir = DBICTest::RunMode->tmpdir;
+ my $lockpath = $tmpdir->file('.dbictest_global.lock');
{
my $u = local_umask(0); # so that the file opens as 666, and any user can lock
- sysopen ($global_lock_fh, $lockpath, O_RDWR|O_CREAT)
- or die "Unable to open $lockpath: $!";
+ sysopen ($global_lock_fh, $lockpath, O_RDWR|O_CREAT) or do {
+ my $err = $!;
+
+ my @x_tests = map { (defined $_) ? ( $_ ? 1 : 0 ) : 'U' } map {(-e, -d, -f, -r, -w, -x, -o)} ($tmpdir, $lockpath);
+
+ die sprintf <<"EOE", $lockpath, $err, scalar $>, scalar $), (stat($tmpdir))[4,5,2], @x_tests;
+Unable to open %s: %s
+Process EUID/EGID: %s / %s
+TmpDir UID/GID: %s / %s
+TmpDir StatMode: %o
+TmpDir X-tests: -e:%s -d:%s -f:%s -r:%s -w:%s -x:%s -o:%s
+TmpFile X-tests: -e:%s -d:%s -f:%s -r:%s -w:%s -x:%s -o:%s
+EOE
+ };
}
for (@_) {
use DBICTest::RunMode;
use base 'DBIx::Class::ResultSet';
+__PACKAGE__->_skip_namespace_frames('^DBICTest');
sub all_hri {
return [ shift->search ({}, { result_class => 'DBIx::Class::ResultClass::HashRefInflator' })->all ];
# make sure null-prefetches do not screw with the final sql:
for my $type (keys %$nulls) {
-# is_same_sql_bind (
-# $cds->search({}, { prefetch => { artist => $nulls->{$type} } })->as_query,
-# $cds->as_query,
-# "same sql with null $type prefetch"
-# );
+ is_same_sql_bind (
+ $cds->search({}, { prefetch => { artist => $nulls->{$type} } })->as_query,
+ '( SELECT me.cdid, me.artist, me.title, me.year, me.genreid, me.single_track,
+ artist.artistid, artist.name, artist.rank, artist.charfield
+ FROM cd me
+ JOIN artist artist
+ ON artist.artistid = me.artist
+ )', [],
+ "same sql with null $type prefetch"
+ );
}
# make sure left join is carried only starting from the first has_many
--- /dev/null
+use strict;
+use warnings;
+
+use Test::More;
+use lib qw(t/lib);
+use DBICTest;
+
+my $schema = DBICTest->init_schema();
+
+my $art = $schema->resultset('Artist')->find(
+ { 'me.artistid' => 1 },
+ { prefetch => 'cds', order_by => { -desc => 'cds.year' } }
+);
+
+is (
+ $art->cds->search({ year => 1999 })->next->year,
+ 1999,
+ 'Found expected CD with year 1999 after refined search',
+);
+
+is (
+ $art->cds->count({ year => 1999 }),
+ 1,
+ 'Correct refined count',
+);
+
+# this still should emit no queries:
+{
+ my $queries = 0;
+ my $orig_debug = $schema->storage->debug;
+ $schema->storage->debugcb(sub { $queries++; });
+ $schema->storage->debug(1);
+
+ my $cds = $art->cds;
+ is (
+ $cds->count,
+ 3,
+ 'Correct prefetched count',
+ );
+
+ my @years = qw(2001 1999 1997);
+ while (my $cd = $cds->next) {
+ is (
+ $cd->year,
+ (shift @years),
+ 'Correct prefetched cd year',
+ );
+ }
+
+ $schema->storage->debug($orig_debug);
+ $schema->storage->debugcb(undef);
+
+ is ($queries, 0, 'No queries on prefetched operations');
+}
+
+done_testing;
# has_a test
my $cd = $schema->resultset("CD")->find(4);
-my ($artist) = ($INC{'DBICTest/HelperRels'}
- ? $cd->artist
- : $cd->search_related('artist'));
+my ($artist) = $cd->search_related('artist');
is($artist->name, 'Random Boy Band', 'has_a search_related ok');
# has_many test with an order_by clause defined
$artist = $schema->resultset("Artist")->find(1);
-my @cds = ($INC{'DBICTest/HelperRels'}
- ? $artist->cds
- : $artist->search_related('cds'));
+my @cds = $artist->search_related('cds');
is( $cds[1]->title, 'Spoonful of bees', 'has_many search_related with order_by ok' );
# search_related with additional abstract query
-@cds = ($INC{'DBICTest/HelperRels'}
- ? $artist->cds({ title => { like => '%of%' } })
- : $artist->search_related('cds', { title => { like => '%of%' } } )
- );
+@cds = $artist->search_related('cds', { title => { like => '%of%' } } );
is( $cds[1]->title, 'Forkful of bees', 'search_related with abstract query ok' );
# creating a related object
-if ($INC{'DBICTest/HelperRels.pm'}) {
- $artist->add_to_cds({ title => 'Big Flop', year => 2005 });
-} else {
- my $big_flop = $artist->create_related( 'cds', {
- title => 'Big Flop',
- year => 2005,
- } );
-
- {
- local $TODO = "Can't fix right now" if $DBIx::Class::VERSION < 0.09;
- lives_ok { $big_flop->genre} "Don't throw exception when col is not loaded after insert";
- };
-}
+$artist->create_related( 'cds', {
+ title => 'Big Flop',
+ year => 2005,
+} );
my $big_flop_cd = ($artist->search_related('cds'))[3];
is( $big_flop_cd->title, 'Big Flop', 'create_related ok' );
'Restricting prefetch left in, selector thrown out'
);
- $rs->result_source->name('schema_qualified.cd');
- # this is expected to fail - we only want to collect the generated SQL
- eval { $rs->delete };
+ # switch artist and cd to fully qualified table names
+ # make sure nothing is stripped out
+ my $cd_rsrc = $schema->source('CD');
+ $cd_rsrc->name('main.cd');
+ $cd_rsrc->relationship_info($_)->{attrs}{cascade_delete} = 0
+ for $cd_rsrc->relationships;
+
+ my $art_rsrc = $schema->source('Artist');
+ $art_rsrc->name(\'main.artist');
+ $art_rsrc->relationship_info($_)->{attrs}{cascade_delete} = 0
+ for $art_rsrc->relationships;
+
+ $rs->delete;
is_same_sql_bind (
$sql,
\@bind,
- 'DELETE FROM schema_qualified.cd WHERE ( year != ? )',
+ 'DELETE FROM main.cd WHERE ( year != ? )',
["'2010'"],
- 'delete with fully qualified table name and subquery correct'
+ 'delete with fully qualified table name'
+ );
+
+ $rs->create({ title => 'foo', artist => 1, year => 2000 });
+ $rs->delete_all;
+ is_same_sql_bind (
+ $sql,
+ \@bind,
+ 'DELETE FROM main.cd WHERE ( cdid = ? )',
+ ["'1'"],
+ 'delete_all with fully qualified table name'
+ );
+
+ $rs->create({ cdid => 42, title => 'foo', artist => 2, year => 2000 });
+ $rs->find(42)->delete;
+ is_same_sql_bind (
+ $sql,
+ \@bind,
+ 'DELETE FROM main.cd WHERE ( cdid = ? )',
+ ["'42'"],
+ 'delete of object from table with fully qualified name'
+ );
+
+ $rs->create({ cdid => 42, title => 'foo', artist => 2, year => 2000 });
+ $rs->find(42)->related_resultset('artist')->delete;
+ is_same_sql_bind (
+ $sql,
+ \@bind,
+ 'DELETE FROM main.artist WHERE ( artistid IN ( SELECT me.artistid FROM main.artist me WHERE ( me.artistid = ? ) ) )',
+ ["'2'"],
+ 'delete of related object from scalarref fully qualified named table',
+ );
+
+ $schema->resultset('Artist')->find(3)->related_resultset('cds')->delete;
+ is_same_sql_bind (
+ $sql,
+ \@bind,
+ 'DELETE FROM main.cd WHERE ( artist = ? )',
+ ["'3'"],
+ 'delete of related object from fully qualified named table',
);
- # this is expected to fail - we only want to collect the generated SQL
- eval { $rs->search({}, { prefetch => 'artist' })->delete };
+ $schema->resultset('Artist')->find(3)->cds_unordered->delete;
is_same_sql_bind (
$sql,
\@bind,
- 'DELETE FROM schema_qualified.cd WHERE ( cdid IN ( SELECT me.cdid FROM schema_qualified.cd me JOIN artist artist ON artist.artistid = me.artist WHERE ( me.year != ? ) ) )',
+ 'DELETE FROM main.cd WHERE ( artist = ? )',
+ ["'3'"],
+ 'delete of related object from fully qualified named table via relaccessor',
+ );
+
+ $rs->search({}, { prefetch => 'artist' })->delete;
+ is_same_sql_bind (
+ $sql,
+ \@bind,
+ 'DELETE FROM main.cd WHERE ( cdid IN ( SELECT me.cdid FROM main.cd me JOIN main.artist artist ON artist.artistid = me.artist WHERE ( me.year != ? ) ) )',
["'2010'"],
'delete with fully qualified table name and subquery correct'
);
- $rs->result_source->name('cd');
-
# check that as_subselect_rs works ok
# inner query is untouched, then a selector
# and an IN condition
$sql,
\@bind,
'
- DELETE FROM cd
+ DELETE FROM main.cd
WHERE (
cdid IN (
SELECT me.cdid
FROM (
SELECT me.cdid, me.artist, me.title, me.year, me.genreid, me.single_track
- FROM cd me
- JOIN artist artist ON artist.artistid = me.artist
+ FROM main.cd me
+ JOIN main.artist artist ON artist.artistid = me.artist
WHERE artist.name = ? AND me.cdid = ?
) me
)
return if m{^(?:
maint/Makefile.PL.inc/.+ # all the maint inc snippets are auto-strictured
|
- lib/DBIx/Class/Admin/Types.pm # MooseX::Types undetected
- |
- lib/DBIx/Class/Storage/DBI/Replicated/Types.pm # MooseX::Types undetected
- |
- lib/DBIx/Class/Storage/BlockRunner.pm # Moo undetected
- |
t/lib/DBICTest/Util/OverrideRequire.pm # no stictures by design (load order sensitive)
- |
- lib/DBIx/Class/Storage/DBI/Replicated/Replicant.pm # Moose::Role no longer detected (RT#83433)
- |
- lib/DBIx/Class/Storage/DBI/Replicated/WithDSN.pm # Moose::Role no longer detected (RT#83433)
- |
- lib/DBIx/Class/Storage/DBI/Replicated/Balancer.pm # Moose::Role no longer detected (RT#83433)
)$}x;
my $f = $_;
{
no warnings 'redefine';
my $is_pm = sub {
- $_[0] !~ /\./ || $_[0] =~ /\.(?:pm|pod|skip|sql|json|proto)$/i || $_[0] =~ /::/;
+ $_[0] !~ /\./ || $_[0] =~ /\.(?:pm|pod|skip|bash|sql|json|proto)$/i || $_[0] =~ /::/;
};
*Test::EOL::_is_perl_module = $is_pm;