QmlDesigner: Update alias property declarations

Alias property declaration removal is now done before the normal
property declarations are synchronized.

Task-number: QDS-4525
Change-Id: Icddf5e041b672e4abfab89540906bbfdcc1a10ba
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Marco Bubke
2021-06-10 16:39:29 +02:00
parent b32f607bc7
commit 3112d063e8
2 changed files with 219 additions and 55 deletions

View File

@@ -70,6 +70,9 @@ public:
updatedTypeIds.push_back(declareType(type));
}
for (auto &&type : types)
synchronizeAliasPropertyDeclarationsRemoval(type);
for (auto &&type : types)
syncType(type);
@@ -111,14 +114,6 @@ public:
16, static_cast<void *>(importIds.data()), static_cast<long long>(importIds.size()));
}
PropertyDeclarationId upsertPropertyDeclaration(TypeId typeId,
Utils::SmallStringView name,
TypeId propertyTypeId)
{
return upsertPropertyDeclarationStatement
.template valueWithTransaction<PropertyDeclarationId>(&typeId, name, &propertyTypeId, 0);
}
PropertyDeclarationId fetchPropertyDeclarationByTypeIdAndName(TypeId typeId,
Utils::SmallStringView name)
{
@@ -488,7 +483,7 @@ private:
auto insert = [&](const Storage::PropertyDeclaration &value) {
auto propertyTypeId = fetchTypeIdByNameUngarded(value.typeName, importIds);
upsertPropertyDeclarationStatement.write(&typeId,
insertPropertyDeclarationStatement.write(&typeId,
value.name,
&propertyTypeId,
static_cast<int>(value.traits));
@@ -513,6 +508,35 @@ private:
Sqlite::insertUpdateDelete(range, propertyDeclarations, compareKey, insert, update, remove);
}
void synchronizeAliasPropertyDeclarationsRemoval(Storage::Type &type)
{
auto &aliasDeclarations = type.aliasDeclarations;
TypeId typeId = type.typeId;
std::sort(aliasDeclarations.begin(), aliasDeclarations.end(), [](auto &&first, auto &&second) {
return Sqlite::compare(first.name, second.name) < 0;
});
auto range = selectPropertyDeclarationsWithAliasForTypeIdStatement
.template range<Storage::AliasPropertyDeclarationView>(&typeId);
auto compareKey = [](const Storage::AliasPropertyDeclarationView &view,
const Storage::AliasPropertyDeclaration &value) {
return Sqlite::compare(view.name, value.name);
};
auto insert = [&](const Storage::AliasPropertyDeclaration &) {};
auto update = [&](const Storage::AliasPropertyDeclarationView &,
const Storage::AliasPropertyDeclaration &) {};
auto remove = [&](const Storage::AliasPropertyDeclarationView &view) {
deletePropertyDeclarationStatement.write(&view.id);
};
Sqlite::insertUpdateDelete(range, aliasDeclarations, compareKey, insert, update, remove);
}
void synchronizeAliasPropertyDeclarations(Storage::Type &type)
{
auto &aliasDeclarations = type.aliasDeclarations;
@@ -556,9 +580,7 @@ private:
&aliasId);
};
auto remove = [&](const Storage::AliasPropertyDeclarationView &view) {
deletePropertyDeclarationStatement.write(&view.id);
};
auto remove = [&](const Storage::AliasPropertyDeclarationView &) {};
Sqlite::insertUpdateDelete(range, aliasDeclarations, compareKey, insert, update, remove);
}
@@ -1002,9 +1024,15 @@ private:
Sqlite::ForeignKeyAction::NoAction,
Sqlite::ForeignKeyAction::Restrict);
propertyDeclarationTable.addColumn("propertyTraits");
propertyDeclarationTable.addColumn("aliasPropertyDeclarationId");
auto &aliasPropertyDeclarationIdColumn = propertyDeclarationTable.addForeignKeyColumn(
"aliasPropertyDeclarationId",
propertyDeclarationTable,
Sqlite::ForeignKeyAction::NoAction,
Sqlite::ForeignKeyAction::Restrict);
propertyDeclarationTable.addUniqueIndex({typeIdColumn, nameColumn});
propertyDeclarationTable.addIndex({aliasPropertyDeclarationIdColumn},
"aliasPropertyDeclarationId IS NOT NULL");
propertyDeclarationTable.initialize(database);
}
@@ -1141,8 +1169,8 @@ public:
" VALUES(?1) "
" UNION ALL "
" SELECT prototypeId FROM types JOIN typeSelection USING(typeId)) "
"SELECT typeId, propertyDeclarationId, propertyTraits FROM propertyDeclarations JOIN "
"typeSelection USING(typeId) "
"SELECT propertyTypeId, propertyDeclarationId, propertyTraits FROM propertyDeclarations "
" JOIN typeSelection USING(typeId) "
" WHERE name=?2 LIMIT 1",
database};
WriteStatement upsertExportedTypesStatement{"INSERT INTO exportedTypes(importId, name, typeId) "
@@ -1210,14 +1238,13 @@ public:
"propertyDeclarations WHERE typeId=? AND aliasPropertyDeclarationId IS NULL ORDER BY "
"name",
database};
WriteStatement upsertPropertyDeclarationStatement{
WriteStatement insertPropertyDeclarationStatement{
"INSERT INTO propertyDeclarations(typeId, name, propertyTypeId, propertyTraits) "
"VALUES(?1, ?2, ?3, ?4) ON CONFLICT DO UPDATE SET propertyTypeId=excluded.propertyTypeId, "
"propertyTraits=excluded.propertyTraits, aliasPropertyDeclarationId=NULL",
"VALUES(?1, ?2, ?3, ?4)",
database};
WriteStatement updatePropertyDeclarationStatement{
"UPDATE propertyDeclarations SET propertyTypeId=?2, propertyTraits=?3 WHERE "
"propertyDeclarationId=?1",
"propertyDeclarationId=?1 OR aliasPropertyDeclarationId=?1",
database};
WriteStatement deletePropertyDeclarationStatement{
"DELETE FROM propertyDeclarations WHERE propertyDeclarationId=?", database};

View File

@@ -529,7 +529,7 @@ protected:
"QAliasItem",
Storage::NativeType{"QQuickItem"},
TypeAccessSemantics::Reference,
sourceId1,
sourceId3,
importIds,
{Storage::ExportedType{"AliasItem"}}});
types.back().propertyDeclarations.push_back(
@@ -541,6 +541,19 @@ protected:
types.back().aliasDeclarations.push_back(
Storage::AliasPropertyDeclaration{"objects", Storage::NativeType{"QQuickItem"}, "objects"});
types.push_back(
Storage::Type{importId3,
"QObject2",
Storage::NativeType{},
TypeAccessSemantics::Reference,
sourceId4,
importIds,
{Storage::ExportedType{"Object2"}, Storage::ExportedType{"Obj2"}}});
types[3].propertyDeclarations.push_back(
Storage::PropertyDeclaration{"objects",
Storage::NativeType{"QObject"},
Storage::PropertyDeclarationTraits::IsList});
return types;
}
@@ -1408,7 +1421,7 @@ TEST_F(ProjectStorageSlowTest, SynchronizeTypesAddFunctionDeclarations)
{
Storage::Types types{createTypes()};
storage.synchronizeTypes(types, {});
storage.synchronizeTypes(types, {sourceId1, sourceId2});
ASSERT_THAT(storage.fetchTypes(),
Contains(AllOf(IsStorageType(importId2,
@@ -2331,7 +2344,7 @@ TEST_F(ProjectStorageSlowTest, SynchronizeTypesAddAliasDeclarations)
{
Storage::Types types{createTypesWithAliases()};
storage.synchronizeTypes(types, {});
storage.synchronizeTypes(types, {sourceId1, sourceId2, sourceId3, sourceId4});
ASSERT_THAT(storage.fetchTypes(),
Contains(AllOf(
@@ -2339,7 +2352,7 @@ TEST_F(ProjectStorageSlowTest, SynchronizeTypesAddAliasDeclarations)
"QAliasItem",
Storage::NativeType{"QQuickItem"},
TypeAccessSemantics::Reference,
sourceId1),
sourceId3),
Field(&Storage::Type::propertyDeclarations,
UnorderedElementsAre(
IsPropertyDeclaration("items",
@@ -2357,9 +2370,9 @@ TEST_F(ProjectStorageSlowTest, SynchronizeTypesAddAliasDeclarations)
TEST_F(ProjectStorageSlowTest, SynchronizeTypesAddAliasDeclarationsAgain)
{
Storage::Types types{createTypesWithAliases()};
storage.synchronizeTypes(types, {});
storage.synchronizeTypes(types, {sourceId1, sourceId2, sourceId3, sourceId4});
storage.synchronizeTypes(types, {});
storage.synchronizeTypes(types, {sourceId1, sourceId2, sourceId3, sourceId4});
ASSERT_THAT(storage.fetchTypes(),
Contains(AllOf(
@@ -2367,7 +2380,7 @@ TEST_F(ProjectStorageSlowTest, SynchronizeTypesAddAliasDeclarationsAgain)
"QAliasItem",
Storage::NativeType{"QQuickItem"},
TypeAccessSemantics::Reference,
sourceId1),
sourceId3),
Field(&Storage::Type::propertyDeclarations,
UnorderedElementsAre(
IsPropertyDeclaration("items",
@@ -2385,10 +2398,10 @@ TEST_F(ProjectStorageSlowTest, SynchronizeTypesAddAliasDeclarationsAgain)
TEST_F(ProjectStorageSlowTest, SynchronizeTypesRemoveAliasDeclarations)
{
Storage::Types types{createTypesWithAliases()};
storage.synchronizeTypes(types, {});
storage.synchronizeTypes(types, {sourceId1, sourceId2, sourceId3, sourceId4});
types[2].aliasDeclarations.pop_back();
storage.synchronizeTypes(types, {});
storage.synchronizeTypes({types[2]}, {sourceId3});
ASSERT_THAT(storage.fetchTypes(),
Contains(AllOf(
@@ -2396,7 +2409,7 @@ TEST_F(ProjectStorageSlowTest, SynchronizeTypesRemoveAliasDeclarations)
"QAliasItem",
Storage::NativeType{"QQuickItem"},
TypeAccessSemantics::Reference,
sourceId1),
sourceId3),
Field(&Storage::Type::propertyDeclarations,
UnorderedElementsAre(
IsPropertyDeclaration("items",
@@ -2413,34 +2426,24 @@ TEST_F(ProjectStorageSlowTest, SynchronizeTypesAddAliasDeclarationsThrowsForWron
Storage::Types types{createTypesWithAliases()};
types[2].aliasDeclarations[0].aliasTypeName = Storage::NativeType{"QQuickItemWrong"};
ASSERT_THROW(storage.synchronizeTypes(types, {}), QmlDesigner::TypeNameDoesNotExists);
ASSERT_THROW(storage.synchronizeTypes({types[2]}, {sourceId4}),
QmlDesigner::TypeNameDoesNotExists);
}
TEST_F(ProjectStorageSlowTest, SynchronizeTypesAddAliasDeclarationsThrowsForWrongPropertyName)
{
Storage::Types types{createTypesWithAliases()};
types[2].aliasDeclarations[0].aliasPropertyName = "childrenWrong";
ASSERT_THROW(storage.synchronizeTypes(types, {}), QmlDesigner::PropertyNameDoesNotExists);
ASSERT_THROW(storage.synchronizeTypes(types, {sourceId4}), QmlDesigner::PropertyNameDoesNotExists);
}
TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangeAliasDeclarationsTypeName)
{
Storage::Types types{createTypesWithAliases()};
types.push_back(Storage::Type{importId1,
"QObject2",
Storage::NativeType{},
TypeAccessSemantics::Reference,
sourceId2,
importIds,
{Storage::ExportedType{"Object2"}, Storage::ExportedType{"Obj2"}}});
types[3].propertyDeclarations.push_back(
Storage::PropertyDeclaration{"objects",
Storage::NativeType{"QObject"},
Storage::PropertyDeclarationTraits::IsList});
storage.synchronizeTypes(types, {});
storage.synchronizeTypes(types, {sourceId1, sourceId2, sourceId3, sourceId4});
types[2].aliasDeclarations[1].aliasTypeName = Storage::ExportedType{"Obj2"};
storage.synchronizeTypes(types, {});
storage.synchronizeTypes({types[2]}, {sourceId3});
ASSERT_THAT(storage.fetchTypes(),
Contains(AllOf(
@@ -2448,7 +2451,7 @@ TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangeAliasDeclarationsTypeName)
"QAliasItem",
Storage::NativeType{"QQuickItem"},
TypeAccessSemantics::Reference,
sourceId1),
sourceId3),
Field(&Storage::Type::propertyDeclarations,
UnorderedElementsAre(
IsPropertyDeclaration("items",
@@ -2456,7 +2459,7 @@ TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangeAliasDeclarationsTypeName)
Storage::PropertyDeclarationTraits::IsList
| Storage::PropertyDeclarationTraits::IsReadOnly),
IsPropertyDeclaration("objects",
Storage::NativeType{"QObject2"},
Storage::NativeType{"QObject"},
Storage::PropertyDeclarationTraits::IsList),
IsPropertyDeclaration("data",
Storage::NativeType{"QObject"},
@@ -2466,10 +2469,10 @@ TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangeAliasDeclarationsTypeName)
TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangeAliasDeclarationsPropertyName)
{
Storage::Types types{createTypesWithAliases()};
storage.synchronizeTypes(types, {});
storage.synchronizeTypes(types, {sourceId1, sourceId2, sourceId3, sourceId4});
types[2].aliasDeclarations[1].aliasPropertyName = "children";
storage.synchronizeTypes(types, {});
storage.synchronizeTypes({types[2]}, {sourceId3});
ASSERT_THAT(
storage.fetchTypes(),
@@ -2478,7 +2481,7 @@ TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangeAliasDeclarationsPropertyNa
"QAliasItem",
Storage::NativeType{"QQuickItem"},
TypeAccessSemantics::Reference,
sourceId1),
sourceId3),
Field(&Storage::Type::propertyDeclarations,
UnorderedElementsAre(
IsPropertyDeclaration("items",
@@ -2497,7 +2500,7 @@ TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangeAliasDeclarationsPropertyNa
TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangeAliasDeclarationsToPropertyDeclaration)
{
Storage::Types types{createTypesWithAliases()};
storage.synchronizeTypes(types, {});
storage.synchronizeTypes(types, {sourceId1, sourceId2, sourceId3, sourceId4});
types[2].aliasDeclarations.pop_back();
types[2].propertyDeclarations.push_back(
Storage::PropertyDeclaration{"objects",
@@ -2505,7 +2508,7 @@ TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangeAliasDeclarationsToProperty
Storage::PropertyDeclarationTraits::IsList
| Storage::PropertyDeclarationTraits::IsReadOnly});
storage.synchronizeTypes(types, {});
storage.synchronizeTypes({types[2]}, {sourceId3});
ASSERT_THAT(
storage.fetchTypes(),
@@ -2514,7 +2517,7 @@ TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangeAliasDeclarationsToProperty
"QAliasItem",
Storage::NativeType{"QQuickItem"},
TypeAccessSemantics::Reference,
sourceId1),
sourceId3),
Field(&Storage::Type::propertyDeclarations,
UnorderedElementsAre(
IsPropertyDeclaration("items",
@@ -2540,9 +2543,9 @@ TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangePropertyDeclarationsToAlias
Storage::NativeType{"QQuickItem"},
Storage::PropertyDeclarationTraits::IsList
| Storage::PropertyDeclarationTraits::IsReadOnly});
storage.synchronizeTypes(typesChanged, {});
storage.synchronizeTypes(typesChanged, {sourceId1, sourceId2, sourceId3, sourceId4});
storage.synchronizeTypes(types, {});
storage.synchronizeTypes(types, {sourceId1, sourceId2, sourceId3, sourceId4});
ASSERT_THAT(storage.fetchTypes(),
Contains(AllOf(
@@ -2550,7 +2553,7 @@ TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangePropertyDeclarationsToAlias
"QAliasItem",
Storage::NativeType{"QQuickItem"},
TypeAccessSemantics::Reference,
sourceId1),
sourceId3),
Field(&Storage::Type::propertyDeclarations,
UnorderedElementsAre(
IsPropertyDeclaration("items",
@@ -2565,4 +2568,138 @@ TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangePropertyDeclarationsToAlias
Storage::PropertyDeclarationTraits::IsList))))));
}
TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangeAliasTargetPropertyDeclarationTraits)
{
Storage::Types types{createTypesWithAliases()};
storage.synchronizeTypes(types, {sourceId1, sourceId2, sourceId3, sourceId4});
types[1].propertyDeclarations[0].traits = Storage::PropertyDeclarationTraits::IsList
| Storage::PropertyDeclarationTraits::IsReadOnly;
storage.synchronizeTypes({types[1]}, {sourceId2});
ASSERT_THAT(
storage.fetchTypes(),
Contains(
AllOf(IsStorageType(importId2,
"QAliasItem",
Storage::NativeType{"QQuickItem"},
TypeAccessSemantics::Reference,
sourceId3),
Field(&Storage::Type::propertyDeclarations,
UnorderedElementsAre(
IsPropertyDeclaration("items",
Storage::NativeType{"QQuickItem"},
Storage::PropertyDeclarationTraits::IsList
| Storage::PropertyDeclarationTraits::IsReadOnly),
IsPropertyDeclaration("objects",
Storage::NativeType{"QObject"},
Storage::PropertyDeclarationTraits::IsList
| Storage::PropertyDeclarationTraits::IsReadOnly),
IsPropertyDeclaration("data",
Storage::NativeType{"QObject"},
Storage::PropertyDeclarationTraits::IsList))))));
}
TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangeAliasTargetPropertyDeclarationTypeName)
{
Storage::Types types{createTypesWithAliases()};
storage.synchronizeTypes(types, {sourceId1, sourceId2, sourceId3, sourceId4});
types[1].propertyDeclarations[0].typeName = Storage::ExportedType{"Item"};
storage.synchronizeTypes({types[1]}, {sourceId2});
ASSERT_THAT(storage.fetchTypes(),
Contains(AllOf(
IsStorageType(importId2,
"QAliasItem",
Storage::NativeType{"QQuickItem"},
TypeAccessSemantics::Reference,
sourceId3),
Field(&Storage::Type::propertyDeclarations,
UnorderedElementsAre(
IsPropertyDeclaration("items",
Storage::NativeType{"QQuickItem"},
Storage::PropertyDeclarationTraits::IsList
| Storage::PropertyDeclarationTraits::IsReadOnly),
IsPropertyDeclaration("objects",
Storage::NativeType{"QQuickItem"},
Storage::PropertyDeclarationTraits::IsList),
IsPropertyDeclaration("data",
Storage::NativeType{"QObject"},
Storage::PropertyDeclarationTraits::IsList))))));
}
TEST_F(ProjectStorageSlowTest, SynchronizeTypesRemovePropertyDeclarationWithAnAliasThrows)
{
Storage::Types types{createTypesWithAliases()};
storage.synchronizeTypes(types, {sourceId1, sourceId2, sourceId3, sourceId4});
types[1].propertyDeclarations.pop_back();
ASSERT_THROW(storage.synchronizeTypes({types[1]}, {sourceId2}),
Sqlite::ConstraintPreventsModification);
}
TEST_F(ProjectStorageSlowTest, SynchronizeTypesRemovePropertyDeclarationAndAlias)
{
Storage::Types types{createTypesWithAliases()};
storage.synchronizeTypes(types, {sourceId1, sourceId2, sourceId3, sourceId4});
types[1].propertyDeclarations.pop_back();
types[2].aliasDeclarations.pop_back();
storage.synchronizeTypes({types[1], types[2]}, {sourceId2, sourceId3});
ASSERT_THAT(storage.fetchTypes(),
Contains(AllOf(
IsStorageType(importId2,
"QAliasItem",
Storage::NativeType{"QQuickItem"},
TypeAccessSemantics::Reference,
sourceId3),
Field(&Storage::Type::propertyDeclarations,
UnorderedElementsAre(
IsPropertyDeclaration("items",
Storage::NativeType{"QQuickItem"},
Storage::PropertyDeclarationTraits::IsList
| Storage::PropertyDeclarationTraits::IsReadOnly),
IsPropertyDeclaration("data",
Storage::NativeType{"QObject"},
Storage::PropertyDeclarationTraits::IsList))))));
}
TEST_F(ProjectStorageSlowTest, SynchronizeTypesRemoveTypeWithAliasTargetPropertyDeclarationThrows)
{
Storage::Types types{createTypesWithAliases()};
types[2].aliasDeclarations[1].aliasTypeName = Storage::ExportedType{"Object2"};
storage.synchronizeTypes(types, {sourceId1, sourceId2, sourceId3, sourceId4});
ASSERT_THROW(storage.synchronizeTypes({}, {sourceId4}), Sqlite::ConstraintPreventsModification);
}
TEST_F(ProjectStorageSlowTest, SynchronizeTypesRemoveTypeAndAliasPropertyDeclaration)
{
Storage::Types types{createTypesWithAliases()};
types[2].aliasDeclarations[1].aliasTypeName = Storage::ExportedType{"Object2"};
storage.synchronizeTypes(types, {sourceId1, sourceId2, sourceId3, sourceId4});
types[2].aliasDeclarations.pop_back();
storage.synchronizeTypes({types[0], types[2]}, {sourceId1, sourceId3});
ASSERT_THAT(storage.fetchTypes(),
Contains(AllOf(
IsStorageType(importId2,
"QAliasItem",
Storage::NativeType{"QQuickItem"},
TypeAccessSemantics::Reference,
sourceId3),
Field(&Storage::Type::propertyDeclarations,
UnorderedElementsAre(
IsPropertyDeclaration("items",
Storage::NativeType{"QQuickItem"},
Storage::PropertyDeclarationTraits::IsList
| Storage::PropertyDeclarationTraits::IsReadOnly),
IsPropertyDeclaration("data",
Storage::NativeType{"QObject"},
Storage::PropertyDeclarationTraits::IsList))))));
}
} // namespace