diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h index 18f3f491a06..6afdedf6f6f 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h @@ -233,7 +233,17 @@ public: return commonTypeCache.template builtinTypeId(); } - auto prototypes(TypeId type) const {} + TypeIds prototypeIds(TypeId type) const + { + return selectPrototypeIdsForTypeIdInOrderStatement.template valuesWithTransaction(16, + type); + } + + TypeIds prototypeAndSelfIds(TypeId type) const + { + return selectPrototypeAndSelfIdsForTypeIdInOrderStatement + .template valuesWithTransaction(16, type); + } PropertyDeclarationId fetchPropertyDeclarationByTypeIdAndName(TypeId typeId, Utils::SmallStringView name) @@ -2968,12 +2978,12 @@ public: " SELECT typeId, prototypeId FROM types WHERE prototypeId IS NOT NULL" " UNION ALL " " SELECT typeId, extensionId FROM types WHERE extensionId IS NOT NULL)," - " prototype_and_extension(typeId) AS (" + " prototypes(typeId) AS (" " SELECT prototypeId FROM all_prototype_and_extension WHERE typeId=?" " UNION ALL " - " SELECT prototypeId FROM all_prototype_and_extension JOIN prototype_and_extension " - " USING(typeId)) " - "SELECT typeId FROM prototype_and_extension", + " SELECT prototypeId FROM all_prototype_and_extension JOIN " + " prototypes USING(typeId)) " + "SELECT typeId FROM prototypes", database}; WriteStatement<3> updatePropertyDeclarationAliasIdAndTypeNameIdStatement{ "UPDATE propertyDeclarations SET aliasPropertyDeclarationId=?2, " @@ -3223,6 +3233,32 @@ public: "UPDATE types SET defaultPropertyId=NULL WHERE defaultPropertyId=?1", database}; mutable ReadStatement<2, 1> selectInfoTypeByTypeIdStatement{ "SELECT defaultPropertyId, traits FROM types WHERE typeId=?", database}; + mutable ReadStatement<1, 1> selectPrototypeIdsForTypeIdInOrderStatement{ + "WITH RECURSIVE " + " all_prototype_and_extension(typeId, prototypeId) AS (" + " SELECT typeId, prototypeId FROM types WHERE prototypeId IS NOT NULL" + " UNION ALL " + " SELECT typeId, extensionId FROM types WHERE extensionId IS NOT NULL)," + " prototypes(typeId, level) AS (" + " SELECT prototypeId, 0 FROM all_prototype_and_extension WHERE typeId=?" + " UNION ALL " + " SELECT prototypeId, p.level+1 FROM all_prototype_and_extension JOIN " + " prototypes AS p USING(typeId)) " + "SELECT typeId FROM prototypes ORDER BY level", + database}; + mutable ReadStatement<1, 1> selectPrototypeAndSelfIdsForTypeIdInOrderStatement{ + "WITH RECURSIVE " + " all_prototype_and_extension(typeId, prototypeId) AS (" + " SELECT typeId, prototypeId FROM types WHERE prototypeId IS NOT NULL" + " UNION ALL " + " SELECT typeId, extensionId FROM types WHERE extensionId IS NOT NULL)," + " typeChain(typeId, level) AS (" + " VALUES(?1, 0)" + " UNION ALL " + " SELECT prototypeId, tc.level+1 FROM all_prototype_and_extension JOIN " + " typeChain AS tc USING(typeId)) " + "SELECT typeId FROM typeChain ORDER BY level", + database}; }; extern template class ProjectStorage; } // namespace QmlDesigner diff --git a/tests/unit/unittest/projectstorage-test.cpp b/tests/unit/unittest/projectstorage-test.cpp index 06043d6c525..f7734ed00af 100644 --- a/tests/unit/unittest/projectstorage-test.cpp +++ b/tests/unit/unittest/projectstorage-test.cpp @@ -6738,4 +6738,81 @@ TEST_F(ProjectStorage, GetBuiltinStringTypeAfterChangingType) ASSERT_THAT(typeId, fetchTypeId(sourceId1, "variant")); } +TEST_F(ProjectStorage, GetPrototypeIds) +{ + auto package{createPackageWithProperties()}; + storage.synchronize(package); + auto typeId = fetchTypeId(sourceId1, "QObject3"); + + auto prototypeIds = storage.prototypeIds(typeId); + + ASSERT_THAT(prototypeIds, + ElementsAre(fetchTypeId(sourceId1, "QObject2"), fetchTypeId(sourceId1, "QObject"))); +} + +TEST_F(ProjectStorage, GetNoPrototypeIdsForNoPrototype) +{ + auto package{createPackageWithProperties()}; + storage.synchronize(package); + auto typeId = fetchTypeId(sourceId1, "QObject"); + + auto prototypeIds = storage.prototypeIds(typeId); + + ASSERT_THAT(prototypeIds, IsEmpty()); +} + +TEST_F(ProjectStorage, GetPrototypeIdsWithExtension) +{ + auto package{createPackageWithProperties()}; + std::swap(package.types[1].extension, package.types[1].prototype); + storage.synchronize(package); + auto typeId = fetchTypeId(sourceId1, "QObject3"); + + auto prototypeIds = storage.prototypeIds(typeId); + + ASSERT_THAT(prototypeIds, + ElementsAre(fetchTypeId(sourceId1, "QObject2"), + fetchTypeId(sourceId1, "QObject"))); +} + +TEST_F(ProjectStorage, GetPrototypeAndSelfIds) +{ + auto package{createPackageWithProperties()}; + storage.synchronize(package); + auto typeId = fetchTypeId(sourceId1, "QObject3"); + + auto prototypeAndSelfIds = storage.prototypeAndSelfIds(typeId); + + ASSERT_THAT(prototypeAndSelfIds, + ElementsAre(fetchTypeId(sourceId1, "QObject3"), + fetchTypeId(sourceId1, "QObject2"), + fetchTypeId(sourceId1, "QObject"))); +} + +TEST_F(ProjectStorage, GetSelfForNoPrototypeIds) +{ + auto package{createPackageWithProperties()}; + storage.synchronize(package); + auto typeId = fetchTypeId(sourceId1, "QObject"); + + auto prototypeAndSelfIds = storage.prototypeAndSelfIds(typeId); + + ASSERT_THAT(prototypeAndSelfIds, ElementsAre(fetchTypeId(sourceId1, "QObject"))); +} + +TEST_F(ProjectStorage, GetPrototypeAndSelfIdsWithExtension) +{ + auto package{createPackageWithProperties()}; + std::swap(package.types[1].extension, package.types[1].prototype); + storage.synchronize(package); + auto typeId = fetchTypeId(sourceId1, "QObject3"); + + auto prototypeAndSelfIds = storage.prototypeAndSelfIds(typeId); + + ASSERT_THAT(prototypeAndSelfIds, + ElementsAre(fetchTypeId(sourceId1, "QObject3"), + fetchTypeId(sourceId1, "QObject2"), + fetchTypeId(sourceId1, "QObject"))); +} + } // namespace