[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