Add some subroutine docs. Must write another test so that I can understand all ins...
Amiri Barksdale at Home [Sun, 11 Apr 2010 18:57:15 +0000 (11:57 -0700)]
.gitignore
README
README.html
lib/DBIx/Class/ResultSource/MultipleTableInheritance.pm
t/01load.t
t/sql/MTITest-0.1-PostgreSQL.sql [moved from MTITest-0.1-PostgreSQL.sql with 98% similarity]

index 059b87d..be510cd 100644 (file)
@@ -1,2 +1,3 @@
 blib
 *.sw?
+*.tmp
diff --git a/README b/README
index 8f0d469..ff755e0 100644 (file)
--- a/README
+++ b/README
@@ -63,9 +63,9 @@ SYNOPSIS
 
     Inherit from this package and you can make a resultset class from a
     view, but that's more than a little bit misleading: the result is
-    writable and updateable--transparently.
+    transparently writable.
 
-    This is accomplished through the use of stored functions that map
+    This is accomplished through the use of stored procedures that map
     changes written to the view to changes to the underlying concrete
     tables.
 
@@ -96,7 +96,7 @@ WHY?
                 has password
         }
 
-        class Investor isa User {
+        class Investor extends User {
             has dollars
         }
 
@@ -152,8 +152,9 @@ WHY?
 
 HOW?
     There is a third strategy implemented here. Make the database do more of
-    the work. It'll save us some typing and it'll make for more expressive
-    code. What if we could do this:
+    the work: hide the nasty bits so we don't have to handle them unless we
+    really want to. It'll save us some typing and it'll make for more
+    expressive code. What if we could do this:
 
         my $new_investor = $schema->resultset('Investor')->create(
             name => $args->{name},
@@ -161,11 +162,16 @@ HOW?
             dollars => $args->{dollars},
         );
 
-    And have it Just Work? The user ( {name => $args->{name}, password =>
-    $args->{password} } ) should be created transparently, and the use of
-    either user or investor in your code should require no special handling.
-    Deleting and updating $new_investor should also delete or update the
-    user row.
+    And have it Just Work? The user...
+
+        {
+            name => $args->{name},
+            password => $args->{password},
+        }
+
+    should be created behind the scenes, and the use of either user or
+    investor in your code should require no special handling. Deleting and
+    updating $new_investor should also delete or update the user row.
 
     It does. User and investor are both views, their concrete tables
     abstracted away behind a set of rules and triggers. You would expect the
@@ -189,6 +195,51 @@ HOW?
         DELETE FROM _investor_table WHERE ("id" = ?);
         DELETE FROM _user_table WHERE ("id" = ?);
 
+METHODS
+    new MTI find the parents, if any, of your resultset class and adds them
+        to the list of parent_sources for the table.
+
+    add_additional_parents
+        Continuing with coffee:
+
+            __PACKAGE__->result_source_instance->add_additional_parents(
+                qw/
+                    MyApp::Schema::Result::Beverage
+                    MyApp::Schema::Result::Liquid
+                /
+            );
+
+        This just lets you manually add additional parents beyond the ones
+        MTI finds.
+
+    add_additional_parent
+            __PACKAGE__->result_source_instance->add_additional_parent(
+                    MyApp::Schema::Result::Beverage
+            );
+
+        You can also add just one.
+
+    attach_additional_sources
+        MTI takes the parents' sources and relationships, creates new
+        DBIx::Class:Table object from them, and registers this as a new,
+        raw, source in the schema, e.g.,
+
+            use MyApp::Schema;
+
+            print STDERR map { "$_\n" } MyApp::Schema->sources;
+
+            # Coffee 
+            # Beverage
+            # Liquid
+            # Sumatra
+            # Raw::Sumatra
+
+        Raw::Sumatra will be used to generate the view.
+
+    view_definition
+        This takes the raw table and generates the view (and stored
+        procedures) you will use.
+
 AUTHOR
     Matt S. Trout, <mst@shadowcatsystems.co.uk>
 
index a25e75b..6506fd7 100644 (file)
 
 <ul>
 
-       <li><a href="#name">NAME</a></li>
        <li><a href="#synopsis">SYNOPSIS</a></li>
        <li><a href="#why">WHY?</a></li>
        <li><a href="#how">HOW?</a></li>
+       <li><a href="#methods">METHODS</a></li>
        <li><a href="#author">AUTHOR</a></li>
        <ul>
 
 
 <p>
 </p>
-<hr />
-<h1><a name="name">NAME</a></h1>
-<p>DBIx::Class::ResultSource::MultipleTableInheritance -- Use multiple tables to define your classes</p>
-<p>
-</p>
-<hr />
 <h1><a name="synopsis">SYNOPSIS</a></h1>
 <pre>
     {
         $VAR1 = 'id';
         $VAR2 = 'flavor';
         $VAR3 = 'aroma';</pre>
-<p>Inherit from this package and you can make a resultset class from a view, but that's more than a little bit misleading: the result is <strong>writable</strong> and updateable--transparently.</p>
-<p>This is accomplished through the use of stored functions that map changes written to the view to changes to the underlying concrete tables.</p>
+<p>Inherit from this package and you can make a resultset class from a view, but that's more than a little bit misleading: the result is <strong>transparently writable</strong>.</p>
+<p>This is accomplished through the use of stored procedures that map changes written to the view to changes to the underlying concrete tables.</p>
 <p>
 </p>
 <hr />
             has password
     }</pre>
 <pre>
-    class Investor isa User {
+    class Investor extends User {
         has dollars
     }</pre>
 <p>Good idea, but how to put this into code?</p>
 </p>
 <hr />
 <h1><a name="how">HOW?</a></h1>
-<p>There is a third strategy implemented here. Make the database do more of the work. It'll save us some typing and it'll make for more expressive code. What if we could do this:</p>
+<p>There is a third strategy implemented here. Make the database do more of the work: hide the nasty bits so we don't have to handle them unless we really want to. It'll save us some typing and it'll make for more expressive code. What if we could do this:</p>
 <pre>
     my $new_investor = $schema-&gt;resultset('Investor')-&gt;create(
         name =&gt; $args-&gt;{name},
         dollars =&gt; $args-&gt;{dollars},
     );
     
-And have it Just Work? The user ( {name =&gt; $args-&gt;{name}, password =&gt; $args-&gt;{password} } ) should be created transparently, and the use of either user or investor in your code should require no special handling. Deleting and updating $new_investor should also delete or update the user row.</pre>
+And have it Just Work? The user...</pre>
+<pre>
+    {
+        name =&gt; $args-&gt;{name},
+        password =&gt; $args-&gt;{password},
+    }</pre>
+<p>should be created behind the scenes, and the use of either user or investor in your code should require no special handling. Deleting and updating $new_investor should also delete or update the user row.</p>
 <p>It does. User and investor are both views, their concrete tables abstracted away behind a set of rules and triggers. You would expect the above DBIC create statement to look like this in SQL:</p>
 <pre>
     INSERT INTO investor (&quot;name&quot;,&quot;password&quot;,&quot;dollars&quot;) VALUES (...);</pre>
@@ -201,7 +201,60 @@ And have it Just Work? The user ( {name =&gt; $args-&gt;{name}, password =&gt; $
 <pre>
     DELETE FROM _investor_table WHERE (&quot;id&quot; = ?);
     DELETE FROM _user_table WHERE (&quot;id&quot; = ?);</pre>
-<p></p>
+<p>
+</p>
+<hr />
+<h1><a name="methods">METHODS</a></h1>
+<dl>
+<dt><strong><a name="new" class="item">new</a></strong></dt>
+
+<dd>
+<p>MTI find the parents, if any, of your resultset class and adds them to the list of parent_sources for the table.</p>
+</dd>
+<dt><strong><a name="add_additional_parents" class="item">add_additional_parents</a></strong></dt>
+
+<dd>
+<p>Continuing with coffee:</p>
+<pre>
+    __PACKAGE__-&gt;result_source_instance-&gt;add_additional_parents(
+        qw/
+            MyApp::Schema::Result::Beverage
+            MyApp::Schema::Result::Liquid
+        /
+    );</pre>
+<p>This just lets you manually add additional parents beyond the ones MTI finds.</p>
+</dd>
+<dt><strong><a name="add_additional_parent" class="item">add_additional_parent</a></strong></dt>
+
+<dd>
+<pre>
+    __PACKAGE__-&gt;result_source_instance-&gt;add_additional_parent(
+            MyApp::Schema::Result::Beverage
+    );</pre>
+<p>You can also add just one.</p>
+</dd>
+<dt><strong><a name="attach_additional_sources" class="item">attach_additional_sources</a></strong></dt>
+
+<dd>
+<p>MTI takes the parents' sources and relationships, creates new DBIx::Class:Table object from them, and registers this as a new, raw, source in the schema, e.g.,</p>
+<pre>
+    use MyApp::Schema;</pre>
+<pre>
+    print STDERR map { &quot;$_\n&quot; } MyApp::Schema-&gt;sources;</pre>
+<pre>
+    # Coffee 
+    # Beverage
+    # Liquid
+    # Sumatra
+    # Raw::Sumatra</pre>
+<p>Raw::Sumatra will be used to generate the view.</p>
+</dd>
+<dt><strong><a name="view_definition" class="item">view_definition</a></strong></dt>
+
+<dd>
+<p>This takes the raw table and generates the view (and stored procedures) you will use.</p>
+</dd>
+</dl>
 <p>
 </p>
 <hr />
index a7cf799..f7468da 100644 (file)
@@ -15,6 +15,21 @@ our $VERSION = 0.01;
 
 __PACKAGE__->mk_group_accessors(simple => qw(parent_source additional_parents));
 
+# how this works:
+#
+# On construction, we hook $self->result_class->result_source_instance
+# if present to get the superclass' source object
+# 
+# When attached to a schema, we need to add sources to that schema with
+# appropriate relationships for the foreign keys so the concrete tables
+# get generated
+#
+# We also generate our own view definition using this class' concrete table
+# and the view for the superclass, and stored procedures for the insert,
+# update and delete operations on this view.
+#
+# deploying the postgres rules through SQLT may be a pain though.
+
 method new ($class: @args) {
   my $new = $class->next::method(@args);
   my $rc = $new->result_class;
@@ -410,31 +425,12 @@ method view_definition () {
 1;
 
 __END__
-
-# how this works:
-#
-# On construction, we hook $self->result_class->result_source_instance
-# if present to get the superclass' source object
-# 
-# When attached to a schema, we need to add sources to that schema with
-# appropriate relationships for the foreign keys so the concrete tables
-# get generated
-#
-# We also generate our own view definition using this class' concrete table
-# and the view for the superclass, and stored procedures for the insert,
-# update and delete operations on this view.
-#
-# deploying the postgres rules through SQLT may be a pain though.
-
-=encoding utf-8
-
 =head1 NAME
 
 DBIx::Class::ResultSource::MultipleTableInheritance -- Use multiple tables to define your classes 
 
 =head1 SYNOPSIS
 
-
     {
         package MyApp::Schema::Result::Coffee;
 
@@ -494,10 +490,10 @@ DBIx::Class::ResultSource::MultipleTableInheritance -- Use multiple tables to de
         $VAR3 = 'aroma';
 
 
+Inherit from this package and you can make a resultset class from a view, but that's more than a little bit misleading: the result is B<transparently writable>.
 
-Inherit from this package and you can make a resultset class from a view, but that's more than a little bit misleading: the result is B<transparentlt writable>.
+This is accomplished through the use of stored procedures that map changes written to the view to changes to the underlying concrete tables.
 
-This is accomplished through the use of stored functions that map changes written to the view to changes to the underlying concrete tables.
 
 =head1 WHY?
 
@@ -526,7 +522,7 @@ That's redundant. Hold on a sec...
             has password
     }
 
-    class Investor isa User {
+    class Investor extends User {
         has dollars
     }
 
@@ -574,9 +570,10 @@ So that investor's PK is just an FK to the user. We can clearly see the class hi
 
 One can cope well with the second strategy, and it seems to be the most popular smart choice.
 
+
 =head1 HOW?
 
-There is a third strategy implemented here. Make the database do more of the work. It'll save us some typing and it'll make for more expressive code. What if we could do this:
+There is a third strategy implemented here. Make the database do more of the work: hide the nasty bits so we don't have to handle them unless we really want to. It'll save us some typing and it'll make for more expressive code. What if we could do this:
 
     my $new_investor = $schema->resultset('Investor')->create(
         name => $args->{name},
@@ -584,7 +581,14 @@ There is a third strategy implemented here. Make the database do more of the wor
         dollars => $args->{dollars},
     );
     
-And have it Just Work? The user ( {name => $args->{name}, password => $args->{password} } ) should be created transparently, and the use of either user or investor in your code should require no special handling. Deleting and updating $new_investor should also delete or update the user row.
+And have it Just Work? The user...
+
+    {
+        name => $args->{name},
+        password => $args->{password},
+    }
+
+should be created behind the scenes, and the use of either user or investor in your code should require no special handling. Deleting and updating $new_investor should also delete or update the user row.
 
 It does. User and investor are both views, their concrete tables abstracted away behind a set of rules and triggers. You would expect the above DBIC create statement to look like this in SQL:
 
@@ -606,11 +610,59 @@ Becomes:
     DELETE FROM _user_table WHERE ("id" = ?);
 
 
-    
+=head1 METHODS
+
+=over
+
+=item new
+
+
+MTI find the parents, if any, of your resultset class and adds them to the list of parent_sources for the table.
+
+
+=item add_additional_parents
+
+
+Continuing with coffee:
+
+    __PACKAGE__->result_source_instance->add_additional_parents(
+        qw/
+            MyApp::Schema::Result::Beverage
+            MyApp::Schema::Result::Liquid
+        /
+    );
+
+This just lets you manually add additional parents beyond the ones MTI finds.
+
+=item add_additional_parent
+
+    __PACKAGE__->result_source_instance->add_additional_parent(
+            MyApp::Schema::Result::Beverage
+    );
+
+You can also add just one.
+
+=item attach_additional_sources
+
+MTI takes the parents' sources and relationships, creates new DBIx::Class:Table object from them, and registers this as a new, raw, source in the schema, e.g.,
+
+    use MyApp::Schema;
+
+    print STDERR map { "$_\n" } MyApp::Schema->sources;
+
+    # Coffee 
+    # Beverage
+    # Liquid
+    # Sumatra
+    # Raw::Sumatra
 
+Raw::Sumatra will be used to generate the view.
 
+=item view_definition
 
+This takes the raw table and generates the view (and stored procedures) you will use.
 
+=back
 
 =head1 AUTHOR
 
index 4d9d24c..10c4e2e 100644 (file)
@@ -31,8 +31,25 @@ is(
   'parent rel points to raw parent'
 );
 
-warn Dumper $raw_bar->_columns;
+my $foo = MTITest->source('Foo');
+my $bar = MTITest->source('Bar');
 
-warn Dumper $raw_bar->_relationships;
+is_deeply(
+  [ $foo->columns ],
+  [ qw(id a) ],
+  'Columns for mti foo are still the same: id a'
+);
+
+
+is_deeply(
+  [ $bar->columns ],
+  [ qw(id a words b) ],
+  'Columns for mti bar now contain those of foo and the mixin: id a words b'
+);
+
+
+#warn Dumper $raw_bar->_columns;
+
+#warn Dumper $raw_bar->_relationships;
 
-warn Dumper(MTITest->source('JustATable')->_relationships);
+#warn Dumper(MTITest->source('JustATable')->_relationships);
similarity index 98%
rename from MTITest-0.1-PostgreSQL.sql
rename to t/sql/MTITest-0.1-PostgreSQL.sql
index e7f13e2..05effce 100644 (file)
@@ -1,6 +1,6 @@
 -- 
 -- Created by SQL::Translator::Producer::PostgreSQL
--- Created on Sat Apr 10 11:29:16 2010
+-- Created on Sun Apr 11 11:56:23 2010
 -- 
 --
 -- Table: just_a_table