Browse Source

Merged in 6.x-0.4-dev

Lacey Sanderson 13 years ago
parent
commit
fbd8c088b8

+ 207 - 66
tripal_core/mviews.php

@@ -11,7 +11,11 @@
  */
 
 /**
- * Add a materialized view to the chado database to help speed data access.
+ * Add a materialized view to the chado database to help speed data access. This
+ * function supports the older style where postgres column specifications 
+ * are provided using the $mv_table, $mv_specs and $indexed variables. It also
+ * supports the newer preferred method where the materialized view is described
+ * using the Drupal Schema API array.  
  *
  * @param $name 
  *   The name of the materialized view.
@@ -26,22 +30,36 @@
  * @param $query 
  *   The SQL query that loads the materialized view with data
  * @param $special_index  
- *   function
+ *   currently not used
+ * @param $comment
+ *   A string containing a description of the materialized view
+ * @param $mv_schema
+ *   If using the newer Schema API array to define the materialized view then
+ *   this variable should contain the array.
  *
  * @ingroup tripal_mviews_api
  */
-function tripal_add_mview ($name,$modulename,$mv_table,$mv_specs,$indexed,$query,$special_index,$comment=NULL){
+function tripal_add_mview ($name, $modulename, $mv_table, $mv_specs, $indexed,
+   $query, $special_index, $comment=NULL, $mv_schema=NULL)
+{
+   // get the table name from the schema array
+   $schema_arr = array();
+   if($mv_schema){
+      // get the schema from the mv_specs and use it to add the custom table
+      eval("\$schema_arr = $mv_schema;");
+      $mv_table = $schema_arr['table'];
+   }
 
    $record = new stdClass();
    $record->name = $name;
    $record->modulename = $modulename;
-   $record->mv_schema = 'DUMMY';
    $record->mv_table = $mv_table;
    $record->mv_specs = $mv_specs;
    $record->indexed = $indexed;
    $record->query = $query;
    $record->special_index = $special_index;
    $record->comment = $comment;
+   $record->mv_schema = $mv_schema;
 
    // add the record to the tripal_mviews table and if successful
    // create the new materialized view in the chado schema
@@ -67,24 +85,34 @@ function tripal_add_mview ($name,$modulename,$mv_table,$mv_specs,$indexed,$query
         }
       }
 
-      // add the table to the database
-      $sql = "CREATE TABLE {$mv_table} ($mv_specs); $index"; 
-      $previous_db = tripal_db_set_active('chado');  // use chado database
-      $results = db_query($sql);
-      tripal_db_set_active($previous_db);  // now use drupal database
-      if($results){
-         drupal_set_message(t("View '$name' created"));
+      // create the table differently depending on if it the traditional method
+      // or the Drupal Schema API method
+      if($mv_schema){
+         if(!tripal_create_chado_table ($ret,$mv_table,$schema_arr)){
+            drupal_set_message("Could not create the materialized view. Check Drupal error report logs.");
+         } else {
+            drupal_set_message(t("View '$name' created"));
+         }
       } else {
-         // if we failed to create the view in chado then
-         // remove the record from the tripal_jobs table
-         $sql = "DELETE FROM {tripal_mviews} ".
-                "WHERE mview_id = $record->mview_id";
-         db_query($sql);
+         // add the table to the database
+         $sql = "CREATE TABLE {$mv_table} ($mv_specs); $index"; 
+         $previous_db = tripal_db_set_active('chado');  // use chado database
+         $results = db_query($sql);
+         tripal_db_set_active($previous_db);  // now use drupal database
+         if($results){
+            drupal_set_message(t("View '$name' created"));
+         } else {
+            drupal_set_message(t("Failed to create the materialized view table: '$mv_table'"));
+         }
       }
    }
 }
 /**
- * Edits a materialized view to the chado database to help speed data access.
+ * Edits a materialized view to the chado database to help speed data access.This
+ * function supports the older style where postgres column specifications 
+ * are provided using the $mv_table, $mv_specs and $indexed variables. It also
+ * supports the newer preferred method where the materialized view is described
+ * using the Drupal Schema API array.  
  *
  * @param $mview_id 
  *   The mview_id of the materialized view to edit
@@ -101,17 +129,32 @@ function tripal_add_mview ($name,$modulename,$mv_table,$mv_specs,$indexed,$query
  * @param $query 
  *   The SQL query that loads the materialized view with data
  * @param $special_index  
- *   function
+ *   currently not used
+ * @param $comment
+ *   A string containing a description of the materialized view
+ * @param $mv_schema
+ *   If using the newer Schema API array to define the materialized view then
+ *   this variable should contain the array.
  *
  * @ingroup tripal_mviews_api
  */
-function tripal_edit_mview ($mview_id,$name,$modulename,$mv_table,$mv_specs,$indexed,$query,$special_index,$comment){
+function tripal_edit_mview ($mview_id,$name,$modulename,$mv_table,$mv_specs,
+   $indexed,$query,$special_index,$comment=NULL,$mv_schema=NULL)
+{
+
+   // get the table name from the schema array
+   $schema_arr = array();
+   if($mv_schema){
+      // get the schema from the mv_specs and use it to add the custom table
+      eval("\$schema_arr = $mv_schema;");
+      $mv_table = $schema_arr['table'];
+   }
 
    $record = new stdClass();
    $record->mview_id = $mview_id;
    $record->name = $name;
    $record->modulename = $modulename;
-   $record->mv_schema = 'DUMMY';
+   $record->mv_schema = $mv_schema;
    $record->mv_table = $mv_table;
    $record->mv_specs = $mv_specs;
    $record->indexed = $indexed;
@@ -154,20 +197,24 @@ function tripal_edit_mview ($mview_id,$name,$modulename,$mv_table,$mv_specs,$ind
            $index .= "CREATE INDEX idx_${mv_table}_${field} ON $mv_table ($field);";
         }
       }
-
-      // recreate the view
-      $sql = "CREATE TABLE {$mv_table} ($mv_specs); $index"; 
-      $previous_db = tripal_db_set_active('chado');  // use chado database
-      $results = db_query($sql);
-      tripal_db_set_active($previous_db);  // now use drupal database
-      if($results){
-         drupal_set_message(t("View '$name' edited and saved.  All results cleared. Please re-populate the view."));
+      // re-create the table differently depending on if it the traditional method
+      // or the Drupal Schema API method
+      if($mv_schema){         
+         if(!tripal_create_chado_table ($ret,$mv_table,$schema_arr)){
+            drupal_set_message("Could not create the materialized view. Check Drupal error report logs.");
+         } else {
+            drupal_set_message(t("View '$name' created"));
+         }
       } else {
-         // if we failed to create the view in chado then
-         // remove the record from the tripal_jobs table
-         $sql = "DELETE FROM {tripal_mviews} ".
-                "WHERE mview_id = $record->mview_id";
-         db_query($sql);
+         $sql = "CREATE TABLE {$mv_table} ($mv_specs); $index"; 
+         $previous_db = tripal_db_set_active('chado');  // use chado database
+         $results = db_query($sql);
+         tripal_db_set_active($previous_db);  // now use drupal database
+         if($results){
+            drupal_set_message(t("View '$name' edited and saved.  All results cleared. Please re-populate the view."));
+         } else {
+            drupal_set_message(t("Failed to create the materialized view table: '$mv_table'"));
+         }
       }
    }
 }
@@ -251,10 +298,10 @@ function tripal_update_mview ($mview_id){
    if($mview){
       $previous_db = tripal_db_set_active('chado');  // use chado database
 	   $results = db_query("DELETE FROM {$mview->mv_table}");
-      $results = db_query("INSERT INTO $mview->mv_table ($mview->query)");
+      $results = db_query("INSERT INTO {$mview->mv_table} ($mview->query)");
       tripal_db_set_active($previous_db);  // now use drupal database
       if($results){
-         $sql = "SELECT count(*) as cnt FROM $mview->mv_table";
+         $sql = "SELECT count(*) as cnt FROM {$mview->mv_table}";
          $count = db_fetch_object(db_query($sql));
 	      $record = new stdClass();
          $record->mview_id = $mview_id;
@@ -413,9 +460,9 @@ function tripal_mviews_form(&$form_state = NULL,$mview_id = NULL){
 
    // get this requested view
    if(strcmp($action,'Edit')==0){
-      $sql = "SELECT * FROM {tripal_mviews} WHERE mview_id = $mview_id ";
-      $mview = db_fetch_object(db_query($sql));
-
+      $sql = "SELECT * FROM {tripal_mviews} WHERE mview_id = %d ";
+      $mview = db_fetch_object(db_query($sql,$mview_id));
+      
       # set the default values.  If there is a value set in the 
       # form_state then let's use that, otherwise, we'll pull 
       # the values from the database 
@@ -446,6 +493,26 @@ function tripal_mviews_form(&$form_state = NULL,$mview_id = NULL){
       }
       if(!$default_comment){
          $default_comment = $mview->comment;
+      }      
+      if(!$default_schema){
+         $default_schema = $mview->mv_schema;
+      }
+      // the mv_table column of the tripal_mviews table always has the table 
+      // name even if it is a custom table. However, for the sake of the form,
+      // we do not want this to show up as the mv_table is needed for the 
+      // traditional style input.  We'll blank it out if we have a custom 
+      // table and it will get reset in the submit function using the 
+      // 'table' value from the schema array
+      if($default_schema){
+         $default_mv_table = '';
+      }
+      
+      // set which fieldset is collapsed 
+      $schema_collapsed = 0;      
+      $traditional_collapsed = 1;
+      if(!$default_schema){
+         $schema_collapsed = 1;      
+         $traditional_collapsed = 0;
       }
    }
    // Build the form
@@ -463,58 +530,80 @@ function tripal_mviews_form(&$form_state = NULL,$mview_id = NULL){
       '#description'   => t('Please enter the name for this materialized view.'),
       '#required'      => TRUE,
       '#default_value' => $default_name,
-      '#weight'        => 1
+   );
+   $form['comment']= array(
+      '#type'          => 'textarea',
+      '#title'         => t('MView Description'),
+      '#description'   => t('Optional.  Please provide a description of the purpose for this materialized vieww.'),
+      '#required'      => FALSE,
+      '#default_value' => $default_comment,
    );
 
-   $form['mv_table']= array(
+   // add a fieldset for the Drupal Schema API
+   $form['schema'] = array(
+     '#type' => 'fieldset',
+     '#title' => 'Drupal Schema API Setup',
+     '#description' => t('Use the Drupal Schema API array to describe a table. The benefit is that it '.
+                         'can be fully integrated with Tripal Views.  Tripal supports an extended '.
+                         'array format to allow for descriptoin of foreign key relationships.'),
+     '#collapsible' => 1,
+     '#collapsed' => $schema_collapsed ,
+   );
+   $form['schema']['schema']= array(
+      '#type'          => 'textarea',
+      '#title'         => t('Schema Array'),
+      '#description'   => t('Please enter the Drupal Schema API compatible array that defines the table.'),
+      '#required'      => FALSE,
+      '#default_value' => $default_schema,
+      '#rows'          => 25,
+   ); 
+   // add a fieldset for the Original Table Description fields
+   $form['traditional'] = array(
+     '#type' => 'fieldset',
+     '#title' => 'Traditional MViews Setup',
+     '#description' => t('Traidtionally with Tripal MViews were created by specifying PostgreSQL style '.
+                         'column types.  This method can be used but is deprecated in favor of the '.
+                         'newer Drupal schema API method provided above.'),
+     '#collapsible' => 1,
+     '#collapsed' => $traditional_collapsed,
+   ); 
+   $form['traditional']['mv_table']= array(
       '#type'          => 'textfield',
       '#title'         => t('Table Name'),
-      '#description'   => t('Please enter the Postgres table name that this view will generate in the database.  You can use the schema and table name for querying the view'),
-      '#required'      => TRUE,
+      '#description'   => t('Please enter the table name that this view will generate in the database.  You can use the schema and table name for querying the view'),
+      '#required'      => FALSE,
       '#default_value' => $default_mv_table,
-      '#weight'        => 3
    );
-   $form['mv_specs']= array(
+   $form['traditional']['mv_specs']= array(
       '#type'          => 'textarea',
       '#title'         => t('Table Definition'),
       '#description'   => t('Please enter the field definitions for this view. Each field should be separated by a comma or enter each field definition on each line.'),
-      '#required'      => TRUE,
+      '#required'      => FALSE,
       '#default_value' => $default_mv_specs,
-      '#weight'        => 4
    );
-   $form['indexed']= array(
+   $form['traditional']['indexed']= array(
       '#type'          => 'textarea',
       '#title'         => t('Indexed Fields'),
       '#description'   => t('Please enter the field names (as provided in the table definition above) that will be indexed for this view.  Separate by a comma or enter each field on a new line.'),
       '#required'      => FALSE,
       '#default_value' => $default_indexed,
-      '#weight'        => 5
-   );
-   $form['mvquery']= array(
-      '#type'          => 'textarea',
-      '#title'         => t('Query'),
-      '#description'   => t('Please enter the SQL statement used to populate the table.'),
-      '#required'      => TRUE,
-      '#default_value' => $default_mvquery,
-      '#weight'        => 6
    );
 /**
-   $form['special_index']= array(
+   $form['traditional']['special_index']= array(
       '#type'          => 'textarea',
       '#title'         => t('View Name'),
       '#description'   => t('Please enter the name for this materialized view.'),
       '#required'      => TRUE,
       '#default_value' => $default_special_index,
-      '#weight'        => 7
    );
 */
-   $form['comment']= array(
+   $form['mvquery']= array(
       '#type'          => 'textarea',
-      '#title'         => t('MView Description'),
-      '#description'   => t('Optional.  Please provide a description of the purpose for this materialized vieww.'),
-      '#required'      => FALSE,
-      '#default_value' => $default_comment,
-      '#weight'        => 8
+      '#title'         => t('Query'),
+      '#description'   => t('Please enter the SQL statement used to populate the table.'),
+      '#required'      => TRUE,
+      '#default_value' => $default_mvquery,
+      '#rows'          => 25,
    );
    if($action == 'Edit'){
       $value = 'Save';
@@ -537,7 +626,56 @@ function tripal_mviews_form(&$form_state = NULL,$mview_id = NULL){
 *
 * @ingroup tripal_core
 */
+function tripal_mviews_form_validate($form, &$form_state){
+   $action = $form_state['values']['action'];
+   $mview_id = $form_state['values']['mview_id'];
+   $name = $form_state['values']['name'];
+   $mv_table = $form_state['values']['mv_table'];
+   $mv_specs = $form_state['values']['mv_specs'];
+   $indexed = $form_state['values']['indexed'];
+   $query = $form_state['values']['mvquery'];
+   $special_index = $form_state['values']['special_index'];
+   $comment = $form_state['values']['comment'];
+   $schema = $form_state['values']['schema'];
+   
+   if($schema and ($mv_table or $mv_specs or $indexed or $special_index)){
+       form_set_error($form_state['values']['schema'], 
+          t('You can create an MView using the Drupal Schema API method or the '.
+            'traditional method but not both.'));
+   }
+   if(!$schema){
+      if(!$mv_specs){
+         form_set_error($form_state['values']['mv_specs'], 
+            t('The Table Definition field is required.'));
+      }
+      if(!$mv_table){
+         form_set_error($form_state['values']['mv_table'], 
+            t('The Table Name field is required.'));
+      }
+   }
+   
+   // make sure the array is valid
+   if($schema){
+      $success = eval("\$schema_array = $schema;");
+      if ($success === FALSE){
+         $error = error_get_last();
+         form_set_error($form_state['values']['schema'], 
+            t("The schema array is improperly formatted. Parse Error : " . $error["message"]));
+      }
+      if(!array_key_exists('table',$schema_array)){
+         form_set_error($form_state['values']['schema'], 
+            t("The schema array must have key named 'table'"));
+      } 
+      // TODO: add in more validation checks of the array to help the user
+   }
+}
+/**
+*
+*
+* @ingroup tripal_core
+*/
 function tripal_mviews_form_submit($form, &$form_state){
+   $ret = array();
    
    $action = $form_state['values']['action'];
    $mview_id = $form_state['values']['mview_id'];
@@ -548,12 +686,15 @@ function tripal_mviews_form_submit($form, &$form_state){
    $query = $form_state['values']['mvquery'];
    $special_index = $form_state['values']['special_index'];
    $comment = $form_state['values']['comment'];
+   $schema = $form_state['values']['schema'];
 
    if(strcmp($action,'Edit')==0){
-      tripal_edit_mview($mview_id,$name, 'tripal_core',$mv_table, $mv_specs,$indexed,$query,$special_index,$comment);
+      tripal_edit_mview($mview_id,$name, 'tripal_core',$mv_table, $mv_specs,
+         $indexed,$query,$special_index,$comment,$schema);
    }
    else if(strcmp($action,'Add')==0){
-      tripal_add_mview ($name, 'tripal_core',$mv_table, $mv_specs,$indexed,$query,$special_index,$comment);
+      tripal_add_mview ($name, 'tripal_core',$mv_table, $mv_specs,
+         $indexed,$query,$special_index,$comment,$schema);
    }
    else {
         drupal_set_message("No action performed.");

+ 220 - 209
tripal_core/tripal_core.api.inc

@@ -108,180 +108,120 @@ require_once "tripal_core.schema.api.inc";
 *
 * @ingroup tripal_chado_api
 */
-function tripal_core_chado_insert($table, $values, $options = array()){
-  $chado_db = tripal_db_persistent_chado();
-  
-  // Determine plan of action
-  if ($options['statement_name']) {
-    $prepared = TRUE;
-    if ($options['prepare']) {
-      $build_sql = TRUE;
-    } else {
-      $build_sql = FALSE;
-    }  
-  } else {
-    $build_sql = TRUE;
-  }
-  
-  // get the table description
-  $table_desc = module_invoke_all('chado_'.$table.'_schema');
-  if (empty($table_desc)) {
-    watchdog('tripal_core', 'tripal_core_chado_insert: There is no table description for !table_name', array('!table_name' => $table), WATCHDOG_WARNING);       
-  }
-  
-  // iterate through the values array and create a new 'insert_values' array
-  // that has all the values needed for insert with all foreign relationsihps
-  // resolved.
-  $insert_values = array();
-  foreach($values as $field => $value){
-    if(is_array($value)){
-       // select the value from the foreign key relationship for this value
-       $results = tripal_core_chado_get_foreign_key($table_desc,$field,$value);
-       if (sizeof($results) > 1) {
-         watchdog('tripal_core', 'tripal_core_chado_insert: Too many records match the criteria supplied for !foreign_key foreign key constraint (!criteria)', array('!foreign_key' => $field, '!criteria' => print_r($value,TRUE)), WATCHDOG_ERROR);         
-       } elseif (sizeof($results) < 1) {
-         //watchdog('tripal_core', 'tripal_core_chado_insert: no record matches criteria supplied for !foreign_key foreign key constraint (!criteria)', array('!foreign_key' => $field, '!criteria' => print_r($value,TRUE)), WATCHDOG_ERROR);
-       } else {
-         $insert_values[$field] = $results[0];
-       }
-    }  
-    else {
-       $insert_values[$field] = $value;
-    }
-  }
-  
-  // check for violation of any unique constraints
-  $ukeys = $table_desc['unique keys'];
-  $ukselect_cols = array();
-  $ukselect_vals = array();
-  if ($ukeys) {
-   foreach($ukeys as $name => $fields){
-      foreach($fields as $index => $field){
-         // build the arrays for performing a select that will check the contraint
-         array_push($ukselect_cols,$field);
-         $ukselect_vals[$field] = $insert_values[$field];
+function tripal_core_chado_insert($table,$values){
+   $insert_values = array();
+   
+   // get the table description
+   $table_desc = module_invoke_all('chado_'.$table.'_schema');
+   if (empty($table_desc)) {
+   	watchdog('tripal_core', 'tripal_core_chado_insert: There is no table description for !table_name', array('!table_name' => $table), WATCHDOG_WARNING);       
+   }
+
+   // iterate through the values array and create a new 'insert_values' array
+   // that has all the values needed for insert with all foreign relationsihps
+   // resolved.
+   foreach($values as $field => $value){
+      if(is_array($value)){
+         // select the value from the foreign key relationship for this value
+         $results = tripal_core_chado_get_foreign_key($table_desc,$field,$value);
+         if (sizeof($results) > 1) {
+           watchdog('tripal_core', 'tripal_core_chado_insert: Too many records match the criteria supplied for !foreign_key foreign key constraint (!criteria)', array('!foreign_key' => $field, '!criteria' => print_r($value,TRUE)), WATCHDOG_ERROR);         
+         } elseif (sizeof($results) < 1) {
+           //watchdog('tripal_core', 'tripal_core_chado_insert: no record matches criteria supplied for !foreign_key foreign key constraint (!criteria)', array('!foreign_key' => $field, '!criteria' => print_r($value,TRUE)), WATCHDOG_ERROR);
+         } else {
+           $insert_values[$field] = $results[0];
+         }
+      }  
+      else {
+         $insert_values[$field] = $value;
       }
-      // now check the constraint
-      if(tripal_core_chado_select($table,$ukselect_cols,$ukselect_vals)){
-         watchdog('tripal_core',"tripal_core_chado_insert: Cannot insert duplicate record into $table table: " . print_r($values,1),array(),'WATCHDOG_ERROR');
+   }
+
+   // check for violation of any unique constraints
+   $ukeys = $table_desc['unique keys'];
+   $ukselect_cols = array();
+   $ukselect_vals = array();
+   if ($ukeys) {
+     foreach($ukeys as $name => $fields){
+        foreach($fields as $index => $field){
+           // build the arrays for performing a select that will check the contraint
+           array_push($ukselect_cols,$field);
+           $ukselect_vals[$field] = $insert_values[$field];
+        }
+        // now check the constraint
+        if(tripal_core_chado_select($table,$ukselect_cols,$ukselect_vals)){
+           watchdog('tripal_core',"tripal_core_chado_insert: Cannot insert duplicate record into $table table: " . print_r($values,1),array(),'WATCHDOG_ERROR');
+           return false;
+        }
+     }
+   }
+
+   // if trying to insert a field that is the primary key, make sure it also is unique
+   $pkey = $table_desc['primary key'][0];
+   if($insert_values[$pkey]){
+      if(tripal_core_chado_select($table,array($pkey),array($pkey => $insert_values[$pkey]))){
+         watchdog('tripal_core',"tripal_core_chado_insert: Cannot insert duplicate primary key into $table table: " . print_r($values,1),array(),'WATCHDOG_ERROR');
          return false;
       }
    }
-  }
-  
-  // if trying to insert a field that is the primary key, make sure it also is unique
-  $pkey = $table_desc['primary key'][0];
-  if($insert_values[$pkey]){
-    if(tripal_core_chado_select($table,array($pkey),array($pkey => $insert_values[$pkey]))){
-       watchdog('tripal_core',"tripal_core_chado_insert: Cannot insert duplicate primary key into $table table: " . print_r($values,1),array(),'WATCHDOG_ERROR');
-       return false;
-    }
-  }
-  
-  // make sure required fields have a value
-  $fields = $table_desc['fields'];
-  if (!is_array($fields)) {
-   $fields = array();
-   watchdog('tripal_core',"tripal_core_chado_insert: %table not defined in tripal schema api", array('%table' => $table), 'WATCHDOG WARNING');
-  }
-  foreach($fields as $field => $def){
-    // a field is considered missing if it cannot be null and there is no default
-    // value for it or it is of type 'serial'
-    if($def['not null'] == 1 and !array_key_exists($field,$insert_values) and !isset($def['default']) and strcmp($def['type'],serial)!=0){
-       watchdog('tripal_core',"tripal_core_chado_insert: Field $table.$field cannot be null: " . print_r($values,1),array(),'WATCHDOG_ERROR');
-       return false;
-    }
-  }
-  
-  // Now build the insert SQL statement
-  $ifields = array();
-  $ivalues = array();
-  $itypes = array();
-  $iplaceholders = array();
-  $i = 1;
-  foreach ($insert_values as $field => $value){
-    array_push($ifields,$field);
-    array_push($ivalues,$value);
-    array_push($iplaceholders,'$'.$i);
-    $i++;
-    if(strcmp($value,'__NULL__')==0){
-       array_push($itypes,"NULL");
-    } 
-    elseif(strcmp($fields[$field]['type'],'serial')==0 or 
-       strcmp($fields[$field]['type'],'int')==0){
-       array_push($itypes,"%d");
-    } 
-    else {
-       array_push($itypes,"'%s'");
-    }
-  }
 
-  if ($build_sql) {   
-    // prepare the statement
-    if ($prepared) {
-      $sql = "INSERT INTO {$table} (" . implode(", ",$ifields) . ") VALUES (". implode(", ",$iplaceholders) .")";
-      
-      $previous_db = tripal_db_set_active('chado');
-      $status = pg_prepare($chado_db, $options['statement_name'], $sql);
-      tripal_db_set_active($previous_db);
-      
-      if (!$status) {
-        watchdog('tripal_core',"tripal_core_chado_insert: not able to prepare '%name' statement for: %sql", array('%name' => $options['statement_name'], '%sql' => $sql), 'WATCHDOG ERROR');
-        return FALSE;
+   // make sure required fields have a value
+   $fields = $table_desc['fields'];
+   if (!is_array($fields)) {
+   	 $fields = array();
+   	 watchdog('tripal_core',"tripal_core_chado_insert: %table not defined in tripal schema api", array('%table' => $table), 'WATCHDOG WARNING');
+   }
+   foreach($fields as $field => $def){
+      // a field is considered missing if it cannot be null and there is no default
+      // value for it or it is of type 'serial'
+      if($def['not null'] == 1 and !array_key_exists($field,$insert_values) and !isset($def['default']) and strcmp($def['type'],serial)!=0){
+         watchdog('tripal_core',"tripal_core_chado_insert: Field $table.$field cannot be null: " . print_r($values,1),array(),'WATCHDOG_ERROR');
+         return false;
       }
-    } else {
-      $sql = "INSERT INTO {$table} (" . implode(", ",$ifields) . ") VALUES (". implode(", ",$itypes) .")";
-    }
-    
-  }
-    
-  // finally perform the insert. 
-  if ($prepared) {
-    
-      $previous_db = tripal_db_set_active('chado');
-      $result = pg_execute($chado_db, $options['statement_name'], $ivalues);
-      tripal_db_set_active($previous_db);
-      if ($result) {
-        // add primary keys to values before return
-        $primary_key = array();
-        if (!is_array($table_desc['primary key'])) {
-          $table_desc['primary key'] = array();
-          watchdog('tripal_core',"tripal_core_chado_insert: %table not defined in tripal schema api", array('%table' => $table), 'WATCHDOG WARNING');
-        }
-        foreach ($table_desc['primary key'] as $field) {
-          $value = db_last_insert_id($table, $field);
-          $values[$field] = $value;
-        }
-        return $values;
-      } else {
-        watchdog('tripal_core',"tripal_core_chado_insert: not able to execute prepared statement '%name' with values: %values", array('%name' => $options['statement_name'], '%values' => print_r($values,1)), 'WATCHDOG ERROR');
-        return FALSE;
+   }
+
+   // Now build the insert SQL statement
+   $ifields = array();
+   $ivalues = array();
+   $itypes = array();
+   foreach ($insert_values as $field => $value){
+      array_push($ifields,$field);
+      array_push($ivalues,$value);
+      if(strcmp($value,'__NULL__')==0){
+         array_push($itypes,"NULL");
+      } 
+      elseif(strcmp($fields[$field]['type'],'serial')==0 or 
+         strcmp($fields[$field]['type'],'int')==0){
+         array_push($itypes,"%d");
+      } 
+      else {
+         array_push($itypes,"'%s'");
       }
+   }
+   $sql = "INSERT INTO {$table} (" . implode(", ",$ifields) . ") VALUES (". implode(", ",$itypes) .")";
 
-  } else {
-    $previous_db = tripal_db_set_active('chado');  // use chado database
-    $result = db_query($sql,$ivalues);
-    tripal_db_set_active($previous_db);  // now use drupal database 
-    if($result){
+   // finally perform the insert. 
+   $previous_db = tripal_db_set_active('chado');  // use chado database
+   $result = db_query($sql,$ivalues);
+   tripal_db_set_active($previous_db);  // now use drupal database 
+   if($result){
       // add primary keys to values before return
       $primary_key = array();
       if (!is_array($table_desc['primary key'])) {
-        $table_desc['primary key'] = array();
-        watchdog('tripal_core',"tripal_core_chado_insert: %table not defined in tripal schema api", array('%table' => $table), 'WATCHDOG WARNING');
+      	$table_desc['primary key'] = array();
+      	watchdog('tripal_core',"tripal_core_chado_insert: %table not defined in tripal schema api", array('%table' => $table), 'WATCHDOG WARNING');
       }
       foreach ($table_desc['primary key'] as $field) {
         $value = db_last_insert_id($table, $field);
         $values[$field] = $value;
       }
       return $values;
-    } 
-    else {
+   } 
+   else {
       watchdog('tripal_core',"tripal_core_chado_insert: Cannot insert record into $table table: " . print_r($values,1),array(),'WATCHDOG_ERROR');
       return false;
-    }
-  }
-  
-  return false;
+   }
+   return false;
 }
 
 /**
@@ -655,7 +595,7 @@ function tripal_core_chado_select($table,$columns,$values,$options = null){
               'case_insensitive_columns' => $options['case_insensitive_columns']
             );
             $results = tripal_core_chado_get_foreign_key($table_desc,$field,$value, $foreign_options);
-            if (sizeof($results) < 1) {
+            if (count($results) ==0) {
               // foreign key records are required
               // thus if none matched then return false and alert the admin through watchdog
               //watchdog('tripal_core', 
@@ -819,10 +759,12 @@ function tripal_core_chado_get_foreign_key($table_desc,$field,$values, $options
                $select_cols = array($right);
                $result = tripal_core_chado_select($table,$select_cols,$values, $options);
                $fields = array();
-               foreach ($result as $obj) {
-                 $fields[] = $obj->$right;
+               if(count($result) > 0){
+                  foreach ($result as $obj) {
+                    $fields[] = $obj->$right;
+                  }
+                  return $fields;
                }
-               return $fields;
             }
          }
       } 
@@ -1419,19 +1361,22 @@ function chado_get_node_id ($table, $id) {
  *   The base table for which the property should be retrieved. Thus to retrieve a property
  *   for a feature the basetable=feature and property is retrieved from featureprop
  * @param $record_id
- *   The primary key of the basetable to retrieve properties for. This should be in integer.
+ *   The foriegn key field of the base table. This should be in integer.
  * @param $property
  *   The cvterm name describing the type of properties to be retrieved
  * @param $cv_name
  *   The name of the cv that the above cvterm is part of
  *
  * @return
- *   A chado variable with the specified properties expanded
+ *   An array in the same format as that generated by the function
+ *   tripal_core_generate_chado_var().  If only one record is returned it
+ *   is a single object.  If more than one record is returned then it is an array
+ *   of objects
  *
  * @ingroup tripal_chado_api
  */
 function tripal_core_get_property($basetable, $record_id, $property, $cv_name){
-
+  
    // get the foreign key for this property table
    $table_desc = module_invoke_all('chado_'.$basetable.'prop_schema');
    $fkcol = key($table_desc['foreign keys'][$basetable]['columns']);
@@ -1447,6 +1392,7 @@ function tripal_core_get_property($basetable, $record_id, $property, $cv_name){
          'is_obsolete' => 0
       ),
    );
+
    $results = tripal_core_generate_chado_var($basetable.'prop',$values);
    $results = tripal_core_expand_chado_vars($results,'field',$basetable.'prop.value');
    return $results;
@@ -1461,7 +1407,7 @@ function tripal_core_get_property($basetable, $record_id, $property, $cv_name){
  *   The base table for which the property should be inserted. Thus to insert a property
  *   for a feature the basetable=feature and property is inserted into featureprop
  * @param $record_id
- *   The primary key of the basetable to insert a property for. This should be in integer.
+ *   The foriegn key field of the base table. This should be in integer. 
  * @param $property
  *   The cvterm name describing the type of properties to be inserted
  * @param $cv_name
@@ -1484,17 +1430,25 @@ function tripal_core_insert_property($basetable, $record_id, $property,
    // first see if the property already exists, if the user want's to update
    // then we can do that, but otherwise we want to increment the rank and
    // insert
-   $prop = tripal_core_get_property($basetable,$record_id,$property,$cv_name);
+   $props = tripal_core_get_property($basetable,$record_id,$property,$cv_name);
+   if(!is_array($props)) { 
+    $props = array($props); 
+   }   
    $rank = 0;
-   if(count($prop)>0){ 
+   if(count($props)>0){       
       if($update_if_present){
-         return tripal_core_update_property($basetable,$record_id,$property,$cv_name,$value) ;
+         return tripal_core_update_property($basetable, $record_id, $property, $cv_name, $value) ;
       } else {
-         // iterate through the properties returned and get the largest rank
-         foreach($prop as $p){
+         // iterate through the properties returned and check to see if the
+         // property with this value already exists if not, get the largest rank
+         // and insert the same property but with this new value
+         foreach($props as $p){
             if($p->rank > $rank){
                $rank = $p->rank;
             }
+            if(strcmp($p->value,$value)==0){
+               return TRUE;
+            }
          }
          // now add 1 to the rank
          $rank++;
@@ -1791,47 +1745,6 @@ function tripal_db_set_active($dbname){
    }
    else return db_set_active($dbname);
 }
-
-/**
- * Instantiate or Return a persistent chado connection
- *
- * NOTE: cannot use $active_db since a new connection is created each time 
- * db_set_active() is called
- *
- * @return
- *   A postgresql connection object which can be used by pg_prepare, pg_execute, etc.
- */
-function tripal_db_persistent_chado () {
-  global $db_url;
-  
-  // get connection if it already exists
-  $connection = variable_get('tripal_perisistent_chado',NULL);
-  
-  if ($connection) {
-    return $connection;
-  
-  // Otherwise we need to set it
-  } else {
-    if (is_array($db_url) && isset($db_url['chado'])) {
-      $connection = db_connect($db_url['chado']);
-      variable_set('tripal_perisistent_chado', $connection); 
-    } else {
-      $connection = db_connect($db_url);
-      variable_set('tripal_perisistent_chado', $connection); 
-    }
-    
-    return $connection;
-  }
-  return FALSE;
-}
-
-/**
- * Release a persistent chado connection
- */
-function tripal_db_release_persistent_chado () {
-  variable_del('tripal_perisistent_chado');
-}
-
 /**
  * Purpose: Get max rank for a given set of criteria
  *   This function was developed with the many property tables in chado in mind
@@ -1884,3 +1797,101 @@ function tripal_get_max_chado_rank ($tablename, $where_options) {
 		return -1;
 	}
 }
+/**
+ * Add a new table to the Chado schema. This function is simply a wrapper for
+ * the db_create_table() function of Drupal, but ensures the table is created
+ * inside the Chado schema rather than the Drupal schema.  If the table already
+ * exists then it will be dropped and recreated using the schema provided.
+ * Howver, it will only drop a table if it exsits in the tripal_custom_tables
+ * table. This way the function cannot be used to accidentally alter existing
+ * non custom tables.
+ * 
+ * @param $ret
+ *   Array to which query results will be added.
+ * @param $table
+ *   The name of the table to create.
+ * @param $schema 
+ *   A Drupal-style Schema API definition of the table
+ *
+ * @return 
+ *   A database query result resource for the new table, or FALSE if table was not constructed.
+ *
+ * @ingroup tripal_core_api
+ */
+function tripal_create_chado_table (&$ret,$table,$schema) {
+   $ret = array();
+
+   // If the table exits in Chado but not in the tripal_custom_tables field
+   // then call an error.  if the table exits in the tripal_custom_tables but
+   // not in Chado then create the table and replace the entry.
+   $sql = "SELECT * FROM {tripal_custom_tables} WHERE table_name = '%s'";
+   $centry = db_fetch_object(db_query($sql,$table));
+   $previous_db = tripal_db_set_active('chado');  // use chado database   
+   $exists = db_table_exists($table);
+   tripal_db_set_active($previous_db);  // now use drupal database
+   if(!$exists){
+      $previous_db = tripal_db_set_active('chado');  // use chado database   
+      db_create_table($ret,$table,$schema);
+      tripal_db_set_active($previous_db);  // now use drupal database  
+      if(count($ret)==0){
+   	   watchdog('tripal_core', "Error adding custom table '!table_name'.", 
+   	      array('!table_name' => $table), WATCHDOG_ERROR); 
+         return FALSE;
+      }       
+   }
+   if($exists and !$centry){
+   	watchdog('tripal_core', "Could not add custom table '!table_name'. It ".
+   	         "already exists but is not known to Tripal as being a custom table.", 
+   	   array('!table_name' => $table), WATCHDOG_WARNING);       
+   	   return FALSE;
+   }
+   if($exists and $centry){
+      // drop the table we'll recreate it with the new schema
+      $previous_db = tripal_db_set_active('chado');  // use chado database   
+      db_drop_table($ret,$table);
+      db_create_table($ret,$table,$schema);
+      tripal_db_set_active($previous_db);  // now use drupal database        
+   }
+   
+   // if the table creation was succesful then add an entry
+   // in the tripal_custom_table
+   $record = new stdClass();
+   $record->table_name = $table;
+   $record->schema = serialize($schema);
+   // if an entry already exists then remove it
+   if($centry){
+      $sql = "DELETE FROM {tripal_custom_tables} WHERE table_name = '%s'";
+      db_query($sql,$table);
+   } 
+   $success = drupal_write_record('tripal_custom_tables',$record);
+   if(!$success){
+	   watchdog('tripal_core', "Error adding custom table.", 
+	      array('!table_name' => $table), WATCHDOG_ERROR); 
+      return FALSE;
+   }
+   return $ret;
+}
+/**
+ * Retrieves the schema in an array for the specified custom table.
+ * 
+ * @param $table
+ *   The name of the table to create.
+ *
+ * @return 
+ *   A Drupal-style Schema API array definition of the table. Returns
+ *   FALSE on failure.
+ *
+ * @ingroup tripal_core_api
+ */
+function tripal_get_chado_custom_schema ($table) {
+   $sql = "SELECT schema FROM {tripal_custom_tables} WHERE table_name = '%s'";
+   $custom = db_fetch_object(db_query($sql,$table));
+   if(!$custom){
+      return FALSE;
+   } 
+   else {
+      return unserialize($custom->schema);
+   }
+}
+
+

+ 22 - 4
tripal_core/tripal_core.install

@@ -28,9 +28,14 @@ function tripal_core_install(){
 * @ingroup tripal_feature
 */
 function tripal_core_update_6000(){
-   // recreate the materialized view
+   // add additional columsn to the tripal_mviews table
    db_add_field($ret, 'tripal_mviews', 'status', array('type' => 'text', 'size' => 'normal', 'not null' => FALSE));
    db_add_field($ret, 'tripal_mviews', 'comment', array('type' => 'text', 'size' => 'normal', 'not null' => FALSE));
+   db_add_field($ret, 'tripal_mviews', 'mv_schema', array('type' => 'text', 'size' => 'normal', 'not null' => FALSE));
+   db_change_field($ret, 'tripal_mviews', 'mv_table','mv_table',array('type' => 'varchar','length' => 128, 'not null' => FALSE));
+   db_change_field($ret, 'tripal_mviews', 'mv_specs','mv_specs',array('type' => 'text', 'size' => 'normal', 'not null' => FALSE));
+   db_change_field($ret, 'tripal_mviews', 'indexed','indexed',array('type' => 'text', 'size' => 'normal', 'not null' => FALSE));
+
    
    // create the custom tables table
    $ret = array();
@@ -51,6 +56,18 @@ function tripal_core_update_6000(){
 */
 function tripal_core_schema() {
    $schema = tripal_core_get_schemas();
+   
+   // if this module is already installed and enabled, then we want to provide
+   // the schemas for all of the custom tables.  This will allow Views to 
+   // see the schemas.  We check if the module is installed because during 
+   // installation we don't want to make these custom tables available as we don't
+   // want them created in the Drupal database.  The custom tables go in the 
+   // Chado database.
+   $sql = 'SELECT * FROM {tripal_custom_tables}';
+   $q = db_query($sql);
+   while($custom = db_fetch_object($q)){
+      $schema[$custom->table_name] = unserialize($custom->schema);
+   }
    return $schema;
 }
 /************************************************************************
@@ -100,9 +117,10 @@ function tripal_core_mviews_schema(){
          'mview_id'      => array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE),
          'name'          => array('type' => 'varchar','length' => 255, 'not null' => TRUE),
          'modulename'    => array('type' => 'varchar','length' => 50, 'not null' => TRUE, 'description' => 'The module name that provides the callback for this job'),
-         'mv_table'      => array('type' => 'varchar','length' => 128, 'not null' => TRUE),
-         'mv_specs'      => array('type' => 'text', 'size' => 'normal', 'not null' => TRUE),
-         'indexed'       => array('type' => 'text', 'size' => 'normal', 'not null' => TRUE),
+         'mv_table'      => array('type' => 'varchar','length' => 128, 'not null' => FALSE),
+         'mv_specs'      => array('type' => 'text', 'size' => 'normal', 'not null' => FALSE),
+         'mv_schema'     => array('type' => 'text', 'size' => 'normal', 'not null' => FALSE),
+         'indexed'       => array('type' => 'text', 'size' => 'normal', 'not null' => FALSE),
          'query'         => array('type' => 'text', 'size' => 'normal', 'not null' => TRUE),
          'special_index' => array('type' => 'text', 'size' => 'normal', 'not null' => FALSE),
          'last_update'   => array('type' => 'int', 'not null' => FALSE, 'description' => 'UNIX integer time'),

+ 1 - 2
tripal_core/tripal_core.module

@@ -133,9 +133,8 @@ function tripal_core_menu() {
      'type' => MENU_CALLBACK,
    );
  
-
+   
    // Materialized Views 
-
    $items['admin/tripal/mviews'] = array(
      'title' => 'MViews',
      'description' => 'Materialized views are used to improve speed of large or complex queries.',

+ 31 - 7
tripal_feature/tripal_feature.admin.inc

@@ -125,7 +125,7 @@ function tripal_feature_module_description_page() {
                visitors.    This browser can be toggled on or off using the 
                <a href="'.url('admin/tripal/tripal_feature/configuration').'">Feature Configuration page</a></p></li>
  
-              <li><p><b>Feature Summary:</b>  The feature summary is a pie chart that indicates the types and quantities
+              <li><p><b>Feature Summary Report:</b>  The feature summary report is a pie chart that indicates the types and quantities
               of feature types (Sequence Ontology terms) that are loaded in the database. It appears on the organism 
               page.  The summary can be toggled on or off using the 
               <a href="'.url('admin/tripal/tripal_feature/configuration').'">Feature Configuration page</a></p></li>             
@@ -225,7 +225,9 @@ function tripal_feature_admin () {
 
       $form['browser'] = array(
          '#type' => 'fieldset',
-         '#title' => t('Feature Browser')
+         '#title' => t('Feature Browser'),
+         '#collapsible' => 1,
+         '#collapsed' => 1 ,
       );
       $allowedoptions1  = array (
         'show_feature_browser' => "Show the feature browser on the organism page. The browser loads when page loads. This may be slow for large sites.",
@@ -286,7 +288,9 @@ function tripal_feature_admin () {
 
       $form['feature_edit'] = array(
          '#type' => 'fieldset',
-         '#title' => t('Feature Editing')
+         '#title' => t('Feature Editing'),
+         '#collapsible' => 1,
+         '#collapsed' => 1 ,
       );
 
       $form['feature_edit']['browser_desc'] = array(
@@ -311,7 +315,9 @@ function tripal_feature_admin () {
 
       $form['summary'] = array(
          '#type' => 'fieldset',
-         '#title' => t('Feature Summary')
+         '#title' => t('Feature Summary Report'),
+         '#collapsible' => 1,
+         '#collapsed' => 1 ,
       );
       $allowedoptions2 ['show_feature_summary'] = "Show the feature summary on the organism page. The summary loads when page loads.";
       $allowedoptions2 ['hide_feature_summary'] = "Hide the feature summary on the organism page. Disables the feature summary.";
@@ -324,6 +330,17 @@ function tripal_feature_admin () {
          '#options' => $allowedoptions2,
          '#default_value'=>variable_get('tripal_feature_summary_setting', 'show_feature_summary'),
       );
+      $form['summary']['feature_mapping'] = array(
+         '#title' => 'Map feature types',
+         '#description' => t('You may specify which Sequence Ontology (SO) terms to show in the '.
+            'feature summary report by listing them in the following text area.   Enter one per line. '.
+            'If left blank, all SO terms for all features will be shown in the report. Only those terms '.
+            'listed below will be shown in the report. Terms will appear in the report in the same order listed. To rename a '.
+            'SO term to be more human readable form, use an \'=\' sign after the SO term (e.g. \'polypeptide = Protein\')'),
+         '#type' => 'textarea',
+         '#rows' => 15,
+         '#default_value'=>variable_get('tripal_feature_summary_report_mapping', ''),
+      );
       $form['summary']['set_summary_button'] = array(
          '#type' => 'submit',
          '#value' => t('Set Summary'),
@@ -396,6 +413,7 @@ function tripal_feature_admin_validate($form, &$form_state) {
 
       case t('Set Summary') :
          variable_set('tripal_feature_summary_setting',$form_state['values']['feature_summary']);
+         variable_set('tripal_feature_summary_report_mapping',$form_state['values']['feature_mapping']);
          break;
 
       case t('Set Feature URLs') :
@@ -413,7 +431,9 @@ function tripal_feature_admin_validate($form, &$form_state) {
 function get_tripal_feature_admin_form_cleanup_set(&$form) {
    $form['cleanup'] = array(
       '#type' => 'fieldset',
-      '#title' => t('Clean Up')
+      '#title' => t('Clean Up'),
+      '#collapsible' => 1,
+      '#collapsed' => 1 ,
    );
    $form['cleanup']['description'] = array(
        '#type' => 'item',
@@ -443,7 +463,9 @@ function get_tripal_feature_admin_form_cleanup_set(&$form) {
 function get_tripal_feature_admin_form_reindex_set(&$form) {
    $form['reindex'] = array(
       '#type' => 'fieldset',
-      '#title' => t('Index/Reindex')
+      '#title' => t('Index/Reindex'),
+      '#collapsible' => 1,
+      '#collapsed' => 1 ,
    );
    $form['reindex']['description'] = array(
        '#type' => 'item',
@@ -471,7 +493,9 @@ function get_tripal_feature_admin_form_taxonomy_set (&$form) {
 
    $form['taxonomy'] = array(
       '#type' => 'fieldset',
-      '#title' => t('Set Taxonomy')
+      '#title' => t('Set Taxonomy'),
+      '#collapsible' => 1,
+      '#collapsed' => 1 ,
    );
 
    $form['taxonomy']['description'] = array(

+ 81 - 16
tripal_feature/tripal_feature.module

@@ -1342,6 +1342,41 @@ function tripal_feature_load_organism_feature_counts($organism){
    if(strcmp($show_counts,'show_feature_summary')!=0){
       return array ('enabled' => false );
    }
+   
+
+   $args = array();
+   $names = array();
+   $order = array();
+   
+   // build the where clause for the SQL statement if we have a custom term list
+   // we'll also keep track of the names the admin provided (if any) and the 
+   // order that the terms should appear.
+   $is_custom = 0;
+   $temp = rtrim(variable_get('tripal_feature_summary_report_mapping', ''));
+   $where = '';
+   if($temp){
+      $is_custom = 1;
+      $temp = explode("\n",$temp);
+      foreach ($temp as $key => $value){
+         // separate the key value pairs
+         $temp2 = explode("=",$value);
+         $feature_type = rtrim($temp2[0]);
+         $args[] = $feature_type;
+         $order[] = $feature_type;
+         // if a new name is provided then use that otherwise just
+         // use the feature type
+         if(count($temp2) == 2){
+            $names[] = rtrim($temp2[1]);
+         } else {
+            $names[] = $feature_type;
+         }
+         $where .= "OFC.feature_type = '%s' OR \n";
+      }
+      if($where){
+         $where = substr($where,0,-5);  # remove OR from the end
+         $where = "($where) AND";
+      }
+   }
 
    // get the feature counts.  This is dependent on a materialized view
    // installed with the organism module
@@ -1349,19 +1384,32 @@ function tripal_feature_load_organism_feature_counts($organism){
       SELECT OFC.num_features,OFC.feature_type,CVT.definition
       FROM {organism_feature_count} OFC
         INNER JOIN {cvterm} CVT on OFC.cvterm_id = CVT.cvterm_id
-      WHERE organism_id = %d 
+      WHERE $where organism_id = %d
       ORDER BY num_features desc
    ";
+   $args[] = $organism->organism_id;
    $previous_db = tripal_db_set_active('chado');  // use chado database
-   $org_features = db_query($sql,$organism->organism_id);
+   $org_features = db_query($sql,$args);
    tripal_db_set_active($previous_db);  // now use drupal database
-
-   $i=0;
+   
+   // iterate through the types 
    $types = array();
    while($type = db_fetch_object($org_features)){
-      $types[$i++] = $type;
+      $types[$type->feature_type] = $type;      
+      // if we don't have an order this means we didn't go through the loop
+      // above to set the names, so do that now
+      if(!$is_custom){
+         $names[] = $type->feature_type;
+         $order[] = $type->feature_type;
+      }
    }
-   return array ( 'types' => $types, 'enabled' => true );
+
+   # now reorder the types
+   $ordered_types = array();
+   foreach ($order as $type){
+      $ordered_types[] = $types[$type];
+   }
+   return array ( 'types' => $ordered_types, 'names' => $names, 'enabled' => true );
 }
 /**
  * 
@@ -1822,20 +1870,37 @@ function tripal_feature_preprocess_tripal_analysis_feature_browser(&$variables){
  */
 function tripal_feature_cv_chart($chart_id){
 
-  // The CV module will create the JSON array necessary for buillding a
-  // pie chart using jgChart and Google Charts.  We have to pass to it
-  // a table that contains count information, tell it which column 
-  // contains the cvterm_id and provide a filter for getting the
-  // results we want from the table.
-  $organism_id = preg_replace("/^tripal_feature_cv_chart_(\d+)$/","$1",$chart_id);
-  $options = array(
+   // we only want the chart to show feature types setup by the admin
+   $temp = rtrim(variable_get('tripal_feature_summary_report_mapping', ''));
+   $where = '';
+   if($temp){
+      $temp = explode("\n",$temp);
+      foreach ($temp as $key => $value){
+         $temp2 = explode("=",$value);
+         $feature_type = rtrim($temp2[0]);
+         $where .= "CNT.feature_type = '$feature_type' OR \n";
+      }
+      if($where){
+         $where = substr($where,0,-5);  # remove OR from the end
+         $where = "($where) AND";
+      }
+   }
+
+   $organism_id = preg_replace("/^tripal_feature_cv_chart_(\d+)$/","$1",$chart_id);
+  
+   // The CV module will create the JSON array necessary for buillding a
+   // pie chart using jgChart and Google Charts.  We have to pass to it
+   // a table that contains count information, tell it which column 
+   // contains the cvterm_id and provide a filter for getting the
+   // results we want from the table.   
+   $options = array(
      count_mview      => 'organism_feature_count',
      cvterm_id_column => 'cvterm_id',
      count_column     => 'num_features',
      size             => '550x200',
-     filter           => "CNT.organism_id = $organism_id",
-  );
-  return $options;
+     filter           => "$where CNT.organism_id = $organism_id",
+   );
+   return $options;
 }
 
 /**

+ 22 - 10
tripal_views/tripal_views.views.inc

@@ -409,7 +409,7 @@ function tripal_views_add_node_ids_to_view (&$view) {
 
 function tripal_views_views_data(){   
   
-   // Define Global Fields -------------
+   // Define Global Fields 
    // Filter handler that lets the admin say: 
    // "Show no results until they enter search parameters"
    $data['views']['search_results'] = array(
@@ -442,7 +442,7 @@ function tripal_views_views_data(){
       $type_prefix = '';
 
       // populate the base table name and fields.  If an $mview_id is given
-      // the get the materialized view info, otherwise get the Chado table info
+      // then get the materialized view info, otherwise get the Chado table info
       if($mview_id){
          $type_prefix = 'MView';
          // get the base table name from the materialized view
@@ -475,10 +475,25 @@ function tripal_views_views_data(){
       else {
          $type_prefix = 'Chado Table';
          $base_table = $tvi_row->table_name;
+         // The chado table could be a regular Chado table or a custom table
+         // in the chado database.  Therefore we'll check both
          $table_desc = module_invoke_all('chado_'.$base_table.'_schema');
+         if(!$table_desc){            
+            $table_desc = tripal_get_chado_custom_schema($base_table);
+         }
          $fields = $table_desc['fields'];
          foreach($fields as $column => $attrs){
-            $base_fields[] = $column;
+            $base_fields[$column] = array(
+              'column_name' => $column,
+              'type' => $attrs['type'],
+            );
+         }
+         // get the field name and descriptions
+         $sql = "SELECT * FROM {tripal_views_field} WHERE setup_id=%d";
+         $query = db_query($sql, $setup_id);
+         while ($field = db_fetch_object($query)) {
+           $base_fields[$field->column_name]['name'] = $field->name;
+           $base_fields[$field->column_name]['help'] = $field->description;
          }
       }
 
@@ -489,7 +504,6 @@ function tripal_views_views_data(){
         'title' => "$type_prefix: $tvi_row->name",
         'help'  => $tvi_row->comment,
       );
-
       // first add the fields
       foreach ($base_fields as $column_name => $base_field){
         $data[$base_table][$column_name] = array(
@@ -499,7 +513,8 @@ function tripal_views_views_data(){
               'click sortable' => TRUE,
            ),
         );
-
+        
+        
         // now add the handlers
         $sql = "SELECT * FROM {tripal_views_handlers} WHERE setup_id = %d AND column_name = '%s'";
         $handlers = db_query($sql,$setup_id,$column_name);
@@ -525,9 +540,7 @@ function tripal_views_views_data(){
         // check to see if the join table is one that correlates with Drupal nodes
         // if so, there will be a chado_<table_name> table in the Drupal database
         // if there is, then we need to add the linking join information
-        $sql = "SELECT tablename FROM pg_tables WHERE tablename = 'chado_$left_table'";
-        if(db_fetch_object(db_query($sql))){
-
+        if(db_table_exists("chado_$left_table")){
            // join the mview to the linker table
            $data[$base_table]['table']['join']["chado_$left_table"] = array(
              'left_field' => $left_field,
@@ -575,8 +588,7 @@ function tripal_views_views_data_alter(&$data) {
         // if there is, then we need to add the linking join information.  We did
         // this step in the hook_views_data function above, but now we need 
         // to add the reciprical joins
-        $sql = "SELECT tablename FROM pg_tables WHERE tablename = '%s'";
-        if(db_fetch_object(db_query($sql,"chado_$left_table"))){
+        if(db_table_exists("chado_$left_table")){
 
            // join the linker table to the mview
            if(array_key_exists("chado_$left_table",$data)){

+ 50 - 29
tripal_views/tripal_views_integration.inc

@@ -65,7 +65,7 @@ function tripal_views_description_page() {
  */
 function tripal_views_integration_setup_list(){
 
-   $header = array('', 'Drupal Views Type Name', 'Table Name', 'Is Mview', 'Priority', 'Comment','');
+   $header = array('', 'Drupal Views Type Name', 'Table Name', 'Legacy Mview', 'Priority', 'Comment','');
    $rows = array();
 
    // get the list of materialized views
@@ -185,16 +185,34 @@ function tripal_views_integration_form(&$form_state, $setup_id = NULL){
                        'and you can specify other tables to join with and handlers.',
    );
 
+  // build the form element for the Chado tables
+  $chado_tables = tripal_core_get_chado_tables();
+  $chado_tables = array_merge(array('Select',), $chado_tables);
+  $form['base_table_type']['table_name'] = array(
+    '#title' => t('Chado/Custom Table'),
+    '#type' => 'select',
+    '#options' => $chado_tables,
+    '#description' => t('Tables from Chado, custom tables and materialized view tables (non-legacy MViews) can be selected for integration.'),
+    '#default_value' => (!$setup_obj->mview_id) ? $setup_obj->table_name : '',
+    '#ahah' => array(
+       'path' => ahah_helper_path(array('view_setup_table')),
+       'wrapper' => 'table-rows-div',
+       'effect' => 'fade',
+       'event' => 'change',
+       'method' => 'replace',
+    ),
+  );
+
 
    // build the form element that lists the materialized views
-   $query = db_query("SELECT mview_id,name FROM {tripal_mviews} ORDER BY name");
+   $query = db_query("SELECT mview_id,name FROM {tripal_mviews} WHERE mv_schema is NULL or mv_schema = '' ORDER BY name");
    $mview_tables = array();
    $mview_tables['0'] = 'Select';
    while ($mview = db_fetch_object($query)){
      $mview_tables[$mview->mview_id] = $mview->name;
    }
    $form['base_table_type']['mview_id'] = array(
-      '#title' => t('Materialized View'),
+      '#title' => t('Legacy Materialized View'),
       '#type' => 'select',
       '#options' => $mview_tables,
       '#description' => 'Which materialized view to use.',
@@ -208,24 +226,6 @@ function tripal_views_integration_form(&$form_state, $setup_id = NULL){
       ),
   );
 
-  // build the form element for the Chado tables
-  $chado_tables = tripal_core_get_chado_tables();
-  $chado_tables = array_merge(array('Select',), $chado_tables);
-  $form['base_table_type']['table_name'] = array(
-    '#title' => t('Chado Table'),
-    '#type' => 'select',
-    '#options' => $chado_tables,
-    '#description' => 'Which Chado table to use.',
-    '#default_value' => (!$setup_obj->mview_id) ? $setup_obj->table_name : '',
-    '#ahah' => array(
-       'path' => ahah_helper_path(array('view_setup_table')),
-       'wrapper' => 'table-rows-div',
-       'effect' => 'fade',
-       'event' => 'change',
-       'method' => 'replace',
-    ),
-  );
-
   $form['views_type'] = array(
      '#type' => 'fieldset',
      '#title' => 'View Type',
@@ -304,12 +304,23 @@ function tripal_views_integration_form(&$form_state, $setup_id = NULL){
        $columns = explode(",",$mview->mv_specs);
     } else {
        $table_desc = module_invoke_all('chado_'.$table_name.'_schema');
-       $fields = $table_desc['fields'];
-       // iterate through the columns and build the format
-       // compatible with the code below. The column name is first followed
-       // by the type with a separating space
-       foreach($fields as $column => $attrs){
-          $columns[] = "$column ".$attrs['type'];
+       if($table_desc){
+          $fields = $table_desc['fields'];
+          // iterate through the columns and build the format
+          // compatible with the code below. The column name is first followed
+          // by the type with a separating space
+          foreach($fields as $column => $attrs){
+             $columns[] = "$column ".$attrs['type'];
+          }
+       }
+       
+       // now do the same for the custom tables
+       $table_desc = tripal_get_chado_custom_schema ($table_name);
+       if($table_desc){
+          $fields = $table_desc['fields'];
+          foreach($fields as $column => $attrs){
+             $columns[] = "$column ".$attrs['type'];
+          }
        }
     }
 
@@ -461,7 +472,12 @@ function tripal_views_integration_form(&$form_state, $setup_id = NULL){
       
       $columns = array();
       if($default_join_table){
+        // get the table description in the typical way and if it returns 
+        // nothing then get the custom table description
         $table_desc = module_invoke_all('chado_'.$default_join_table.'_schema');
+        if(!$table_desc){
+           $table_desc = tripal_get_chado_custom_schema ($default_join_table);
+        }
         foreach ($table_desc['fields'] as $column => $def){
            $columns[$column] = $column;
         }
@@ -513,7 +529,7 @@ function tripal_views_integration_form(&$form_state, $setup_id = NULL){
             if($column_type == 'integer' or $column_type == 'int' or $column_type == 'serial'){
                $default_field_handler = 'chado_views_handler_field_numeric';
             }
-            elseif(preg_match("/character varying/",$column_type) or $column_type == 'char' or $column_type == 'text'){
+            elseif(preg_match("/character varying/",$column_type) or $column_type == 'char' or $column_type == 'text' or $column_type = 'varchar'){
                $default_field_handler = 'chado_views_handler_field';
             }
             elseif($column_type == 'boolean'){
@@ -831,9 +847,14 @@ function tripal_views_integration_form_submit($form, &$form_state){
       $left_column = $form_state['values']["fields_join_column_$table_id-$i"];
 
       if($left_column){
+         if($mview_id){
+            $base_table = $mview->mv_table;
+         } else {
+            $base_table = $table_name;
+         }
          $view_join_record = array(
            'setup_id' => $tripal_views_record['setup_id'],
-           'base_table' => $mview->mv_table,
+           'base_table' => $base_table,
            'base_field' => $key,
            'left_table' => $left_table,
            'left_field' => $left_column,