From 60fc76c5c548e992adddd3dabf364fac1a756679 Mon Sep 17 00:00:00 2001 From: Rafal Galka Date: Mon, 29 Dec 2014 10:00:35 +0100 Subject: [PATCH] [Contact] ContactManager.find() implementation (without filters & sorting) [Verification] TCT "ContactManager_find" should pass Change-Id: Ic819e80d4c047f916125185f863811c193187231 --- src/contact/contact_instance.cc | 51 +-- src/contact/contact_instance.h | 2 +- src/contact/contact_manager.cc | 319 +++++++++++++++++- src/contact/contact_manager.h | 8 +- .../js/tizen.contact.ContactManager.js | 2 +- 5 files changed, 353 insertions(+), 29 deletions(-) diff --git a/src/contact/contact_instance.cc b/src/contact/contact_instance.cc index f43209ed..a383c40c 100644 --- a/src/contact/contact_instance.cc +++ b/src/contact/contact_instance.cc @@ -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 & response) { picojson::object& obj = response->get(); 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(args), - val.get()); + ContactManager::ContactManager_update(common::JsonCast(args), val.get()); 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(args), - val.get()); + ContactManager::ContactManager_remove(common::JsonCast(args), val.get()); 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(); + + auto get = [this, args](const std::shared_ptr &response) -> void { + try { + JsonValue result = JsonValue(JsonArray()); + ContactManager::ContactManager_find(common::JsonCast(args), + result.get()); + ReportSuccess(result, response->get()); + } catch (const PlatformException &e) { + ReportError(e, response->get()); + } + }; + + auto get_response = [this, callback_id](const std::shared_ptr &response) { + picojson::object &obj = response->get(); + obj.insert(std::make_pair("callbackId", callback_id)); + PostMessage(response->serialize().c_str()); + }; + + TaskQueue::GetInstance().Queue(get, get_response, + std::shared_ptr(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(args), val.get()); diff --git a/src/contact/contact_instance.h b/src/contact/contact_instance.h index e8645aa4..ea137875 100644 --- a/src/contact/contact_instance.h +++ b/src/contact/contact_instance.h @@ -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 diff --git a/src/contact/contact_manager.cc b/src/contact/contact_manager.cc index 6561742a..30dec6e1 100644 --- a/src/contact/contact_manager.cc +++ b/src/contact/contact_manager.cc @@ -20,6 +20,7 @@ #include "common/converter.h" #include "common/picojson.h" #include "common/logger.h" +#include "common/filter-utils.h" #include #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> 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(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(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(JsonCast(match_value)); + } else { + value = common::stol(JsonCast(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(initial_value); + } + if (end_value_exists) { + end_value_bool = JsonCast(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(initial_value); + } + + if (end_value_exists) { + end_value_str = JsonCast(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(JsonCast(initial_value)); + } else { + initial_value_int = common::stol(JsonCast(initial_value)); + } + } + + if (end_value_exists) { + if (property.type == kPrimitiveTypeLong) { + end_value_int = static_cast(JsonCast(end_value)); + } else { + end_value_int = common::stol(JsonCast(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()); + }); + + 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(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(id_value))); + + contacts_list_next(person_list); + } } void ContactManager_importFromVCard(const JsonObject& args, JsonObject& out) { diff --git a/src/contact/contact_manager.h b/src/contact/contact_manager.h index 49ca1824..06d2c436 100644 --- a/src/contact/contact_manager.h +++ b/src/contact/contact_manager.h @@ -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); diff --git a/src/contact/js/tizen.contact.ContactManager.js b/src/contact/js/tizen.contact.ContactManager.js index 6ac40502..f6f756ae 100644 --- a/src/contact/js/tizen.contact.ContactManager.js +++ b/src/contact/js/tizen.contact.ContactManager.js @@ -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 }; -- 2.34.1