Browse Source

Fixed a major problem in the feature API where functions from the old theme file got copied over incorrectly to the API

Stephen Ficklin 6 years ago
parent
commit
d314f44d56

+ 87 - 2
legacy/tripal_feature/theme/tripal_feature.theme.inc

@@ -53,7 +53,7 @@ function tripal_feature_load_featureloc_sequences($feature_id, $featurelocs) {
 
   // get the list of relationships (including any aggregators) and iterate
   // through each one to find information needed to color-code the reference sequence
-  $relationships = _tripal_feature_get_aggregate_relationships($feature_id);
+  $relationships = tripal_feature_get_aggregate_relationships($feature_id);
   if (!$relationships) {
     return array();
   }
@@ -243,7 +243,7 @@ function tripal_feature_load_featurelocs($feature_id, $side = 'as_parent', $aggr
   if ($aggregate and strcmp($side, 'as_parent')==0) {
     // get the relationships for this feature without substituting any children
     // for the parent. We want all relationships
-    $relationships = _tripal_feature_get_aggregate_relationships($feature_id, 0);
+    $relationships = tripal_feature_get_aggregate_relationships($feature_id, 0);
     foreach ($relationships as $rindex => $rel) {
       // get the featurelocs for each of the relationship features
       $rel_featurelocs = tripal_feature_load_featurelocs($rel->subject_id, 'as_child', 0);
@@ -945,3 +945,88 @@ function tripal_feature_preprocess_tripal_feature_bar_chart_type_organism_summar
   // it in our js script.
   drupal_add_js(array('tripalFeature' => array('admin' => $vars['chart_details'])), 'setting');
 }
+
+
+/**
+ * Get features related to the current feature to a given depth. Recursive function.
+ *
+ * @param $feature_id
+ * @param $substitute
+ * @param $levels
+ * @param $base_type_id
+ * @param $depth
+ *
+ */
+function tripal_feature_get_aggregate_relationships($feature_id, $substitute=1,
+  $levels=0, $base_type_id=NULL, $depth=0) {
+    
+    // we only want to recurse to as many levels deep as indicated by the
+    // $levels variable, but only if this variable is > 0. If 0 then we
+    // recurse until we reach the end of the relationships tree.
+    if ($levels > 0 and $levels == $depth) {
+      return NULL;
+    }
+    
+    // first get the relationships for this feature
+    return tripal_feature_load_relationships($feature_id, 'as_object');
+    
+}
+
+/**
+ * Get the relationships for a feature.
+ *
+ * @param $feature_id
+ *   The feature to get relationships for
+ * @param $side
+ *   The side of the relationship this feature is (ie: 'as_subject' or
+ *   'as_object')
+ *
+ *
+ */
+function tripal_feature_load_relationships($feature_id, $side = 'as_subject') {
+  // Get the relationships for this feature.  The query below is used for both
+  // querying the object and subject relationships
+  $sql = "
+    SELECT
+      FS.name as subject_name, FS.uniquename as subject_uniquename,
+      CVTS.name as subject_type, CVTS.cvterm_id as subject_type_id,
+      FR.subject_id, FR.type_id as relationship_type_id, FR.object_id, FR.rank,
+      CVT.name as rel_type,
+      FO.name as object_name, FO.uniquename as object_uniquename,
+      CVTO.name as object_type, CVTO.cvterm_id as object_type_id
+    FROM {feature_relationship} FR
+     INNER JOIN {cvterm} CVT  ON FR.type_id    = CVT.cvterm_id
+     INNER JOIN {feature} FS  ON FS.feature_id = FR.subject_id
+     INNER JOIN {feature} FO  ON FO.feature_id = FR.object_id
+     INNER JOIN {cvterm} CVTO ON FO.type_id    = CVTO.cvterm_id
+     INNER JOIN {cvterm} CVTS ON FS.type_id    = CVTS.cvterm_id
+  ";
+  if (strcmp($side, 'as_object')==0) {
+    $sql .= " WHERE FR.object_id = :feature_id";
+  }
+  if (strcmp($side, 'as_subject')==0) {
+    $sql .= " WHERE FR.subject_id = :feature_id";
+  }
+  $sql .= " ORDER BY FR.rank";
+  
+  // Get the relationships.
+  $results = chado_query($sql, array(':feature_id' => $feature_id));
+  
+  // Iterate through the relationships, put these in an array and add
+  // in the Drupal node id if one exists.
+  $i=0;
+  $nodesql = "SELECT nid FROM {chado_feature} WHERE feature_id = :feature_id";
+  $relationships = array();
+  while ($rel = $results->fetchObject()) {
+    $node = db_query($nodesql, array(':feature_id' => $rel->subject_id))->fetchObject();
+    if ($node) {
+      $rel->subject_nid = $node->nid;
+    }
+    $node = db_query($nodesql, array(':feature_id' => $rel->object_id))->fetchObject();
+    if ($node) {
+      $rel->object_nid = $node->nid;
+    }
+    $relationships[$i++] = $rel;
+  }
+  return $relationships;
+}

+ 28 - 625
tripal_chado/api/modules/tripal_chado.feature.api.inc

@@ -139,23 +139,23 @@ function chado_reverse_compliment_sequence($sequence) {
 function chado_get_feature_sequences($feature, $options) {
 
   // Default values for finding the feature.
-  $feature_id         = array_key_exists('feature_id', $feature)     ? $feature['feature_id']     : 0;
-  $parent_id          = array_key_exists('parent_id', $feature)      ? $feature['parent_id']      : 0;
-  $featureloc_id      = array_key_exists('featureloc_id', $feature)  ? $feature['featureloc_id']  : 0;
-  $feature_name       = array_key_exists('name', $feature)           ? $feature['name']           : '';
+  $feature_id = array_key_exists('feature_id', $feature) ? $feature['feature_id']     : 0;
+  $parent_id = array_key_exists('parent_id', $feature) ? $feature['parent_id']      : 0;
+  $featureloc_id = array_key_exists('featureloc_id', $feature) ? $feature['featureloc_id']  : 0;
+  $feature_name = array_key_exists('name', $feature) ? $feature['name']           : '';
 
   // Default values for building the sequence.
-  $num_bases_per_line = array_key_exists('width', $options)              ? $options['width']              : 50;
+  $num_bases_per_line = array_key_exists('width', $options) ? $options['width']              : 50;
   $derive_from_parent = array_key_exists('derive_from_parent', $options) ? $options['derive_from_parent'] : 0;
-  $aggregate          = array_key_exists('aggregate', $options)          ? $options['aggregate']          : 0;
-  $upstream           = array_key_exists('upstream', $options)           ? $options['upstream']           : 0;
-  $downstream         = array_key_exists('downstream', $options)         ? $options['downstream']         : 0;
-  $sub_features       = array_key_exists('sub_feature_types', $options)  ? $options['sub_feature_types']  : array();
-  $relationship       = array_key_exists('relationship_type', $options)  ? $options['relationship_type']  : '';
-  $rel_part           = array_key_exists('relationship_part', $options)  ? $options['relationship_part']  : '';
-  $is_html            = array_key_exists('is_html', $options)            ? $options['is_html']            : 0;
-  $is_txt             = array_key_exists('is_txt', $options)             ? $options['is_txt']             : 0;
-  $is_raw             = array_key_exists('is_raw', $options)             ? $options['is_raw']             : 1;
+  $aggregate = array_key_exists('aggregate', $options) ? $options['aggregate']          : 0;
+  $upstream = array_key_exists('upstream', $options) ? $options['upstream']           : 0;
+  $downstream = array_key_exists('downstream', $options) ? $options['downstream']         : 0;
+  $sub_features = array_key_exists('sub_feature_types', $options) ? $options['sub_feature_types']  : array();
+  $relationship = array_key_exists('relationship_type', $options) ? $options['relationship_type']  : '';
+  $rel_part = array_key_exists('relationship_part', $options) ? $options['relationship_part']  : '';
+  $is_html = array_key_exists('is_html', $options) ? $options['is_html']            : 0;
+  $is_txt = array_key_exists('is_txt', $options) ? $options['is_txt']             : 0;
+  $is_raw = array_key_exists('is_raw', $options) ? $options['is_raw']             : 1;
 
   if (!$upstream) {
     $upstream = 0;
@@ -591,21 +591,21 @@ function chado_get_feature_sequences($feature, $options) {
 function chado_get_bulk_feature_sequences($options) {
 
   // Default values for building the sequence
-  $org_commonname     = array_key_exists('org_commonname', $options)     ? $options['org_commonname']    : '';
-  $genus              = array_key_exists('genus', $options)              ? $options['genus']             : '';
-  $species            = array_key_exists('species', $options)            ? $options['species']           : '';
-  $analysis_name      = array_key_exists('analysis_name', $options)      ? $options['analysis_name']     : '';
-  $type               = array_key_exists('type', $options)               ? $options['type']              : '';
-  $feature_name       = array_key_exists('feature_name', $options)       ? $options['feature_name']      : '';
-  $feature_uname      = array_key_exists('feature_uname', $options)      ? $options['feature_uname']     : '';
+  $org_commonname = array_key_exists('org_commonname', $options) ? $options['org_commonname']    : '';
+  $genus = array_key_exists('genus', $options) ? $options['genus']             : '';
+  $species = array_key_exists('species', $options) ? $options['species']           : '';
+  $analysis_name = array_key_exists('analysis_name', $options) ? $options['analysis_name']     : '';
+  $type = array_key_exists('type', $options) ? $options['type']              : '';
+  $feature_name = array_key_exists('feature_name', $options) ? $options['feature_name']      : '';
+  $feature_uname = array_key_exists('feature_uname', $options) ? $options['feature_uname']     : '';
   $derive_from_parent = array_key_exists('derive_from_parent', $options) ? $options['derive_from_parent'] : 0;
-  $aggregate          = array_key_exists('aggregate', $options)          ? $options['aggregate']          : 0;
-  $sub_features       = array_key_exists('sub_feature_types', $options)  ? $options['sub_feature_types']  : array();
-  $relationship       = array_key_exists('relationship_type', $options)  ? $options['relationship_type']  : '';
-  $rel_part           = array_key_exists('relationship_part', $options)  ? $options['relationship_part']  : '';
-  $num_bases_per_line = array_key_exists('width', $options)              ? $options['width']              : 50;
-  $upstream           = array_key_exists('upstream', $options)           ? $options['upstream']       : 0;
-  $downstream         = array_key_exists('downstream', $options)         ? $options['downstream']     : 0;
+  $aggregate = array_key_exists('aggregate', $options) ? $options['aggregate']          : 0;
+  $sub_features = array_key_exists('sub_feature_types', $options) ? $options['sub_feature_types']  : array();
+  $relationship = array_key_exists('relationship_type', $options) ? $options['relationship_type']  : '';
+  $rel_part = array_key_exists('relationship_part', $options) ? $options['relationship_part']  : '';
+  $num_bases_per_line = array_key_exists('width', $options) ? $options['width']              : 50;
+  $upstream = array_key_exists('upstream', $options) ? $options['upstream']       : 0;
+  $downstream = array_key_exists('downstream', $options) ? $options['downstream']     : 0;
 
   if (!$type and !$feature_name and !$genus) {
     print "Please provide a type, feature name or genus\n";
@@ -786,600 +786,3 @@ function chado_get_location_string($featureloc) {
   return $featureloc->srcfeature_id->name . ":" . ($featureloc->fmin + 1) . ".." . $featureloc->fmax .  $strand;
 }
 
-
-/**
- * Quickly retrieves relationships for a feature.
- *
- * Using the chado_expand_var function to retrieve a set
- * of relationships can be very slow, especialy if there are many relationships.
- * This function is intended to help speed up the retrieval of relationships
- * by only retrieving the base information for the relationship and returning
- * an array.
- *
- * @param $feature
- *   The feature object
-
- * @return
- *   An array with two objects
- *
- * @ingroup tripal_feature_api
- */
-function chado_get_feature_relationships($feature) {
-  // Expand the feature object to include the feature relationships.
-  $options = array(
-    'return_array' => 1,
-    'order_by' => array('rank' => 'ASC'),
-    // We don't want to fully recurse we only need information about the
-    // relationship type and the object and subject features (including feature 
-    // type and organism).
-    'include_fk' => array(
-      'type_id' => 1,
-      'object_id' => array(
-        'type_id' => 1,
-        'organism_id' => 1
-      ),
-      'subject_id'  => array(
-        'type_id' => 1,
-        'organism_id' => 1
-      ),
-    ),
-  );
-  $feature = chado_expand_var($feature, 'table', 'feature_relationship', $options);
-
-  // Get the subject relationships.
-  $srelationships = $feature->feature_relationship->subject_id;
-  $orelationships = $feature->feature_relationship->object_id;
-
-
-  // Get alignment as child. The $feature->featureloc element
-  // is already populated from the alignment preprocess function.
-  $options = array(
-    'return_array' => 1,
-    'include_fk' => array(
-      'srcfeature_id' => 1,
-      'feature_id' => 1,
-    ),
-  );
-  $feature = chado_expand_var($feature, 'table', 'featureloc', $options);
-  $cfeaturelocs = $feature->featureloc->feature_id;
-  if (!$cfeaturelocs) {
-    $cfeaturelocs = array();
-  }
-  elseif (!is_array($cfeaturelocs)) {
-    $cfeaturelocs = array($cfeaturelocs);
-  }
-
-  // Prepare the SQL statement to get the featureloc for the
-  // feature in the relationships.
-  $flrels_sql = "
-    SELECT
-      FL.featureloc_id, F.name as srcfeature_name, FL.srcfeature_id,
-      FL.feature_id, FL.fmin, FL.fmax, FL.strand, FL.phase
-    FROM {featureloc} FL
-      INNER JOIN {feature} F ON F.feature_id = FL.srcfeature_id
-    WHERE FL.feature_id = :feature_id and FL.srcfeature_id = :srcfeature_id
-  ";
-
-  // Combine both object and subject relationshisp into a single array.
-  $relationships = array();
-  $relationships['object'] = array();
-  $relationships['subject'] = array();
-
-  // Iterate through the object relationships.
-  if ($orelationships) {
-    foreach ($orelationships as $relationship) {
-      $rel = new stdClass();
-      // Get locations where the child feature and this feature overlap with the
-      // same landmark feature.
-      $rel->child_featurelocs = array();
-      foreach ($cfeaturelocs as $featureloc) {
-        $res = chado_query($flrels_sql, array(':feature_id' => $relationship->subject_id->feature_id, ':srcfeature_id' => $featureloc->srcfeature_id->feature_id));
-        while ($loc = $res->fetchObject()) {
-          // Add in the node id of the src feature if it exists and save this 
-          // location.
-          if (property_exists($featureloc->srcfeature_id, 'nid')) {
-            $loc->nid = $featureloc->srcfeature_id->nid;
-          }
-          $rel->child_featurelocs[] = $loc;
-        }
-      }
-      $rel->record = $relationship;
-
-      // Get the relationship and child types.
-      $rel_type = t(preg_replace('/_/', " ", $relationship->type_id->name));
-      $child_type = $relationship->subject_id->type_id->name;
-
-      // get the node id of the subject
-//       $sql = "SELECT nid FROM {chado_feature} WHERE feature_id = :feature_id";
-//       $n = db_query($sql, array(':feature_id' => $relationship->subject_id->feature_id))->fetchObject();
-//       if ($n) {
-//         $rel->record->nid = $n->nid;
-//       }
-
-      if (!array_key_exists($rel_type, $relationships['object'])) {
-        $relationships['object'][$rel_type] = array();
-      }
-      if (!array_key_exists($child_type, $relationships['object'][$rel_type])) {
-        $relationships['object'][$rel_type][$child_type] = array();
-      }
-      $relationships['object'][$rel_type][$child_type][] = $rel;
-    }
-  }
-
-  // Now add in the subject relationships.
-  if ($srelationships) {
-    foreach ($srelationships as $relationship) {
-      $rel = new stdClass();
-      // Get locations where this feature overlaps with the parent.
-      $rel->parent_featurelocs = array();
-      foreach ($cfeaturelocs as $featureloc) {
-        $res = chado_query($flrels_sql, array(':feature_id' => $relationship->object_id->feature_id, ':srcfeature_id' => $featureloc->srcfeature_id->feature_id));
-        while ($loc = $res->fetchObject()) {
-          // Add in the node id of the src feature if it exists and save this 
-          // location.
-          if (property_exists($featureloc->srcfeature_id, 'nid')) {
-            $loc->nid = $featureloc->srcfeature_id->nid;
-          }
-          $rel->parent_featurelocs[] = $loc;
-        }
-      }
-      $rel->record = $relationship;
-      $rel_type = t(preg_replace('/_/', " ", $relationship->type_id->name));
-      $parent_type = $relationship->object_id->type_id->name;
-
-//       // get the node id of the subject
-//       $sql = "SELECT nid FROM {chado_feature} WHERE feature_id = :feature_id";
-//       $n = db_query($sql, array(':feature_id' => $relationship->object_id->feature_id))->fetchObject();
-//       if ($n) {
-//         $rel->record->nid = $n->nid;
-//       }
-
-      if (!array_key_exists($rel_type, $relationships['subject'])) {
-        $relationships['subject'][$rel_type] = array();
-      }
-      if (!array_key_exists($parent_type, $relationships['subject'][$rel_type])) {
-        $relationships['subject'][$rel_type][$parent_type] = array();
-      }
-      $relationships['subject'][$rel_type][$parent_type][] = $rel;
-    }
-  }
-  return $relationships;
-}
-
-/**
- *
- * @param unknown $feature_id
- * @param unknown $featurelocs
- * @return multitype:|Ambigous <multitype:, an>
- */
-function chado_get_featureloc_sequences($feature_id, $featurelocs) {
-
-  // if we don't have any featurelocs then no point in continuing
-  if (!$featurelocs) {
-    return array();
-  }
-
-  // Get the list of relationships (including any aggregators) and iterate
-  // through each one to find information needed to color-code the reference 
-  // sequence.
-  $relationships = _chado_feature_get_aggregate_relationships($feature_id);
-  if (!$relationships) {
-    return array();
-  }
-
-
-  // Iterate through each of the realtionships features and get their
-  // locations.
-  foreach ($relationships as $rindex => $rel) {
-    // Get the featurelocs for each of the relationship features.
-    $rel_featurelocs = chado_get_featurelocs($rel->subject_id, 'as_child', 0);
-    foreach ($rel_featurelocs as $rfindex => $rel_featureloc) {
-      // Keep track of this unique source feature.
-      $src = $rel_featureloc->src_feature_id . "-" . $rel_featureloc->src_cvterm_id;
-
-      // Copy over the results to the relationship object.  Since there can
-      // be more than one feature location for each relationship feature we
-      // use the '$src' variable to keep track of these.
-      $rel->featurelocs = new stdClass();
-      $rel->featurelocs->$src = new stdClass();
-      $rel->featurelocs->$src->src_uniquename = $rel_featureloc->src_uniquename;
-      $rel->featurelocs->$src->src_cvterm_id  = $rel_featureloc->src_cvterm_id;
-      $rel->featurelocs->$src->src_cvname     = $rel_featureloc->src_cvname;
-      $rel->featurelocs->$src->fmin           = $rel_featureloc->fmin;
-      $rel->featurelocs->$src->fmax           = $rel_featureloc->fmax;
-      $rel->featurelocs->$src->src_name       = $rel_featureloc->src_name;
-
-      // keep track of the individual parts for each relationship
-      $start = $rel->featurelocs->$src->fmin;
-      $end   = $rel->featurelocs->$src->fmax;
-      $type  = $rel->subject_type;
-      $rel_locs[$src]['parts'][$start][$type]['start'] = $start;
-      $rel_locs[$src]['parts'][$start][$type]['end']   = $end;
-      $rel_locs[$src]['parts'][$start][$type]['type']  = $type;
-    }
-  }
-
-  // The featurelocs array provided to the function contains the locations
-  // where this feature is found.   We want to get the sequence for each
-  // location and then annotate it with the parts found from the relationships
-  // locations determiend above.
-  $floc_sequences = array();
-  foreach ($featurelocs as $featureloc) {
-
-    // build the src name so we can keep track of the different parts for each feature
-    $src = $featureloc->srcfeature_id->feature_id . "-" . $featureloc->srcfeature_id->type_id->cvterm_id;
-
-    // orient the parts to the beginning of the feature sequence
-    if (!empty($rel_locs[$src]['parts'])) {
-      $parts = $rel_locs[$src]['parts'];
-      $rparts = array();  // we will fill this up if we're on the reverse strand
-
-      foreach ($parts as $start => $types) {
-        foreach ($types as $type_name => $type) {
-          if ($featureloc->strand >= 0) {
-            // this is on the forward strand.  We need to convert the start on the src feature to the
-            // start on this feature's sequence
-            $parts[$start][$type_name]['start'] = $parts[$start][$type_name]['start'] - $featureloc->fmin;
-            $parts[$start][$type_name]['end']   = $parts[$start][$type_name]['end'] - $featureloc->fmin;
-            $parts[$start][$type_name]['type']  = $type_name;
-          }
-          else {
-            // this is on the reverse strand.  We need to swap the start and stop and calculate from the
-            // begining of the reverse sequence
-            $size = ($featureloc->fmax - $featureloc->fmin);
-            $start_orig = $parts[$start][$type_name]['start'];
-            $end_orig = $parts[$start][$type_name]['end'];
-            $new_start = $size - ($end_orig - $featureloc->fmin);
-            $new_end = $size - ($start_orig - $featureloc->fmin);
-
-            $rparts[$new_start][$type_name]['start'] = $new_start;
-            $rparts[$new_start][$type_name]['end']   = $new_end;
-            $rparts[$new_start][$type_name]['type']  = $type_name;
-          }
-        }
-      }
-
-      // now sort the parts
-      // if we're on the reverse strand we need to resort
-      if ($featureloc->strand >= 0) {
-        usort($parts, '_chado_feature__residues_sort_rel_parts_by_start');
-      }
-      else {
-        usort($rparts, '_chado_feature__residues_sort_rel_parts_by_start');
-        $parts = $rparts;
-      }
-
-      $floc_sequences[$src]['id'] = $src;
-      $floc_sequences[$src]['type'] = $featureloc->feature_id->type_id->name;
-      $args = array(':feature_id' => $featureloc->srcfeature_id->feature_id);
-      $start = $featureloc->fmin + 1;
-      $size = $featureloc->fmax - $featureloc->fmin;
-
-      // TODO: fix the hard coded $start and $size
-      // the $start and $size variables are hard-coded in the SQL statement
-      // because the db_query function places quotes around all placeholders
-      // (e.g. :start & :size) and screws up the substring function
-      $sql = "
-        SELECT substring(residues from $start for $size) as residues
-        FROM {feature}
-        WHERE feature_id = :feature_id
-      ";
-      $sequence = chado_query($sql, $args)->fetchObject();
-      $residues = $sequence->residues;
-      if ($featureloc->strand < 0) {
-        $residues = chado_reverse_compliment_sequence($residues);
-      }
-      $strand = '.';
-      if ($featureloc->strand == 1) {
-        $strand = '+';
-      }
-      elseif ($featureloc->strand == -1) {
-        $strand = '-';
-      }
-      $floc_sequences[$src]['location'] = chado_get_location_string($featureloc);
-      $floc_sequences[$src]['defline'] = chado_get_fasta_defline($featureloc->feature_id, '', $featureloc, '', strlen($residues));
-      $floc_sequences[$src]['featureloc'] = $featureloc;
-      $floc_sequences[$src]['residues'] = $residues;
-      //$floc_sequences[$src]['formatted_seq'] =  tripal_feature_color_sequence($residues, $parts, $floc_sequences[$src]['defline']);
-    }
-  }
-  return $floc_sequences;
-}
-
-/**
- * Get features related to the current feature to a given depth. Recursive function.
- *
- * @param $feature_id
- * @param $substitute
- * @param $levels
- * @param $base_type_id
- * @param $depth
- *
- */
-function chado_get_aggregate_feature_relationships($feature_id, $substitute=1,
-  $levels=0, $base_type_id=NULL, $depth=0) {
-
-  // we only want to recurse to as many levels deep as indicated by the
-  // $levels variable, but only if this variable is > 0. If 0 then we
-  // recurse until we reach the end of the relationships tree.
-  if ($levels > 0 and $levels == $depth) {
-    return NULL;
-  }
-
-  // first get the relationships for this feature
-  return chado_get_feature_relationships($feature_id, 'as_object');
-
-}
-
-/**
- * Get the relationships for a feature.
- *
- * @param $feature_id
- *   The feature to get relationships for
- * @param $side
- *   The side of the relationship this feature is (ie: 'as_subject' or 'as_object')
- *
- */
-function chado_get_feature_relationships($feature_id, $side = 'as_subject') {
-
-  $feature = chado_generate_var('feature', array('feature_id' => $feature_id));
-
-  // get the relationships for this feature.  The query below is used for both
-  // querying the object and subject relationships
-  $sql = "
-    SELECT
-    FS.name as subject_name, FS.uniquename as subject_uniquename,
-      CVTS.name as subject_type, CVTS.cvterm_id as subject_type_id,
-      FR.subject_id, FR.type_id as relationship_type_id, FR.object_id, FR.rank,
-      CVT.name as rel_type,
-      FO.name as object_name, FO.uniquename as object_uniquename,
-      CVTO.name as object_type, CVTO.cvterm_id as object_type_id
-    FROM {feature_relationship} FR
-     INNER JOIN {cvterm} CVT  ON FR.type_id    = CVT.cvterm_id
-     INNER JOIN {feature} FS  ON FS.feature_id = FR.subject_id
-     INNER JOIN {feature} FO  ON FO.feature_id = FR.object_id
-     INNER JOIN {cvterm} CVTO ON FO.type_id    = CVTO.cvterm_id
-     INNER JOIN {cvterm} CVTS ON FS.type_id    = CVTS.cvterm_id
-  ";
-  if (strcmp($side, 'as_object')==0) {
-    $sql .= " WHERE FR.object_id = :feature_id";
-  }
-  if (strcmp($side, 'as_subject')==0) {
-    $sql .= " WHERE FR.subject_id = :feature_id";
-  }
-  $sql .= " ORDER BY FR.rank";
-
-  // get the relationships
-  $results = chado_query($sql, array(':feature_id' => $feature_id));
-
-  // Get the bundle for this feature type, if one exists.
-  $term = tripal_load_term_entity(array(
-    'vocabulary' => $feature->type_id->dbxref_id->db_id->name,
-    'accession' => $feature->type_id->dbxref_id->accession,
-  ));
-  $bundle = tripal_load_bundle_entity(array('term_id' => $term->id));
-
-  // iterate through the relationships, put these in an array and add
-  // in the Drupal node id if one exists
-  $i=0;
-  $relationships = array();
-  while ($rel = $results->fetchObject()) {
-
-    $entity = chado_get_record_entity_by_bundle($bundle, $rel->subject_id);
-    if ($entity) {
-      $rel->subject_entity_id = $entity->entity_id;
-    }
-    $entity = chado_get_record_entity_by_bundle($bundle, $rel->object_id);
-    if ($entity) {
-      $rel->object_entity_id = $entity->entity_id;
-    }
-    $relationships[$i++] = $rel;
-  }
-  return $relationships;
-}
-
-/**
- * Load the locations for a given feature.
- *
- * @param $feature_id
- *   The feature to look up locations for.
- * @param $side
- *   Whether the feature is the scrfeature, 'as_parent', or feature, 'as_child'.
- * @param $aggregate
- *   Whether or not to get the locations for related features.
- *
- * @ingroup tripal_feature_api
- */
-function chado_get_featurelocs($feature_id, $side = 'as_parent', $aggregate = 1) {
-
-  $sql = "
-    SELECT
-       F.name, F.feature_id, F.uniquename,
-       FS.name as src_name, FS.feature_id as src_feature_id, FS.uniquename as src_uniquename,
-       CVT.name as cvname, CVT.cvterm_id,
-       CVTS.name as src_cvname, CVTS.cvterm_id as src_cvterm_id,
-       FL.fmin, FL.fmax, FL.is_fmin_partial, FL.is_fmax_partial,FL.strand, FL.phase
-     FROM {featureloc} FL
-       INNER JOIN {feature} F   ON FL.feature_id = F.feature_id
-       INNER JOIN {feature} FS  ON FS.feature_id = FL.srcfeature_id
-       INNER JOIN {cvterm} CVT  ON F.type_id     = CVT.cvterm_id
-       INNER JOIN {cvterm} CVTS ON FS.type_id    = CVTS.cvterm_id
-       ";
-  if (strcmp($side, 'as_parent')==0) {
-    $sql .= "WHERE FL.srcfeature_id = :feature_id ";
-  }
-  if (strcmp($side, 'as_child')==0) {
-    $sql .= "WHERE FL.feature_id = :feature_id ";
-  }
-
-  $flresults = chado_query($sql, array(':feature_id' => $feature_id));
-
-  // Copy the results into an array.
-  $i=0;
-  $featurelocs = array();
-  while ($loc = $flresults->fetchObject()) {
-    // If a drupal entity exists for this feature then add the nid to the
-    // results object.
-
-
-    // Get the bundle for this feature type, if one exists.
-    $ffeature = chado_generate_var('feature', array('feature_id' => $loc->feature_id));
-    $sfeature = chado_generate_var('feature', array('feature_id' => $loc->src_feature_id));
-    $fterm = tripal_load_term_entity(array(
-      'vocabulary' => $ffeature->type_id->dbxref_id->db_id->name,
-      'accession' => $ffeature->type_id->dbxref_id->accession,
-    ));
-    $sterm = tripal_load_term_entity(array(
-      'vocabulary' => $sfeature->type_id->dbxref_id->db_id->name,
-      'accession' => $sfeature->type_id->dbxref_id->accession,
-    ));
-
-    if($fterm) {
-      $fbundle = tripal_load_bundle_entity(array('term_id' => $fterm->id));
-      $loc->feid = chado_get_record_entity_by_bundle($fbundle, $loc->feature_id);
-    }
-    if ($sterm) {
-      $sbundle = tripal_load_bundle_entity(array('term_id' => $sterm->id));
-      $loc->seid = chado_get_record_entity_by_bundle($sbundle, $loc->src_feature_id);
-    }
-    // Add the result to the array.
-    $featurelocs[$i++] = $loc;
-  }
-
-  // Add the relationship feature locs if aggregate is turned on.
-  if ($aggregate and strcmp($side, 'as_parent')==0) {
-  // Get the relationships for this feature without substituting any children
-  // for the parent. We want all relationships.
-  $relationships = _chado_feature_get_aggregate_relationships($feature_id, 0);
-  foreach ($relationships as $rindex => $rel) {
-    // Get the featurelocs for each of the relationship features.
-    $rel_featurelocs = tripal_feature_load_featurelocs($rel->subject_id, 'as_child', 0);
-      foreach ($rel_featurelocs as $findex => $rfloc) {
-        $featurelocs[$i++] = $rfloc;
-      }
-    }
-  }
-
-  usort($featurelocs, '_chado_feature__residues_sort_locations');
-  return $featurelocs;
-}
-
-/**
- * Get features related to the current feature to a given depth. 
- * Recursive function.
- *
- * @param $feature_id
- * @param $substitute
- * @param $levels
- * @param $base_type_id
- * @param $depth
- * 
- *
- */
-function _chado_feature_get_aggregate_relationships($feature_id, $substitute=1,
-    $levels=0, $base_type_id=NULL, $depth=0) {
-
-  // we only want to recurse to as many levels deep as indicated by the
-  // $levels variable, but only if this variable is > 0. If 0 then we
-  // recurse until we reach the end of the relationships tree.
-  if ($levels > 0 and $levels == $depth) {
-    return NULL;
-  }
-
-  // first get the relationships for this feature
-  return _chado_feature_load_relationships($feature_id, 'as_object');
-
-}
-
-/**
- * Get the relationships for a feature.
- *
- * @param $feature_id
- *   The feature to get relationships for
- * @param $side
- *   The side of the relationship this feature is (ie: 'as_subject' or 
- *   'as_object')
- * 
- *
- */
-function _chado_feature_load_relationships($feature_id, $side = 'as_subject') {
-  // Get the relationships for this feature.  The query below is used for both
-  // querying the object and subject relationships
-  $sql = "
-    SELECT
-      FS.name as subject_name, FS.uniquename as subject_uniquename,
-      CVTS.name as subject_type, CVTS.cvterm_id as subject_type_id,
-      FR.subject_id, FR.type_id as relationship_type_id, FR.object_id, FR.rank,
-      CVT.name as rel_type,
-      FO.name as object_name, FO.uniquename as object_uniquename,
-      CVTO.name as object_type, CVTO.cvterm_id as object_type_id
-    FROM {feature_relationship} FR
-     INNER JOIN {cvterm} CVT  ON FR.type_id    = CVT.cvterm_id
-     INNER JOIN {feature} FS  ON FS.feature_id = FR.subject_id
-     INNER JOIN {feature} FO  ON FO.feature_id = FR.object_id
-     INNER JOIN {cvterm} CVTO ON FO.type_id    = CVTO.cvterm_id
-     INNER JOIN {cvterm} CVTS ON FS.type_id    = CVTS.cvterm_id
-  ";
-  if (strcmp($side, 'as_object')==0) {
-    $sql .= " WHERE FR.object_id = :feature_id";
-  }
-  if (strcmp($side, 'as_subject')==0) {
-    $sql .= " WHERE FR.subject_id = :feature_id";
-  }
-  $sql .= " ORDER BY FR.rank";
-
-  // Get the relationships.
-  $results = chado_query($sql, array(':feature_id' => $feature_id));
-
-  // Iterate through the relationships, put these in an array and add
-  // in the Drupal node id if one exists.
-  $i=0;
-  $nodesql = "SELECT nid FROM {chado_feature} WHERE feature_id = :feature_id";
-  $relationships = array();
-  while ($rel = $results->fetchObject()) {
-    $node = db_query($nodesql, array(':feature_id' => $rel->subject_id))->fetchObject();
-    if ($node) {
-      $rel->subject_nid = $node->nid;
-    }
-    $node = db_query($nodesql, array(':feature_id' => $rel->object_id))->fetchObject();
-    if ($node) {
-      $rel->object_nid = $node->nid;
-    }
-    $relationships[$i++] = $rel;
-  }
-  return $relationships;
-}
-/**
- * Used to sort the list of relationship parts by start position.
- * 
- * @param $a
- * @param $b
- * 
- */
-function _chado_feature__residues_sort_rel_parts_by_start($a, $b) {
-  foreach ($a as $type_name => $details) {
-    $astart = $a[$type_name]['start'];
-    break;
-  }
-  foreach ($b as $type_name => $details) {
-    $bstart = $b[$type_name]['start'];
-    break;
-  }
-  return strnatcmp($astart, $bstart);
-}
-/**
- * Used to sort the feature locs by start position.
- *
- * @param $a
- *   One featureloc record (as an object).
- * @param $b
- *   The other featureloc record (as an object).
- *
- * @return
- *   Which feature location comes first.
- *
- */
-function _chado_feature__residues_sort_locations($a, $b) {
-  return strnatcmp($a->fmin, $b->fmin);
-}
-