QmlDesiger: ProjectStorage provides properties for typeId

It returns all properties of the type and the prototype chain in a
sorted order.

Task-nubmer: QDS-7276
Change-Id: I95c16abd16d9d0f1fdf68d3425780a888dc056b7
Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
This commit is contained in:
Marco Bubke
2022-07-11 15:43:59 +02:00
parent 0490e3426d
commit e7a013cbfc
2 changed files with 175 additions and 1 deletions

View File

@@ -149,6 +149,18 @@ public:
.template valueWithTransaction<TypeId>(&moduleId, exportedTypeName);
}
PropertyDeclarationIds propertyIds(TypeId typeId) const
{
return selectPropertyDeclarationIdsForTypeStatement
.template valuesWithTransaction<PropertyDeclarationId>(32, &typeId);
}
Utils::optional<Utils::SmallString> propertyName(PropertyDeclarationId propertyDeclarationId) const
{
return selectPropertyNameStatement.template optionalValueWithTransaction<Utils::SmallString>(
&propertyDeclarationId);
}
PropertyDeclarationId fetchPropertyDeclarationByTypeIdAndName(TypeId typeId,
Utils::SmallStringView name)
{
@@ -2658,7 +2670,7 @@ public:
"aliasPropertyDeclarationId IS NULL RETURNING typeId, propertyDeclarationId, "
"propertyImportedTypeNameId",
database};
ReadStatement<1, 1> selectPropertyNameStatement{
mutable ReadStatement<1, 1> selectPropertyNameStatement{
"SELECT name FROM propertyDeclarations WHERE propertyDeclarationId=?", database};
WriteStatement<2> updatePropertyDeclarationTypeStatement{
"UPDATE propertyDeclarations SET propertyTypeId=?2 WHERE propertyDeclarationId=?1", database};
@@ -2845,6 +2857,16 @@ public:
" moduleExportedImportId "
"FROM imports",
database};
mutable ReadStatement<1, 1> selectPropertyDeclarationIdsForTypeStatement{
"WITH RECURSIVE "
" typeChain(typeId) AS ("
" VALUES(?1)"
" UNION ALL "
" SELECT prototypeId FROM types JOIN typeChain "
" USING(typeId) WHERE prototypeId IS NOT NULL)"
"SELECT propertyDeclarationId FROM typeChain JOIN propertyDeclarations "
" USING(typeId) ORDER BY propertyDeclarationId",
database};
};
extern template class ProjectStorage<Sqlite::Database>;
} // namespace QmlDesigner

View File

@@ -176,6 +176,51 @@ MATCHER_P4(IsPropertyDeclaration,
&& propertyDeclaration.traits == traits;
}
class HasNameMatcher
{
public:
using is_gtest_matcher = void;
HasNameMatcher(const QmlDesigner::ProjectStorage<Sqlite::Database> &storage,
Utils::SmallStringView name)
: storage{storage}
, name{name}
{}
bool MatchAndExplain(QmlDesigner::PropertyDeclarationId id, std::ostream *listener) const
{
auto propertyName = storage.propertyName(id);
bool success = propertyName && *propertyName == name;
if (success)
return true;
if (listener) {
if (propertyName)
*listener << "name is '" << *propertyName << "', not '" << name << "'";
else
*listener << "there is no '" << name << "'";
}
return false;
}
void DescribeTo(std::ostream *os) const { *os << "is '" << name << "'"; }
void DescribeNegationTo(std::ostream *os) const { *os << "is not '" << name << "'"; }
private:
const QmlDesigner::ProjectStorage<Sqlite::Database> &storage;
Utils::SmallStringView name;
};
#define HasName(name) Matcher<QmlDesigner::PropertyDeclarationId>(HasNameMatcher{storage, name})
MATCHER(IsSorted, std::string(negation ? "isn't sorted" : "is sorted"))
{
return std::is_sorted(begin(arg), end(arg));
}
class ProjectStorage : public testing::Test
{
protected:
@@ -577,6 +622,59 @@ protected:
return package;
}
auto createPackageWithProperties()
{
SynchronizationPackage package;
package.imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId1);
package.types.push_back(Storage::Type{
"QObject",
Storage::ImportedType{},
TypeAccessSemantics::Reference,
sourceId1,
{Storage::ExportedType{qmlModuleId, "Object", Storage::Version{}}},
{Storage::PropertyDeclaration{"data",
Storage::ImportedType{"Object"},
Storage::PropertyDeclarationTraits::IsList},
Storage::PropertyDeclaration{"children",
Storage::ImportedType{"Object"},
Storage::PropertyDeclarationTraits::IsList
| Storage::PropertyDeclarationTraits::IsReadOnly}}});
package.types.push_back(Storage::Type{
"QObject2",
Storage::ImportedType{"Object"},
TypeAccessSemantics::Reference,
sourceId1,
{Storage::ExportedType{qmlModuleId, "Object2", Storage::Version{}}},
{Storage::PropertyDeclaration{"data2",
Storage::ImportedType{"Object3"},
Storage::PropertyDeclarationTraits::IsList},
Storage::PropertyDeclaration{"children2",
Storage::ImportedType{"Object3"},
Storage::PropertyDeclarationTraits::IsList
| Storage::PropertyDeclarationTraits::IsReadOnly}}});
package.types.push_back(Storage::Type{
"QObject3",
Storage::ImportedType{"Object2"},
TypeAccessSemantics::Reference,
sourceId1,
{Storage::ExportedType{qmlModuleId, "Object3", Storage::Version{}}},
{Storage::PropertyDeclaration{"data3",
Storage::ImportedType{"Object2"},
Storage::PropertyDeclarationTraits::IsList},
Storage::PropertyDeclaration{"children3",
Storage::ImportedType{"Object2"},
Storage::PropertyDeclarationTraits::IsList
| Storage::PropertyDeclarationTraits::IsReadOnly}}});
package.updatedSourceIds.push_back(sourceId1);
shuffle(package.types);
return package;
}
auto createModuleExportedImportSynchronizationPackage()
{
SynchronizationPackage package;
@@ -5047,4 +5145,58 @@ TEST_F(ProjectStorage, GetNoTypeIdWithCompleteVersionForWrongMajorVersion)
ASSERT_FALSE(typeId);
}
TEST_F(ProjectStorage, GetProperties)
{
auto package{createPackageWithProperties()};
storage.synchronize(package);
auto itemTypeId = fetchTypeId(sourceId1, "QObject3");
auto propertyIds = storage.propertyIds(itemTypeId);
ASSERT_THAT(propertyIds,
UnorderedElementsAre(HasName("data"),
HasName("children"),
HasName("data2"),
HasName("children2"),
HasName("data3"),
HasName("children3")));
}
TEST_F(ProjectStorage, GetPropertiesAreReturnedSorted)
{
auto package{createPackageWithProperties()};
storage.synchronize(package);
auto itemTypeId = fetchTypeId(sourceId1, "QObject3");
auto propertyIds = storage.propertyIds(itemTypeId);
ASSERT_THAT(propertyIds, IsSorted());
}
TEST_F(ProjectStorage, GetNoPropertiesPropertiesFromDerivedTypes)
{
auto package{createPackageWithProperties()};
storage.synchronize(package);
auto itemTypeId = fetchTypeId(sourceId1, "QObject2");
auto propertyIds = storage.propertyIds(itemTypeId);
ASSERT_THAT(propertyIds,
UnorderedElementsAre(HasName("data"),
HasName("children"),
HasName("data2"),
HasName("children2")));
}
TEST_F(ProjectStorage, GetNoPropertiesForWrongTypeId)
{
auto package{createPackageWithProperties()};
storage.synchronize(package);
auto itemTypeId = fetchTypeId(sourceId1, "WrongObject");
auto propertyIds = storage.propertyIds(itemTypeId);
ASSERT_THAT(propertyIds, IsEmpty());
}
} // namespace