Author: spadkins
Date: Wed Sep  1 09:40:16 2010
New Revision: 14366

Modified:
   p5ee/trunk/App-Repository/CHANGES
   p5ee/trunk/App-Repository/lib/App/Repository.pm
   p5ee/trunk/App-Repository/lib/App/Repository/DBI.pm
   p5ee/trunk/App-Repository/t/DBI-insert.t
   p5ee/trunk/App-Repository/t/DBI-select-join.t

Log:
add summary table support

Modified: p5ee/trunk/App-Repository/CHANGES
==============================================================================
--- p5ee/trunk/App-Repository/CHANGES   (original)
+++ p5ee/trunk/App-Repository/CHANGES   Wed Sep  1 09:40:16 2010
@@ -2,6 +2,9 @@
 # CHANGE LOG
 #########################################
 
+0.968
+ x summary_tables are now implemented
+
 0.967
  x App::Repository::get_index()/get_unique_index(): now work for arrays as 
well as hashrefs
  x App::Repository::_load_table_metadata(): can load single-table metadata 
from external *.pl file

Modified: p5ee/trunk/App-Repository/lib/App/Repository.pm
==============================================================================
--- p5ee/trunk/App-Repository/lib/App/Repository.pm     (original)
+++ p5ee/trunk/App-Repository/lib/App/Repository.pm     Wed Sep  1 09:40:16 2010
@@ -621,11 +621,11 @@
             @$cols = @$columns;
         }
 
-        my $cache_skip = $context_options->{cache_skip};
-        $cache_skip = $options->{cache_skip} if (!defined $cache_skip);
-        my $tabledef = $self->{table}{$table};
+        my $cache_skip = $options->{cache_skip};
+        $cache_skip = $context_options->{cache_skip} if (!defined $cache_skip);
+        my $table_def = $self->{table}{$table};
         my ($sds, $hashkey, @cache_colidx_map);
-        if ($tabledef->{cache_name} && !$cache_skip) {
+        if ($table_def->{cache_name} && !$cache_skip) {
             my $cache_refresh = $context_options->{cache_refresh};
             $cache_refresh = $options->{cache_refresh} if (!defined 
$cache_refresh);
             my $cache_exception_on_miss = $options->{cache_exception_on_miss};
@@ -633,7 +633,7 @@
                 $options = { %$options };
                 delete $options->{cache_exception_on_miss};
             }
-            my $cache_minimum_columns = $tabledef->{cache_minimum_columns};
+            my $cache_minimum_columns = $table_def->{cache_minimum_columns};
             if ($cache_minimum_columns) {
                 my (%colidx, $col);
                 my $cache_columns = [ @$cache_minimum_columns ];
@@ -653,7 +653,7 @@
                 }
                 $cols = $cache_columns;
             }
-            $sds = $context->shared_datastore($tabledef->{cache_name});
+            $sds = $context->shared_datastore($table_def->{cache_name});
             my ($hash_options);
             if (defined $options) {
                 $hash_options = { %$options };
@@ -724,7 +724,7 @@
                 $context->log("Cache Save:  $table $hashkey (get_row)\n") if 
($log_cache);
             }
         }
-        if ($sds && $tabledef->{cache_minimum_columns} && $row) {
+        if ($sds && $table_def->{cache_minimum_columns} && $row) {
             $row = [ @{$ro...@cache_colidx_map] ];
         }
     }
@@ -942,12 +942,12 @@
             @$cols = @$columns;
         }
 
-        my $cache_skip = $context_options->{cache_skip};
-        $cache_skip = $options->{cache_skip} if (!defined $cache_skip);
+        my $cache_skip = $options->{cache_skip};
+        $cache_skip = $context_options->{cache_skip} if (!defined $cache_skip);
 
-        my $tabledef = $self->{table}{$table};
+        my $table_def = $self->{table}{$table};
         my ($sds, $hashkey, @cache_colidx_map);
-        if ($tabledef->{cache_name} && !$cache_skip) {
+        if ($table_def->{cache_name} && !$cache_skip) {
             my $cache_refresh = $context_options->{cache_refresh};
             $cache_refresh = $options->{cache_refresh} if (!defined 
$cache_refresh);
             my $cache_exception_on_miss = $options->{cache_exception_on_miss};
@@ -955,7 +955,7 @@
                 $options = { %$options };
                 delete $options->{cache_exception_on_miss};
             }
-            my $cache_minimum_columns = $tabledef->{cache_minimum_columns};
+            my $cache_minimum_columns = $table_def->{cache_minimum_columns};
             if ($cache_minimum_columns) {
                 my (%colidx, $col);
                 my $cache_columns = [ @$cache_minimum_columns ];
@@ -973,7 +973,7 @@
                 }
                 $cols = $cache_columns;
             }
-            $sds = $context->shared_datastore($tabledef->{cache_name});
+            $sds = $context->shared_datastore($table_def->{cache_name});
             my ($hash_options);
             if (defined $options) {
                 $hash_options = { %$options };
@@ -1039,31 +1039,74 @@
                 $cols = $new_cols;        # then point to the new columns 
regardless
             }
 
-            my ($summary_table, $summary_column_defs, 
$summary_repository_name);
-            #my $summary_tables = $table_def->{summary_tables};
-            #if ($summary_tables) {
-            #    foreach my $summary_table_spec (@$summary_tables) {
-            #        ($summary_table, $summary_column_defs, 
$summary_repository_name) = @$summary_table_spec;   # assume this summary will 
work
-            #        foreach $col (@$cols) {
-            #            if (!$column_defs->{$col}{expr} && 
!$summary_columns_defs->{$col}) {   # the column doesn't exist on the summary 
table
-            #                $summary_table = undef;                           
                 # so the summary won't work
-            #                last;
-            #            }
-            #        }
-            #        last if ($summary_table);
-            #    }
-            #}
+            my ($summary_table, $summary_table_def, $summary_column_defs, 
$summary_repository_name);
+            my $summary_tables = $table_def->{summary_tables};
+
+            my $summary_skip = $options->{summary_skip};
+            $summary_skip = $context_options->{summary_skip} if (!defined 
$summary_skip);
+
+            if ($summary_tables && !$summary_skip) {
+                die "{summary_tables} must be an array ref in table [$table] 
definition" if (ref($summary_tables) ne "ARRAY");
+                foreach my $summary_table_spec (@$summary_tables) {
+                    ($summary_table, $summary_column_defs, 
$summary_repository_name) = @$summary_table_spec;   # assume this summary will 
work
+                    #print STDERR "get_rows($table) : checking 
summary_table=[$summary_table]\n";
+                    if (!$summary_column_defs) {
+                        if ($summary_repository_name) {
+                            my $rep = 
$context->repository($summary_repository_name);
+                            $summary_table_def = 
$rep->get_table_def($summary_table);
+                            $summary_column_defs = 
$summary_table_def->{column};
+                        }
+                        else {
+                            $summary_table_def = 
$self->get_table_def($summary_table);
+                            $summary_column_defs = 
$summary_table_def->{column};
+                        }
+                    }
+                    foreach $col (@$cols) {
+                        #print STDERR "get_rows($table) : checking 
summary_table=[$summary_table] : column=[$col]\n";
+                        if (!$column_defs->{$col}{expr} && 
!$summary_column_defs->{$col}) {   # the column doesn't exist on the summary 
table
+                            #print STDERR "get_rows($table) : checking 
summary_table=[$summary_table] : column=[$col] : Not defined\n";
+                            #print STDERR "get_rows($table) : 
summary_columns=[", join(",", keys %$summary_column_defs), "]\n";
+                            $summary_table = undef;                            
               # so the summary won't work
+                            last;
+                        }
+                    }
+                    last if ($summary_table);
+                }
+            }
     
             if ($summary_table) {
-                if ($summary_repository_name) {
-                    my $rep = $context->repository($summary_repository_name);
-                    $rows = $rep->get_rows($summary_table, $params, $cols, 
$options);
+                my $summary_ready = $self->_is_summary_ready($summary_table, 
$params);
+                if (!defined $summary_ready || $summary_ready) {
+                    if ($summary_repository_name) {
+                        my $rep = 
$context->repository($summary_repository_name);
+                        $rows = $rep->get_rows($summary_table, $params, $cols, 
$options);
+                    }
+                    else {
+                        $rows = $self->get_rows($summary_table, $params, 
$cols, $options);
+                    }
+                    if (!defined $summary_ready) {   # We weren't sure if the 
summary was ready, so we check the resulting rows.
+                        if ($#$rows == -1) {         # There were no summary 
rows. The summary must not have been ready.
+                            $summary_table = undef;  # We fall back to 
querying the detail table.
+                        }
+                        elsif ($#$rows == 0) {       # There is 1 summary row. 
Let's check to see if it is full of NULL's exclusively.
+                            my $row = $rows->[0];
+                            my $all_nulls = 1;
+                            foreach my $value (@$row) {
+                                if (defined $value) {
+                                    $all_nulls = 0;
+                                    last;
+                                }
+                            }
+                            $summary_table = undef if ($all_nulls);   # The 
summary is not ready. We fall back to querying the detail table.
+                        }
+                    }
                 }
                 else {
-                    $rows = $self->get_rows($summary_table, $params, $cols, 
$options);
+                    # The summary is not ready. We fall back to querying the 
detail table.
+                    $summary_table = undef if ($#$rows == -1);  # got no rows
                 }
-                $summary_table = undef if ($#$rows == -1);  # got no rows
             }
+
             if (!$summary_table) {
                 $rows = $self->_get_rows($table, $params, $cols, $options);
             }
@@ -1078,7 +1121,7 @@
             }
         }
 
-        if ($sds && $tabledef->{cache_minimum_columns}) {
+        if ($sds && $table_def->{cache_minimum_columns}) {
             my $requested_rows = [];
             foreach my $row (@$rows) {
                 push(@$requested_rows, [ @{$ro...@cache_colidx_map] ]);
@@ -1090,6 +1133,15 @@
     return($rows);
 }
 
+# This method exists so that it can be overridden in a subclass
+sub _is_summary_ready {
+    &App::sub_entry if ($App::trace);
+    my ($self, $summary_table, $params) = @_;
+    my $is_ready = undef;
+    &App::sub_exit($is_ready) if ($App::trace);
+    return($is_ready);
+}
+
 sub _get_default_columns {
     &App::sub_entry if ($App::trace);
     my ($self, $table) = @_;
@@ -2246,7 +2298,12 @@
     $self->_check_default_and_required_fields($object);
 
     $options = $options ? { %$options } : {};
-    $options->{last_inserted_id} = 1;
+    my $primary_key_auto_increment = $table_def->{primary_key_auto_increment};
+    $primary_key_auto_increment = 1 if (!defined $primary_key_auto_increment);
+
+    if ($primary_key_auto_increment) {
+        $options->{last_inserted_id} = 1;
+    }
     if ($options->{temp}) {
         my $constructor = ($class =~ /Moose/) ? "new" : undef; # TODO: I might 
want to make this more general/configurable
         if ($constructor) {
@@ -2263,11 +2320,12 @@
     else {
         my $retval = $self->insert_row($table, $object, undef, $options);
         die "new($table) unable to create a new row" if (!$retval);
-        my $params = $self->last_inserted_id($table);
+        my ($params);
+        $params = $self->last_inserted_id($table) if 
($primary_key_auto_increment);
         if (!$params) {
             $params = {};
             foreach my $col (keys %$object) {
-                $params->{$col . ".eq"} = $object->{$col};
+                $params->{$col . ".eq"} = $object->{$col} if ($col !~ /^_/);
             }
         }
         $object = $self->get_object($table, $params, undef, $options);
@@ -4369,6 +4427,74 @@
     # load up all additional information from the native metadata
     $self->_load_table_metadata_from_source($table);
 
+    if ($table_def->{overlay_from_table}) {
+        #print STDERR "load_table_metadata($table) : 
OVERLAY=[$table_def->{overlay_from_table}]\n";
+
+        # overlay_from_table => "hotel_bkg_stay",
+        # overlay_sections => ["cache_name", "cache_minimum_columns", "alias", 
"tablealiases", "tablealias", "column", ],
+        # overlay_column_exceptions => 
["^(pos_|agent_|los|guests|loyalty_|rm_type_|rate_level)"],
+
+        my $overlay_from_table        = $table_def->{overlay_from_table};
+        my $overlay_sections          = $table_def->{overlay_sections} || 
["tablealiases", "tablealias", "column"];
+        my $overlay_columns           = $table_def->{overlay_columns};
+        my $overlay_column_exceptions = 
$table_def->{overlay_column_exceptions};
+
+        my $overlay_from_table_def = $self->get_table_def($overlay_from_table);
+        foreach my $section (@$overlay_sections) {
+            #print STDERR "load_table_metadata($table) : 
OVERLAY=[$table_def->{overlay_from_table}] : section=[$section]\n";
+            if ($section eq "column") {
+                #print STDERR "load_table_metadata($table) : columns=[", 
join(",", keys %{$table_def->{column}}), "]\n";
+                #print STDERR "load_table_metadata($table) : 
OVERLAY=[$table_def->{overlay_from_table}] : section=[$section] : 
cols=[$overlay_columns] !cols=[$overlay_column_exceptions]\n";
+                my @overlay_columns           = $overlay_columns ?
+                                                (ref($overlay_columns)         
  ? @$overlay_columns           : $overlay_columns) :
+                                                ();
+                my @overlay_column_exceptions = $overlay_column_exceptions ?
+                                                
(ref($overlay_column_exceptions) ? @$overlay_column_exceptions : 
$overlay_column_exceptions) :
+                                                ();
+                $table_def->{column} = {} if (!$table_def->{column});
+                COLUMN: foreach my $column (keys 
%{$overlay_from_table_def->{column}}) {
+                    if (!$table_def->{column}{$column}) {
+                        if ($overlay_columns) {
+                            foreach (@overlay_columns) {
+                                next COLUMN if ($column !~ /$_/);
+                            }
+                        }
+                        if ($overlay_column_exceptions) {
+                            foreach (@overlay_column_exceptions) {
+                                next COLUMN if ($column =~ /$_/);
+                            }
+                        }
+                        $table_def->{column}{$column} = 
$overlay_from_table_def->{column}{$column};
+                        #print STDERR "load_table_metadata($table) : 
OVERLAY=[$table_def->{overlay_from_table}] : section=[$section] : 
column=[$column]\n";
+                    }
+                }
+                #print STDERR "load_table_metadata($table) : columns=[", 
join(",", keys %{$table_def->{column}}), "]\n";
+            }
+            elsif ($section eq "tablealiases") {
+                if ($table_def->{$section}) {
+                    my (%array_element_seen);
+                    foreach my $value (@{$table_def->{$section}}) {
+                        $array_element_seen{$value} = 1;
+                    }
+                    foreach my $value (@{$overlay_from_table_def->{$section}}) 
{
+                        push(@{$table_def->{$section}}, $value) if 
(!$array_element_seen{$value});
+                    }
+                }
+                else {
+                    $table_def->{$section} = 
$overlay_from_table_def->{$section};
+                }
+            }
+            else {
+                if ($table_def->{$section}) {
+                    App::Reference->overlay($table_def->{$section}, 
$overlay_from_table_def->{$section});
+                }
+                else {
+                    $table_def->{$section} = 
$overlay_from_table_def->{$section};
+                }
+            }
+        }
+    }
+
     $columns = $table_def->{columns};
     if (! defined $columns) {
         $columns = [];

Modified: p5ee/trunk/App-Repository/lib/App/Repository/DBI.pm
==============================================================================
--- p5ee/trunk/App-Repository/lib/App/Repository/DBI.pm (original)
+++ p5ee/trunk/App-Repository/lib/App/Repository/DBI.pm Wed Sep  1 09:40:16 2010
@@ -3268,6 +3268,7 @@
             $table_def->{primary_key}   = 
$self->_get_primary_key_from_source($table)    if (!$table_def->{primary_key});
             $table_def->{alternate_key} = 
$self->_get_alternate_keys_from_source($table) if 
(!$table_def->{alternate_key});
         }
+        $table_def->{primary_key_auto_increment} = 
$self->_is_primary_key_auto_increment($table_def);
     }
 
     {
@@ -3502,6 +3503,25 @@
     return($alternate_keys);
 }
 
+sub _is_primary_key_auto_increment {
+    &App::sub_entry if ($App::trace);
+    my ($self, $table_def) = @_;
+    my $primary_key_auto_increment = 1;
+    my $primary_key = $table_def->{primary_key};
+    if (!$primary_key || $#$primary_key != 0) {
+        $primary_key_auto_increment = 0;
+    }
+    else {
+        my $pk_column = $primary_key->[0];
+        my $pk_column_type = $table_def->{column}{$pk_column}{type};
+        if (defined $pk_column_type && $pk_column_type ne "integer") {
+            $primary_key_auto_increment = 0;
+        }
+    }
+    &App::sub_exit($primary_key_auto_increment) if ($App::trace);
+    return($primary_key_auto_increment);
+}
+
 sub _column_metadata_specifiers {
     &App::sub_entry if ($App::trace);
     my ($self, $table) = @_;

Modified: p5ee/trunk/App-Repository/t/DBI-insert.t
==============================================================================
--- p5ee/trunk/App-Repository/t/DBI-insert.t    (original)
+++ p5ee/trunk/App-Repository/t/DBI-insert.t    Wed Sep  1 09:40:16 2010
@@ -256,12 +256,55 @@
 EOF
         $sql = $db->_mk_insert_rows_sql("test_person", ["person_id", 
"age","first_name","gender","state"], $dup_rows, { update => 1 });
         is($sql, $expect_sql, "_mk_insert_rows_sql(): 7 rows, bulk 
insert/update");
+
+        $expect_sql = <<EOF;
+insert into test_person
+  (person_id, age, first_name, gender, state)
+values
+  (1, 39, 'stephen', 'M', 'GA'),
+  (2, 37, 'susan', 'F', 'GA'),
+  (3, 6, 'maryalice', 'F', 'GA'),
+  (4, 3, 'paul', 'M', 'GA'),
+  (5, 1, 'christine', 'F', 'GA'),
+  (6, 45, 'tim', 'M', 'GA'),
+  (7, 39, 'keith', 'M', 'GA')
+on duplicate key update
+   age = values(age),
+   gender = values(gender),
+   state = values(state)
+EOF
+        $sql = $db->_mk_insert_rows_sql("test_person", ["person_id", 
"age","first_name","gender","state"], $dup_rows, { update => { age => 1, gender 
=> 1, state => 1} });
+        is($sql, $expect_sql, "_mk_insert_rows_sql(): 7 rows, bulk 
insert/update, with named columns");
+
+        $expect_sql = <<EOF;
+insert into test_person
+  (person_id, age, first_name, gender, state)
+values
+  (1, 39, 'stephen', 'M', 'GA'),
+  (2, 37, 'susan', 'F', 'GA'),
+  (3, 6, 'maryalice', 'F', 'GA'),
+  (4, 3, 'paul', 'M', 'GA'),
+  (5, 1, 'christine', 'F', 'GA'),
+  (6, 45, 'tim', 'M', 'GA'),
+  (7, 39, 'keith', 'M', 'GA')
+on duplicate key update
+   age = (case when values(gender) = 'F' then age-1 else values(age) end),
+   gender = values(gender),
+   state = values(state)
+EOF
+        $sql = $db->_mk_insert_rows_sql("test_person", ["person_id", 
"age","first_name","gender","state"], $dup_rows, { update => { age => "(case 
when values(gender) = 'F' then age-1 else values(age) end)", gender => 1, state 
=> 1} });
+        is($sql, $expect_sql, "_mk_insert_rows_sql(): 7 rows, bulk 
insert/update, with named columns and custom expressions");
+
         $nrows = $db->insert_rows("test_person", 
["age","first_name","gender","state"], $new_rows);
         is($nrows, 7, "insert_rows(): 7 rows, bulk insert");
         $nrows = $db->insert_rows("test_person", 
["person_id","age","first_name","gender","state"], $dup_rows, { replace => 1 });
         is($nrows, 7, "insert_rows(): 7 rows, bulk replace");
         $nrows = $db->insert_rows("test_person", ["person_id", 
"age","first_name","gender","state"], $dup_rows, { update => 1 });
         is($nrows, 7, "insert_rows(): 7 rows, bulk insert/update");
+        $nrows = $db->insert_rows("test_person", ["person_id", 
"age","first_name","gender","state"], $dup_rows, { update => { age => 1, gender 
=> 1, state => 1} });
+        is($nrows, 7, "insert_rows(): 7 rows, bulk insert/update w/ named 
columns");
+        $nrows = $db->insert_rows("test_person", ["person_id", 
"age","first_name","gender","state"], $dup_rows, { update => { age => "(case 
when values(gender) = 'F' then age-1 else values(age) end)", gender => 1, state 
=> 1} });
+        is($nrows, 7, "insert_rows(): 7 rows, bulk insert/update w/ named 
columns and custom expressions");
         $nrows = $db->insert_rows("test_person", 
["person_id","age","first_name","gender","state"], $dup_rows, { replace => 1, 
maxrows => 4 });
         is($nrows, 7, "insert_rows(): 7 rows, bulk replace (4 at a time)");
         $nrows = $db->insert_rows("test_person", ["person_id", 
"age","first_name","gender","state"], $dup_rows, { update => 1, maxrows => 4 });

Modified: p5ee/trunk/App-Repository/t/DBI-select-join.t
==============================================================================
--- p5ee/trunk/App-Repository/t/DBI-select-join.t       (original)
+++ p5ee/trunk/App-Repository/t/DBI-select-join.t       Wed Sep  1 09:40:16 2010
@@ -1622,9 +1622,9 @@
 &check_select($sql,0);
 
 
#################################################################################################
-# &drop_table($rep, "test_person");
-# &drop_table($rep, "test_country");
-# &drop_table($rep, "test_city");
-# &drop_table($rep, "test_hotel_prop");
-# &drop_table($rep, "test_hotel_bkg");
+&drop_table($rep, "test_person");
+&drop_table($rep, "test_country");
+&drop_table($rep, "test_city");
+&drop_table($rep, "test_hotel_prop");
+&drop_table($rep, "test_hotel_bkg");
 

Reply via email to