Browse Source

Fixed bug in paging of a collection in web services. Added order capability to filtering in WS

Stephen Ficklin 8 years ago
parent
commit
00618a17dd

+ 15 - 3
tripal_chado/includes/TripalFields/ChadoField.inc

@@ -48,7 +48,7 @@ class ChadoField extends TripalField {
   public static $module = 'tripal_chado';
 
   /**
-   * A query function used to find records that match a given condition.
+   * Used to filter records that match a given condition.
    *
    * Entities can be filtered using the fields.  This function should be
    * implemented if the field  supports filtering.  To provide filtering,
@@ -65,13 +65,25 @@ class ChadoField extends TripalField {
    *   nor ordering or group by.
    * - You may join to materialized views if need be to help speed queries.
    *
+   * @param $query
+   *   A SelectQuery object.
    * @param $condition
    *   The field specific condition as set in the TripalFieldQuery object.
+   */
+  public function query($query, $condition) {
+
+  }
+
+  /**
+   * Used to sort records that have been filtered.
+   *
    * @param $query
    *   A SelectQuery object.
+   * @param $order
+   *   The field ordering as set in the TripalFieldQuery object.  This function
+   *   should handle the ordering request as specified by this object.
    */
-  public function query($condition, &$query) {
+  public function queryOrder($query, $order) {
 
   }
-
 }

+ 22 - 1
tripal_chado/includes/TripalFields/obi__organism/obi__organism.inc

@@ -191,7 +191,7 @@ class obi__organism extends ChadoField {
   /**
    * @see ChadoField::query()
    */
-  public function query($condition, &$query) {
+  public function query($query, $condition) {
     $alias = $this->field['field_name'];
     $query->join('organism', $alias, "base.organism_id = $alias.organism_id");
 
@@ -202,4 +202,25 @@ class obi__organism extends ChadoField {
       $query->condition("$alias.genus", $condition['value']);
     }
   }
+
+  /**
+   * @see ChadoField::queryOrder()
+   */
+  public function queryOrder($query, $order) {
+
+    // If the table hasn't yet been joined then add it.
+    $joins = $query->getTables();
+    if (!in_array($this->field['field_name'], $joins)) {
+      $alias = $this->field['field_name'];
+      $query->join('organism', $alias, "base.organism_id = $alias.organism_id");
+    }
+
+    // Now perform the sort.
+    if ($order['column'] == 'organism.species') {
+      $query->orderBy("$alias.genus", $order['direction']);
+    }
+    if ($order['column'] == 'organism.genus') {
+      $query->orderBy("$alias.species", $order['direction']);
+    }
+  }
 }

+ 9 - 1
tripal_chado/includes/TripalFields/sbo__relationship/sbo__relationship.inc

@@ -298,7 +298,8 @@ class sbo__relationship extends ChadoField {
   /**
    * @see ChadoField::query()
    */
-  public function query($condition, &$query) {
+  public function query($query, $condition) {
+
     $alias = $this->field['field_name'];
     $chado_table = $this->instance['settings']['chado_table'];
     $base_table = $this->instance['settings']['base_table'];
@@ -780,4 +781,11 @@ class sbo__relationship extends ChadoField {
   }
 
 
+
+  /**
+   * @see ChadoField::queryOrder()
+   */
+  public function queryOrder($query, $order) {
+
+  }
 }

+ 40 - 13
tripal_chado/includes/tripal_chado.field_storage.inc

@@ -410,6 +410,7 @@ function tripal_chado_field_storage_query($query) {
   // a chado_select_record compatible set of filters.
   foreach ($query->fieldConditions as $index => $condition) {
     $field = $condition['field'];
+    $field_name = $field['field_name'];
     $field_type = $field['type'];
 
     // Skip conditions that don't belong to this storage type.
@@ -438,39 +439,65 @@ function tripal_chado_field_storage_query($query) {
       $instance = field_info_instance('TripalEntity', $field['field_name'], $bundle_name);
       if (tripal_load_include_field_class($field_type)) {
         $field_obj = new $field_type($field, $instance);
-        $field_obj->query($condition, $cquery);
+        $field_obj->query($cquery, $condition);
       }
     }
   } // end foreach ($query->fieldConditions as $index => $condition) {
-/*
 
   // Now get the list for sorting.
   foreach ($query->order as $index => $sort) {
+    // We only handle ordering by field type here.
+    if ($sort['type'] != 'field') {
+      continue;
+    }
+
     $field = $sort['specifier']['field'];
+    $field_type = $field['type'];
+    $field_name = $field['field_name'];
 
     // Skip sorts that don't belong to this storage type.
     if ($field['storage']['type'] != 'field_chado_storage') {
       continue;
     }
-
+    $column = $sort['specifier']['column'];
     $direction = $sort['direction'];
 
-    $field_type = $field['type'];
-    $field_module = $field['module'];
-    $settings = $field['settings'];
-    $chado_table = $settings['chado_table'];
-    $chado_column = $settings['chado_column'];
-
-    $sorting[$chado_table][$chado_column] = $direction;
+    // See if there is a ChadoField class for this instance. If not then do
+    // our best to order the field.
+    $instance = field_info_instance('TripalEntity', $field_name, $bundle_name);
+    if (tripal_load_include_field_class($field_type)) {
+      $field_obj = new $field_type($field, $instance);
+      $field_obj->queryOrder($cquery, array('column' => $column, 'direction' => $direction));
+    }
+    // There is no class so do our best to order the data by this field
+    else {
+      $base_table = $instance['settings']['base_table'];
+      $chado_table = $instance['settings']['chado_table'];
+      $table_column = tripal_get_chado_semweb_column($chado_table, $column);
+      if ($table_column) {
+         if ($chado_table == $base_table) {
+           $cquery->orderBy('base.' . $table_column, $direction);
+         }
+         else {
+           // TODO: how do we handle a field that doesn't map to the base table.
+           // We would expect that all of these would be custom field and
+           // the ChadoField::queryOrder() function would be implemented.
+         }
+      }
+      else {
+        // TODO: handle when the name can't be matched to a table column.
+      }
+    }
   }
- */
+
 
   // Now join with the chado_entity table to get published records only.
   $cquery->join('chado_entity', 'CE', "CE.record_id = base.$pkey");
+  $cquery->join('tripal_entity', 'TE', "CE.entity_id = TE.id");
   $cquery->fields('CE', array('entity_id'));
   $cquery->condition('CE.data_table', $data_table);
-  if (array_key_exists('start', $condition['range'])) {
-    $cquery->range($condition['ragne']['start'], $condition['ragne']['length']);
+  if (array_key_exists('start', $query->range)) {
+    $cquery->range($query->range['start'], $query->range['length']);
   }
   $records = $cquery->execute();
 

+ 58 - 18
tripal_ws/includes/tripal_ws.rest_v0.1.inc

@@ -349,13 +349,45 @@ function tripal_ws_services_v0_1_get_content_type($api_url, &$response, $ws_path
   }
   // Convert the filters to their field names
   $new_params = array();
+  $order = array();
+  $order_dir = array();
+  $URL_add = array();
   foreach ($params as $param => $value) {
+    $URL_add[] = "$param=$value";
 
     // Ignore non filter parameters
     if ($param == 'page' or $param == 'limit') {
       continue;
     }
 
+    // Handle order separately
+    if ($param == 'order') {
+      $temp = explode(',', $value);
+      foreach ($temp as $key) {
+        $matches = array();
+        $dir = 'ASC';
+        // The user can provide a direction by separating the field key and the
+        // direction with a '|' character.
+        if (preg_match('/^(.*)\|(.*)$/', $key, $matches)) {
+          $key = $matches[1];
+          if ($matches[2] == 'ASC' or $matches[2] == 'DESC') {
+            $dir = $matches[2];
+          }
+          else {
+            // TODO: handle error of providing an incorrect direction.
+          }
+        }
+        if (array_key_exists($key, $field_mapping)) {
+          $order[$field_mapping[$key]] = $key;
+          $order_dir[] = $dir;
+        }
+        else {
+          // TODO: handle error of providing a non existing field name.
+        }
+      }
+      continue;
+    }
+
     // Break apart any operators
     $key = $param;
     $op = '=';
@@ -442,41 +474,49 @@ function tripal_ws_services_v0_1_get_content_type($api_url, &$response, $ws_path
   $page = array_key_exists('page', $params) ? $params['page'] : 1;
   if ($num_records > 0) {
     $response['view'] = array(
-      '@id' => $URL . "?page=$page&limit=$limit",
+      '@id' => $URL . '?' . implode('&', array_merge($URL_add, array("page=$page", "limit=$limit"))),
       '@type' => 'PartialCollectionView',
-      'first' => $URL . "?page=1&limit=$limit",
-      'last' => $URL . "?page=$total_pages&limit=$limit",
+      'first' => $URL . '?' . implode('&', array_merge($URL_add, array("page=1", "limit=$limit"))),
+      'last' => $URL . '?' . implode('&', array_merge($URL_add, array("page=$total_pages", "limit=$limit"))),
     );
     $prev = $page - 1;
     $next = $page + 1;
     if ($prev > 0) {
-      $response['view']['previous'] = $URL . "?page=$prev&limit=$limit";
+      $response['view']['previous'] = $URL . '?' . implode('&', array_merge($URL_add, array("page=$prev", "limit=$limit")));
     }
     if ($next < $total_pages) {
-      $response['view']['next'] = $URL . "?page=$next&limit=$limit";
+      $response['view']['next'] = $URL . '?' . implode('&', array_merge($URL_add, array("page=$next", "limit=$limit")));
     }
   }
 
-  // Now perform the query.
+  // Set the query order
+  $order_keys = array_keys($order);
+  for($i = 0; $i < count($order_keys); $i++) {
+    $query->fieldOrderBy($order_keys[$i], $order[$order_keys[$i]], $order_dir[$i]);
+  }
+
+  // Set the query range
   $start = ($page - 1) * $limit;
   $query->range($start, $limit);
+
+  // Now perform the query.
   $results = $query->execute();
 
   // Iterate through the entities and add them to the list.
   $i = 0;
   foreach ($results['TripalEntity'] as $entity_id => $stub) {
-   $vocabulary = '';
-   $term_name = '';
-
-   // We don't need all of the attached fields for an entity so, we'll
-   // not use the entity_load() function.  Instead just pull it from the
-   // database table.
-   $query = db_select('tripal_entity', 'TE');
-   $query->join('tripal_term', 'TT', 'TE.term_id = TT.id');
-   $query->fields('TE');
-   $query->fields('TT', array('name'));
-   $query->condition('TE.id', $entity_id);
-   $entity = $query->execute()->fetchObject();
+    $vocabulary = '';
+    $term_name = '';
+
+    // We don't need all of the attached fields for an entity so, we'll
+    // not use the entity_load() function.  Instead just pull it from the
+    // database table.
+    $query = db_select('tripal_entity', 'TE');
+    $query->join('tripal_term', 'TT', 'TE.term_id = TT.id');
+    $query->fields('TE');
+    $query->fields('TT', array('name'));
+    $query->condition('TE.id', $entity_id);
+    $entity = $query->execute()->fetchObject();
 
     //$entity = tripal_load_entity('TripalEntity', array($entity->id));
     $response['member'][] = array(