[Jifty-commit] r2701 - in jifty/branches/template-declare: .
lib/Jifty lib/Jifty/Module lib/Jifty/Plugin/REST
jifty-commit at lists.jifty.org
jifty-commit at lists.jifty.org
Sun Jan 28 22:19:11 EST 2007
Author: trs
Date: Sun Jan 28 22:19:11 2007
New Revision: 2701
Modified:
jifty/branches/template-declare/ (props changed)
jifty/branches/template-declare/Makefile.PL
jifty/branches/template-declare/lib/Jifty/ClassLoader.pm
jifty/branches/template-declare/lib/Jifty/Config.pm
jifty/branches/template-declare/lib/Jifty/CurrentUser.pm
jifty/branches/template-declare/lib/Jifty/Handle.pm
jifty/branches/template-declare/lib/Jifty/Logger.pm
jifty/branches/template-declare/lib/Jifty/Module/Pluggable.pm
jifty/branches/template-declare/lib/Jifty/Plugin/REST/Dispatcher.pm
jifty/branches/template-declare/lib/Jifty/Record.pm
jifty/branches/template-declare/lib/Jifty/Script/App.pm
jifty/branches/template-declare/lib/Jifty/Script/Schema.pm
jifty/branches/template-declare/lib/Jifty/Util.pm
Log:
Mergedown from trunk
r19241 at zot (orig r2677): audreyt | 2007-01-28 08:06:19 -0500
* Jifty::Script::App - Make the generated Makefile.PL more canonical.
r19242 at zot (orig r2678): audreyt | 2007-01-28 08:08:49 -0500
* Jifty::Util - Add a generate_uuid method and use it to generate ApplicationUUID.
r19244 at zot (orig r2680): jesse | 2007-01-28 08:34:47 -0500
r21608 at hualien: jesse | 2007-01-28 21:31:51 +0800
* Added the 'bootstrap' option to vanilla Jifty::CurrentUser. Now there's one fiewer cases where you need a custom CurrentUser class
r19245 at zot (orig r2681): jesse | 2007-01-28 08:35:39 -0500
r21609 at hualien: jesse | 2007-01-28 21:32:21 +0800
* Added "create db" and "drop db" methods to Jifty::Handle
r19246 at zot (orig r2682): jesse | 2007-01-28 08:36:30 -0500
r21610 at hualien: jesse | 2007-01-28 21:33:22 +0800
* Added table and column schema generation methods to Jifty::Record, based on an extraction of Jifty::Script::Schema
r19248 at zot (orig r2684): jesse | 2007-01-28 08:57:35 -0500
r21616 at hualien: jesse | 2007-01-28 21:56:23 +0800
* Extract the "load model related classes" logic in the class loader to its own function
* A new method provides a tantalizing glimpse of jifty's forthcoming "load models from the database" support
r19249 at zot (orig r2685): jesse | 2007-01-28 09:03:54 -0500
r21618 at hualien: jesse | 2007-01-28 22:03:22 +0800
* Refactored Jifty::Script::Schema to use extracted column, table and db manipulation routines
r19252 at zot (orig r2688): audreyt | 2007-01-28 09:35:50 -0500
* Jifty::Logger - Properly respect previous $SIG{__WARN__} handler
if Log4Perl isn't yet initialized; that means we won't silently
discard compile-time errors from our model classes, though they
are still demoted as warnings.
r19254 at zot (orig r2690): jesse | 2007-01-28 09:52:47 -0500
r21628 at hualien: jesse | 2007-01-28 22:52:22 +0800
* A better implementation of our Module::Pluggable custom 'require' method.
r19257 at zot (orig r2693): jesse | 2007-01-28 10:56:10 -0500
r21633 at hualien: jesse | 2007-01-28 23:54:24 +0800
* Actually carp from within our log warning handler, to not swallow critical debugging into
r19258 at zot (orig r2694): jesse | 2007-01-28 10:57:04 -0500
r21634 at hualien: jesse | 2007-01-28 23:55:16 +0800
* Alternate implementation of Module::Pluggable::Object's _require method to avoid a useless string eval.
r19260 at zot (orig r2696): audreyt | 2007-01-28 11:02:46 -0500
* Additionally require Module::Pluggable::Object to silence dep.t
r19261 at zot (orig r2697): audreyt | 2007-01-28 11:08:00 -0500
* strict, warnings, and redefinition warning avoidance for J::Module::Pluggable.
r19267 at zot (orig r2700): trs | 2007-01-28 22:17:23 -0500
r19265 at zot: tom | 2007-01-28 22:17:12 -0500
Squash warning
Modified: jifty/branches/template-declare/Makefile.PL
==============================================================================
--- jifty/branches/template-declare/Makefile.PL (original)
+++ jifty/branches/template-declare/Makefile.PL Sun Jan 28 22:19:11 2007
@@ -48,7 +48,8 @@
requires('Log::Log4perl');
requires('LWP::UserAgent'); # Net::HTTP
requires('MIME::Types');
-requires('Module::Pluggable' => '3.1');
+requires('Module::Pluggable' => '3.1'); # Module::Pluggable::Object
+requires('Module::Pluggable::Object');
requires('Module::CoreList');
requires('Module::Refresh');
requires('Module::ScanDeps');
Modified: jifty/branches/template-declare/lib/Jifty/ClassLoader.pm
==============================================================================
--- jifty/branches/template-declare/lib/Jifty/ClassLoader.pm (original)
+++ jifty/branches/template-declare/lib/Jifty/ClassLoader.pm Sun Jan 28 22:19:11 2007
@@ -209,7 +209,10 @@
return unless ($base);
Jifty::Util->require($base);
Jifty::Util->require($base."::CurrentUser");
- eval {
+
+ my %models;
+
+
Jifty::Module::Pluggable->import(
# $base goes last so we pull in the view class AFTER the model classes
search_path => [map { $base . "::" . $_ } ('Model', 'Action', 'Notification', 'Event')],
@@ -217,19 +220,52 @@
except => qr/\.#/,
inner => 0
);
- };
-
- if ($@) {
- warn "$@";
- }
- my %models;
$models{$_} = 1 for grep {/^($base)::Model::(.*)$/ and not /Collection$/} $self->plugins;
$self->models(sort keys %models);
for my $full ($self->models) {
+ $self->_require_model_related_classes($full);
+ }
+
+}
+
+sub _require_model_related_classes {
+ my $self = shift;
+ my $full = shift;
+ my $base = $self->{base};
my($short) = $full =~ /::Model::(.*)/;
Jifty::Util->require($full . "Collection");
Jifty::Util->require($base . "::Action::" . $_ . $short)
for qw/Create Update Delete Search/;
+
+}
+
+
+=head2 require_classes_from_database
+
+Jifty supports model classes that aren't files on disk but instead records
+in your database. It's a little bit mind bending, but basically, you can
+build an application entirely out of the database without ever writing a
+line of code(*).
+
+* As of early 2007, this forward looking statement is mostly a lie. But we're
+working on it.
+
+This method finds all database-backed models and instantiates jifty classes for
+them it returns a list of classnames of the models it created.
+
+=cut
+
+sub require_classes_from_database {
+ my $self = shift;
+ my @instantiated;
+
+ require Jifty::Model::ModelClassCollection;
+ require Jifty::Model::ModelClass;
+ my $models = Jifty::Model::ModelClassCollection->new(current_user => Jifty::CurrentUser->superuser);
+ $models->unlimit();
+ while (my $model = $models->next) {
+ $model->instantiate();
+ $self->_require_model_related_classes($model->qualified_class);
}
}
Modified: jifty/branches/template-declare/lib/Jifty/Config.pm
==============================================================================
--- jifty/branches/template-declare/lib/Jifty/Config.pm (original)
+++ jifty/branches/template-declare/lib/Jifty/Config.pm Sun Jan 28 22:19:11 2007
@@ -233,6 +233,7 @@
$app_class =~ s/-/::/g;
my $db_name = lc $app_name;
$db_name =~ s/-/_/g;
+ my $app_uuid = Jifty::Util->generate_uuid;
my $guess = {
framework => {
@@ -241,6 +242,7 @@
ApplicationClass => $app_class,
TemplateClass => $app_class."::View",
ApplicationName => $app_name,
+ ApplicationUUID => $app_uuid,
LogLevel => 'INFO',
PubSub => {
Enable => undef,
Modified: jifty/branches/template-declare/lib/Jifty/CurrentUser.pm
==============================================================================
--- jifty/branches/template-declare/lib/Jifty/CurrentUser.pm (original)
+++ jifty/branches/template-declare/lib/Jifty/CurrentUser.pm Sun Jan 28 22:19:11 2007
@@ -38,9 +38,11 @@
sub new {
my $class = shift;
- my $self = {};
+ my $self = {};
bless $self, $class;
- $self->_init(@_);
+ my %args = (@_);
+ if ( delete $args{'_bootstrap'} ) { $self->is_bootstrap_user(1); }
+ $self->_init(%args);
return $self;
}
@@ -72,9 +74,7 @@
my $self = shift;
my %args = (@_);
- if (delete $args{'_bootstrap'} ) {
- $self->is_bootstrap_user(1);
- } elsif (keys %args) {
+ if (keys %args) {
$self->user_object(Wifty::Model::User->new(current_user => $self));
$self->user_object->load_by_cols(%args);
}
Modified: jifty/branches/template-declare/lib/Jifty/Handle.pm
==============================================================================
--- jifty/branches/template-declare/lib/Jifty/Handle.pm (original)
+++ jifty/branches/template-declare/lib/Jifty/Handle.pm Sun Jan 28 22:19:11 2007
@@ -159,6 +159,55 @@
}
+=head2 create_database MODE
+
+C<MODE> is either "print" or "execute".
+
+This method either prints the commands necessary to create the database
+or actually creates it, depending on the value of MODE.
+
+=cut
+
+sub create_database {
+ my $self = shift;
+ my $mode = shift || 'execute';
+ my $database = $self->canonical_database_name;
+ my $driver = Jifty->config->framework('Database')->{'Driver'};
+ my $query = "CREATE DATABASE $database;\n";
+ if ( $mode eq 'print') {
+ print $query;
+ } elsif ( $driver !~ /SQLite/ ) {
+ $self->simple_query($query);
+ }
+}
+
+=head2 drop_database MODE
+
+C<MODE> is either "print" or "execute".
+
+This method either prints the commands necessary to drop the database
+or actually drops it, depending on the value of MODE.
+
+=cut
+
+sub drop_database {
+ my $self = shift;
+ my $mode = shift || 'execute';
+ my $database = $self->canonical_database_name;
+ my $driver = Jifty->config->framework('Database')->{'Driver'};
+ if ( $mode eq 'print' ) {
+ print "DROP DATABASE $database;\n";
+ } elsif ( $driver =~ /SQLite/ ) {
+
+ # Win32 complains when you try to unlink open DB
+ $self->disconnect if $^O eq 'MSWin32';
+ unlink($database);
+ } else {
+ $self->simple_query("DROP DATABASE $database");
+ }
+}
+
+
=head1 AUTHOR
Various folks at BestPractical Solutions, LLC.
Modified: jifty/branches/template-declare/lib/Jifty/Logger.pm
==============================================================================
--- jifty/branches/template-declare/lib/Jifty/Logger.pm (original)
+++ jifty/branches/template-declare/lib/Jifty/Logger.pm Sun Jan 28 22:19:11 2007
@@ -70,6 +70,7 @@
=cut
use Log::Log4perl;
+use Carp;
use base qw/Jifty::Object/;
@@ -105,6 +106,7 @@
# whenever Perl wants to warn something out capture it with a signal
# handler and pass it to log4perl
+ my $previous_warning_handler = $SIG{__WARN__};
$SIG{__WARN__} = sub {
# This caller_depth line tells Log4perl to report
@@ -120,6 +122,16 @@
# the aliasing so we can remove trailing newlines
my @lines = map {"$_"} @_;
$logger->warn(map {chomp; $_} @lines);
+ carp (map {chomp; $_} @lines);
+ }
+ elsif ($previous_warning_handler) {
+ # Fallback to the old handler
+ goto &$previous_warning_handler;
+ }
+ else {
+ # Now handler - just carp about it for now
+ local $SIG{__WARN__};
+ carp(@_);
}
};
Modified: jifty/branches/template-declare/lib/Jifty/Module/Pluggable.pm
==============================================================================
--- jifty/branches/template-declare/lib/Jifty/Module/Pluggable.pm (original)
+++ jifty/branches/template-declare/lib/Jifty/Module/Pluggable.pm Sun Jan 28 22:19:11 2007
@@ -1,4 +1,6 @@
package Jifty::Module::Pluggable;
+use strict;
+use warnings;
use base qw/Module::Pluggable/;
=head1 NAME
@@ -30,13 +32,28 @@
was done.
+=head3 But Simon is lying...
+
+What we actually need to override is Module::Pluggable::Object::_require, which we do below.
+
+
=cut
-sub require {
+use Module::Pluggable::Object;
+use UNIVERSAL::require;
+
+no warnings 'redefine';
+sub Module::Pluggable::Object::_require {
my $self = shift;
my $module = shift;
- Jifty::Util->require($module);
-}
+
+ # Module::Pluggable::Object::_require expects a true value (the error message) on failure
+ # On success, it expects you to return undef.
+
+ local $UNIVERSAL::require::ERROR;
+ $module->require(); # We'd prefer to use Jifty::Util->require() here, but it spews crazy warnings
+ return $UNIVERSAL::require::ERROR;
+}
1;
Modified: jifty/branches/template-declare/lib/Jifty/Plugin/REST/Dispatcher.pm
==============================================================================
--- jifty/branches/template-declare/lib/Jifty/Plugin/REST/Dispatcher.pm (original)
+++ jifty/branches/template-declare/lib/Jifty/Plugin/REST/Dispatcher.pm Sun Jan 28 22:19:11 2007
@@ -121,7 +121,7 @@
}
}
- warn "Unable to handle object of type ", ref $obj, ", attempting to stringify.\n";
+ # Attempt to stringify as last resort
return stringify( $obj );
}
Modified: jifty/branches/template-declare/lib/Jifty/Record.pm
==============================================================================
--- jifty/branches/template-declare/lib/Jifty/Record.pm (original)
+++ jifty/branches/template-declare/lib/Jifty/Record.pm Sun Jan 28 22:19:11 2007
@@ -402,5 +402,88 @@
};
}
+=head2 since
+
+By default, all models exist since C<undef>, the ur-time when the application was created. Please override it for your midel class.
+
+=cut
+
+
+
+=head2 printable_table_schema
+
+When called, this method will generate the SQL schema for the current version of this
+class and return it as a scalar, suitable for printing or execution in your database's command line.
+
+=cut
+
+
+sub printable_table_schema {
+ my $class = shift;
+
+ my $schema_gen = $class->_make_schema();
+ return $schema_gen->create_table_sql_text;
+}
+
+=head2 create_table_in_db
+
+When called, this method will generate the SQL schema for the current version of this
+class and insert it into the application's currently open database.
+
+=cut
+
+sub create_table_in_db {
+ my $class = shift;
+
+ my $schema_gen = $class->_make_schema();
+
+ # Run all CREATE commands
+ for my $statement ( $schema_gen->create_table_sql_statements ) {
+ my $ret = Jifty->handle->simple_query($statement);
+ $ret or die "error creating table $class: " . $ret->error_message;
+ }
+
+}
+
+sub _make_schema {
+ my $class = shift;
+
+ my $schema_gen = Jifty::DBI::SchemaGenerator->new( Jifty->handle )
+ or die "Can't make Jifty::DBI::SchemaGenerator";
+ my $ret = $schema_gen->add_model( $class->new );
+ $ret or die "couldn't add model $class: " . $ret->error_message;
+
+ return $schema_gen;
+}
+
+=head2 add_column_sql column_name
+
+Returns the SQL statement neccessary to add C<column_name> to this class's representation in the database
+
+=cut
+
+sub add_column_sql {
+ my $self = shift;
+ my $column_name = shift;
+
+ my $col = $self->column($column_name);
+ my $definition = $self->_make_schema()->column_definition_sql($self->table => $col->name);
+ return "ALTER TABLE " . $self->table . " ADD COLUMN " . $definition;
+}
+
+=head2 drop_column_sql column_name
+
+Returns the SQL statement neccessary to remove C<column_name> from this class's representation in the database
+
+=cut
+
+sub drop_column_sql {
+ my $self = shift;
+ my $column_name = shift;
+
+ my $col = $self->column($column_name);
+ return "ALTER TABLE " . $self->table . " DROP COLUMN " . $col->name;
+}
+
1;
Modified: jifty/branches/template-declare/lib/Jifty/Script/App.pm
==============================================================================
--- jifty/branches/template-declare/lib/Jifty/Script/App.pm (original)
+++ jifty/branches/template-declare/lib/Jifty/Script/App.pm Sun Jan 28 22:19:11 2007
@@ -92,9 +92,10 @@
open(MAKEFILE, ">$prefix/Makefile.PL") or die "Can't write Makefile.PL: $!";
print MAKEFILE <<"EOT";
use inc::Module::Install;
-name('$mod_name');
-version('0.01');
-requires('Jifty' => '@{[$Jifty::VERSION]}');
+
+name '$mod_name';
+version '0.01';
+requires 'Jifty' => '@{[$Jifty::VERSION]}';
WriteAll;
EOT
Modified: jifty/branches/template-declare/lib/Jifty/Script/Schema.pm
==============================================================================
--- jifty/branches/template-declare/lib/Jifty/Script/Schema.pm (original)
+++ jifty/branches/template-declare/lib/Jifty/Script/Schema.pm Sun Jan 28 22:19:11 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 ) } } ) )
+ );
}
}
}
Modified: jifty/branches/template-declare/lib/Jifty/Util.pm
==============================================================================
--- jifty/branches/template-declare/lib/Jifty/Util.pm (original)
+++ jifty/branches/template-declare/lib/Jifty/Util.pm Sun Jan 28 22:19:11 2007
@@ -263,6 +263,20 @@
return ( $INC{$path} ? 1 : 0);
}
+=head2 generate_uuid
+
+Generate a new UUID using B<Data::UUID>.
+
+=cut
+
+my $Data_UUID_instance;
+sub generate_uuid {
+ ($Data_UUID_instance ||= do {
+ require Data::UUID;
+ Data::UUID->new;
+ })->create_str;
+}
+
=head1 AUTHOR
Various folks at Best Practical Solutions, LLC.
More information about the Jifty-commit
mailing list