[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