Browse Source

Altering properties API

Stephen Ficklin 10 năm trước cách đây
mục cha
commit
309b659684

+ 444 - 224
tripal_core/api/tripal_core.chado_general.api.inc

@@ -122,18 +122,28 @@ function chado_get_table_max_rank($tablename, $where_options) {
 }
 
 /**
- * Retrieve a property for a given base table record
+ * Retrieve a property for a given base table record.
  *
- * @param $basetable
- *   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 foriegn key field of the base table. This should be in integer.
+ * @param $record
+ *   An associative array used to identify the record to which the property
+ *   should be updated.  The following keys must be used:
+ *     -table: The base table for which the property should be updated. 
+ *         Thus to update a property for a feature the base_table=feature.
+ *     -id: The primary key value of the base table. The property will be
+ *         associated with the record that matches this id.
+ *     -prop_id: The primary key in the [table]prop table.  If this value
+ *         is supplied then the 'table' and 'id' keys are not needed.
  * @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
- *
+ *   An associative array used to specify the property to be updated.  It can 
+ *   contain the following keys. The keys must be specified to uniquely identify 
+ *   the term to be applied.  If the options identify more than one CV term
+ *   then an error will occur.
+ *     -type_name: The cvterm name to be selected.
+ *     -type_id: The cvterm_id of the term to be selected.
+ *     -cv_id: The cv_id of the CV that contains the term.
+ *     -cv_name: The name of the CV that contains the term.
+ *     -value: The specific value for the property.
+ *     -rank: The specific rank for the property.
  * @return
  *   An array in the same format as that generated by the function
  *   chado_generate_var().  If only one record is returned it
@@ -142,335 +152,545 @@ function chado_get_table_max_rank($tablename, $where_options) {
  *
  * @ingroup tripal_chado_api
  */
-function chado_get_property($basetable, $record_id, $property, $cv_name, $property_id = FALSE) {
+function chado_get_property($record, $property) {
+  
+  $base_table  = array_key_exists('table', $record) ? $record['table'] : '';
+  $base_id     = array_key_exists('id', $record) ? $record['id'] : '';
+  $prop_id     = array_key_exists('prop_id', $record) ? $record['prop_id'] : '';
+  
+  $type_name   = array_key_exists('type_name', $property) ? $property['type_name'] : '';
+  $type_id     = array_key_exists('type_id', $property) ? $property['type_id'] : '';
+  $cv_name     = array_key_exists('cv_name', $property) ? $property['cv_name'] : '';
+  $cv_id       = array_key_exists('cv_id', $property) ? $property['cv_id'] : '';
+  $value       = array_key_exists('value', $property) ? $property['value'] : '';
+  $rank        = array_key_exists('rank', $property) ? $property['rank'] : 0;
+
+  
+  // Build the values array for checking if the CVterm exists and for
+  // inserting the term as a property.
+  $type = array();
+  if ($cv_id) {
+    $type['cv_id'] = $cv_id;
+  }
+  if ($cv_name) {
+    $type['cv_id'] = array(
+      'name' => $cv_name,
+    );
+  }
+  if ($type_name) {
+    $type['name'] = $type_name;
+  }
+  if ($type_id) {
+    $type['cvterm_id'] = $type_id;
+  }
+  
+  // Make sure the CV term exists;
+  $options = array();
+  $term = chado_select_record('cvterm', array('cvterm_id'), $type, $options);
+  if (!$term or count($term) == 0) {
+    tripal_report_error('tripal_core', TRIPAL_ERROR, "chado_get_property: " .
+        "Cannot find the term described by: %property.",
+        array('%property' => print_r($property, TRUE)));
+        return FALSE;
+  }
+  if (count($term) > 1) {
+    tripal_report_error('tripal_core', TRIPAL_ERROR, "chado_get_property: " .
+        "Multiple terms found. Cannot add the property. Property was described " .
+        "by: %property.",
+        array('%property' => print_r($property, TRUE)));    return FALSE;
+  }
+  
   // get the foreign key for this property table
-  $table_desc = chado_get_schema($basetable . 'prop');
-  $fkcol = key($table_desc['foreign keys'][$basetable]['columns']);
+  $table_desc = chado_get_schema($base_table . 'prop');
+  $fkcol = key($table_desc['foreign keys'][$base_table]['columns']);
 
   // construct the array of values to be selected
   $values = array(
     $fkcol => $record_id,
-    'type_id' => array(
-      'cv_id' => array(
-        'name' => $cv_name,
-      ),
-      'name' => $property,
-      'is_obsolete' => 0
-    ),
+    'type_id' => $type,
   );
+  
   // if we have the unique property_id make sure to add that to the values
-  if ($property_id) {
+  if ($prop_id) {
     $property_pkey = $table_desc['primary key'][0];
-    $values[$property_pkey] = $property_id;
+    $values[$property_pkey] = $prop_id;
   }
-  $results = chado_generate_var($basetable . 'prop', $values);
+  $results = chado_generate_var($base_table . 'prop', $values);
   if ($results) {
-    $results = chado_expand_var($results, 'field', $basetable . 'prop.value');
+    $results = chado_expand_var($results, 'field', $base_table . 'prop.value');
   }
 
   return $results;
 }
 
 /**
- * Insert a property for a given base table.  By default if the property already
- * exists a new property is added with the next available rank.  If
- * $update_if_present argument is specified then the record will be updated if it
- * exists rather than adding a new property.
+ * Insert a property for a given base table.  
+ * 
+ * By default if the property already exists a new property is added with the 
+ * next available rank.  If the option 'update_if_present' is specified then 
+ * the record will be updated if it exists rather than adding a new property.
  *
- * @param $basetable
- *   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 foriegn key value of the base table. This should be in integer.
+ * @param $record
+ *   An associative array used to identify the record to which the property
+ *   should be assigned.  The following keys must be used:
+ *     -table: The base table for which the property should be inserted. 
+ *         Thus to insert a property for a feature the base_table=feature and 
+ *         property is inserted into featureprop
+ *     -id: The primary key value of the base table. The property will be
+ *         associated with the record that matches this id.
  * @param $property
- *   The cvterm name describing the type of properties to be inserted
- * @param $cv_name
- *   The name of the cv that the above cvterm is part of
- * @param $value
- *   The value of the property to be inserted (can be empty)
- * @param $update_if_present
- *   A boolean indicating whether an existing record should be updated. If the
- *   property already exists and this value is not specified or is zero then
- *   a new property will be added with the next largest rank.
+ *   An associative array used to specify the property to be added.  It can 
+ *   contain the following keys. The keys must be specified to uniquely identify 
+ *   the term to be applied.  If the options identify more than one CV term
+ *   then an error will occur.
+ *     -type_name: The cvterm name to be selected.
+ *     -type_id: The cvterm_id of the term to be selected.
+ *     -cv_id: The cv_id of the CV that contains the term.
+ *     -cv_name: The name of the CV that contains the term.
+ *     -value: The specific value for the property.
+ *     -rank: The specific rank for the property.
+ * @param $options
+ *   An associative array containing the following keys:
+ *     -update_if_present:  A boolean indicating whether an existing record 
+ *        should be updated. If the property already exists and this value is 
+ *        not specified or is zero then a new property will be added with the 
+ *        next largest rank.
+ *     -force_rank:  If the specified rank is already used by another property
+ *        recrod for the same base_id, then set force_rank to TRUE to require 
+ *        that only the specified rank can be used. Otherwise, the next 
+ *        available rank will be used.  If 'update_if_present' is FALSE and
+ *        'force_rank' is set then an error will occur.
  *
  * @return
- *   Return True on Insert/Update and False otherwise
+ *   Return TRUE if successful and FALSE otherwise
  *
  * @ingroup tripal_chado_api
  */
-function chado_insert_property($basetable, $record_id, $property,
-  $cv_name, $value, $update_if_present = 0) {
+function chado_insert_property($record, $property, $options) {
+
+  $base_table  = array_key_exists('table', $record) ? $record['table'] : '';
+  $base_id     = array_key_exists('id', $record) ? $record['id'] : '';
+
+  $type_name   = array_key_exists('type_name', $property) ? $property['type_name'] : '';
+  $type_id     = array_key_exists('type_id', $property) ? $property['type_id'] : '';
+  $cv_name     = array_key_exists('cv_name', $property) ? $property['cv_name'] : '';
+  $cv_id       = array_key_exists('cv_id', $property) ? $property['cv_id'] : '';
+  $value       = array_key_exists('value', $property) ? $property['value'] : '';
+  $rank        = array_key_exists('rank', $property) ? $property['rank'] : 0;
+
+  $update_if_present = array_key_exists('update_if_present', $options) ? $options['update_if_present'] : FALSE;
+  $force_rank = array_key_exists('force_rank', $options) ? $options['force_rank'] : FALSE;
 
-  // 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
-  $props = chado_get_property($basetable, $record_id, $property, $cv_name);
+  // First see if the property is already assigned to the record. I
+  $props = chado_get_property($record, $property);
   if (!is_array($props) and $props) {
     $props = array($props);
   }
-
-  $rank = 0;
   if (count($props) > 0) {
+    // The property is already assigned, so, see if we should update it.
     if ($update_if_present) {
-      return chado_update_property($basetable, $record_id, $property, $cv_name, $value);
+      return chado_update_property($record, $property);
     }
     else {
-      // 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;
+      if (!$force_rank) {
+        // 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 $prop) {
+          if ($prop->rank > $rank) {
+            $rank = $prop->rank;
+          }
+          if (strcmp($prop->value, $value) == 0) {
+            return TRUE;
+          }
         }
+        // now add 1 to the rank
+        $rank++;
+      }
+      else {
+        tripal_report_error('tripal_core', TRIPAL_ERROR, "chado_insert_property: " . 
+         "The property is already assigned to the record with the following " .
+         "rank.  And, because the 'force_rank' option is used, the property " .
+         "cannot be added: %property.",
+          array('%property' => print_r($property, true)));
+        return FALSE;
       }
-      // now add 1 to the rank
-      $rank++;
     }
   }
 
-  // make sure the cvterm exists.  
-  $values = array(
-    'cv_id' => array(
+  // Build the values array for checking if the CVterm exists and for
+  // inserting the term as a property. 
+  $values = array();
+  if ($cv_id) {
+    $values['cv_id'] = $cv_id;
+  }
+  if ($cv_name) {
+    $values['cv_id'] = array(
       'name' => $cv_name,
-    ),
-    'name' => $property,
-  );
+    );
+  }
+  if ($type_name) {
+    $values['name'] = $type_name;
+  }
+  if ($type_id) {
+    $values['cvterm_id'] = $type_id;
+  }
 
+  // Make sure the CV term exists;
   $options = array();
   $term = chado_select_record('cvterm', array('cvterm_id'), $values, $options);
   if (!$term or count($term) == 0) {
-    tripal_report_error('tripal_core', TRIPAL_ERROR, "Cannot find property '%prop_name' in vocabulary '%cvname'.",
-    array('%prop_name' => $property, '%cvname' => $cv_name));
+    tripal_report_error('tripal_core', TRIPAL_ERROR, "chado_insert_property: " .
+      "Cannot find the term described by: %property.",
+      array('%property' => print_r($property, TRUE)));
     return FALSE;
   }
+  if (count($term) > 1) {
+    tripal_report_error('tripal_core', TRIPAL_ERROR, "chado_insert_property: " .
+      "Multiple terms found. Cannot add the property. Property was described " .
+      "by: %property.",
+      array('%property' => print_r($property, TRUE)));    return FALSE;
+  }
+  
+  // Get the foreign key for this property table
+  $table_desc = chado_get_schema($base_table . 'prop');
+  $fkcol = key($table_desc['foreign keys'][$base_table]['columns']);
 
-  // get the foreign key for this property table
-  $table_desc = chado_get_schema($basetable . 'prop');
-  $fkcol = key($table_desc['foreign keys'][$basetable]['columns']);
-
-  // construct the array of values to be inserted
+  // Add the property to the record.
   $values = array(
-    $fkcol => $record_id,
-    'type_id' => array(
-      'cv_id' => array(
-        'name' => $cv_name,
-      ),
-      'name' => $property,
-    ),
+    $fkcol => $base_id,
+    'type_id' => $values,
     'value' => $value,
     'rank' => $rank,
   );
-
-  $options = array();
-  $result = chado_insert_record($basetable . 'prop', $values, $options);
+  $result = chado_insert_record($base_table . 'prop', $values);
   return $result;
 }
 
 /**
- * Update a property for a given base table record and property name.  This
- * function should be used only if one record of the property will be present.
- * If the property name can have multiple entries (with increasing rank) then
- * use the function named chado_update_propertyID
- *
- * @param $basetable
- *   The base table for which the property should be updated. The property table
- *   is constructed using  a combination of the base table name and the suffix
- *   'prop' (e.g. basetable = feature then property tabie is featureprop).
- * @param $record_id
- *   The foreign key of the basetable to update a property for. This should be in integer.
- *   For example, if the basetable is 'feature' then the $record_id should be the feature_id
+ * Update a property for a given base table record and property name.
+ * 
+ * @param $record
+ *   An associative array used to identify the record to which the property
+ *   should be updated.  The following keys must be used:
+ *     -table: The base table for which the property should be updated. 
+ *         Thus to update a property for a feature the base_table=feature.
+ *     -id: The primary key value of the base table. The property will be
+ *         associated with the record that matches this id.
+ *     -prop_id: The primary key in the [table]prop table.  If this value
+ *         is supplied then the 'table' and 'id' keys are not needed.
  * @param $property
- *   The cvterm name of property to be updated
- * @param $cv_name
- *   The name of the cv that the above cvterm is part of
- * @param $value
- *   The value of the property to be inserted (can be empty)
- * @param $insert_if_missing
- *   A boolean indicating whether a record should be inserted if one doesn't exist to update
+ *   An associative array used to specify the property to be updated.  It can 
+ *   contain the following keys. The keys must be specified to uniquely identify 
+ *   the term to be applied.  If the options identify more than one CV term
+ *   then an error will occur.
+ *     -type_name: The cvterm name to be selected.
+ *     -type_id: The cvterm_id of the term to be selected.
+ *     -cv_id: The cv_id of the CV that contains the term.
+ *     -cv_name: The name of the CV that contains the term.
+ *     -value: The specific value for the property.
+ *     -rank: The specific rank for the property.
+ * @param $options
+ *   An associative array containing the following keys:
+ *     -insert_if_missing: A boolean indicating whether a record should be 
+ *         inserted if one doesn't exist to update.
  *
- * Note: The property to be updated is select via the unique combination of $record_id and
- * $property and then it is updated with the supplied value
  *
  * @return
- *   Return True on Update/Insert and False otherwise
+ *   Return TRUE on Update/Insert and FALSE otherwise
  *
  * @ingroup tripal_chado_api
  */
-function chado_update_property($basetable, $record_id, $property,
-$cv_name, $value, $insert_if_missing = FALSE, $property_id = FALSE) {
+function chado_update_property($property, $options) {
+
+  $base_table  = array_key_exists('table', $record) ? $record['table'] : '';
+  $base_id     = array_key_exists('id', $record) ? $record['id'] : '';
+  $prop_id     = array_key_exists('prop_id', $record) ? $record['prop_id'] : '';
+  
+  $type_name   = array_key_exists('type_name', $property) ? $property['type_name'] : '';
+  $type_id     = array_key_exists('type_id', $property) ? $property['type_id'] : '';
+  $cv_name     = array_key_exists('cv_name', $property) ? $property['cv_name'] : '';
+  $cv_id       = array_key_exists('cv_id', $property) ? $property['cv_id'] : '';
+  $value       = array_key_exists('value', $property) ? $property['value'] : '';
+  $rank        = array_key_exists('rank', $property) ? $property['rank'] : 0;
+
+  $insert_if_missing = array_key_exists('insert_if_missing', $options) ? $options['insert_if_missing'] : FALSE;
 
   // first see if the property is missing (we can't update a missing property
-  $prop = chado_get_property($basetable, $record_id, $property, $cv_name, $property_id);
-  if (count($prop)==0) {
+  $prop = chado_get_property($record, $property);
+  if (count($prop) == 0) {
     if ($insert_if_missing) {
-      return chado_insert_property($basetable, $record_id, $property, $cv_name, $value);
+      return chado_insert_property($record, $property);
     }
     else {
       return FALSE;
     }
   }
+  
+  // Build the values array for checking if the CVterm exists and for
+  // inserting the term as a property.
+  $type = array();
+  if ($cv_id) {
+    $type['cv_id'] = $cv_id;
+  }
+  if ($cv_name) {
+    $type['cv_id'] = array(
+      'name' => $cv_name,
+    );
+  }
+  if ($type_name) {
+    $type['name'] = $type_name;
+  }
+  if ($type_id) {
+    $type['cvterm_id'] = $type_id;
+  }
+  
+  // Make sure the CV term exists;
+  $options = array();
+  $term = chado_select_record('cvterm', array('cvterm_id'), $type, $options);
+  if (!$term or count($term) == 0) {
+    tripal_report_error('tripal_core', TRIPAL_ERROR, "chado_update_property: " .
+        "Cannot find the term described by: %property.",
+        array('%property' => print_r($property, TRUE)));
+        return FALSE;
+  }
+  if (count($term) > 1) {
+    tripal_report_error('tripal_core', TRIPAL_ERROR, "chado_update_property: " .
+        "Multiple terms found. Cannot add the property. Property was described " .
+        "by: %property.",
+        array('%property' => print_r($property, TRUE)));    return FALSE;
+  }
+  
 
-  // get the foreign key for this property table
-  $table_desc = chado_get_schema($basetable . 'prop');
-  $fkcol = key($table_desc['foreign keys'][$basetable]['columns']);
+  // Get the foreign key for this property table
+  $table_desc = chado_get_schema($base_table . 'prop');
+  $fkcol = key($table_desc['foreign keys'][$base_table]['columns']);
 
+  
   // construct the array that will match the exact record to update
   $match = array(
     $fkcol => $record_id,
-    'type_id' => array(
-      'cv_id' => array(
-        'name' => $cv_name,
-      ),
-      'name' => $property,
-    ),
+    'type_id' => $type,
   );
-  // If we have the unique property_id, make sure to use it in the match to ensure
-  // we get the exact record. Doesn't rely on there only being one property of that type
-  if ($property_id) {
+  // If we have the unique property_id, make sure to use it in the match to 
+  // ensure we get the exact record. Doesn't rely on there only being one 
+  // property of that type.
+  if ($prop_id) {
     $property_pkey = $table_desc['primary key'][0];
     $match = array(
-      $property_pkey => $property_id
+      $property_pkey => $prop_id,
     );
   }
 
-  // construct the array of values to be updated
-  $values = array(
-    'value' => $value,
-  );
+  // Construct the array of values to be updated.
+  $values = array();
+  $values['value'] = $value;
+  if ($rank) {
+    $values['rank'] = $rank;
+  }
+  
   // If we have the unique property_id then we can also update the type
   // thus add it to the values to be updated
-  if ($property_id) {
-    $values['type_id'] = array(
-      'cv_id' => array(
-        'name' => $cv_name,
-      ),
-      'name' => $property,
-    );
+  if ($prop_id) {
+    $values['type_id'] = $type;
   }
 
-  return chado_update_record($basetable . 'prop', $match, $values);
+  return chado_update_record($base_table . 'prop', $match, $values);
 }
 
 /**
  * Deletes a property for a given base table record using the property name
- *
- * @param $basetable
- *   The base table for which the property should be deleted. Thus to deleted a property
- *   for a feature the basetable=feature and property is deleted from featureprop
- * @param $record_id
- *   The primary key of the basetable to delete a property for. This should be in integer.
+ * 
+ * @param $record
+ *   An associative array used to identify the record to which the property
+ *   should be deleted.  The following keys must be used:
+ *     -table: The base table for which the property should be deleted. 
+ *         Thus to update a property for a feature the base_table=feature.
+ *     -id: The primary key value of the base table. The property will be
+ *         deleted from the record that matches this id.
+ *     -prop_id: The primary key in the [table]prop table to be deleted.  If 
+ *         this value is supplied then the 'table' and 'id' keys are not needed.
  * @param $property
- *   The cvterm name describing the type of property to be deleted
- * @param $cv_name
- *   The name of the cv that the above cvterm is part of
- *
- * Note: The property to be deleted is select via the unique combination of $record_id and $property
+ *   An associative array used to specify the property to be updated.  It can 
+ *   contain the following keys. The keys must be specified to uniquely identify 
+ *   the term to be applied.  If the options identify more than one CV term
+ *   then an error will occur.
+ *     -type_name: The cvterm name to be selected.
+ *     -type_id: The cvterm_id of the term to be selected.
+ *     -cv_id: The cv_id of the CV that contains the term.
+ *     -cv_name: The name of the CV that contains the term.
+ *     -value: The specific value for the property.
+ *     -rank: The specific rank for the property.
  *
  * @return
- *   Return True on Delete and False otherwise
+ *   Return TRUE on successful deletion and FALSE otherwise
  *
  * @ingroup tripal_chado_api
  */
-function chado_delete_property($basetable, $record_id, $property, $cv_name) {
-
+function chado_delete_property($record, $property) {
+
+  $base_table  = array_key_exists('table', $record) ? $record['table'] : '';
+  $base_id     = array_key_exists('id', $record) ? $record['id'] : '';
+  $prop_id     = array_key_exists('prop_id', $record) ? $record['prop_id'] : '';
+  
+  $type_name   = array_key_exists('type_name', $property) ? $property['type_name'] : '';
+  $type_id     = array_key_exists('type_id', $property) ? $property['type_id'] : '';
+  $cv_name     = array_key_exists('cv_name', $property) ? $property['cv_name'] : '';
+  $cv_id       = array_key_exists('cv_id', $property) ? $property['cv_id'] : '';
+  $value       = array_key_exists('value', $property) ? $property['value'] : '';
+  $rank        = array_key_exists('rank', $property) ? $property['rank'] : 0;
+  
+  
+  // Build the values array for checking if the CVterm exists
+  $type = array();
+  if ($cv_id) {
+    $type['cv_id'] = $cv_id;
+  }
+  if ($cv_name) {
+    $type['cv_id'] = array(
+      'name' => $cv_name,
+    );
+  }
+  if ($type_name) {
+    $type['name'] = $type_name;
+  }
+  if ($type_id) {
+    $type['cvterm_id'] = $type_id;
+  }
+  
+  // Make sure the CV term exists;
+  $options = array();
+  $term = chado_select_record('cvterm', array('cvterm_id'), $type, $options);
+  if (!$term or count($term) == 0) {
+    tripal_report_error('tripal_core', TRIPAL_ERROR, "chado_delete_property: " .
+        "Cannot find the term described by: %property.",
+        array('%property' => print_r($property, TRUE)));
+        return FALSE;
+  }
+  if (count($term) > 1) {
+    tripal_report_error('tripal_core', TRIPAL_ERROR, "chado_delete_property: " .
+        "Multiple terms found. Cannot add the property. Property was described " .
+        "by: %property.",
+        array('%property' => print_r($property, TRUE)));    return FALSE;
+  }
+  
   // get the foreign key for this property table
-  $table_desc = chado_get_schema($basetable . 'prop');
-  $fkcol = key($table_desc['foreign keys'][$basetable]['columns']);
+  $table_desc = chado_get_schema($base_table . 'prop');
+  $fkcol = key($table_desc['foreign keys'][$base_table]['columns']);
 
+  // If we have the unique property_id, make sure to use it in the match to ensure
+  // we get the exact record. Doesn't rely on there only being one property of that type
+  if ($prop_id) {
+    $property_pkey = $table_desc['primary key'][0];
+    $match = array(
+      $property_pkey => $prop_id
+    );
+  }
   // construct the array that will match the exact record to update
-  $match = array(
-    $fkcol => $record_id,
-    'type_id' => array(
-      'cv_id' => array(
-        'name' => $cv_name,
-      ),
-      'name' => $property,
-    ),
-  );
-
-  return chado_delete_record($basetable . 'prop', $match);
+  else {
+    $match = array(
+      $fkcol => $record_id,
+      'type_id' => $type,
+    );
+  }
+  return chado_delete_record($base_table . 'prop', $match);
 }
 
 /**
- * Get all records with a given property.
+ * Get all records in the base table assigned one or more properties.
+ * 
+ * The property or properties of interest are specified using the $property
+ * argument.
  *
- * @param $basetable
- *   The base table for which variables should be generated.
- * @param $property
- *   An array/object describing the property to select records for. It should at least
- *   have either a type_name (if unique across cvs) or type_id. Other supported keys
- *   include: cv_id/cv_name (of the type), value and rank
  * @param $record
- *   An array/object describing the base table record. This can be used to restrict the
- *   base table records returned to a given type or organism
- * @param $options
- *   An array of options. Supported keys include:
- *     - Any keys supported by chado_generate_var(). See that function definition for
- *       additional details.
+ *   An associative array used to identify the table and subset of records to
+ *   to be searched:
+ *     -table: The base table for which the property should be updated. 
+ *         Thus to update a property for a feature the base_table=feature.
+ *     -base_records: An array in the format accepted by the chado_select_record
+ *         for specifying a subset of records in the base table.
+ * @param $property
+ *   An associative array used to specify the property to be selected for. It 
+ *   can contain the following keys. The keys must be specified to uniquely 
+ *   identify the term to be searched.  If the options identify more than one 
+ *   CV term then an error will occur.
+ *     -type_name: The cvterm name to be selected.
+ *     -type_id: The cvterm_id of the term to be selected.
+ *     -cv_id: The cv_id of the CV that contains the term.
+ *     -cv_name: The name of the CV that contains the term.
+ *     -value: The specific value for the property.
+ *     -rank: The specific rank for the property.
  *
  * @return
  *   An array of chado variables with the given property
  *
  * @ingroup tripal_chado_api
  */
-function chado_get_record_with_property($basetable, $property, $record = array(), $options = array()) {
-  $property_table = $basetable . 'prop';
-  $foreignkey_name = $basetable . '_id';
-
-  // Get paramters in the correct format
-  if (is_array($property)) {
-    $property = (object) $property;
-  }
-  if (is_object($record)) {
-    $record = (array) $record;
+function chado_get_record_with_property($record, $property) {
+  
+  $base_table  = array_key_exists('table', $record) ? $record['table'] : '';
+  $base_records= array_key_exists('base_records', $record) ? $record['base_records'] : array();
+  
+  $type_name   = array_key_exists('type_name', $property) ? $property['type_name'] : '';
+  $type_id     = array_key_exists('type_id', $property) ? $property['type_id'] : '';
+  $cv_name     = array_key_exists('cv_name', $property) ? $property['cv_name'] : '';
+  $cv_id       = array_key_exists('cv_id', $property) ? $property['cv_id'] : '';
+  $value       = array_key_exists('value', $property) ? $property['value'] : '';
+  $rank        = array_key_exists('rank', $property) ? $property['rank'] : '';
+
+  $property_table = $base_table . 'prop';
+  $foreignkey_name = $base_table . '_id';
+
+  // Build the values array for checking if the CVterm exists and for
+  // inserting the term as a property.
+  $type = array();
+  if ($cv_id) {
+    $type['cv_id'] = $cv_id;
   }
-
-  // Check parameters
-  if (!isset($property->type_name) AND !isset($property->type_id)) {
-    tripal_report_error('chado_api', TRIPAL_ERROR,
-      "chado_get_record_with_property: You must identify the type of property you want to
-       select records for by supplying either a type_name or type_id. You identified the
-       property as %prop.",
-      array('%prop'=> print_r($property, TRUE))
+  if ($cv_name) {
+    $type['cv_id'] = array(
+      'name' => $cv_name,
     );
   }
-
-  // Build the select values array based on the type
-  if (isset($property->type_name)) {
-    $values = array();
-    $values['type_id'] = array(
-      'name' => $property->type_name
-    );
-
-    // If the cv is set, add that too
-    if (isset($property->cv_name)) {
-      $values['type_id']['cv_id']['name'] = $property->cv_name;
-    }
-    elseif (isset($property->cv_id)) {
-      $values['type_id']['cv_id'] = $property->cv_id;
-    }
+  if ($type_name) {
+    $type['name'] = $type_name;
   }
-  elseif ($property->type_id) {
-    $values = array('type_id' => $property->type_id);
+  if ($type_id) {
+    $type['cvterm_id'] = $type_id;
   }
-
-  // Add the value and rank to values array if present
-  if (isset($property->value)) {
-    $values['value'] = $property->value;
+  
+  // Make sure the CV term exists;
+  $options = array();
+  $term = chado_select_record('cvterm', array('cvterm_id'), $type, $options);
+  if (!$term or count($term) == 0) {
+    tripal_report_error('tripal_core', TRIPAL_ERROR, "chado_update_property: " .
+        "Cannot find the term described by: %property.",
+        array('%property' => print_r($property, TRUE)));
+        return FALSE;
   }
-  if (isset($property->rank)) {
-    $values['rank'] = $property->rank;
+  if (count($term) > 1) {
+    tripal_report_error('tripal_core', TRIPAL_ERROR, "chado_update_property: " .
+        "Multiple terms found. Cannot add the property. Property was described " .
+        "by: %property.",
+        array('%property' => print_r($property, TRUE)));    return FALSE;
   }
 
-  // Add the record details to the values array
-  if (!empty($record)) {
-    $values[$foreignkey_name] = $record;
+  // Build the array for identifying the property.
+  $values = array();
+  $values['type_id'] = $type;
+  if ($rank) {
+    $values['rank'] = $rank;
+  }
+  if ($value) {
+    $values['value'] = $value;
+  }
+  
+  // Add the base records details to the values array.
+  if (!empty($base_records)) {
+    $values[$foreignkey_name] = $base_records;
   }
 
-  // Now select the ids of the properties that match
+  // Now select the ids of the base table that have the properties we want that match.
   $select = chado_select_record($property_table, array($foreignkey_name), $values);
 
   // For each of these ids, pull out the full base records
@@ -478,7 +698,7 @@ function chado_get_record_with_property($basetable, $property, $record = array()
   foreach ($select as $s) {
     $id = $s->{$foreignkey_name};
     $values = array($foreignkey_name => $id);
-    $records[$id] = chado_generate_var($basetable, $values, $options);
+    $records[$id] = chado_generate_var($base_table, $values, $options);
   }
 
   return $records;

+ 0 - 1
tripal_featuremap/includes/tripal_featuremap.chado_node.inc

@@ -109,7 +109,6 @@ function chado_featuremap_form($node, &$form_state) {
 
   // get the list of unit types
   $units = tripal_get_cvterm_default_select_options('featuremap', 'unittype_id', 'map unit types');
-  $units[0] = 'Select a Type';
 
   $form['unittype_id'] = array(
     '#title'       => t('Map Units'),

+ 14 - 2
tripal_featuremap/tripal_featuremap.install

@@ -60,7 +60,7 @@ function tripal_featuremap_install() {
   // set the default vocabularies
   tripal_set_default_cv('featuremapprop', 'type_id', 'featuremap_property');
   tripal_set_default_cv('featureposprop', 'type_id', 'featurepos_property');
-  tripal_set_default_cv('featuremap', 'uinittype_id', 'featuremap_units');
+  tripal_set_default_cv('featuremap', 'unittype_id', 'featuremap_units');
 }
 
 /**
@@ -641,4 +641,16 @@ function tripal_featuremap_update_7201() {
     $error = $e->getMessage();
     throw new DrupalUpdateException('Failed to update foriegn key: '. $error);
   }
-}
+}
+/**
+ * Fixes a typo when setting the default CV for the unittype_id field of the featuremap table.
+ */
+function tripal_featuremap_update_7202() {
+  try {
+    tripal_set_default_cv('featuremap', 'unittype_id', 'featuremap_units');
+  }
+  catch (\PDOException $e) {
+    $error = $e->getMessage();
+    throw new DrupalUpdateException('Failed to update featurmap CV default: '. $error);
+  }
+}