[Jifty-commit] r2685 - in jifty/trunk: lib/Jifty/Script

jifty-commit at lists.jifty.org jifty-commit at lists.jifty.org
Sun Jan 28 09:03:54 EST 2007


Author: jesse
Date: Sun Jan 28 09:03:54 2007
New Revision: 2685

Modified:
   jifty/trunk/   (props changed)
   jifty/trunk/lib/Jifty/Script/Schema.pm

Log:
 r21618 at hualien:  jesse | 2007-01-28 22:03:22 +0800
 * Refactored Jifty::Script::Schema to use extracted column, table and db manipulation routines
 


Modified: jifty/trunk/lib/Jifty/Script/Schema.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Script/Schema.pm	(original)
+++ jifty/trunk/lib/Jifty/Script/Schema.pm	Sun Jan 28 09:03:54 2007
@@ -12,13 +12,11 @@
 
 Jifty::Module::Pluggable->import(
     require     => 1,
-    search_path => [ "SQL::ReservedWords"],
-    sub_name => '_sql_dialects',
-);  
-        
-            
+    search_path => ["SQL::ReservedWords"],
+    sub_name    => '_sql_dialects',
+);
 
-our %_SQL_RESERVED = ();
+our %_SQL_RESERVED          = ();
 our @_SQL_RESERVED_OVERRIDE = qw(value);
 foreach my $dialect ( 'SQL::ReservedWords', &_sql_dialects ) {
     foreach my $word ( $dialect->words ) {
@@ -27,11 +25,11 @@
 }
 
 # XXX TODO: QUESTIONABLE ENGINEERING DECISION
-# The SQL standard forbids columns named 'value', but just about everone on the planet 
+# The SQL standard forbids columns named 'value', but just about everone on the planet
 # actually supports it. Rather than going about scaremongering, we choose
 # not to warn people about columns named 'value'
 
-delete $_SQL_RESERVED{lc($_)} for (@_SQL_RESERVED_OVERRIDE);
+delete $_SQL_RESERVED{ lc($_) } for (@_SQL_RESERVED_OVERRIDE);
 
 =head2 options
 
@@ -39,16 +37,15 @@
 
 =cut
 
-
 sub options {
     return (
-        "setup"             => "setup_tables",
-        "print|p"           => "print",
-        "create-database|c" => "create_database",
+        "setup"                 => "setup_tables",
+        "print|p"               => "print",
+        "create-database|c"     => "create_database",
         "ignore-reserved-words" => "ignore_reserved",
-        "drop-database"     => "drop_database",
-        "help|?"            => "help",
-        "man"               => "man"
+        "drop-database"         => "drop_database",
+        "help|?"                => "help",
+        "man"                   => "man"
     );
 }
 
@@ -80,7 +77,6 @@
     }
 }
 
-
 =head2 setup_environment
 
 Sets up a minimal Jifty environment.
@@ -95,7 +91,6 @@
     Jifty::Util->require("Jifty::Model::Metadata");
 }
 
-
 =head2 print_help
 
 Prints out help for the package using pod2usage.
@@ -116,11 +111,9 @@
         if $self->{man};
 }
 
-
 =head2 prepare_model_classes
 
-Reads in our application class from the config file, sets up a schema
-generator and finds all our app's models.
+Reads in our application class from the config file and finds all our app's models.
 
 =cut
 
@@ -128,24 +121,17 @@
 
     my $self = shift;
 
-    # Set up application-specific parts
-    $self->{'_schema_generator'}
-        = Jifty::DBI::SchemaGenerator->new( Jifty->handle )
-        or die "Can't make Jifty::DBI::SchemaGenerator";
-
-# This creates a sub "models" which when called, finds packages under
-# the application's ::Model, requires them, and returns a list of their
-# names.
+    # This creates a sub "models" which when called, finds packages under
+    # the application's ::Model, requires them, and returns a list of their
+    # names.
     Jifty::Module::Pluggable->import(
         require     => 1,
         except      => qr/\.#/,
-        search_path =>
-            [ "Jifty::Model", Jifty->app_class("Model") ],
-        sub_name => 'models',
+        search_path => [ "Jifty::Model", Jifty->app_class("Model") ],
+        sub_name    => 'models',
     );
 }
 
-
 =head2 probe_database_existence
 
 Probes our database to see if it exists and is up to date.
@@ -156,7 +142,7 @@
     my $self = shift;
 
     my $no_handle = 0;
-    if ( $self->{'create_database'} or $self->{'drop_database'}) {
+    if ( $self->{'create_database'} or $self->{'drop_database'} ) {
         $no_handle = 1;
     }
 
@@ -167,33 +153,39 @@
             logger_component => 'SchemaTool',
         );
     };
-    
-    if ( $@ =~ /doesn't match (application schema|running jifty) version/i) {
+
+    if ( $@ =~ /doesn't match (application schema|running jifty) version/i ) {
+
         # We found an out-of-date DB.  Upgrade it
         $self->{setup_tables} = 1;
     } elsif ( $@ =~ /no version in the database/i ) {
+
         # No version table.  Assume the DB is empty.
         $self->{create_all_tables} = 1;
-    } elsif ( $@ =~ /database .*? does not exist/i or $@ =~ /unknown database/) {
+    } elsif ( $@ =~ /database .*? does not exist/i
+        or $@ =~ /unknown database/ ) {
+
         # No database exists; we'll need to make one and fill it up
         $self->{create_database}   = 1;
         $self->{create_all_tables} = 1;
     } elsif ($@) {
+
         # Some other unexpected error; rethrow it
         die $@;
     }
 
     # Setting up tables requires creating the DB if we just dropped it
-    $self->{create_database} = 1   if $self->{drop_database} and $self->{setup_tables};
+    $self->{create_database} = 1
+        if $self->{drop_database} and $self->{setup_tables};
 
-    # Setting up tables on a just-created DB is the same as setting them all up
-    $self->{create_all_tables} = 1 if $self->{create_database} and $self->{setup_tables};
+   # Setting up tables on a just-created DB is the same as setting them all up
+    $self->{create_all_tables} = 1
+        if $self->{create_database} and $self->{setup_tables};
 
     # Give us some kind of handle if we don't have one by now
     Jifty->handle( Jifty::Handle->new() ) unless Jifty->handle;
 }
 
-
 =head2 create_all_tables
 
 Create all tables for this application's models. Generally, this
@@ -204,72 +196,31 @@
 sub create_all_tables {
     my $self = shift;
 
-    my $log    = Log::Log4perl->get_logger("SchemaTool");
-    $log->info(
-        "Generating SQL for application @{[Jifty->app_class]}...");
-
-    my $appv
-        = version->new( Jifty->config->framework('Database')->{'Version'} );
-    my $jiftyv
-        = version->new( $Jifty::VERSION || '0.60426' );
+    my $log = Log::Log4perl->get_logger("SchemaTool");
+    $log->info("Generating SQL for application @{[Jifty->app_class]}...");
 
-    for my $model ( __PACKAGE__->models ) {
+    my $appv = version->new( Jifty->config->framework('Database')->{'Version'} );
+    my $jiftyv = version->new( $Jifty::VERSION  );
 
-        # We don't want to get the Collections, or models that have a
-        # 'since' that is after the current application version.
+    # Start a transaction
+    Jifty->handle->begin_transaction;
 
-       # TODO XXX FIXME:
-       #   This *will* try to generate SQL for abstract base classes you might
-       #   stick in $AC::Model::.
-        next unless $model->isa( 'Jifty::Record' );
-        if ( $model->can( 'since' ) and ($model =~ /^Jifty::Model::/ ? $jiftyv : $appv) < $model->since ) {
-            $log->info("Skipping $model"); 
-            next;
-        }
-        $log->info("Using $model");
-        my $ret = $self->{'_schema_generator'}->add_model( $model->new );
-        $ret or die "couldn't add model $model: " . $ret->error_message;
-        unless ($self->{'ignore_reserved'} or
-         !Jifty->config->framework('Database')->{'CheckSchema'} ) {
-                $self->_check_reserved($model);
-        }
-
-
-    }
-     
-
-
-    if ( $self->{'print'} ) {
-        print $self->{'_schema_generator'}->create_table_sql_text;
-    } else {
-        # Start a transaction
-        Jifty->handle->begin_transaction;
-
-        # Run all CREATE commands
-        for my $statement (
-            $self->{'_schema_generator'}->create_table_sql_statements )
-        {
-            my $ret = Jifty->handle->simple_query($statement);
-            $ret or die "error creating a table: " . $ret->error_message;
-        }
+    $self->create_tables_for_models (grep {$_->isa('Jifty::DBI::Record')}  __PACKAGE__->models );
 
-        # Update the versions in the database
-        Jifty::Model::Metadata->store( application_db_version => $appv);
-        Jifty::Model::Metadata->store( jifty_db_version => $jiftyv);
+    # Update the versions in the database
+    Jifty::Model::Metadata->store( application_db_version => $appv );
+    Jifty::Model::Metadata->store( jifty_db_version       => $jiftyv );
 
-        # Load initial data
-        eval {
-            my $bootstrapper = Jifty->app_class("Bootstrap");
-            Jifty::Util->require($bootstrapper);
-
-            $bootstrapper->run()
-                if  $bootstrapper->can( 'run' );
-        };
-        die $@ if $@;
+    # Load initial data
+    eval {
+        my $bootstrapper = Jifty->app_class("Bootstrap");
+        Jifty::Util->require($bootstrapper);
+        $bootstrapper->run() if $bootstrapper->can('run');
+    };
+    die $@ if $@;
 
-        # Commit it all
-        Jifty->handle->commit;
-    }
+    # Commit it all
+    Jifty->handle->commit;
 
     Jifty::Util->require('IPC::PubSub');
     IPC::PubSub->new(
@@ -282,6 +233,43 @@
     $log->info("Set up version $appv, jifty version $jiftyv");
 }
 
+=head2 create_tables_for_models TABLEs
+
+Given a list of items that are the scalar names of subclasses of Jifty::Record, 
+either prints SQL or creates all those models in your database.
+
+=cut
+
+sub create_tables_for_models {
+    my $self = shift;
+    my @models = (@_);
+
+    my $log = Log::Log4perl->get_logger("SchemaTool");
+    my $appv = version->new( Jifty->config->framework('Database')->{'Version'} );
+    my $jiftyv = version->new( $Jifty::VERSION  );
+
+    for my $model ( @models) {
+
+       # TODO XXX FIXME:
+       #   This *will* try to generate SQL for abstract base classes you might
+       #   stick in $AC::Model::.
+        if ( $model->can( 'since' ) and ($model =~ /^Jifty::Model::/ ? $jiftyv : $appv) < $model->since ) {
+            $log->info( "Skipping $model, as it should already be in the database");
+            next;
+        }
+        $log->info("Using $model, as it appears to be new.");
+
+            $self->_check_reserved($model)
+        unless ( $self->{'ignore_reserved'}
+            or !Jifty->config->framework('Database')->{'CheckSchema'} );
+
+        if ( $self->{'print'} ) {
+            print $model->printable_table_schema;
+        } else {
+            $model->create_table_in_db;
+        }
+    }
+}
 
 =head2 upgrade_jifty_tables
 
@@ -291,22 +279,22 @@
 
 sub upgrade_jifty_tables {
     my $self = shift;
-    my $dbv  = Jifty::Model::Metadata->load( 'jifty_db_version' );
+    my $dbv  = Jifty::Model::Metadata->load('jifty_db_version');
     unless ($dbv) {
         # Backwards combatibility -- it usd to be 'key' not 'data_key';
         eval {
             local $SIG{__WARN__} = sub { };
             $dbv = Jifty->handle->fetch_result(
-                "SELECT value FROM _jifty_metadata WHERE key = 'jifty_db_version'");
+                "SELECT value FROM _jifty_metadata WHERE key = 'jifty_db_version'"
+            );
         };
     }
-    $dbv ||= '0.60426';
-    $dbv = version->new($dbv);
 
-    my $appv = version->new( $Jifty::VERSION );
+    $dbv = version->new($dbv || '0.60426');
+    my $appv = version->new($Jifty::VERSION);
 
-    return unless $self->upgrade_tables( "Jifty" => $dbv, $appv, "Jifty::Upgrade::Internal" );
-    if( $self->{print} ) {
+    return unless $self->upgrade_tables( "Jifty" => $dbv, $appv, "Jifty::Upgrade::Internal");
+    if ( $self->{print} ) {
         warn "Need to upgrade jifty_db_version to $appv here!";
     } else {
         Jifty::Model::Metadata->store( jifty_db_version => $appv );
@@ -321,12 +309,11 @@
 
 sub upgrade_application_tables {
     my $self = shift;
-    my $dbv = version->new( Jifty::Model::Metadata->load( 'application_db_version' ) );
-    my $appv
-        = version->new( Jifty->config->framework('Database')->{'Version'} );
+    my $dbv  = version->new( Jifty::Model::Metadata->load('application_db_version') );
+    my $appv = version->new( Jifty->config->framework('Database')->{'Version'} );
 
     return unless $self->upgrade_tables( Jifty->app_class, $dbv, $appv );
-    if( $self->{print} ) {
+    if ( $self->{print} ) {
         warn "Need to upgrade application_db_version to $appv here!";
     } else {
         Jifty::Model::Metadata->store( application_db_version => $appv );
@@ -343,10 +330,11 @@
 
 sub upgrade_tables {
     my $self = shift;
-    my ($baseclass, $dbv, $appv, $upgradeclass ) = @_;
-    $upgradeclass ||= $baseclass."::Upgrade";
+    my ( $baseclass, $dbv, $appv, $upgradeclass ) = @_;
+    $upgradeclass ||= $baseclass . "::Upgrade";
+
+    my $log = Log::Log4perl->get_logger("SchemaTool");
 
-    my $log    = Log::Log4perl->get_logger("SchemaTool");
     # Find current versions
 
     if ( $appv < $dbv ) {
@@ -357,9 +345,7 @@
         print "$baseclass version $appv up to date.\n";
         return;
     }
-    $log->info(
-        "Generating SQL to upgrade $baseclass $dbv database to $appv"
-    );
+    $log->info( "Generating SQL to upgrade $baseclass $dbv database to $appv" );
 
     # Figure out what versions the upgrade knows about.
     Jifty::Util->require($upgradeclass) or return;
@@ -370,105 +356,89 @@
             $upgradeclass->versions();
     };
 
-    for my $model ( grep {/^\Q$baseclass\E::Model::/} __PACKAGE__->models ) {
+    for my $model_class ( grep {/^\Q$baseclass\E::Model::/} __PACKAGE__->models ) {
 
         # We don't want to get the Collections, for example.
-        do {next} unless $model->isa( 'Jifty::Record' );
+        next unless $model_class->isa('Jifty::DBI::Record');
 
         # Set us up the table
-        $model = $model->new;
-        my $t = $self->{'_schema_generator'}
-            ->_db_schema_table_from_model($model);
-
-        # If this whole table is new
-        if (    $model->can( 'since' )
-            and $appv >= $model->since
-            and $dbv < $model->since )
-        {
-
-            # Create it
-            unshift @{ $UPGRADES{ $model->since } },
-                $t->sql_create_table( Jifty->handle->dbh );
-        } else {
+        my $model = $model_class->new;
 
+        # If this whole table is new Create it
+        if (defined $model->since and  $appv >= $model->since and $model->since >$dbv ) {
+            unshift @{ $UPGRADES{ $model->since } }, $model->printable_table_schema();
+        } else {
             # Go through the columns
-            for my $column ( $model->columns ) {
-                next if $column->virtual;
+            for my $col  (grep {not $_->virtual} $model->columns ) {
 
                 # If they're old, drop them
-                if ($column->can('till') and defined $column->till
-                    and $appv >= $column->till
-                    and $dbv < $column->till )
-                {
-                    push @{ $UPGRADES{ $column->till } },
-                        "ALTER TABLE "
-                        . $model->table
-                        . " DROP COLUMN "
-                        . $column->name;
+               if ( defined $col->till and $appv >= $col->till and $ $col->till > $dbv ) {
+                   push @{ $UPGRADES{ $col->till } }, $model->drop_column_sql($col->name);
                 }
 
                 # If they're new, add them
-                if (    defined $column->since
-                    and $appv >= $column->since
-                    and $dbv < $column->since )
-                {
-                    unshift @{ $UPGRADES{ $column->since } },
-                        "ALTER TABLE "
-                        . $model->table
-                        . " ADD COLUMN "
-                        . $t->column( $column->name )
-                        ->line( Jifty->handle->dbh );
+                if (defined $col->since and $appv >= $col->since and $col->since >$dbv ) {
+                    unshift @{ $UPGRADES{ $col->since } }, $model->add_column_sql($col->name);
                 }
             }
         }
     }
 
     if ( $self->{'print'} ) {
-        for (
-            map  { @{ $UPGRADES{$_} } }
-            sort { version->new($a) <=> version->new($b) }
-            keys %UPGRADES
-            )
-        {
-            if ( ref $_ ) {
-                print "-- Upgrade subroutine:\n";
-                require Data::Dumper;
-                $Data::Dumper::Pad     = "-- ";
-                $Data::Dumper::Deparse = 1;
-                $Data::Dumper::Indent  = 1;
-                $Data::Dumper::Terse   = 1;
-                print Data::Dumper::Dumper($_);
-            } else {
-                print "$_;\n";
-            }
-        }
+        $self->_print_upgrades(%UPGRADES);
+
     } else {
-        Jifty->handle->begin_transaction;
-        for my $version (
-            sort { version->new($a) <=> version->new($b) }
-            keys %UPGRADES
-            )
-        {
-            $log->info("Upgrading through $version");
-            for my $thing ( @{ $UPGRADES{$version} } ) {
-                if ( ref $thing ) {
-                    $log->info("Running upgrade script");
-                    $thing->();
-                } else {
-                    my $ret = Jifty->handle->simple_query($thing);
-                    $ret
-                        or die "error updating a table: "
-                        . $ret->error_message;
-                }
-            }
-        }
+       eval { $self->_execute_upgrades(%UPGRADES);
         $log->info("Upgraded to version $appv");
-        Jifty->handle->commit;
+    }; die $@ if $@;
     }
     return 1;
 }
 
 
+
+sub _execute_upgrades {
+    my $self     = shift;
+    my %UPGRADES = (@_);
+    Jifty->handle->begin_transaction;
+    my $log = Log::Log4perl->get_logger("SchemaTool");
+    for my $version ( sort { version->new($a) <=> version->new($b) } keys %UPGRADES) {
+        $log->info("Upgrading through $version");
+        for my $thing ( @{ $UPGRADES{$version} } ) {
+            if ( ref $thing ) {
+                $log->info("Running upgrade script");
+                $thing->();
+            } else {
+                my $ret = Jifty->handle->simple_query($thing);
+                $ret
+                    or die "error updating a table: " . $ret->error_message;
+            }
+        }
+    }
+    Jifty->handle->commit;
+}
+
+sub _print_upgrades {
+    my %UPGRADES = (@_);
+    for (
+        map  { @{ $UPGRADES{$_} } }
+        sort { version->new($a) <=> version->new($b) }
+        keys %UPGRADES
+        ) {
+        if ( ref $_ ) {
+            print "-- Upgrade subroutine:\n";
+            require Data::Dumper;
+            $Data::Dumper::Pad     = "-- ";
+            $Data::Dumper::Deparse = 1;
+            $Data::Dumper::Indent  = 1;
+            $Data::Dumper::Terse   = 1;
+            print Data::Dumper::Dumper($_);
+        } else {
+            print "$_;\n";
+        }
+    }
+}
+
 =head2 manage_database_existence
 
 If the user wants the database created, creates the database. If the
@@ -477,63 +447,68 @@
 =cut
 
 sub manage_database_existence {
-    my $self     = shift;
-    my $handle   = Jifty::Handle->new();
-    my $database = Jifty::Handle->canonical_database_name;
-    my $driver   = Jifty->config->framework('Database')->{'Driver'};
+    my $self = shift;
 
-    # Everything but the template1 database is assumed
-    my %connect_args;
-    $connect_args{'database'} = 'template1' if ( $driver eq 'Pg' );
-    $connect_args{'database'} = '' if ( $driver eq 'mysql' );
-    $handle->connect(%connect_args);
+    my $handle = $self->_connect_to_db_for_management();
 
-    if ( $self->{'drop_database'} ) {
-        if ( $self->{'print'} ) {
-            print "DROP DATABASE $database;\n";
-        } elsif ( $driver =~ /SQLite/ ) {
-            # Win32 complains when you try to unlink open DB
-            $handle->disconnect if $^O eq 'MSWin32';
-            unlink($database);
-        } else {
-            $handle->simple_query("DROP DATABASE $database");
-        }
+        if ( $self->{'drop_database'} ) {
+        $handle->drop_database($self->{'print'} ? 'print' : 'execute');
     }
 
     if ( $self->{'create_database'} ) {
-        if ( $self->{'print'} ) {
-            print "CREATE DATABASE $database;\n";
-        } elsif ( $driver !~ /SQLite/ ) {
-            $handle->simple_query("CREATE DATABASE $database");
-        }
+        $handle->create_database($self->{'print'} ? 'print' : 'execute');
     }
 
     $handle->disconnect;
 
     # If we drop and didn't re-create, then don't reconnect
-    return if $self->{'drop_database'} and not $self->{'create_database'};
+    if ( $self->{'drop_database'} and not $self->{'create_database'} ) {
+        return;
+    }
 
     # Likewise if we didn't get a connection before, and we're just
     # printing, the connect below will fail
-    return if $self->{'print'} and not ( Jifty->handle and Jifty->handle->dbh->ping );
+    elsif ( $self->{'print'}
+        and not( Jifty->handle and Jifty->handle->dbh->ping ) ) {
+        return;
+    } else {
+        $self->_reinit_handle();
+    }
+}
+
+sub _connect_to_db_for_management {
+    my $handle = Jifty::Handle->new();
 
-    # Otherwise, reinit our handle
+    my $driver   = Jifty->config->framework('Database')->{'Driver'};
+
+    # Everything but the template1 database is assumed
+    my %connect_args;
+    $connect_args{'database'} = 'template1' if ( $driver eq 'Pg' );
+    $connect_args{'database'} = ''          if ( $driver eq 'mysql' );
+    $handle->connect(%connect_args);
+    return $handle;
+}
+
+sub _reinit_handle {
     Jifty->handle( Jifty::Handle->new() );
     Jifty->handle->connect();
 }
 
 sub __parenthesize {
-    if (not defined $_[0]) { return () }
-    if (@_ == 1)           { return $_[0] }
-    return "(" . (join ", ", @_) . ")";
+    if ( not defined $_[0] ) { return () }
+    if ( @_ == 1 )           { return $_[0] }
+    return "(" . ( join ", ", @_ ) . ")";
 }
 
 sub _classify {
     my %dbs;
+
     # Guess names of databases + their versions by breaking on last space,
     # e.g., "SQL Server 7" is ("SQL Server", "7"), not ("SQL", "Server 7").
-    push @{ $dbs{$_->[0]} }, $_->[1] for map { [ split /\s+(?!.*\s)/, $_, 2 ] } @_;
-    return map { join " ", $_, __parenthesize(@{ $dbs{$_} }) } sort keys %dbs;
+    push @{ $dbs{ $_->[0] } }, $_->[1]
+        for map { [ split /\s+(?!.*\s)/, $_, 2 ] } @_;
+    return
+        map { join " ", $_, __parenthesize( @{ $dbs{$_} } ) } sort keys %dbs;
 }
 
 sub _check_reserved {
@@ -542,10 +517,13 @@
     my $log   = Log::Log4perl->get_logger("SchemaTool");
     foreach my $col ( $model->columns ) {
         if ( exists $_SQL_RESERVED{ lc( $col->name ) } ) {
-            $log->error( $model . ": "
+            $log->error(
+                      $model . ": "
                     . $col->name
                     . " is a reserved word in these SQL dialects: "
-                    . join( ', ', _classify(@{ $_SQL_RESERVED{ lc( $col->name ) } }) ) );
+                    . join( ', ',
+                    _classify( @{ $_SQL_RESERVED{ lc( $col->name ) } } ) )
+            );
         }
     }
 }


More information about the Jifty-commit mailing list