[Contact] ContactManager.find() implementation
authorRafal Galka <r.galka@samsung.com>
Mon, 29 Dec 2014 09:00:35 +0000 (10:00 +0100)
committerRafal Galka <r.galka@samsung.com>
Mon, 29 Dec 2014 13:35:30 +0000 (22:35 +0900)
(without filters & sorting)

[Verification]
TCT "ContactManager_find" should pass

Change-Id: Ic819e80d4c047f916125185f863811c193187231

src/contact/contact_instance.cc
src/contact/contact_instance.h
src/contact/contact_manager.cc
src/contact/contact_manager.h
src/contact/js/tizen.contact.ContactManager.js

index f43209e..a383c40 100644 (file)
@@ -41,7 +41,7 @@ ContactInstance::ContactInstance() {
   REGISTER_SYNC("ContactManager_updateBatch", ContactManager_updateBatch);
   REGISTER_SYNC("ContactManager_remove", ContactManager_remove);
   REGISTER_SYNC("ContactManager_removeBatch", ContactManager_removeBatch);
-  REGISTER_SYNC("ContactManager_find", ContactManager_find);
+  REGISTER_ASYNC("ContactManager_find", ContactManager_find);
   REGISTER_SYNC("ContactManager_importFromVCard", ContactManager_importFromVCard);
   REGISTER_SYNC("ContactManager_startListening", ContactManager_startListening);
   REGISTER_SYNC("ContactManager_stopListening", ContactManager_stopListening);
@@ -146,7 +146,6 @@ void ContactInstance::AddressBook_find(const JsonValue& args, JsonObject& out) {
   auto get_response = [this, callback_id](const std::shared_ptr <JsonValue>& response) {
     picojson::object& obj = response->get<picojson::object>();
     obj.insert(std::make_pair("callbackId", callback_id));
-    LoggerD("response is %s", response->serialize().c_str());
     PostMessage(response->serialize().c_str());
 
   };
@@ -252,39 +251,53 @@ void ContactInstance::ContactManager_get(const JsonValue& args,
   ReportSuccess(val, out);
 }
 
-void ContactInstance::ContactManager_update(const JsonValue& args,
-                                            JsonObject& out) {
+void ContactInstance::ContactManager_update(const JsonValue& args, JsonObject& out) {
   JsonValue val{JsonObject{}};
-  ContactManager::ContactManager_update(common::JsonCast<JsonObject>(args),
-                                        val.get<JsonObject>());
+  ContactManager::ContactManager_update(common::JsonCast<JsonObject>(args), val.get<JsonObject>());
   ReportSuccess(out);
 }
 
-void ContactInstance::ContactManager_updateBatch(const JsonValue& args,
-                                                 JsonObject& out) {
+void ContactInstance::ContactManager_updateBatch(const JsonValue& args, JsonObject& out) {
   // @todo implement
 }
 
-void ContactInstance::ContactManager_remove(const JsonValue& args,
-                                            JsonObject& out) {
+void ContactInstance::ContactManager_remove(const JsonValue& args, JsonObject& out) {
   JsonValue val{JsonObject{}};
-  ContactManager::ContactManager_remove(common::JsonCast<JsonObject>(args),
-                                        val.get<JsonObject>());
+  ContactManager::ContactManager_remove(common::JsonCast<JsonObject>(args), val.get<JsonObject>());
   ReportSuccess(out);
 }
 
-void ContactInstance::ContactManager_removeBatch(const JsonValue& args,
-                                                 JsonObject& out) {
+void ContactInstance::ContactManager_removeBatch(const JsonValue& args, JsonObject& out) {
   // @todo implement
 }
 
-void ContactInstance::ContactManager_find(const JsonValue& args,
-                                          JsonObject& out) {
-  // @todo implement
+void ContactInstance::ContactManager_find(const JsonValue &args, JsonObject &out) {
+  LoggerD("entered");
+
+  const double callback_id = args.get("callbackId").get<double>();
+
+  auto get = [this, args](const std::shared_ptr <JsonValue> &response) -> void {
+    try {
+      JsonValue result = JsonValue(JsonArray());
+      ContactManager::ContactManager_find(common::JsonCast<JsonObject>(args),
+          result.get<JsonArray>());
+      ReportSuccess(result, response->get<picojson::object>());
+    } catch (const PlatformException &e) {
+      ReportError(e, response->get<picojson::object>());
+    }
+  };
+
+  auto get_response = [this, callback_id](const std::shared_ptr <JsonValue> &response) {
+    picojson::object &obj = response->get<picojson::object>();
+    obj.insert(std::make_pair("callbackId", callback_id));
+    PostMessage(response->serialize().c_str());
+  };
+
+  TaskQueue::GetInstance().Queue<JsonValue>(get, get_response,
+      std::shared_ptr<JsonValue>(new JsonValue(JsonObject())));
 }
 
-void ContactInstance::ContactManager_importFromVCard(const JsonValue& args,
-                                                     JsonObject& out) {
+void ContactInstance::ContactManager_importFromVCard(const JsonValue& args, JsonObject& out) {
   JsonValue val{JsonObject{}};
   ContactManager::ContactManager_importFromVCard(
       common::JsonCast<JsonObject>(args), val.get<JsonObject>());
index e8645aa..ea13787 100644 (file)
@@ -161,7 +161,7 @@ class ContactInstance : public common::ParsedInstance {
    * {status: 'success', result: {persons}}
    * @endcode
    */
-  void ContactManager_find(const JsonValue& args, JsonObject& out);
+  void ContactManager_find(const JsonValue &args, JsonObject &out);
 
   /**
    * Signature: @code void getAddressBook(contactString); @endcode
index 6561742..30dec6e 100644 (file)
@@ -20,6 +20,7 @@
 #include "common/converter.h"
 #include "common/picojson.h"
 #include "common/logger.h"
+#include "common/filter-utils.h"
 
 #include <contacts.h>
 #include "contact/contact_instance.h"
@@ -205,11 +206,323 @@ void ContactManager_remove(const JsonObject& args, JsonObject&) {
   }
 }
 
-void ContactManager_find(const JsonObject& args, JsonObject& out) {
+void ContactManager_find(const JsonObject &args, JsonArray &out) {
   ContactUtil::CheckDBConnection();
 
-  // @todo implement
-  throw common::NotFoundException("Not implemented");
+  contacts_query_h contacts_query = nullptr;
+  int error_code = contacts_query_create(_contacts_person._uri, &contacts_query);
+  ContactUtil::ErrorChecker(error_code, "Failed contacts_query_create");
+
+  ContactUtil::ContactsQueryHPtr contacts_query_ptr(&contacts_query,
+      ContactUtil::ContactsQueryDeleter);
+
+  // Add filter to query
+  std::vector<std::vector<ContactUtil::ContactsFilterPtr>> intermediate_filters(1);
+  if (!IsNull(args, "filter")) {
+    FilterVisitor visitor;
+    visitor.SetOnAttributeFilter([&](const std::string &name,
+        AttributeMatchFlag match_flag,
+        const JsonValue &match_value) {
+
+      const Person::PersonProperty &property = Person::PersonProperty_fromString(name);
+
+      contacts_filter_h contacts_filter = nullptr;
+      int error_code = contacts_filter_create(_contacts_person._uri, &contacts_filter);
+      ContactUtil::ErrorChecker(error_code, "Failed contacts_query_set_filter");
+      ContactUtil::ContactsFilterPtr contacts_filter_ptr(
+          contacts_filter, ContactUtil::ContactsFilterDeleter);
+
+      if (property.type == kPrimitiveTypeBoolean) {
+        bool value = true;
+        if (AttributeMatchFlag::kExists != match_flag) {
+          value = JsonCast<bool>(match_value);
+        }
+        error_code = contacts_filter_add_bool(contacts_filter, property.propertyId, value);
+        ContactUtil::ErrorChecker(error_code, "Failed contacts_filter_add_bool");
+      } else if (property.type == kPrimitiveTypeString) {
+        std::string value = JsonCast<std::string>(match_value);
+
+        contacts_match_str_flag_e flag = CONTACTS_MATCH_EXISTS;
+        if (AttributeMatchFlag::kExactly == match_flag) {
+          flag = CONTACTS_MATCH_EXACTLY;
+        } else if (AttributeMatchFlag::kFullString == match_flag) {
+          flag = CONTACTS_MATCH_FULLSTRING;
+        } else if (AttributeMatchFlag::kContains == match_flag) {
+          flag = CONTACTS_MATCH_CONTAINS;
+        } else if (AttributeMatchFlag::kStartsWith == match_flag) {
+          flag = CONTACTS_MATCH_STARTSWITH;
+        } else if (AttributeMatchFlag::kEndsWith == match_flag) {
+          flag = CONTACTS_MATCH_ENDSWITH;
+        } else if (AttributeMatchFlag::kExists == match_flag) {
+          flag = CONTACTS_MATCH_EXISTS;
+          value = "";
+        }
+        error_code = contacts_filter_add_str(contacts_filter, property.propertyId,
+            flag, value.c_str());
+        ContactUtil::ErrorChecker(error_code, "Failed contacts_filter_add_str");
+      } else if (property.type == kPrimitiveTypeLong ||
+          property.type == kPrimitiveTypeId) {
+        int value;
+        if (property.type == kPrimitiveTypeLong) {
+          value = static_cast<int>(JsonCast<double>(match_value));
+        } else {
+          value = common::stol(JsonCast<std::string>(match_value));
+        }
+        if (value < 0) {
+          throw InvalidValuesException("Match value cannot be less than 0");
+        }
+        contacts_match_int_flag_e flag;
+        if (AttributeMatchFlag::kExists == match_flag) {
+          flag = CONTACTS_MATCH_GREATER_THAN_OR_EQUAL;
+          value = 0;
+        } else if (AttributeMatchFlag::kStartsWith == match_flag ||
+            AttributeMatchFlag::kContains == match_flag) {
+          flag = CONTACTS_MATCH_GREATER_THAN_OR_EQUAL;
+        } else if (AttributeMatchFlag::kEndsWith == match_flag) {
+          flag = CONTACTS_MATCH_LESS_THAN_OR_EQUAL;
+        } else {
+          flag = CONTACTS_MATCH_EQUAL;
+        }
+
+        error_code = contacts_filter_add_int(contacts_filter, property.propertyId, flag, value);
+        ContactUtil::ErrorChecker(error_code, "Failed contacts_filter_add_str");
+      } else {
+        throw UnknownException("Invalid primitive type!");
+      }
+      intermediate_filters[intermediate_filters.size() - 1]
+          .push_back(std::move(contacts_filter_ptr));
+    });
+
+    visitor.SetOnAttributeRangeFilter([&](const std::string &name,
+        const JsonValue &initial_value,
+        const JsonValue &end_value) {
+
+      const Person::PersonProperty &property = Person::PersonProperty_fromString(name);
+
+      contacts_filter_h contacts_filter = nullptr;
+      int error_code = contacts_filter_create(_contacts_person._uri, &contacts_filter);
+      ContactUtil::ErrorChecker(error_code, "Failed contacts_query_set_filter");
+      ContactUtil::ContactsFilterPtr contacts_filter_ptr(
+          contacts_filter, ContactUtil::ContactsFilterDeleter);
+
+      bool initial_value_exists = (!IsNull(initial_value));
+      bool end_value_exists = (!IsNull(end_value));
+
+      if (property.type == kPrimitiveTypeBoolean) {
+        bool initial_value_bool = false;
+        bool end_value_bool = false;
+
+        if (initial_value_exists) {
+          initial_value_bool = JsonCast<bool>(initial_value);
+        }
+        if (end_value_exists) {
+          end_value_bool = JsonCast<bool>(end_value);
+        }
+
+        if (initial_value_exists && end_value_exists) {
+          if (initial_value_bool == end_value_bool) {
+            error_code = contacts_filter_add_bool(
+                contacts_filter, property.propertyId, initial_value_bool);
+            ContactUtil::ErrorChecker(error_code, "Failed contacts_filter_add_bool");
+          }
+        } else if (initial_value_exists) {
+          if (initial_value_bool) {
+            error_code = contacts_filter_add_bool(contacts_filter, property.propertyId, true);
+            ContactUtil::ErrorChecker(error_code,
+                "Failed contacts_filter_add_bool");
+          }
+        } else if (end_value_exists) {
+          if (!end_value_bool) {
+            error_code = contacts_filter_add_bool(contacts_filter, property.propertyId, false);
+            ContactUtil::ErrorChecker(error_code, "Failed contacts_filter_add_bool");
+          }
+        }
+      } else if (property.type == kPrimitiveTypeString) {
+        std::string initial_value_str;
+        std::string end_value_str;
+
+        if (initial_value_exists) {
+          initial_value_str = JsonCast<std::string>(initial_value);
+        }
+
+        if (end_value_exists) {
+          end_value_str = JsonCast<std::string>(end_value);
+        }
+
+        if (initial_value_exists && end_value_exists) {
+          contacts_filter_h sub_filter = NULL;
+
+          error_code = contacts_filter_create(_contacts_person._uri, &sub_filter);
+          ContactUtil::ErrorChecker(error_code, "Failed contacts_filter_add_str");
+
+          ContactUtil::ContactsFilterPtr sub_filter_ptr(
+              sub_filter, ContactUtil::ContactsFilterDeleter);
+
+          error_code = contacts_filter_add_str(sub_filter, property.propertyId,
+              CONTACTS_MATCH_STARTSWITH,
+              initial_value_str.c_str());
+          ContactUtil::ErrorChecker(error_code, "Failed contacts_filter_add_str");
+          error_code = contacts_filter_add_operator(sub_filter,
+              CONTACTS_FILTER_OPERATOR_AND);
+          ContactUtil::ErrorChecker(error_code, "Failed contacts_filter_add_str");
+
+          error_code = contacts_filter_add_str(sub_filter, property.propertyId,
+              CONTACTS_MATCH_ENDSWITH,
+              end_value_str.c_str());
+          ContactUtil::ErrorChecker(error_code, "Failed contacts_filter_add_str");
+
+          error_code = contacts_filter_add_filter(contacts_filter, sub_filter);
+          ContactUtil::ErrorChecker(error_code, "Failed contacts_filter_add_str");
+        } else if (initial_value_exists) {
+          error_code = contacts_filter_add_str(
+              contacts_filter, property.propertyId, CONTACTS_MATCH_STARTSWITH,
+              initial_value_str.c_str());
+          ContactUtil::ErrorChecker(error_code, "Failed contacts_filter_add_str");
+        } else if (end_value_exists) {
+          error_code = contacts_filter_add_str(
+              contacts_filter, property.propertyId, CONTACTS_MATCH_ENDSWITH,
+              end_value_str.c_str());
+          ContactUtil::ErrorChecker(error_code, "Failed contacts_filter_add_str");
+        }
+      } else if (property.type == kPrimitiveTypeLong || property.type == kPrimitiveTypeId) {
+        int initial_value_int = 0;
+        int end_value_int = 0;
+
+        if (initial_value_exists) {
+          if (property.type == kPrimitiveTypeLong) {
+            initial_value_int = static_cast<int>(JsonCast<double>(initial_value));
+          } else {
+            initial_value_int = common::stol(JsonCast<std::string>(initial_value));
+          }
+        }
+
+        if (end_value_exists) {
+          if (property.type == kPrimitiveTypeLong) {
+            end_value_int = static_cast<int>(JsonCast<double>(end_value));
+          } else {
+            end_value_int = common::stol(JsonCast<std::string>(end_value));
+          }
+        }
+
+        if (initial_value_exists && end_value_exists) {
+          contacts_filter_h sub_filter = NULL;
+
+          error_code = contacts_filter_create(_contacts_person._uri, &sub_filter);
+          ContactUtil::ErrorChecker(error_code, "Failed contacts_filter_add_bool");
+          ContactUtil::ContactsFilterPtr sub_filter_ptr(
+              sub_filter, ContactUtil::ContactsFilterDeleter);
+
+          error_code = contacts_filter_add_int(
+              sub_filter, property.propertyId,
+              CONTACTS_MATCH_GREATER_THAN_OR_EQUAL, initial_value_int);
+          ContactUtil::ErrorChecker(error_code, "Failed contacts_filter_add_int");
+
+          error_code = contacts_filter_add_operator(sub_filter,
+              CONTACTS_FILTER_OPERATOR_AND);
+          ContactUtil::ErrorChecker(error_code, "Failed contacts_filter_add_operator");
+
+          error_code = contacts_filter_add_int(sub_filter, property.propertyId,
+              CONTACTS_MATCH_LESS_THAN_OR_EQUAL,
+              end_value_int);
+          ContactUtil::ErrorChecker(error_code, "Failed contacts_filter_add_int");
+
+          error_code = contacts_filter_add_filter(contacts_filter, sub_filter);
+          ContactUtil::ErrorChecker(error_code, "Failed contacts_filter_add_filter");
+        } else if (initial_value_exists) {
+          error_code = contacts_filter_add_int(
+              contacts_filter, property.propertyId,
+              CONTACTS_MATCH_GREATER_THAN_OR_EQUAL, initial_value_int);
+          ContactUtil::ErrorChecker(error_code, "Failed contacts_filter_add_int");
+        } else if (end_value_exists) {
+          error_code = contacts_filter_add_int(
+              contacts_filter, property.propertyId,
+              CONTACTS_MATCH_LESS_THAN_OR_EQUAL, end_value_int);
+          ContactUtil::ErrorChecker(error_code, "Failed contacts_filter_add_int");
+        }
+      } else {
+        throw UnknownException("Invalid primitive type!");
+      }
+      intermediate_filters[intermediate_filters.size() - 1]
+          .push_back(std::move(contacts_filter_ptr));
+    });
+
+    visitor.SetOnCompositeFilterBegin([&](CompositeFilterType type) {
+      intermediate_filters.push_back(std::vector<ContactUtil::ContactsFilterPtr>());
+    });
+
+    visitor.SetOnCompositeFilterEnd([&](CompositeFilterType type) {
+      if (intermediate_filters.size() == 0) {
+        throw UnknownException("Reached stack size equal to 0!");
+      }
+
+      contacts_filter_h merged_filter = nullptr;
+      int error_code = contacts_filter_create(_contacts_person._uri, &merged_filter);
+      ContactUtil::ErrorChecker(error_code, "Failed contacts_query_set_filter");
+      ContactUtil::ContactsFilterPtr merged_filter_ptr(
+          merged_filter, ContactUtil::ContactsFilterDeleter);
+
+      for (std::size_t i = 0; i < intermediate_filters.back().size(); ++i) {
+        error_code = contacts_filter_add_filter(
+            merged_filter, intermediate_filters.back().at(i).get());
+        ContactUtil::ErrorChecker(error_code, "Failed contacts_query_set_filter");
+        if (CompositeFilterType::kIntersection == type) {
+          error_code = contacts_filter_add_operator(merged_filter,
+              CONTACTS_FILTER_OPERATOR_AND);
+          ContactUtil::ErrorChecker(error_code, "Failed contacts_query_set_filter");
+        } else if (CompositeFilterType::kUnion == type) {
+          error_code = contacts_filter_add_operator(merged_filter,
+              CONTACTS_FILTER_OPERATOR_OR);
+          ContactUtil::ErrorChecker(error_code, "Failed contacts_query_set_filter");
+        } else {
+          throw InvalidValuesException("Invalid union type!");
+        }
+      }
+
+      intermediate_filters.pop_back();
+      intermediate_filters.back().push_back(std::move(merged_filter_ptr));
+    });
+
+    visitor.Visit(FromJson<JsonObject>(args, "filter"));
+    // Should compute only one filter always.
+    if ((intermediate_filters.size() != 1) || (intermediate_filters[0].size() != 1)) {
+      LoggerE("Bad filter evaluation!");
+      throw UnknownException("Bad filter evaluation!");
+    }
+    // Filter is generated
+    error_code = contacts_query_set_filter(contacts_query, intermediate_filters[0][0].get());
+    ContactUtil::ErrorChecker(error_code, "Failed contacts_query_set_filter");
+  }
+
+  contacts_list_h person_list = nullptr;
+  error_code = contacts_db_get_records_with_query(contacts_query, 0, 0, &person_list);
+
+  ContactUtil::ErrorChecker(error_code, "Failed contacts_db_get_records_with_query");
+
+  ContactUtil::ContactsListHPtr person_list_ptr(&person_list, ContactUtil::ContactsListDeleter);
+
+  int record_count = 0;
+  error_code = contacts_list_get_count(person_list, &record_count);
+  ContactUtil::ErrorChecker(error_code, "Failed contacts_list_get_count");
+
+  contacts_list_first(person_list);
+
+  for (unsigned int i = 0; i < record_count; i++) {
+    contacts_record_h contacts_record;
+    error_code = contacts_list_get_current_record_p(person_list, &contacts_record);
+    if (error_code != CONTACTS_ERROR_NONE || contacts_record == NULL) {
+      LoggerW("Failed group record (ret:%d)", error_code);
+      continue;
+    }
+
+    int id_value = 0;
+    error_code = contacts_record_get_int(contacts_record, _contacts_person.id, &id_value);
+
+    ContactUtil::ErrorChecker(error_code, "Failed contacts_record_get_int");
+
+    out.push_back(JsonValue(static_cast<double>(id_value)));
+
+    contacts_list_next(person_list);
+  }
 }
 
 void ContactManager_importFromVCard(const JsonObject& args, JsonObject& out) {
index 49ca182..06d2c43 100644 (file)
@@ -32,15 +32,13 @@ void ContactManager_get(const JsonObject& args, JsonObject& out);
 
 void ContactManager_update(const JsonObject& args, JsonObject&);
 
-void ContactManager_updateBatch(const JsonObject& /*args*/,
-                                JsonObject& /*out*/);
+void ContactManager_updateBatch(const JsonObject& args, JsonObject& out);
 
 void ContactManager_remove(const JsonObject& args, JsonObject&);
 
-void ContactManager_removeBatch(const JsonObject& /*args*/,
-                                JsonObject& /*out*/);
+void ContactManager_removeBatch(const JsonObject& args, JsonObject& out);
 
-void ContactManager_find(const JsonObject& /*args*/, JsonObject& /*out*/);
+void ContactManager_find(const JsonObject &args, JsonArray &out);
 
 void ContactManager_importFromVCard(const JsonObject& args, JsonObject& out);
 
index 6ac4050..f6f756a 100644 (file)
@@ -280,7 +280,7 @@ ContactManager.prototype.find = function() {
 
   // TODO implement contact filtering/sorting.
   var data = {
-    //filter: Common.repackFilter(args.filter),
+    filter: null, //Common.repackFilter(args.filter),
     sortMode: args.sortMode
   };