Implementation: Refactored Person to keep all contact records instead of partial data about default contact
Change-Id: I18d5a96aeffff96d07c2a53a7aa7e257ede5f74e
Signed-off-by: Sergei Kobec <s.kobec@samsung.com>
#include "Utils/Iterator.h"
#include "Utils/Range.h"
+#include <contacts.h>
namespace Common
{
return { record, property, size_t(count) };
}
- inline Utils::Range<ChildRecordIterator> makeRange(contacts_record_h record, int property)
+ /**
+ * @brief Contact child record range
+ */
+ typedef Utils::Range<ChildRecordIterator> ChildRecordRange;
+
+ inline ChildRecordRange makeRange(contacts_record_h record, int property)
{
return { begin(record, property), end(record, property) };
}
* @return _contacts_person ID.
*/
EXPORT_API int getPersonId(int contactId);
+
+ /**
+ * @brief Get record list
+ * @remark Return value MUST be destroyed with contacts_list_destroy by you
+ * @param[in] uri Record uri
+ * @param[in] propertyId Filter property ID
+ * @param[in] value Value that should be equal to @a propertyId field value
+ * @param[in] parentFilter Parent filter, optional
+ * @return Contacts list on success, otherwise nullptr
+ */
+ EXPORT_API contacts_list_h getRecordList(const char *uri, unsigned propertyId, int value, contacts_filter_h parentFilter = nullptr);
+
+ /**
+ * @brief Get record list
+ * @remark Return value MUST be destroyed with contacts_list_destroy by you
+ * @param[in] uri Record uri
+ * @param[in] propertyId Filter property ID
+ * @param[in] values List of values, which should be equal with @a propertyId field value
+ * @param[in] parentFilter Parent filter, optional
+ * @return Contacts list on success, otherwise nullptr
+ */
+ EXPORT_API contacts_list_h getRecordList(const char *uri, unsigned propertyId, Utils::Range<int *> values, contacts_filter_h parentFilter = nullptr);
}
}
#ifndef COMMON_DATABASE_RECORD_UTILS_H
#define COMMON_DATABASE_RECORD_UTILS_H
-#include <contacts.h>
#include "Utils/String.h"
+#include "Common/Database/ChildRecordIterator.h"
+
+#include <contacts.h>
#define CONTACTS_LIST_FOREACH(list, record) \
bool success = (contacts_list_get_current_record_p(list, &record) == CONTACTS_ERROR_NONE); \
}
/**
+ * @brief Get first child record
+ * @remark Good way to get single child record
+ * @param[in] record Parent record
+ * @param[in] property @record property, that points to child DB view
+ * @return Child record on success, otherwise nullptr
+ */
+ inline contacts_record_h getChildRecord(contacts_record_h record, unsigned property)
+ {
+ contacts_record_h childRecord = nullptr;
+ contacts_record_get_child_record_at_p(record, property, 0, &childRecord);
+ return childRecord;
+ }
+
+ /**
+ * @brief Get child record
+ * @param[in] record Parent record
+ * @param[in] property @record property, that points to child DB view
+ * @param[in] predicate Unary function, that accepts child record
+ * from parent record range and returns bool value
+ * @return Child record on success, otherwise nullptr
+ */
+ template <typename Pred>
+ inline contacts_record_h getChildRecord(contacts_record_h record, unsigned property,
+ Pred predicate)
+ {
+ for (auto childRecord : makeRange(record, property)) {
+ if (predicate(childRecord)) {
+ return childRecord;
+ }
+ }
+
+ return nullptr;
+ }
+
+ /**
* @brief Compare two records by the same string property.
* @param[in] record1 First record
* @param[in] records Second record
return id;
}
+
+contacts_list_h Database::getRecordList(const char *uri, unsigned propertyId, int value, contacts_filter_h parentFilter)
+{
+ contacts_filter_h filter = nullptr;
+ contacts_filter_create(uri, &filter);
+ contacts_filter_add_int(filter, propertyId, CONTACTS_MATCH_EQUAL, value);
+ if (parentFilter) {
+ contacts_filter_add_filter(parentFilter, filter);
+ }
+
+ contacts_query_h query = nullptr;
+ contacts_query_create(uri, &query);
+ contacts_query_set_filter(query, filter);
+
+ contacts_list_h list = nullptr;
+ int err = contacts_db_get_records_with_query(query, 0, 0, &list);
+ RETVM_IF_ERR(err, nullptr, "contacts_db_get_records_with_query failed.");
+
+ contacts_query_destroy(query);
+ contacts_filter_destroy(filter);
+
+ return list;
+}
+
+contacts_list_h Database::getRecordList(const char *uri, unsigned propertyId, Utils::Range<int *> values, contacts_filter_h parentFilter)
+{
+ contacts_filter_h filter = nullptr;
+ contacts_filter_create(uri, &filter);
+ for (auto it = values.begin(); it != values.end(); ++it) {
+ if (it != values.begin()) {
+ contacts_filter_add_operator(filter, CONTACTS_FILTER_OPERATOR_OR);
+ }
+
+ contacts_filter_add_int(filter, propertyId, CONTACTS_MATCH_EQUAL, *it);
+ }
+ if (parentFilter) {
+ contacts_filter_add_filter(parentFilter, filter);
+ }
+
+ contacts_query_h query = nullptr;
+ contacts_query_create(uri, &query);
+ contacts_query_set_filter(query, filter);
+
+ contacts_list_h list = nullptr;
+ int err = contacts_db_get_records_with_query(query, 0, 0, &list);
+ RETVM_IF_ERR(err, nullptr, "contacts_db_get_records_with_query failed.");
+
+ contacts_query_destroy(query);
+ contacts_filter_destroy(filter);
+
+ return list;
+}
private:
virtual contacts_list_h getPersonList() const override;
virtual contacts_record_h getPersonRecord(int id, IdType idType) const override;
- virtual bool insertPerson(int id, IdType idType) override;
+ virtual void insertPerson(contacts_record_h personRecord) override;
virtual void deletePerson(DataList::const_iterator personIt) override;
contacts_list_h getPersonUsageList() const;
#include "Contacts/Model/ContactData.h"
#include "Utils/UniString.h"
+
#include <contacts.h>
#include <vector>
enum PersonField
{
PersonFieldSortValue = FieldMax, /**< Sort value*/
+ PersonFieldContact, /**< Contact field */
PersonFieldMax /**< Sentinel value */
};
*/
enum PersonChangedInfo
{
- ChangedSortValue = 1 << PersonFieldSortValue /**< Sort value has changed */
+ ChangedSortValue = 1 << PersonFieldSortValue, /**< Sort value has changed */
+ ChangedContact = 1 << PersonFieldContact /**< Whole contact has changed */
};
/**
*/
bool operator<(const Person &that) const;
+ /**
+ * @brief Add contact to person
+ * @param[in] record Contact record
+ */
+ void addContact(contacts_record_h record);
+
+ /**
+ * @brief Remove contact from person
+ * @param[in] id Contact ID
+ */
+ void removeContact(int id);
+
+ /**
+ * @brief Get count of linked contacts in person
+ */
+ size_t getContactCount() const;
+
private:
friend class PersonProvider;
const Utils::UniString &getSortValue() const;
- void update(contacts_record_h record);
+ void update(contacts_record_h personRecord);
int updateName(contacts_record_h record, unsigned sortProperty);
- int updateNumber(int personId);
contacts_record_h m_Record;
- mutable contacts_record_h m_NameRecord;
- mutable contacts_record_h m_NumberRecord;
+ contacts_record_h m_DefaultContactRecord;
+ std::vector<contacts_record_h> m_ContactRecords;
Utils::UniString m_IndexLetter;
mutable Utils::UniString m_SortValue;
virtual contacts_record_h getPersonRecord(int id, IdType idType) const;
/**
- * @brief Fetch person from database by ID and insert it into person list.
- * @param[in] id Person or display contact ID
- * @param[in] idType Type of ID
- * @return Whether insert was successful.
+ * @brief Insert person into person list.
+ * @param[in] personRecord Person record
*/
- virtual bool insertPerson(int id, IdType idType);
+ virtual void insertPerson(contacts_record_h personRecord);
/**
* @brief Update person from database.
- * @param[in] personIt Person iterator
+ * @param[in] personIt Person iterator
+ * @param[in] personRecord Person DB record
+ * @param[in] contactId Updated contact ID
* @return Whether update was successful.
*/
- virtual bool updatePerson(DataList::const_iterator personIt);
+ virtual bool updatePerson(DataList::const_iterator personIt, contacts_record_h personRecord, int contactId);
/**
* @brief Delete person from person list.
private:
void updatePersonList();
+ void addContacts();
+ void removeContact(int contactId);
+
void subscribe();
void unsubscribe();
void resetDbVersion();
contacts_record_h MfcProvider::getPersonRecord(int id, PersonProvider::IdType idType) const
{
if (idType == ContactId) {
- id = getPersonId(id);
+ return nullptr;
}
for (auto &&usageRecord : makeRange(getPersonUsageList())) {
return nullptr;
}
-bool MfcProvider::insertPerson(int id, IdType idType)
+void MfcProvider::insertPerson(contacts_record_h personRecord)
{
- if (idType == ContactId) {
- return false;
+ if (!personRecord) {
+ return;
}
- return update();
+ update();
}
void MfcProvider::deletePerson(DataList::const_iterator personIt)
#include "Common/Database/Queries.h"
#include "Common/Database/RecordUtils.h"
#include "Common/Database/RecordIterator.h"
-#include "Common/Database/ChildRecordIterator.h"
#include "Utils/Logger.h"
+#include <algorithm>
+
using namespace Common::Database;
using namespace Contacts;
using namespace Contacts::Model;
return record;
}
- contacts_record_h getNumberRecord(int personId)
+ contacts_record_h getNumberRecord(contacts_record_h contactRecord)
{
- int id = 0;
- contacts_record_h record = nullptr;
- contacts_person_get_default_property(CONTACTS_PERSON_PROPERTY_NUMBER, personId, &id);
- contacts_db_get_record(_contacts_number._uri, id, &record);
-
- return record;
+ return getChildRecord(contactRecord, _contacts_contact.number,
+ [](contacts_record_h record) {
+ return getRecordBool(record, _contacts_number.is_default);
+ });
}
}
Person::Person(contacts_record_h record)
: ContactData(TypePerson),
- m_Record(record), m_NameRecord(nullptr), m_NumberRecord(nullptr),
+ m_Record(record), m_DefaultContactRecord(nullptr),
m_SortProperty(getSortProperty())
{
m_IndexLetter = getRecordStr(m_Record, _contacts_person.display_name_index);
for (auto &&number : m_Numbers) {
delete number;
}
- contacts_record_destroy(m_NameRecord, true);
- contacts_record_destroy(m_NumberRecord, true);
+ for (auto &&contact : m_ContactRecords) {
+ contacts_record_destroy(contact, true);
+ }
contacts_record_destroy(m_Record, true);
}
const char *Person::getNumber() const
{
- if (!m_NumberRecord) {
- m_NumberRecord = getNumberRecord(getId());
- }
- return getRecordStr(m_NumberRecord, _contacts_number.number);
+ return getRecordStr(getNumberRecord(m_DefaultContactRecord), _contacts_number.number);
}
const char *Person::getImagePath() const
return getSortValue() < that.getSortValue();
}
-const UniString &Person::getSortValue() const
+void Person::addContact(contacts_record_h record)
{
- if (m_SortValue.getI18nStr().empty()) {
- if (!m_NameRecord) {
- m_NameRecord = getNameRecord(getContactId());
+ if (getContactId() == getRecordInt(record, _contacts_contact.id)) {
+ m_DefaultContactRecord = record;
+ }
+
+ if (!m_ContactRecords.empty()) {
+ auto it = std::find_if(m_ContactRecords.begin(), m_ContactRecords.end(),
+ [record](contacts_record_h contactRecord) {
+ return compareRecordsInt(contactRecord, record, _contacts_contact.id);
+ }
+ );
+
+ if (it != m_ContactRecords.end()) {
+ contacts_record_destroy(*it, true);
+ *it = record;
+ return;
}
+ }
+
+ m_ContactRecords.push_back(record);
+}
- const char *value = getRecordStr(m_NameRecord, m_SortProperty);
+void Person::removeContact(int id)
+{
+ auto it = std::find_if(m_ContactRecords.begin(), m_ContactRecords.end(),
+ [id](contacts_record_h contactRecord) {
+ return getRecordInt(contactRecord, _contacts_contact.id) == id;
+ }
+ );
+
+ if (it != m_ContactRecords.end()) {
+ bool isDefault = *it == m_DefaultContactRecord;
+
+ contacts_record_destroy(*it, true);
+ m_ContactRecords.erase(it);
+
+ if (isDefault && !m_ContactRecords.empty()) {
+ int id = getId();
+ contacts_record_destroy(m_Record, true);
+ contacts_db_get_record(_contacts_person._uri, id, &m_Record);
+
+ int displayContactId = getRecordInt(m_Record, _contacts_person.display_contact_id);
+ auto it = std::find_if(m_ContactRecords.begin(), m_ContactRecords.end(),
+ [this, displayContactId](contacts_record_h contactRecord) {
+ return displayContactId == getRecordInt(contactRecord, _contacts_contact.id);
+ }
+ );
+ if (it != m_ContactRecords.end()) {
+ m_DefaultContactRecord = *it;
+ }
+ }
+ }
+}
+
+size_t Person::getContactCount() const
+{
+ return m_ContactRecords.size();
+}
+
+const UniString &Person::getSortValue() const
+{
+ if (m_SortValue.getI18nStr().empty()) {
+ contacts_record_h nameRecord = getChildRecord(m_DefaultContactRecord, _contacts_contact.name);
+ const char *value = getRecordStr(nameRecord, m_SortProperty);
m_SortValue = (value && *value) ? value : getName();
}
return m_SortValue;
}
-void Person::update(contacts_record_h record)
+void Person::update(contacts_record_h personRecord)
{
int changes = ChangedNone;
- if (!compareRecordsStr(m_Record, record, _contacts_person.display_name)) {
+ if (!compareRecordsStr(m_Record, personRecord, _contacts_person.display_name)) {
changes |= ChangedName;
}
- if (!compareRecordsStr(m_Record, record, _contacts_person.image_thumbnail_path)) {
+ if (!compareRecordsStr(m_Record, personRecord, _contacts_person.image_thumbnail_path)) {
changes |= ChangedImage;
}
unsigned sortProperty = getSortProperty();
if ((changes & ChangedName) || m_SortProperty != sortProperty) {
- changes |= updateName(record, sortProperty);
- }
- if (m_NumberRecord) {
- changes |= updateNumber(getId());
+ changes |= updateName(personRecord, sortProperty);
}
+ changes |= ChangedContact;
contacts_record_destroy(m_Record, true);
- m_Record = record;
+ m_Record = personRecord;
onUpdated(changes);
}
int Person::updateName(contacts_record_h record, unsigned sortProperty)
{
int contactId = getRecordInt(record, _contacts_person.display_contact_id);
- contacts_record_h nameRecord = getNameRecord(contactId);
+ contacts_record_h nameRecord = getNameRecord(contactId);//Todo: Get rid of this query invocation
int changes = ChangedNone;
if (!Utils::safeCmp(
- getRecordStr(m_NameRecord, m_SortProperty),
+ getRecordStr(getChildRecord(m_DefaultContactRecord, _contacts_contact.name), m_SortProperty),
getRecordStr(nameRecord, sortProperty))) {
changes |= ChangedSortValue;
m_SortValue.clear();
m_IndexLetter = getRecordStr(record, _contacts_person.display_name_index);
}
- contacts_record_destroy(m_NameRecord, true);
- m_NameRecord = nameRecord;
m_SortProperty = sortProperty;
-
- return changes;
-}
-
-int Person::updateNumber(int personId)
-{
- contacts_record_h numberRecord = getNumberRecord(personId);
-
- int changes = ChangedNone;
- if (!compareRecordsStr(m_NumberRecord, numberRecord, _contacts_number.number)) {
- changes |= ChangedNumber;
- }
-
- contacts_record_destroy(m_NumberRecord, true);
- m_NumberRecord = numberRecord;
-
+ contacts_record_destroy(nameRecord, true);
return changes;
}
const PersonProvider::DataList &PersonProvider::getDataList()
{
if (!m_IsFilled) {
- contacts_list_h list = getPersonList();
- for (auto &&record : makeRange(list)) {
+ contacts_list_h persons = getPersonList();
+ for (auto &&record : makeRange(persons)) {
m_PersonList.push_back(createPerson(record));
}
- contacts_list_destroy(list, false);
+ contacts_list_destroy(persons, false);
+ addContacts();
subscribe();
m_IsFilled = true;
contacts_list_h list = getPersonList();
for (auto &&record : makeRange(list)) {
- PersonProvider::insertPerson(getRecordInt(record, _contacts_person.id), PersonId);
+ PersonProvider::insertPerson(record);
}
contacts_list_destroy(list, true);
return record;
}
-bool PersonProvider::insertPerson(int id, IdType idType)
+void PersonProvider::insertPerson(contacts_record_h personRecord)
{
- contacts_record_h record = getPersonRecord(id, idType);
- if (record) {
- m_PersonList.push_back(createPerson(record));
+ if (personRecord) {
+ Person *person = createPerson(personRecord);
+
+ contacts_list_h contacts = getRecordList(_contacts_contact._uri, _contacts_contact.person_id,
+ person->getId());
+
+ for (auto &&contact : makeRange(contacts)) {
+ person->addContact(contact);
+ }
+
+ m_PersonList.push_back(person);
onInserted(*m_PersonList.back());
- return true;
- }
- return false;
+ contacts_list_destroy(contacts, false);
+ }
}
-bool PersonProvider::updatePerson(DataList::const_iterator personIt)
+bool PersonProvider::updatePerson(DataList::const_iterator personIt, contacts_record_h personRecord, int contactId)
{
Person *person = static_cast<Person *>(*personIt);
- contacts_record_h record = getPersonRecord(person->getId(), PersonId);
+ if (personRecord) {
+ person->update(personRecord);
- if (record) {
- person->update(record);
- return true;
+ contacts_record_h contactRecord = nullptr;
+ contacts_db_get_record(_contacts_contact._uri, contactId, &contactRecord);
+ person->addContact(contactRecord);
+ } else {
+ deletePerson(personIt);
}
- return false;
+ return personRecord != nullptr;
}
void PersonProvider::deletePerson(DataList::const_iterator personIt)
PersonProvider::DataList::const_iterator PersonProvider::findPerson(int id, IdType idType)
{
- int propId = getIdProperty(idType);
- return std::find_if(m_PersonList.begin(), m_PersonList.end(),
- [id, propId](::Model::DataItem *data) {
- Person *person = static_cast<Person *>(data);
- return getRecordInt(person->getRecord(), propId) == id;
- }
- );
+ if (idType == PersonId) {
+ return std::find_if(m_PersonList.begin(), m_PersonList.end(),
+ [id](::Model::DataItem *data) {
+ Person *person = static_cast<Person *>(data);
+ return person->getId() == id;
+ }
+ );
+ } else {
+ return std::find_if(m_PersonList.begin(), m_PersonList.end(),
+ [id](::Model::DataItem *data) {
+ Person *person = static_cast<Person *>(data);
+ return std::find_if(person->m_ContactRecords.begin(), person->m_ContactRecords.end(),
+ [id](contacts_record_h contactRecord) {
+ return getRecordInt(contactRecord, _contacts_contact.id) == id;
+ }
+ ) != person->m_ContactRecords.end();
+ }
+ );
+ }
}
int PersonProvider::getIdProperty(IdType idType)
switch (changeType) {
case CONTACTS_CHANGE_INSERTED:
{
- insertPerson(contactId, ContactId);
+ insertPerson(getPersonRecord(contactId, ContactId));
break;
}
case CONTACTS_CHANGE_UPDATED:
{
int personId = getPersonId(contactId);
+ contacts_record_h personRecord = getPersonRecord(contactId, ContactId);
auto personIt = findPerson(personId, PersonId);
+
if (personIt != m_PersonList.end()) {
- if (!updatePerson(personIt)) {
- deletePerson(personIt);
- }
+ updatePerson(personIt, personRecord, contactId);
} else {
- insertPerson(personId, PersonId);
+ insertPerson(personRecord);
}
break;
}
case CONTACTS_CHANGE_DELETED:
- {
- auto personIt = findPerson(contactId, ContactId);
- if (personIt != m_PersonList.end()) {
- deletePerson(personIt);
- }
+ removeContact(contactId);
break;
- }
}
}
onUpdateFinished();
}
+
+void PersonProvider::addContacts()
+{
+ contacts_list_h contacts = nullptr;
+ contacts_db_get_all_records(_contacts_contact._uri, 0, 0, &contacts);
+ for (auto &&record : makeRange(contacts)) {
+ auto it = findPerson(getRecordInt(record, _contacts_contact.person_id), PersonId);
+ if (it != m_PersonList.end()) {
+ Person *person = static_cast<Person *>(*it);
+ person->addContact(record);
+ } else {
+ contacts_record_destroy(record, true);
+ }
+ }
+ contacts_list_destroy(contacts, false);
+}
+
+void PersonProvider::removeContact(int contactId)
+{
+ auto personIt = findPerson(contactId, ContactId);
+ if (personIt != m_PersonList.end()) {
+ Person &person = static_cast<Person &>(**personIt);
+ person.removeContact(contactId);
+ if (!person.getContactCount()) {
+ deletePerson(personIt);
+ }
+ }
+}
+
void PersonProvider::subscribe()
{
resetDbVersion();