[Bio] / Sprout / ERDB.pm Repository:
ViewVC logotype

Diff of /Sprout/ERDB.pm

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.95, Wed Jan 23 00:56:31 2008 UTC revision 1.103, Tue Sep 16 18:57:59 2008 UTC
# Line 11  Line 11 
11      use Time::HiRes qw(gettimeofday);      use Time::HiRes qw(gettimeofday);
12      use Digest::MD5 qw(md5_base64);      use Digest::MD5 qw(md5_base64);
13      use CGI;      use CGI;
14  #    use WikiTools;  ## HACK      use WikiTools;
15    
16  =head1 Entity-Relationship Database Package  =head1 Entity-Relationship Database Package
17    
# Line 390  Line 390 
390                                    Entities => 'Entity',                                    Entities => 'Entity',
391                                    Fields => 'Field',                                    Fields => 'Field',
392                                    Indexes => 'Index',                                    Indexes => 'Index',
393                                    IndexFields => 'IndexField'                                    IndexFields => 'IndexField',
394                                      Issues => 'Issue',
395                                      Shapes => 'Shape'
396                                  },                                  },
397                    KeyAttr =>    { Relationship => 'name',                    KeyAttr =>    { Relationship => 'name',
398                                    Entity => 'name',                                    Entity => 'name',
399                                    Field => 'name'                                    Field => 'name',
400                                      Shape => 'name'
401                                  },                                  },
402                    SuppressEmpty => 1,                    SuppressEmpty => 1,
403                   );                   );
404    
405  my %XmlInOpts  = (  my %XmlInOpts  = (
406                    ForceArray => ['Field', 'Index', 'IndexField', 'Relationship', 'Entity'],                    ForceArray => [qw(Field Index IndexField Relationship Entity Shape)],
407                    ForceContent => 1,                    ForceContent => 1,
408                    NormalizeSpace => 2,                    NormalizeSpace => 2,
409                   );                   );
# Line 409  Line 412 
412                    XMLDecl => 1,                    XMLDecl => 1,
413                   );                   );
414    
   
415  =head2 Public Methods  =head2 Public Methods
416    
417  =head3 new  =head3 new
# Line 680  Line 682 
682      # Get the entity and relationship lists.      # Get the entity and relationship lists.
683      my $entityList = $metadata->{Entities};      my $entityList = $metadata->{Entities};
684      my $relationshipList = $metadata->{Relationships};      my $relationshipList = $metadata->{Relationships};
685        my $shapeList = $metadata->{Shapes};
686      # Start with the introductory text.      # Start with the introductory text.
687      push @retVal, WikiTools::Heading(2, "Introduction");      push @retVal, WikiTools::Heading(2, "Introduction");
688      if (my $notes = $metadata->{Notes}) {      if (my $notes = $metadata->{Notes}) {
689          push @retVal, WikiNote($notes->{content});          push @retVal, WikiNote($notes->{content});
690      }      }
691        # Generate issue list.
692        if (my $issues = $metadata->{Issues}) {
693            push @retVal, WikiTools::Heading(3, 'Issues');
694            push @retVal, WikiTools::List(map { $_->{content} } @{$issues});
695        }
696      # Start the entity section.      # Start the entity section.
697      push @retVal, WikiTools::Heading(2, "Entities");      push @retVal, WikiTools::Heading(2, "Entities");
698      # Loop through the entities. Note that unlike the situation with HTML, we      # Loop through the entities. Note that unlike the situation with HTML, we
# Line 696  Line 704 
704          # Get the entity data.          # Get the entity data.
705          my $entityData = $entityList->{$key};          my $entityData = $entityList->{$key};
706          # Plant the notes here, if there are any.          # Plant the notes here, if there are any.
707          if (my $notes = $entityData->{Notes}) {          push @retVal, _ObjectNotes($entityData);
             push @retVal, "", WikiNote($notes->{content});  
         }  
         # Get the entity's relations.  
         my $relationList = $entityData->{Relations};  
         # Loop through the relations, displaying them.  
         for my $relation (sort keys %{$relationList}) {  
             my $wikiString = _WikiRelationTable($relation, $relationList->{$relation});  
             push @retVal, $wikiString;  
         }  
708          # Now we list the entity's relationships (if any). First, we build a list          # Now we list the entity's relationships (if any). First, we build a list
709          # of the relationships relevant to this entity.          # of the relationships relevant to this entity.
710          my @rels = ();          my @rels = ();
# Line 722  Line 721 
721          }          }
722          # Add the relationships as a Wiki list.          # Add the relationships as a Wiki list.
723          push @retVal, WikiTools::List(@rels);          push @retVal, WikiTools::List(@rels);
724            # Get the entity's relations.
725            my $relationList = $entityData->{Relations};
726            # Loop through the relations, displaying them.
727            for my $relation (sort keys %{$relationList}) {
728                my $wikiString = _WikiRelationTable($relation, $relationList->{$relation});
729                push @retVal, $wikiString;
730            }
731      }      }
732      # Now the entities are documented. Next we do the relationships.      # Now the entities are documented. Next we do the relationships.
733      push @retVal, WikiTools::Heading(2, "Relationships");      push @retVal, WikiTools::Heading(2, "Relationships");
# Line 741  Line 747 
747          if ($arity eq "11") {          if ($arity eq "11") {
748              push @listElements, "Each $boldCode$fromEntity$boldCode relates to at most one $boldCode$toEntity$boldCode.";              push @listElements, "Each $boldCode$fromEntity$boldCode relates to at most one $boldCode$toEntity$boldCode.";
749          } else {          } else {
750              push @listElements, "Each $boldCode$fromEntity$boldCode relates to multiple $boldCode${toEntity}s$boldCode.\n";              push @listElements, "Each $boldCode$fromEntity$boldCode relates to multiple $boldCode${toEntity}s$boldCode.";
751              if ($arity eq "MM" && $fromEntity ne $toEntity) {              if ($arity eq "MM" && $fromEntity ne $toEntity) {
752                  push @listElements, "Each $boldCode$toEntity$boldCode relates to multiple $boldCode${fromEntity}s$boldCode.\n";                  push @listElements, "Each $boldCode$toEntity$boldCode relates to multiple $boldCode${fromEntity}s$boldCode.";
753              }              }
754          }          }
755          push @retVal, WikiTools::List(@listElements);          push @retVal, WikiTools::List(@listElements);
756          # Plant the notes here, if there are any.          # Plant the notes here, if there are any.
757          if (my $notes = $relationshipData->{Notes}) {          push @retVal, _ObjectNotes($relationshipData);
             push @retVal, "", WikiNote($notes->{content});  
         }  
758          # Finally, the relationship table.          # Finally, the relationship table.
759          my $wikiString = _WikiRelationTable($key, $relationshipData->{Relations}->{$key});          my $wikiString = _WikiRelationTable($key, $relationshipData->{Relations}->{$key});
760          push @retVal, $wikiString;          push @retVal, $wikiString;
761      }      }
762        # Now loop through the miscellaneous shapes.
763        if ($shapeList) {
764            push @retVal, WikiTools::Heading(2, "Miscellaneous");
765            for my $shape (sort keys %$shapeList) {
766                push @retVal, WikiTools::Heading(3, $shape);
767                my $shapeData = $shapeList->{$shape};
768                push @retVal, _ObjectNotes($shapeData);
769            }
770        }
771      # All done. Return the lines.      # All done. Return the lines.
772      return @retVal;      return @retVal;
773  }  }
# Line 1049  Line 1062 
1062          # Push the result into the field list.          # Push the result into the field list.
1063          push @fieldList, $fieldString;          push @fieldList, $fieldString;
1064      }      }
     # If this is a root table, add the "new_record" flag. It defaults to 0, so  
     if ($rootFlag) {  
         push @fieldList, "new_record $TypeTable{boolean}->{sqlType} NOT NULL DEFAULT 0";  
     }  
1065      # Convert the field list into a comma-delimited string.      # Convert the field list into a comma-delimited string.
1066      my $fieldThing = join(', ', @fieldList);      my $fieldThing = join(', ', @fieldList);
1067      # Insure the table is not already there.      # Insure the table is not already there.
# Line 1519  Line 1528 
1528      return sort keys %{$entityList};      return sort keys %{$entityList};
1529  }  }
1530    
1531    
1532    =head3 GetConnectingRelationships
1533    
1534        my @list = $erdb->GetConnectingRelationships($entityName);
1535    
1536    Return a list of the relationships connected to the specified entity.
1537    
1538    =over 4
1539    
1540    =item entityName
1541    
1542    Entity whose connected relationships are desired.
1543    
1544    =item RETURN
1545    
1546    Returns a list of the relationships that originate from the entity.
1547    If the entity is on the from end, it will return the relationship
1548    name. If the entity is on the to end it will return the converse of
1549    the relationship name.
1550    
1551    =back
1552    
1553    =cut
1554    
1555    sub GetConnectingRelationships {
1556        # Get the parameters.
1557        my ($self, $entityName) = @_;
1558        # Declare the return variable.
1559        my @retVal;
1560        # Get the relationship list.
1561        my $relationships = $self->{_metaData}->{Relationships};
1562        # Find the entity.
1563        my $entity = $self->{_metaData}->{Entities}->{$entityName};
1564        # Only proceed if the entity exists.
1565        if (! defined $entity) {
1566            Trace("Entity $entityName not found.") if T(3);
1567        } else {
1568            # Loop through the relationships.
1569            my @rels = keys %$relationships;
1570            Trace(scalar(@rels) . " relationships found in connection search.") if T(3);
1571            for my $relationshipName (@rels) {
1572                my $relationship = $relationships->{$relationshipName};
1573                if ($relationship->{from} eq $entityName) {
1574                    # Here we have a forward relationship.
1575                    push @retVal, $relationshipName;
1576                } elsif ($relationship->{to} eq $entityName) {
1577                    # Here we have a backward relationship. In this case, the
1578                    # converse relationship name is preferred if it exists.
1579                    my $converse = $relationship->{converse} || $relationshipName;
1580                    push @retVal, $converse;
1581                }
1582            }
1583        }
1584        # Return the result.
1585        return @retVal;
1586    }
1587    
1588    
1589  =head3 GetDataTypes  =head3 GetDataTypes
1590    
1591      my %types = ERDB::GetDataTypes();      my %types = ERDB::GetDataTypes();
# Line 2303  Line 2370 
2370      }      }
2371      # Now we parse the key names into sort parameters. First, we prime the return      # Now we parse the key names into sort parameters. First, we prime the return
2372      # string.      # string.
2373      my $retVal = "sort -t\"\t\" ";      my $retVal = "sort -S 1G -T\"$FIG_Config::temp\" -t\"\t\" ";
2374      # Get the relation's field list.      # Get the relation's field list.
2375      my @fields = @{$relationData->{Fields}};      my @fields = @{$relationData->{Fields}};
2376      # Loop through the keys.      # Loop through the keys.
# Line 2333  Line 2400 
2400                  # will stop the inner loop. Note that the field number is                  # will stop the inner loop. Note that the field number is
2401                  # 1-based in the sort command, so we have to increment the                  # 1-based in the sort command, so we have to increment the
2402                  # index.                  # index.
2403                  $fieldSpec = ($i + 1) . $modifier;                  my $realI = $i + 1;
2404                    $fieldSpec = "$realI,$realI$modifier";
2405              }              }
2406          }          }
2407          # Add this field to the sort command.          # Add this field to the sort command.
# Line 2724  Line 2792 
2792                  push @missing, $fieldName;                  push @missing, $fieldName;
2793              }              }
2794          }          }
         # If we are the primary relation, add the new-record flag.  
         if ($relationName eq $newObjectType) {  
             push @valueList, 1;  
             push @fieldNameList, "new_record";  
         }  
2795          # Only proceed if there are no missing fields.          # Only proceed if there are no missing fields.
2796          if (@missing > 0) {          if (@missing > 0) {
2797              Trace("Relation $relationName for $newObjectType skipped due to missing fields: " .              Trace("Relation $relationName for $newObjectType skipped due to missing fields: " .
# Line 2933  Line 2996 
2996          $retVal->Add("tables");          $retVal->Add("tables");
2997          my $size = -s $fileName;          my $size = -s $fileName;
2998          Trace("$size bytes loaded into $relationName.") if T(2);          Trace("$size bytes loaded into $relationName.") if T(2);
2999            $retVal->Add("bytes", $size);
3000          # If we're rebuilding, we need to create the table indexes.          # If we're rebuilding, we need to create the table indexes.
3001          if ($options{truncate}) {          if ($options{truncate}) {
3002              # Indexes are created here for PostGres. For PostGres, indexes are              # Indexes are created here for PostGres. For PostGres, indexes are
# Line 2957  Line 3021 
3021      # Analyze the table to improve performance.      # Analyze the table to improve performance.
3022      if (! $options{partial}) {      if (! $options{partial}) {
3023          Trace("Analyzing and compacting $relationName.") if T(3);          Trace("Analyzing and compacting $relationName.") if T(3);
3024          $dbh->vacuum_it($relationName);          $self->Analyze($relationName);
3025      }      }
3026      Trace("$relationName load completed.") if T(3);      Trace("$relationName load completed.") if T(3);
3027      # Return the statistics.      # Return the statistics.
3028      return $retVal;      return $retVal;
3029  }  }
3030    
3031    =head3 Analyze
3032    
3033        $erdb->Analyze($tableName);
3034    
3035    Analyze and compact a table in the database. This is useful after a load
3036    to improve the performance of the indexes.
3037    
3038    =over 4
3039    
3040    =item tableName
3041    
3042    Name of the table to be analyzed and compacted.
3043    
3044    =back
3045    
3046    =cut
3047    
3048    sub Analyze {
3049        # Get the parameters.
3050        my ($self, $tableName) = @_;
3051        # Analyze the table.
3052        $self->{_dbh}->vacuum_it($tableName);
3053    }
3054    
3055    =head3 TruncateTable
3056    
3057        $erdb->TruncateTable($table);
3058    
3059    Delete all rows from a table quickly. This uses the built-in SQL
3060    C<TRUNCATE> statement, which effectively drops and re-creates a table
3061    with all its settings intact.
3062    
3063    =over 4
3064    
3065    =item table
3066    
3067    Name of the table to be cleared.
3068    
3069    =back
3070    
3071    =cut
3072    
3073    sub TruncateTable {
3074        # Get the parameters.
3075        my ($self, $table) = @_;
3076        # Get the database handle.
3077        my $dbh = $self->{_dbh};
3078        # Execute a truncation comment.
3079        $dbh->SQL("TRUNCATE TABLE $table");
3080    }
3081    
3082    
3083  =head3 CreateSearchIndex  =head3 CreateSearchIndex
3084    
3085      $erdb->CreateSearchIndex($objectName);      $erdb->CreateSearchIndex($objectName);
# Line 3144  Line 3260 
3260      my $query = $self->Get([$entityType], "$entityType(id) = ?", [$ID]);      my $query = $self->Get([$entityType], "$entityType(id) = ?", [$ID]);
3261      # Get the first (and only) object.      # Get the first (and only) object.
3262      my $retVal = $query->Fetch();      my $retVal = $query->Fetch();
3263        if (T(3)) {
3264            if ($retVal) {
3265                Trace("Entity $entityType \"$ID\" found.");
3266            } else {
3267                Trace("Entity $entityType \"$ID\" not found.");
3268            }
3269        }
3270      # Return the result.      # Return the result.
3271      return $retVal;      return $retVal;
3272  }  }
# Line 3336  Line 3459 
3459          push @retVal, \@rowData;          push @retVal, \@rowData;
3460          $fetched++;          $fetched++;
3461      }      }
     Trace("$fetched rows returned in GetAll.") if T(SQL => 4);  
3462      # Return the resulting list.      # Return the resulting list.
3463      return @retVal;      return @retVal;
3464  }  }
# Line 5430  Line 5552 
5552      return $retVal;      return $retVal;
5553  }  }
5554    
5555  =head2 HTML Documentation Utility Methods  =head2 Documentation Utility Methods
5556    
5557  =head3 _ComputeRelationshipSentence  =head3 _ComputeRelationshipSentence
5558    
# Line 5551  Line 5673 
5673          # Push this row onto the table list.          # Push this row onto the table list.
5674          push @rows, \@row;          push @rows, \@row;
5675      }      }
5676      # Store the rows as a Wiki table.      # Store the rows as a Wiki table with a level-4 heading.
5677      my $retVal = WikiTools::Table(@rows);      my $retVal = join("\n\n", WikiTools::Heading(4, "$relationName Table"),
5678                          WikiTools::Table(@rows));
5679      # Now we show the relation's indexes. These are formatted as another      # Now we show the relation's indexes. These are formatted as another
5680      # table.      # table.
5681      @rows = ();      @rows = ();
# Line 5583  Line 5706 
5706      $retVal .= "\n\n" . WikiTools::Table(@rows);      $retVal .= "\n\n" . WikiTools::Table(@rows);
5707  }  }
5708    
   
5709  =head3 _ShowRelationTable  =head3 _ShowRelationTable
5710    
5711  Generate the HTML string for a particular relation. The relation's data will be formatted as an HTML  Generate the HTML string for a particular relation. The relation's data will be formatted as an HTML
# Line 5757  Line 5879 
5879      return $htmlString;      return $htmlString;
5880  }  }
5881    
5882    =head3 _ObjectNotes
5883    
5884        my @noteParagraphs = _ObjectNotes($objectData);
5885    
5886    Return a list of the notes and asides for an entity or relationship in
5887    Wiki format.
5888    
5889    =over 4
5890    
5891    =item objectData
5892    
5893    The metadata for the desired entity or relationship.
5894    
5895    =item RETURN
5896    
5897    Returns a list of text paragraphs in Wiki markup form.
5898    
5899    =back
5900    
5901    =cut
5902    
5903    sub _ObjectNotes {
5904        # Get the parameters.
5905        my ($objectData) = @_;
5906        # Declare the return variable.
5907        my @retVal;
5908        # Loop through the types of notes.
5909        for my $noteType (qw(Notes Asides)) {
5910            my $text = $objectData->{$noteType};
5911            if ($text) {
5912                push @retVal, "", WikiNote($text->{content});
5913            }
5914        }
5915        # Return the result.
5916        return @retVal;
5917    }
5918    
5919  1;  1;

Legend:
Removed from v.1.95  
changed lines
  Added in v.1.103

MCS Webmaster
ViewVC Help
Powered by ViewVC 1.0.3