generate function bodies
Matt S Trout [Sun, 2 Aug 2009 00:08:30 +0000 (20:08 -0400)]
lib/DBIx/Class/ResultSource/MultipleTableInheritance.pm

index 8f5fe21..2c3fafe 100644 (file)
@@ -7,6 +7,7 @@ use Method::Signatures::Simple;
 use Carp::Clan qw/^DBIx::Class/;
 use aliased 'DBIx::Class::ResultSource::Table';
 use aliased 'DBIx::Class::ResultClass::HashRefInflator';
+use String::TT qw(strip tt);
 use namespace::autoclean;
 
 # how this works:
@@ -65,6 +66,7 @@ method _attach_additional_sources () {
         map $schema->source($_), $schema->sources;
     confess "Couldn't find attached source for parent $parent_name - did you use load_classes? This module is only compatible with load_namespaces"
       unless $parent;
+    $self->parent_source($parent); # so our parent is the one in this schema
   }
 
   # create the raw table source
@@ -107,7 +109,7 @@ method set_primary_key (@args) {
 
 method raw_source_name () {
   my $base = $self->source_name;
-  confess "Can't generate raw source name when we don't have a source_name"
+  confess "Can't generate raw source name for ${\$self->name} when we don't have a source_name"
     unless $base;
   return 'Raw::'.$base;
 }
@@ -147,14 +149,43 @@ BEGIN {
       $source->primary_columns;
   };
 
-  *names_of = sub (@cols) { map $_->{name}, @cols };
+  *name_of = *names_of = sub (@cols) { map $_->{name}, @cols };
 
-  *arglist = sub (@cols) {
-    map join(' ', @{$_}{qw(name data_type)}), @cols;
+  *function_body = sub ($name, $args, $body_parts) {
+    my $arglist = join(
+      ', ',
+        map '_'.join(' ', @{$_}{qw(name data_type)}),
+          @$args
+    );
+    my $body = join("\n", '', map "          $_;", @$body_parts);
+    return strip tt q{
+      CREATE OR REPLACE FUNCTION [% name %]
+        ([% arglist %])
+        RETURNS VOID AS $function$
+        BEGIN
+          [%- body %]
+        END;
+      $function$ LANGUAGE plpgsql;
+    };
   };
     
 }
 
+BEGIN {
+
+  use signatures;
+
+  *arg_hash = sub ($source) {
+    map +($_ => \(argify $_)), names_of body_cols $source;
+  };
+}
+
+method root_table () {
+  $self->parent_source
+    ? $self->parent_source->root_table
+    : $self->schema->source($self->raw_source_name)
+}
+
 method view_definition () {
   my $schema = $self->schema;
   confess "Can't generate view without connected schema, sorry"
@@ -178,8 +209,51 @@ method view_definition () {
          ])
       : ($table->name)),
     [ (qualify_with $table, names_of @pk_cols), names_of @body_cols ],
-  );
-  return $select;
+  ).';';
+  my ($now, $next) = grep defined, $super_view, $table;
+  # NOTE: this assumes a single PK col called id with a sequence somewhere
+  # but nothing else -should- so fixing this should make everything work
+  my $insert_func =
+    function_body
+      $self->name.'_insert',
+      \@body_cols,
+      [
+        $sqla->insert( # INSERT INTO _tbl (foo, ...) VALUES (_foo, ...)
+          $now->name,
+          { arg_hash $now },
+        ),
+        ($next
+          ? $sqla->insert( # INSERT INTO super_view (id, ...)
+                           #   VALUES (currval('_root_tbl_id_seq'), ...)
+              $next->name,
+              {
+                (arg_hash $next),
+                id => \"currval('${\$self->root_table->name}_id_seq')",
+              }
+            )
+          : ()
+        )
+      ];
+  # note - similar to arg_hash but not quite enough to share code sanely
+  my $pk_where = { # id = _id AND id2 = _id2 ...
+    map +($_ => \"= ${\argify $_}"), names_of @pk_cols
+  };
+  my $update_func =
+    function_body
+      $self->name.'_update',
+      [ @pk_cols, @body_cols ],
+      [ map $sqla->update(
+          $_->name, # UPDATE foo
+          { arg_hash $_ }, # SET a = _a
+          $pk_where,
+        ), @sources
+      ];
+  my $delete_func =
+    function_body
+      $self->name.'_delete',
+      [ @pk_cols ],
+      [ map $sqla->delete($_->name, $pk_where), @sources ];
+  return join("\n\n", $select, $insert_func, $update_func, $delete_func);
 }
 
 1;