Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[qtcontacts-sqlite] Store display label group sort order to table man…
…ually. Contributes to JB#44742
  • Loading branch information
Chris Adams committed Apr 15, 2019
1 parent d1af84a commit 905f6b7
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 52 deletions.
9 changes: 6 additions & 3 deletions src/engine/contactreader.cpp
Expand Up @@ -1411,7 +1411,10 @@ static QString buildOrderBy(const QContactSortOrder &order, QStringList *joins,
return QString();
}

QString sortExpression(QStringLiteral("%1.%2").arg(detail.joinToSort ? detail.table : QStringLiteral("Contacts")).arg(field.column));
const bool isDisplayLabelGroup = detail.detailType == QContactDisplayLabel::Type && field.field == QContactDisplayLabel__FieldLabelGroup;
QString sortExpression(QStringLiteral("%1.%2")
.arg(detail.joinToSort ? detail.table : QStringLiteral("Contacts"))
.arg(isDisplayLabelGroup ? QStringLiteral("DisplayLabelGroupSortOrder") : field.column));
bool sortBlanks = true;
bool collate = true;
bool localized = field.fieldType == LocalizedField;
Expand Down Expand Up @@ -1458,7 +1461,7 @@ static QString buildOrderBy(const QContactSortOrder &order, QStringList *joins,

result.append(sortExpression);

if (collate) {
if (!isDisplayLabelGroup && collate) {
if (localized && useLocale) {
result.append(QLatin1String(" COLLATE localeCollation"));
} else {
Expand Down Expand Up @@ -1936,7 +1939,7 @@ QContactManager::Error ContactReader::queryContacts(
QContactManager::Error err = QContactManager::NoError;

const QString idsQueryStatement(QString::fromLatin1(
"SELECT " // Contacts.*, but order can change due to schema upgrades, so list manually.
"SELECT " // order and content can change due to schema upgrades, so list manually.
"Contacts.contactId, "
"Contacts.displayLabel, "
"Contacts.displayLabelGroup, "
Expand Down
51 changes: 48 additions & 3 deletions src/engine/contactsdatabase.cpp
Expand Up @@ -67,7 +67,8 @@ static const char *createContactsTable =
"\n CREATE TABLE Contacts ("
"\n contactId INTEGER PRIMARY KEY ASC AUTOINCREMENT,"
"\n displayLabel TEXT,"
"\n displayLabelGroup TEXT," // Don't specify `COLLATE localeCollation` as a change in locale would be equivalent to a database corruption
"\n displayLabelGroup TEXT,"
"\n displayLabelGroupSortOrder INTEGER,"
"\n firstName TEXT,"
"\n lowerFirstName TEXT,"
"\n lastName TEXT,"
Expand Down Expand Up @@ -1715,6 +1716,24 @@ static bool addDisplayLabelGroup(QSqlDatabase &database)
}
alterQuery.finish();
}
// add the display label group sort order column (precalculated sort index)
{
QSqlQuery alterQuery(database);
const QString statement = QStringLiteral("ALTER TABLE Contacts ADD COLUMN displayLabelGroupSortOrder INTEGER");
if (!alterQuery.prepare(statement)) {
QTCONTACTS_SQLITE_WARNING(QString::fromLatin1("Failed to prepare add display label group sort order column query: %1\n%2")
.arg(alterQuery.lastError().text())
.arg(statement));
return false;
}
if (!alterQuery.exec()) {
QTCONTACTS_SQLITE_WARNING(QString::fromLatin1("Failed to add display label group sort order column: %1\n%2")
.arg(alterQuery.lastError().text())
.arg(statement));
return false;
}
alterQuery.finish();
}

return true;
}
Expand Down Expand Up @@ -1844,6 +1863,7 @@ static bool executeDisplayLabelGroupLocalizationStatements(QSqlDatabase &databas
// for every single contact in our database, read the data required to generate the display label group data.
QVariantList contactIds;
QVariantList displayLabelGroups;
QVariantList displayLabelGroupSortOrders;
{
QSqlQuery selectQuery(database);
selectQuery.setForwardOnly(true);
Expand Down Expand Up @@ -1876,7 +1896,9 @@ static bool executeDisplayLabelGroupLocalizationStatements(QSqlDatabase &databas
c.saveDetail(&n);
c.saveDetail(&dl);

displayLabelGroups.append(cdb->determineDisplayLabelGroup(c));
const QString dlg = cdb->determineDisplayLabelGroup(c);
displayLabelGroups.append(dlg);
displayLabelGroupSortOrders.append(cdb->possibleDisplayLabelGroups().indexOf(dlg) + 1);
}
selectQuery.finish();
}
Expand All @@ -1886,17 +1908,19 @@ static bool executeDisplayLabelGroupLocalizationStatements(QSqlDatabase &databas
{
for (int i = 0; i < displayLabelGroups.size(); i += 167) {
const QVariantList groups = displayLabelGroups.mid(i, qMin(displayLabelGroups.size() - i, 167));
const QVariantList sortorders = displayLabelGroupSortOrders.mid(i, qMin(displayLabelGroups.size() - i, 167));
const QVariantList ids = contactIds.mid(i, qMin(displayLabelGroups.size() - i, 167));

QSqlQuery updateQuery(database);
const QString statement = QStringLiteral("UPDATE Contacts SET displayLabelGroup = ? WHERE contactId = ?");
const QString statement = QStringLiteral("UPDATE Contacts SET displayLabelGroup = ?, displayLabelGroupSortOrder = ? WHERE contactId = ?");
if (!updateQuery.prepare(statement)) {
QTCONTACTS_SQLITE_WARNING(QString::fromLatin1("Failed to prepare update display label groups query: %1\n%2")
.arg(updateQuery.lastError().text())
.arg(statement));
return false;
}
updateQuery.addBindValue(groups);
updateQuery.addBindValue(sortorders);
updateQuery.addBindValue(ids);
if (!updateQuery.execBatch()) {
QTCONTACTS_SQLITE_WARNING(QString::fromLatin1("Failed to update display label groups: %1\n%2")
Expand Down Expand Up @@ -2743,6 +2767,22 @@ bool ContactsDatabase::open(const QString &connectionName, bool nonprivileged, b
}
}
m_dlgGenerators.append(m_defaultGenerator.data());

// and build a "superlist" of possible display label groups
// which defines a total sort ordering for display label groups.
const QLocale locale;
for (auto generator : m_dlgGenerators) {
if (generator->validForLocale(locale)) {
const QStringList groups = generator->displayLabelGroups();
for (const QString &group : groups) {
if (!m_possibleDisplayLabelGroups.contains(group)) {
m_possibleDisplayLabelGroups.append(group);
}
}
}
}
m_possibleDisplayLabelGroups.removeAll(QStringLiteral("#"));
m_possibleDisplayLabelGroups.append(QStringLiteral("#"));
}

if (m_database.isOpen()) {
Expand Down Expand Up @@ -3323,6 +3363,11 @@ QStringList ContactsDatabase::displayLabelGroups() const
return groups;
}

QStringList ContactsDatabase::possibleDisplayLabelGroups() const
{
return m_possibleDisplayLabelGroups;
}

#include "../extensions/qcontactdeactivated_impl.h"
#include "../extensions/qcontactincidental_impl.h"
#include "../extensions/qcontactoriginmetadata_impl.h"
Expand Down
2 changes: 2 additions & 0 deletions src/engine/contactsdatabase.h
Expand Up @@ -154,6 +154,7 @@ class ContactsDatabase

QString determineDisplayLabelGroup(const QContact &c) const;
QStringList displayLabelGroups() const;
QStringList possibleDisplayLabelGroups() const;

static bool execute(QSqlQuery &query);
static bool executeBatch(QSqlQuery &query, QSqlQuery::BatchExecutionMode mode = QSqlQuery::ValuesAsRows);
Expand All @@ -179,6 +180,7 @@ class ContactsDatabase
QHash<QString, QSqlQuery> m_preparedQueries;
QVector<QtContactsSqliteExtensions::DisplayLabelGroupGenerator*> m_dlgGenerators;
QScopedPointer<QtContactsSqliteExtensions::DisplayLabelGroupGenerator> m_defaultGenerator;
QStringList m_possibleDisplayLabelGroups;
};

#endif
70 changes: 38 additions & 32 deletions src/engine/contactwriter.cpp
Expand Up @@ -5542,6 +5542,7 @@ ContactsDatabase::Query ContactWriter::bindContactDetails(const QContact &contac
" INSERT INTO Contacts ("
" displayLabel,"
" displayLabelGroup,"
" displayLabelGroupSortOrder,"
" firstName,"
" lowerFirstName,"
" lastName,"
Expand All @@ -5564,6 +5565,7 @@ ContactsDatabase::Query ContactWriter::bindContactDetails(const QContact &contac
" VALUES ("
" :displayLabel,"
" :displayLabelGroup,"
" :displayLabelGroupSortOrder,"
" :firstName,"
" :lowerFirstName,"
" :lastName,"
Expand All @@ -5588,6 +5590,7 @@ ContactsDatabase::Query ContactWriter::bindContactDetails(const QContact &contac
" UPDATE Contacts SET"
" displayLabel = :displayLabel,"
" displayLabelGroup = :displayLabelGroup,"
" displayLabelGroupSortOrder = :displayLabelGroupSortOrder,"
" firstName = :firstName,"
" lowerFirstName = :lowerFirstName,"
" lastName = :lastName,"
Expand Down Expand Up @@ -5620,29 +5623,32 @@ ContactsDatabase::Query ContactWriter::bindContactDetails(const QContact &contac
QContactDisplayLabel label = contact.detail<QContactDisplayLabel>();
const QString displayLabel = label.label().trimmed();
query.bindValue(0, displayLabel);
query.bindValue(1, m_database.determineDisplayLabelGroup(contact));

query.bindValue(2, firstName);
query.bindValue(3, firstName.toLower());
query.bindValue(4, lastName);
query.bindValue(5, lastName.toLower());
query.bindValue(6, name.value<QString>(QContactName::FieldMiddleName).trimmed());
query.bindValue(7, name.value<QString>(QContactName::FieldPrefix).trimmed());
query.bindValue(8, name.value<QString>(QContactName::FieldSuffix).trimmed());
query.bindValue(9, name.value<QString>(QContactName__FieldCustomLabel).trimmed());
const QString displayLabelGroup = m_database.determineDisplayLabelGroup(contact);
query.bindValue(1, displayLabelGroup);
const int displayLabelGroupSortOrder = m_database.possibleDisplayLabelGroups().indexOf(displayLabelGroup) + 1;
query.bindValue(2, displayLabelGroupSortOrder);

query.bindValue(3, firstName);
query.bindValue(4, firstName.toLower());
query.bindValue(5, lastName);
query.bindValue(6, lastName.toLower());
query.bindValue(7, name.value<QString>(QContactName::FieldMiddleName).trimmed());
query.bindValue(8, name.value<QString>(QContactName::FieldPrefix).trimmed());
query.bindValue(9, name.value<QString>(QContactName::FieldSuffix).trimmed());
query.bindValue(10, name.value<QString>(QContactName__FieldCustomLabel).trimmed());

const QString syncTarget(contact.detail<QContactSyncTarget>().syncTarget());
query.bindValue(10, syncTarget);
query.bindValue(11, syncTarget);

const QContactTimestamp timestamp = contact.detail<QContactTimestamp>();
query.bindValue(11, ContactsDatabase::dateTimeString(timestamp.value<QDateTime>(QContactTimestamp::FieldCreationTimestamp).toUTC()));
query.bindValue(12, ContactsDatabase::dateTimeString(timestamp.value<QDateTime>(QContactTimestamp::FieldModificationTimestamp).toUTC()));
query.bindValue(12, ContactsDatabase::dateTimeString(timestamp.value<QDateTime>(QContactTimestamp::FieldCreationTimestamp).toUTC()));
query.bindValue(13, ContactsDatabase::dateTimeString(timestamp.value<QDateTime>(QContactTimestamp::FieldModificationTimestamp).toUTC()));

const QContactGender gender = contact.detail<QContactGender>();
query.bindValue(13, QString::number(static_cast<int>(gender.gender())));
query.bindValue(14, QString::number(static_cast<int>(gender.gender())));

const QContactFavorite favorite = contact.detail<QContactFavorite>();
query.bindValue(14, favorite.isFavorite());
query.bindValue(15, favorite.isFavorite());

// Does this contact contain the information needed to update hasPhoneNumber?
bool hasPhoneNumberKnown = definitionMask.isEmpty() || detailListContains<QContactPhoneNumber>(definitionMask);
Expand Down Expand Up @@ -5677,26 +5683,26 @@ ContactsDatabase::Query ContactWriter::bindContactDetails(const QContact &contac
}

if (update) {
query.bindValue(15, hasPhoneNumberKnown);
query.bindValue(16, hasPhoneNumber);
query.bindValue(17, hasEmailAddressKnown);
query.bindValue(18, hasEmailAddress);
query.bindValue(19, hasOnlineAccountKnown);
query.bindValue(20, hasOnlineAccount);
query.bindValue(21, isOnlineKnown);
query.bindValue(22, isOnline);
query.bindValue(23, isDeactivatedKnown);
query.bindValue(24, isDeactivated);
query.bindValue(25, contactId);
query.bindValue(16, hasPhoneNumberKnown);
query.bindValue(17, hasPhoneNumber);
query.bindValue(18, hasEmailAddressKnown);
query.bindValue(19, hasEmailAddress);
query.bindValue(20, hasOnlineAccountKnown);
query.bindValue(21, hasOnlineAccount);
query.bindValue(22, isOnlineKnown);
query.bindValue(23, isOnline);
query.bindValue(24, isDeactivatedKnown);
query.bindValue(25, isDeactivated);
query.bindValue(26, contactId);
} else {
query.bindValue(15, hasPhoneNumber);
query.bindValue(16, hasEmailAddress);
query.bindValue(17, hasOnlineAccount);
query.bindValue(18, isOnline);
query.bindValue(19, isDeactivated);
query.bindValue(16, hasPhoneNumber);
query.bindValue(17, hasEmailAddress);
query.bindValue(18, hasOnlineAccount);
query.bindValue(19, isOnline);
query.bindValue(20, isDeactivated);

// Incidental state only applies to creation
query.bindValue(20, !contact.details<QContactIncidental>().isEmpty());
query.bindValue(21, !contact.details<QContactIncidental>().isEmpty());
}

return query;
Expand Down
16 changes: 8 additions & 8 deletions tests/auto/displaylabelgroups/test/tst_displaylabelgroups.cpp
Expand Up @@ -238,8 +238,8 @@ void tst_DisplayLabelGroups::testDisplayLabelGroups()
// fixup for potential ambiguity in sort order. 3, 7 and 9 all sort equally.
actualOrder.replace(QChar('7'), QChar('3'));
actualOrder.replace(QChar('9'), QChar('3'));
QCOMPARE(actualOrder, QStringLiteral("158233346"));
QCOMPARE(actualGroups, QStringLiteral("1345EEEOZ"));
QCOMPARE(actualOrder, QStringLiteral("615824333"));
QCOMPARE(actualGroups, QStringLiteral("Z1345OEEE"));

// Now sort by display label group followed by last name.
// We expect the same sorting as display-group-only sorting,
Expand All @@ -259,8 +259,8 @@ void tst_DisplayLabelGroups::testDisplayLabelGroups()
}
// fixup for potential ambiguity in sort order. 3 and 9 sort equally.
actualOrder.replace(QChar('9'), QChar('3'));
QCOMPARE(actualOrder, QStringLiteral("158233746"));
QCOMPARE(actualGroups, QStringLiteral("1345EEEOZ"));
QCOMPARE(actualOrder, QStringLiteral("615824337"));
QCOMPARE(actualGroups, QStringLiteral("Z1345OEEE"));

// Now sort by display label group followed by first name.
// We expect the same sorting as display-group-only sorting,
Expand All @@ -278,8 +278,8 @@ void tst_DisplayLabelGroups::testDisplayLabelGroups()
}
actualGroups += c.detail<QContactDisplayLabel>().value(QContactDisplayLabel__FieldLabelGroup).toString();
}
QCOMPARE(actualOrder, QStringLiteral("158279346"));
QCOMPARE(actualGroups, QStringLiteral("1345EEEOZ"));
QCOMPARE(actualOrder, QStringLiteral("615824793"));
QCOMPARE(actualGroups, QStringLiteral("Z1345OEEE"));

// Now sort by display label group followed by last name followed by first name.
// We expect the same sorting as display-group-only sorting,
Expand All @@ -295,8 +295,8 @@ void tst_DisplayLabelGroups::testDisplayLabelGroups()
}
actualGroups += c.detail<QContactDisplayLabel>().value(QContactDisplayLabel__FieldLabelGroup).toString();
}
QCOMPARE(actualOrder, QStringLiteral("158293746"));
QCOMPARE(actualGroups, QStringLiteral("1345EEEOZ"));
QCOMPARE(actualOrder, QStringLiteral("615824937"));
QCOMPARE(actualGroups, QStringLiteral("Z1345OEEE"));
}

QTEST_MAIN(tst_DisplayLabelGroups)
Expand Down
Expand Up @@ -77,8 +77,8 @@ QStringList TestDlgg::displayLabelGroups() const
QStringLiteral("3"),
QStringLiteral("4"),
QStringLiteral("5"),
QStringLiteral("O"), // sort O before E to test DisplayLabelGroupSortOrder semantics
QStringLiteral("E"),
QStringLiteral("O"),
};
return allGroups;
}
Expand Down
Expand Up @@ -1923,11 +1923,6 @@ void tst_QContactManagerFiltering::sorting_data()
// Note - the current display label algorithm follows that of nemo-qml-plugin-contacts, and does not include prefix
//newMRow("display label insensitive, binary collation", manager) << manager << dldef << dlfld << asc << false << 0 << ci << "bcdefgaijhk" << "efg"; // the display label is synthesized so that A has "Sir" at the start of it (instead of "Aaron").
//newMRow("display label sensitive, binary collation", manager) << manager << dldef << dlfld << asc << false << 0 << cs << "bcdefgaikjh" << "efg";

#ifdef DISPLAY_LABEL_GROUP_STORAGE_SUPPORTED
FieldIdentifier dlgfld = QContactDisplayLabel__FieldLabelGroup;
newMRow("display label group descending, locale collation", manager) << manager << dldef << dlgfld << asc << false << 0 << cs << "abcdefghijk" << "hijk";
#endif
}
}

Expand Down

0 comments on commit 905f6b7

Please sign in to comment.