chore(LeftJoinModel): add detection of duplicated roles

This commit is contained in:
Michał Cieślak 2023-10-28 18:42:36 +02:00 committed by Michał
parent cc964508f1
commit 7847cb3b11
2 changed files with 176 additions and 18 deletions

View File

@ -22,41 +22,56 @@ void LeftJoinModel::initialize()
auto leftRoleNames = m_leftModel->roleNames();
auto rightRoleNames = m_rightModel->roleNames();
if (leftRoleNames.isEmpty() || rightRoleNames.isEmpty()) {
qWarning() << "Both left and right models have to contain some roles!";
auto leftNames = leftRoleNames.values();
auto rightNames = rightRoleNames.values();
QSet<QByteArray> leftNamesSet(leftNames.cbegin(), leftNames.cend());
QSet<QByteArray> rightNamesSet(rightNames.cbegin(), rightNames.cend());
if (leftNames.size() != leftNamesSet.size()
|| rightNames.size() != rightNamesSet.size()) {
qWarning() << "Each of the source models must have unique role names!";
return;
}
auto leftModelJoinRoleList = leftRoleNames.keys(m_joinRole.toUtf8());
auto rightModelJoinRoleList = rightRoleNames.keys(m_joinRole.toUtf8());
auto namesIntersection = leftNamesSet.intersect(rightNamesSet);
auto hasCommonJoinRole = namesIntersection.remove(m_joinRole.toUtf8());
if (leftModelJoinRoleList.size() != 1
|| rightModelJoinRoleList.size() != 1) {
if (!hasCommonJoinRole) {
qWarning().noquote() << QString("Both left and right models have to "
"contain join role %1!").arg(m_joinRole);
return;
}
m_leftModelJoinRole = leftModelJoinRoleList.at(0);
m_rightModelJoinRole = rightModelJoinRoleList.at(0);
if (!namesIntersection.isEmpty()) {
qWarning().nospace() << "Source models contain conflicting model names: "
<< QList(namesIntersection.cbegin(),
namesIntersection.cend())
<< "!";
return;
}
auto leftRoles = leftRoleNames.keys();
auto maxLeftRole = std::max_element(leftRoles.cbegin(), leftRoles.cend());
auto rightRolesOffset = *maxLeftRole + 1;
auto roleNames = leftRoleNames;
QVector<int> joinedRoles;
auto i = rightRoleNames.constBegin();
while (i != rightRoleNames.constEnd()) {
if (i.value() != m_joinRole) {
auto roleWithOffset = i.key() + rightRolesOffset;
roleNames.insert(roleWithOffset, i.value());
m_joinedRoles.append(roleWithOffset);
joinedRoles.append(roleWithOffset);
}
++i;
}
m_roleNames = std::move(roleNames);
m_joinedRoles = std::move(joinedRoles);
m_leftModelJoinRole = leftRoleNames.key(m_joinRole.toUtf8());
m_rightModelJoinRole = rightRoleNames.key(m_joinRole.toUtf8());
m_rightModelRolesOffset = rightRolesOffset;
m_roleNames = roleNames;
connect(m_rightModel, &QAbstractItemModel::dataChanged, this,
[this](auto& topLeft, auto& bottomRight, auto& roles) {

View File

@ -11,7 +11,6 @@ namespace {
class TestSourceModel : public QAbstractListModel {
public:
explicit TestSourceModel(QList<QPair<QString, QVariantList>> data)
: m_data(std::move(data))
{
@ -86,7 +85,7 @@ private:
QHash<int, QByteArray> m_roles;
};
}
} // anonymous namespace
class TestLeftJoinModel: public QObject
{
@ -102,6 +101,25 @@ private slots:
QCOMPARE(model.roleNames(), {});
}
void setSourceModelDirectlyTest()
{
TestSourceModel leftModel({
{ "title", { "Token 1", "Token 2" }},
{ "communityId", { "community_1", "community_2" }}
});
LeftJoinModel model;
QAbstractItemModelTester tester(&model);
QTest::ignoreMessage(QtWarningMsg,
"Source model is not intended to be set directly "
"on this model. Use setLeftModel and setRightModel instead!");
model.setSourceModel(&leftModel);
QCOMPARE(model.rowCount(), 0);
QCOMPARE(model.roleNames(), {});
}
void initializationTest()
{
TestSourceModel leftModel({
@ -135,23 +153,145 @@ private slots:
QCOMPARE(model.roleNames(), roles);
}
void setSourceModelDirectlyTest()
void collidingRolesTest()
{
TestSourceModel leftModel({
{ "title", { "Token 1", "Token 2" }},
{ "name", { "Token 1", "Token 2" }},
{ "communityId", { "community_1", "community_2" }}
});
TestSourceModel rightModel({
{ "name", { "Community 1", "Community 2" }},
{ "communityId", { "community_1", "community_2" }}
});
LeftJoinModel model;
QAbstractItemModelTester tester(&model);
QTest::ignoreMessage(QtWarningMsg,
"Source model is not intended to be set directly "
"on this model. Use setLeftModel and setRightModel instead!");
model.setSourceModel(&leftModel);
model.setLeftModel(&leftModel);
QCOMPARE(model.rowCount(), 0);
QCOMPARE(model.roleNames(), {});
model.setRightModel(&rightModel);
QCOMPARE(model.rowCount(), 0);
QCOMPARE(model.roleNames(), {});
QTest::ignoreMessage(QtWarningMsg,
"Source models contain conflicting model names: "
"(\"name\")!");
model.setJoinRole("communityId");
QCOMPARE(model.rowCount(), 0);
QCOMPARE(model.roleNames(), {});
}
void duplicatedRolesTest()
{
{
TestSourceModel leftModel({
{ "name", { "Token 1", "Token 2" }},
{ "name", { "Token 1", "Token 2" }},
{ "communityId", { "community_1", "community_2" }}
});
TestSourceModel rightModel({
{ "title", { "Community 1", "Community 2" }},
{ "communityId", { "community_1", "community_2" }}
});
LeftJoinModel model;
QAbstractItemModelTester tester(&model);
model.setLeftModel(&leftModel);
QCOMPARE(model.rowCount(), 0);
QCOMPARE(model.roleNames(), {});
model.setRightModel(&rightModel);
QCOMPARE(model.rowCount(), 0);
QCOMPARE(model.roleNames(), {});
QTest::ignoreMessage(QtWarningMsg,
"Each of the source models must have unique "
"role names!");
model.setJoinRole("communityId");
QCOMPARE(model.rowCount(), 0);
QCOMPARE(model.roleNames(), {});
}
{
TestSourceModel leftModel({
{ "name", { "Token 1", "Token 2" }},
{ "communityId", { "community_1", "community_2" }},
{ "communityId", { "community_1", "community_2" }}
});
TestSourceModel rightModel({
{ "title", { "Community 1", "Community 2" }},
{ "communityId", { "community_1", "community_2" }}
});
LeftJoinModel model;
QAbstractItemModelTester tester(&model);
model.setLeftModel(&leftModel);
QCOMPARE(model.rowCount(), 0);
QCOMPARE(model.roleNames(), {});
model.setRightModel(&rightModel);
QCOMPARE(model.rowCount(), 0);
QCOMPARE(model.roleNames(), {});
QTest::ignoreMessage(QtWarningMsg,
"Each of the source models must have unique "
"role names!");
model.setJoinRole("communityId");
QCOMPARE(model.rowCount(), 0);
QCOMPARE(model.roleNames(), {});
}
{
TestSourceModel leftModel({
{ "name", { "Token 1", "Token 2" }},
{ "communityId", { "community_1", "community_2" }}
});
TestSourceModel rightModel({
{ "title", { "Community 1", "Community 2" }},
{ "title", { "Community 1", "Community 2" }},
{ "communityId", { "community_1", "community_2" }}
});
LeftJoinModel model;
QAbstractItemModelTester tester(&model);
model.setLeftModel(&leftModel);
QCOMPARE(model.rowCount(), 0);
QCOMPARE(model.roleNames(), {});
model.setRightModel(&rightModel);
QCOMPARE(model.rowCount(), 0);
QCOMPARE(model.roleNames(), {});
QTest::ignoreMessage(QtWarningMsg,
"Each of the source models must have unique "
"role names!");
model.setJoinRole("communityId");
QCOMPARE(model.rowCount(), 0);
QCOMPARE(model.roleNames(), {});
}
}
void noJoinRoleTest()
@ -266,6 +406,7 @@ private slots:
TestSourceModel rightModel({
{ "name", { "Community 1", "Community 2" }},
{ "color", { "red", "blue" }},
{ "communityId", { "community_1", "community_2" }}
});
@ -283,6 +424,8 @@ private slots:
QCOMPARE(model.data(model.index(1, 0), 1), QString("community_2"));
QCOMPARE(model.data(model.index(0, 0), 2), QString("Community 1"));
QCOMPARE(model.data(model.index(1, 0), 2), QString("Community 2"));
QCOMPARE(model.data(model.index(0, 0), 3), QString("red"));
QCOMPARE(model.data(model.index(1, 0), 3), QString("blue"));
}
void changesPropagationTest()