Tighten up select list processing in ::SQLMaker
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Schema / Versioned.pm
index 052f8e7..f6d598b 100644 (file)
@@ -26,7 +26,7 @@ __PACKAGE__->add_columns
           'size' => '20'
           },
       );
-__PACKAGE__->set_primary_key('version');
+__PACKAGE__->result_source_instance->set_primary_key('version');
 
 package # Hide from PAUSE
   DBIx::Class::Version::TableCompat;
@@ -41,7 +41,7 @@ __PACKAGE__->add_columns
           'data_type' => 'VARCHAR',
           },
       );
-__PACKAGE__->set_primary_key('Version');
+__PACKAGE__->result_source_instance->set_primary_key('Version');
 
 package # Hide from PAUSE
   DBIx::Class::Version;
@@ -49,6 +49,13 @@ use base 'DBIx::Class::Schema';
 use strict;
 use warnings;
 
+# no point sanity checking, unless we are running asserts
+__PACKAGE__->schema_sanity_checker(
+  DBIx::Class::_ENV_::ASSERT_NO_FAILING_SANITY_CHECKS
+    ? 'DBIx::Class::Schema::SanityChecker'
+    : ''
+);
+
 __PACKAGE__->register_class('Table', 'DBIx::Class::Version::Table');
 
 package # Hide from PAUSE
@@ -57,6 +64,13 @@ use base 'DBIx::Class::Schema';
 use strict;
 use warnings;
 
+# no point sanity checking, unless we are running asserts
+__PACKAGE__->schema_sanity_checker(
+  DBIx::Class::_ENV_::ASSERT_NO_FAILING_SANITY_CHECKS
+    ? 'DBIx::Class::Schema::SanityChecker'
+    : ''
+);
+
 __PACKAGE__->register_class('TableCompat', 'DBIx::Class::Version::TableCompat');
 
 
@@ -96,10 +110,31 @@ this will attempt to upgrade the database from its current version to the curren
 schema version using a diff from your I<upgrade_directory>. If a suitable diff is
 not found then no upgrade is possible.
 
-NB: At the moment, only SQLite and MySQL are supported. This is due to
-spotty behaviour in the SQL::Translator producers, please help us by
-enhancing them. Ask on the mailing list or IRC channel for details (community details
-in L<DBIx::Class>).
+=head1 SEE ALSO
+
+L<DBIx::Class::DeploymentHandler> is a much more powerful alternative to this
+module.  Examples of things it can do that this module cannot do include
+
+=over
+
+=item *
+
+Downgrades in addition to upgrades
+
+=item *
+
+Multiple sql files per upgrade/downgrade/install
+
+=item *
+
+Perl scripts allowed for upgrade/downgrade/install
+
+=item *
+
+Just one set of files needed for upgrade, unlike this module where one might
+need to generate C<factorial(scalar @versions)>
+
+=back
 
 =head1 GETTING STARTED
 
@@ -180,16 +215,18 @@ use strict;
 use warnings;
 use base 'DBIx::Class::Schema';
 
-use Carp::Clan qw/^DBIx::Class/;
-use Time::HiRes qw/gettimeofday/;
-use Try::Tiny;
+use DBIx::Class::Carp;
+use DBIx::Class::_Util qw( dbic_internal_try UNRESOLVABLE_CONDITION );
+use Scalar::Util 'weaken';
 use namespace::clean;
 
-__PACKAGE__->mk_classdata('_filedata');
-__PACKAGE__->mk_classdata('upgrade_directory');
-__PACKAGE__->mk_classdata('backup_directory');
-__PACKAGE__->mk_classdata('do_backup');
-__PACKAGE__->mk_classdata('do_diff_on_init');
+__PACKAGE__->mk_group_accessors( inherited => qw(
+  _filedata
+  upgrade_directory
+  backup_directory
+  do_backup
+  do_diff_on_init
+) );
 
 
 =head1 METHODS
@@ -217,7 +254,7 @@ Call this to initialise a previously unversioned database. The table 'dbix_class
 
 Takes one argument which should be the version that the database is currently at. Defaults to the return value of L</schema_version>.
 
-See L</getting_started> for more details.
+See L</GETTING STARTED> for more details.
 
 =cut
 
@@ -277,7 +314,7 @@ sub create_upgrade_path {
 
 =over 4
 
-=item Returns: a list of version numbers, ordered from lowest to highest
+=item Return Value: a list of version numbers, ordered from lowest to highest
 
 =back
 
@@ -325,7 +362,7 @@ sub upgrade {
 
     # db and schema at same version. do nothing
     if ( $db_version eq $self->schema_version ) {
-        carp "Upgrade not necessary\n";
+        carp 'Upgrade not necessary';
         return;
     }
 
@@ -396,7 +433,7 @@ sub upgrade_single_step
 
   # db and schema at same version. do nothing
   if ($db_version eq $target_version) {
-    carp "Upgrade not necessary\n";
+    carp 'Upgrade not necessary';
     return;
   }
 
@@ -416,7 +453,7 @@ sub upgrade_single_step
   $self->create_upgrade_path({ upgrade_file => $upgrade_file });
 
   unless (-f $upgrade_file) {
-    carp "Upgrade not possible, no upgrade file found ($upgrade_file), please create one\n";
+    carp "Upgrade not possible, no upgrade file found ($upgrade_file), please create one";
     return;
   }
 
@@ -505,7 +542,7 @@ sub get_db_version
     my ($self, $rs) = @_;
 
     my $vtable = $self->{vschema}->resultset('Table');
-    my $version = try {
+    my $version = dbic_internal_try {
       $vtable->search({}, { order_by => { -desc => 'installed' }, rows => 1 } )
               ->get_column ('version')
                ->next;
@@ -568,9 +605,15 @@ sub _on_connect
 {
   my ($self) = @_;
 
-  my $conn_info = $self->storage->connect_info;
-  $self->{vschema} = DBIx::Class::Version->connect(@$conn_info);
-  my $conn_attrs = $self->{vschema}->storage->_dbic_connect_attributes || {};
+  weaken (my $w_storage = $self->storage );
+
+  $self->{vschema} = DBIx::Class::Version->clone->connection(
+    sub { $w_storage->dbh },
+
+    # proxy some flags from the main storage
+    { map { $_ => $w_storage->$_ } qw( unsafe ) },
+  );
+  my $conn_attrs = $w_storage->_dbic_connect_attributes || {};
 
   my $vtable = $self->{vschema}->resultset('Table');
 
@@ -579,11 +622,11 @@ sub _on_connect
 
   # check for legacy versions table and move to new if exists
   unless ($self->_source_exists($vtable)) {
-    my $vtable_compat = DBIx::Class::VersionCompat->connect(@$conn_info)->resultset('TableCompat');
+    my $vtable_compat = DBIx::Class::VersionCompat->clone->connection(sub { $w_storage->dbh })->resultset('TableCompat');
     if ($self->_source_exists($vtable_compat)) {
       $self->{vschema}->deploy;
-      map { $vtable->create({ installed => $_->Installed, version => $_->Version }) } $vtable_compat->all;
-      $self->storage->_get_dbh->do("DROP TABLE " . $vtable_compat->result_source->from);
+      map { $vtable->new_result({ installed => $_->Installed, version => $_->Version })->insert } $vtable_compat->all;
+      $w_storage->_get_dbh->do("DROP TABLE " . $vtable_compat->result_source->from);
     }
   }
 
@@ -591,18 +634,18 @@ sub _on_connect
 
   if($pversion eq $self->schema_version)
     {
-#         carp "This version is already installed\n";
+        #carp "This version is already installed";
         return 1;
     }
 
   if(!$pversion)
     {
-        carp "Your DB is currently unversioned. Please call upgrade on your schema to sync the DB.\n";
+        carp "Your DB is currently unversioned. Please call upgrade on your schema to sync the DB.";
         return 1;
     }
 
   carp "Versions out of sync. This is " . $self->schema_version .
-    ", your database contains version $pversion, please call upgrade on your Schema.\n";
+    ", your database contains version $pversion, please call upgrade on your Schema.";
 }
 
 # is this just a waste of time? if not then merge with DBI.pm
@@ -619,8 +662,9 @@ sub _create_db_to_schema_diff {
     return;
   }
 
-  unless (DBIx::Class::Optional::Dependencies->req_ok_for ('deploy')) {
-    $self->throw_exception("Unable to proceed without " . DBIx::Class::Optional::Dependencies->req_missing_for ('deploy') );
+  require DBIx::Class::Optional::Dependencies;
+  if ( my $missing = DBIx::Class::Optional::Dependencies->req_missing_for('deploy') ) {
+    $self->throw_exception("Unable to proceed without $missing");
   }
 
   my $db_tr = SQL::Translator->new({
@@ -663,7 +707,7 @@ sub _create_db_to_schema_diff {
   print $file $diff;
   close($file);
 
-  carp "WARNING: There may be differences between your DB and your DBIC schema. Please review and if necessary run the SQL in $filename to sync your DB.\n";
+  carp "WARNING: There may be differences between your DB and your DBIC schema. Please review and if necessary run the SQL in $filename to sync your DB.";
 }
 
 
@@ -687,9 +731,10 @@ sub _set_db_version {
   # not possible to format the string sanely, as the column is a varchar(20).
   # The 'v' character is added to the front of the string, so that any version
   # formatted by this new function will sort _after_ any existing 200... strings.
-  my @tm = gettimeofday();
+  require Time::HiRes;
+  my @tm = Time::HiRes::gettimeofday();
   my @dt = gmtime ($tm[0]);
-  my $o = $vtable->create({
+  my $o = $vtable->new_result({
     version => $version,
     installed => sprintf("v%04d%02d%02d_%02d%02d%02d.%03.0f",
       $dt[5] + 1900,
@@ -698,9 +743,9 @@ sub _set_db_version {
       $dt[2],
       $dt[1],
       $dt[0],
-      $tm[1] / 1000, # convert to millisecs, format as up/down rounded int above
+      int($tm[1] / 1000), # convert to millisecs
     ),
-  });
+  })->insert;
 }
 
 sub _read_sql_file {
@@ -723,21 +768,28 @@ sub _read_sql_file {
 
 sub _source_exists
 {
-    my ($self, $rs) = @_;
-
-    my $c = try { $rs->search({ 1, 0 })->count };
-
-    return (defined $c) ? 1 : 0;
+  my ($self, $rs) = @_;
+
+  ( dbic_internal_try {
+    $rs->search( UNRESOLVABLE_CONDITION )->cursor->next;
+    1;
+  } )
+    ? 1
+    : 0
+  ;
 }
 
-1;
+=head1 FURTHER QUESTIONS?
 
+Check the list of L<additional DBIC resources|DBIx::Class/GETTING HELP/SUPPORT>.
 
-=head1 AUTHORS
+=head1 COPYRIGHT AND LICENSE
 
-Jess Robinson <castaway@desert-island.me.uk>
-Luke Saunders <luke@shadowcatsystems.co.uk>
+This module is free software L<copyright|DBIx::Class/COPYRIGHT AND LICENSE>
+by the L<DBIx::Class (DBIC) authors|DBIx::Class/AUTHORS>. You can
+redistribute it and/or modify it under the same terms as the
+L<DBIx::Class library|DBIx::Class/COPYRIGHT AND LICENSE>.
 
-=head1 LICENSE
+=cut
 
-You may distribute this code under the same terms as Perl itself.
+1;