Merge 'trunk' into 'view-deps'
Peter Rabbitson [Sun, 30 May 2010 22:39:14 +0000 (22:39 +0000)]
r9420@Thesaurus (orig r9406):  caelum | 2010-05-20 16:28:18 +0200
support INSERT OR UPDATE triggers for Oracle
r9421@Thesaurus (orig r9407):  matthewt | 2010-05-20 19:19:14 +0200
don't try and ensure_class_loaded an object. this doesn't work.
r9422@Thesaurus (orig r9408):  matthewt | 2010-05-20 19:36:01 +0200
fix result_class setter behaviour to not stuff attrs (line commented out to prevent this regression being mistakenly re-introduced)
r9423@Thesaurus (orig r9409):  matthewt | 2010-05-20 19:49:32 +0200
forgot to commit fixes
r9424@Thesaurus (orig r9410):  matthewt | 2010-05-20 20:09:52 +0200
fix find() since that was also broken in r8754
r9435@Thesaurus (orig r9421):  rabbit | 2010-05-25 11:14:29 +0200
Fix undef warning
r9436@Thesaurus (orig r9422):  rabbit | 2010-05-25 11:15:01 +0200
Rewrite test as to not propagate several ways to do the same thing
r9452@Thesaurus (orig r9438):  caelum | 2010-05-25 21:33:37 +0200
 r24317@hlagh (orig r9367):  tonvoon | 2010-05-14 12:24:35 -0400
 Branch for converting eval {} to Try::Tiny

 r24319@hlagh (orig r9369):  tonvoon | 2010-05-14 17:25:02 -0400
 Conversion of eval => try (part 1)

 r24325@hlagh (orig r9375):  tonvoon | 2010-05-14 18:03:03 -0400
 Add eval => try

 r24326@hlagh (orig r9376):  tonvoon | 2010-05-14 18:22:57 -0400
 Another eval => try

 r24327@hlagh (orig r9377):  tonvoon | 2010-05-14 18:45:27 -0400
 Corrected usage of $@ in catch block

 r24328@hlagh (orig r9378):  tonvoon | 2010-05-14 19:29:52 -0400
 txn_do's eval => try

 r24329@hlagh (orig r9379):  tonvoon | 2010-05-14 19:46:44 -0400
 eval => try where tests for $@ done

 r24330@hlagh (orig r9380):  tonvoon | 2010-05-14 20:38:43 -0400
 All expected evals converted to try, except where no test is done,
 runtime evaluation, or base perl (such as "require"). Only one test
 failure due to string difference in output

 r24346@hlagh (orig r9396):  tonvoon | 2010-05-17 08:52:28 -0400
 Fix missing $@ in try::tiny conversion

 r24347@hlagh (orig r9397):  tonvoon | 2010-05-17 08:55:13 -0400
 Revert to eval instead of try::tiny because no check for $@

 r24348@hlagh (orig r9398):  tonvoon | 2010-05-17 08:55:45 -0400
 Added myself to contributors

 r24349@hlagh (orig r9399):  tonvoon | 2010-05-17 10:23:57 -0400
 Fixed exception logic due to not being able to use return with a catch{}

 r24350@hlagh (orig r9400):  tonvoon | 2010-05-17 10:31:32 -0400
 Removed tab

 r24430@hlagh (orig r9424):  ribasushi | 2010-05-25 10:09:39 -0400
 More try::tiny conversions
 r24432@hlagh (orig r9426):  ribasushi | 2010-05-25 11:40:45 -0400
 Try::Tiny conversion finished
 r24433@hlagh (orig r9427):  ribasushi | 2010-05-25 11:46:52 -0400
 Missed use
 r24440@hlagh (orig r9434):  rkitover | 2010-05-25 13:47:25 -0400
 fix Oracle
 r24441@hlagh (orig r9435):  rkitover | 2010-05-25 14:04:10 -0400
 fix odbc/mssql dynamic cursors
 r24442@hlagh (orig r9436):  rkitover | 2010-05-25 14:32:41 -0400
 fix hang in SQLAnywhere DateTime tests

r9454@Thesaurus (orig r9440):  rabbit | 2010-05-26 11:28:37 +0200
Simplify oracle retrial logic
r9455@Thesaurus (orig r9441):  rabbit | 2010-05-26 12:00:20 +0200
Can not return from within a try block
r9456@Thesaurus (orig r9442):  rabbit | 2010-05-26 12:17:55 +0200
Really fix logic
r9464@Thesaurus (orig r9450):  jester | 2010-05-27 16:06:43 +0200
Light doc tweaks

r9475@Thesaurus (orig r9461):  ribasushi | 2010-05-31 00:17:29 +0200
Rewrite GenericSubQ from SQLA::L to be actually useful
Since it now works it is no longer necessary to turn on softlimit when genericsubq is detected
Switch all sprintf()ed limit/offset specs to unsigned integers
Lower the default rows-without-offset to 2^32
r9476@Thesaurus (orig r9462):  rabbit | 2010-05-31 00:25:01 +0200
New format of changelog (easier to read)
r9477@Thesaurus (orig r9463):  rabbit | 2010-05-31 00:27:18 +0200
Fix MC double-object creation (important for e.g. IC::FS which otherwise leaves orphaned files)
r9479@Thesaurus (orig r9465):  rabbit | 2010-05-31 00:37:23 +0200
Fix tests to survive the new SQLA bindtype checks

lib/DBIx/Class.pm
lib/DBIx/Class/ResultSource/View.pm
lib/SQL/Translator/Parser/DBIx/Class.pm
t/105view_deps.t [new file with mode: 0644]
t/lib/ViewDeps.pm [new file with mode: 0644]
t/lib/ViewDeps/Result/Bar.pm [new file with mode: 0644]
t/lib/ViewDeps/Result/Baz.pm [new file with mode: 0644]
t/lib/ViewDeps/Result/Foo.pm [new file with mode: 0644]
t/lib/ViewDeps/Result/JustATable.pm [new file with mode: 0644]
t/lib/ViewDeps/Result/Mixin.pm [new file with mode: 0644]
t/lib/ViewDeps/Result/Quux.pm [new file with mode: 0644]

index 6d86134..c4c7928 100644 (file)
@@ -225,6 +225,8 @@ abraxxa: Alexander Hartmaier <abraxxa@cpan.org>
 
 aherzog: Adam Herzog <adam@herzogdesigns.com>
 
+amiri: Amiri Barksdale <amiri@metalabel.com>
+
 amoore: Andrew Moore <amoore@cpan.org>
 
 andyg: Andy Grundman <andy@hybridized.org>
index 3dde9bd..6693060 100644 (file)
@@ -4,12 +4,13 @@ use strict;
 use warnings;
 
 use DBIx::Class::ResultSet;
+use SQL::Translator::Parser::DBIx::Class;
+use Data::Dumper::Concise;
 
 use base qw/DBIx::Class/;
 __PACKAGE__->load_components(qw/ResultSource/);
 __PACKAGE__->mk_group_accessors(
-  'simple' => qw(is_virtual view_definition)
-);
+    'simple' => qw(is_virtual view_definition deploy_depends_on) );
 
 =head1 NAME
 
@@ -130,9 +131,33 @@ database-based view.
 An SQL query for your view. Will not be translated across database
 syntaxes.
 
+=head2 deploy_depends_on 
+
+  __PACKAGE__->result_source_instance->deploy_depends_on(
+      "MyDB::Schema::Result::Year","MyDB::Schema::Result::CD"
+      );
+
+Specify the result classes that comprise this view. Pass this
+method a list.
 
 =head1 OVERRIDDEN METHODS
 
+=head2 new
+
+The constructor. This is a private method, as only other DBIC modules
+should call this.
+
+=cut
+
+sub new {
+    my ( $self, @args ) = @_;
+    my $new = $self->next::method(@args);
+    $new->{deploy_depends_on}
+        = { map { $_->result_source_instance->name => 1 } @{ $new->{deploy_depends_on}||[] } }
+        unless ref $new->{deploy_depends_on} eq 'HASH';
+    return $new;
+}
+
 =head2 from
 
 Returns the FROM entry for the table (i.e. the view name)
@@ -141,11 +166,20 @@ or the SQL as a subselect if this is a virtual view.
 =cut
 
 sub from {
-  my $self = shift;
-  return \"(${\$self->view_definition})" if $self->is_virtual;
-  return $self->name;
+    my $self = shift;
+    return \"(${\$self->view_definition})" if $self->is_virtual;
+    return $self->name;
 }
 
+=head1 PRIVATE METHODS
+
+=head2 deploy_depends_on
+
+An internal method for the construction of a hashref of the view's
+superclasses, e.g., the sources that comprise it.
+
+=cut
+
 1;
 
 =head1 AUTHORS
@@ -160,6 +194,8 @@ Jess Robinson <castaway@desert-island.me.uk>
 
 Wallace Reis <wreis@cpan.org>
 
+Amiri Barksdale <amiri@metalabel.com>
+
 =head1 LICENSE
 
 You may distribute this code under the same terms as Perl itself.
index ca25aa2..073a45c 100644 (file)
@@ -269,6 +269,7 @@ sub parse {
     my $dependencies = {
       map { $_ => _resolve_deps ($_, \%tables) } (keys %tables)
     };
+
     for my $table (sort
       {
         keys %{$dependencies->{$a} || {} } <=> keys %{ $dependencies->{$b} || {} }
@@ -297,9 +298,20 @@ EOW
     }
 
     my %views;
-    foreach my $moniker (sort keys %view_monikers)
+
+    my @view_sources =
+    sort {
+        keys %{ $dependencies->{$a} || {} }
+        <=>
+        keys %{ $dependencies->{$b} || {} }
+        ||
+        $a cmp $b
+    }
+    map { $dbicschema->source($_) }
+    keys %view_monikers;
+
+    foreach my $source (@view_sources)
     {
-        my $source = $dbicschema->source($moniker);
         my $view_name = $source->name;
 
         # FIXME - this isn't the right way to do it, but sqlt does not
diff --git a/t/105view_deps.t b/t/105view_deps.t
new file mode 100644 (file)
index 0000000..b584cbd
--- /dev/null
@@ -0,0 +1,66 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Test::More;
+use Test::Exception;
+use lib qw(t/lib);
+use ViewDeps;
+
+BEGIN {
+    use_ok('DBIx::Class::ResultSource::View');
+}
+
+### SANITY
+
+my $view = DBIx::Class::ResultSource::View->new( { name => 'Quux' } );
+
+isa_ok( $view, 'DBIx::Class::ResultSource', 'A new view' );
+isa_ok( $view, 'DBIx::Class', 'A new view also' );
+
+can_ok( $view, $_ ) for qw/new from deploy_depends_on/;
+
+### DEPS
+
+my $schema = ViewDeps->connect;
+ok( $schema, 'Connected to ViewDeps schema OK' );
+
+
+my $bar_rs = $schema->resultset('Bar');
+
+my @bar_deps
+    = keys %{ $schema->resultset('Bar')->result_source->deploy_depends_on };
+
+my @foo_deps
+    = keys %{ $schema->resultset('Foo')->result_source->deploy_depends_on };
+
+isa_ok( $schema->resultset('Bar')->result_source,
+    'DBIx::Class::ResultSource::View', 'Bar' );
+
+is( $bar_deps[0], 'baz',   'which is reported to depend on baz...' );
+is( $bar_deps[1], 'mixin', 'and on mixin.' );
+is( $foo_deps[0], undef,   'Foo has no dependencies...' );
+
+isa_ok(
+    $schema->resultset('Foo')->result_source,
+    'DBIx::Class::ResultSource::View',
+    'though Foo'
+);
+isa_ok(
+    $schema->resultset('Baz')->result_source,
+    'DBIx::Class::ResultSource::Table',
+    "Baz on the other hand"
+);
+dies_ok {
+    ViewDeps::Result::Baz->result_source_instance
+        ->deploy_depends_on("ViewDeps::Result::Mixin");
+}
+"...and you cannot use deploy_depends_on with that";
+
+is(ViewDeps->source('Foo')->view_definition, $schema->resultset('Bar')->result_source->view_definition, "Package Foo's view definition is equivalent to resultset Bar's view definition");
+
+my $dir = "t/sql";
+$schema->create_ddl_dir( ['PostgreSQL','SQLite'], 0.1, $dir );
+
+done_testing;
diff --git a/t/lib/ViewDeps.pm b/t/lib/ViewDeps.pm
new file mode 100644 (file)
index 0000000..05fea95
--- /dev/null
@@ -0,0 +1,11 @@
+package # hide from PAUSE
+    ViewDeps;
+## Used in 105view_deps.t
+
+use strict;
+use warnings;
+use parent qw(DBIx::Class::Schema);
+
+__PACKAGE__->load_namespaces;
+
+1;
diff --git a/t/lib/ViewDeps/Result/Bar.pm b/t/lib/ViewDeps/Result/Bar.pm
new file mode 100644 (file)
index 0000000..b81d430
--- /dev/null
@@ -0,0 +1,26 @@
+package    # hide from PAUSE
+    ViewDeps::Result::Bar;
+
+use strict;
+use warnings;
+use base qw/ViewDeps::Result::Foo/;
+
+require ViewDeps::Result::Mixin;
+
+__PACKAGE__->table('bar');
+
+__PACKAGE__->result_source_instance->deploy_depends_on(
+    ["ViewDeps::Result::Mixin", "ViewDeps::Result::Baz"] );
+
+__PACKAGE__->add_columns( b => { data_type => 'integer' } );
+
+__PACKAGE__->belongs_to(
+    'table',
+    'ViewDeps::Result::JustATable',
+    { 'foreign.id' => 'self.b' },
+);
+
+__PACKAGE__->has_many( 'foos', 'ViewDeps::Result::Foo',
+    { 'foreign.id' => 'self.id' } );
+
+1;
diff --git a/t/lib/ViewDeps/Result/Baz.pm b/t/lib/ViewDeps/Result/Baz.pm
new file mode 100644 (file)
index 0000000..db80ab2
--- /dev/null
@@ -0,0 +1,22 @@
+package    # hide from PAUSE
+    ViewDeps::Result::Baz;
+## Used in 105view_deps.t
+
+use strict;
+use warnings;
+use base qw(DBIx::Class::Core);
+
+__PACKAGE__->table('baz');
+
+__PACKAGE__->add_columns( id => { data_type => 'integer' } );
+
+__PACKAGE__->belongs_to(
+    'table',
+    'ViewDeps::Result::JustATable',
+    { 'foreign.id' => 'self.b' },
+);
+
+__PACKAGE__->has_many( 'foos', 'ViewDeps::Result::Foo',
+    { 'foreign.a' => 'self.id' } );
+
+1;
diff --git a/t/lib/ViewDeps/Result/Foo.pm b/t/lib/ViewDeps/Result/Foo.pm
new file mode 100644 (file)
index 0000000..07f7c90
--- /dev/null
@@ -0,0 +1,24 @@
+package    # hide from PAUSE
+    ViewDeps::Result::Foo;
+
+use strict;
+use warnings;
+use base qw(ViewDeps::Result::Quux);
+
+__PACKAGE__->table_class('DBIx::Class::ResultSource::View');
+__PACKAGE__->table('foo');
+
+__PACKAGE__->result_source_instance->view_definition(
+    "select * from just_a_table");
+
+__PACKAGE__->add_columns(
+    id => { data_type => 'integer', is_auto_increment => 1 },
+    a  => { data_type => 'integer', is_nullable       => 1 }
+);
+
+__PACKAGE__->set_primary_key('id');
+
+__PACKAGE__->belongs_to( 'bar', 'ViewDeps::Result::Bar',
+    { 'foreign.id' => 'self.a' } );
+
+1;
diff --git a/t/lib/ViewDeps/Result/JustATable.pm b/t/lib/ViewDeps/Result/JustATable.pm
new file mode 100644 (file)
index 0000000..7281b17
--- /dev/null
@@ -0,0 +1,19 @@
+package    # hide from PAUSE
+    ViewDeps::Result::JustATable;
+## Used in 105view_deps.t
+
+use base qw(DBIx::Class::Core);
+
+__PACKAGE__->table('just_a_table');
+
+__PACKAGE__->add_columns(
+    id   => { data_type => 'integer', is_auto_increment => 1 },
+    name => { data_type => 'varchar', size              => 255 }
+);
+
+__PACKAGE__->set_primary_key('id');
+
+__PACKAGE__->has_many( 'bars', 'ViewDeps::Result::Bar',
+    { 'foreign.b' => 'self.id' } );
+
+1;
diff --git a/t/lib/ViewDeps/Result/Mixin.pm b/t/lib/ViewDeps/Result/Mixin.pm
new file mode 100644 (file)
index 0000000..b45dd94
--- /dev/null
@@ -0,0 +1,20 @@
+package # hide from PAUSE
+    ViewDeps::Result::Mixin;
+## Used in 105view_deps.t
+
+use strict;
+use warnings;
+use base qw(DBIx::Class::Core);
+
+__PACKAGE__->table('mixin');
+
+__PACKAGE__->add_columns(
+  id => {
+    data_type => 'integer', is_auto_increment => 1, sequence => 'foo_id_seq'
+  },
+  words => { data_type => 'text' }
+);
+
+__PACKAGE__->set_primary_key('id');
+
+1;
diff --git a/t/lib/ViewDeps/Result/Quux.pm b/t/lib/ViewDeps/Result/Quux.pm
new file mode 100644 (file)
index 0000000..77862f6
--- /dev/null
@@ -0,0 +1,24 @@
+package    # hide from PAUSE
+    ViewDeps::Result::Quux;
+
+use strict;
+use warnings;
+use base qw(DBIx::Class::Core);
+
+__PACKAGE__->table_class('DBIx::Class::ResultSource::View');
+__PACKAGE__->table('quux');
+
+__PACKAGE__->result_source_instance->view_definition(
+    "select * from quux");
+
+__PACKAGE__->add_columns(
+    etc => { data_type => 'text' },
+    c  => { data_type => 'integer', is_nullable => 1 }
+);
+
+__PACKAGE__->set_primary_key('c');
+
+__PACKAGE__->belongs_to( 'foo', 'ViewDeps::Result::Foo',
+    { 'foreign.a' => 'self.c' } );
+
+1;