Sqlite: Add compound id

Saving the source context id as part of the source id simplyfies file
path handling. It is now very easy to see if a two source ids have the
same source context id.

Change-Id: I6c86942d9f026fc047c49bbde3fffd6af14d81de
Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
This commit is contained in:
Marco Bubke
2024-08-01 14:14:18 +02:00
parent 0d571b5e95
commit 2ae8ae75af
24 changed files with 392 additions and 501 deletions

View File

@@ -77,7 +77,7 @@ public:
void bind(int index, ValueView value);
void bind(int index, BlobView blobView);
template<typename Type, typename = std::enable_if_t<Type::IsBasicId::value>>
template<typename Type, typename std::enable_if_t<Type::IsBasicId::value, bool> = true>
void bind(int index, Type id)
{
if (!id.isNull())
@@ -527,8 +527,7 @@ private:
operator BlobView() { return statement.fetchBlobValue(column); }
operator ValueView() { return statement.fetchValueView(column); }
template<typename ConversionType,
typename = std::enable_if_t<ConversionType::IsBasicId::value>>
template<typename ConversionType, typename = std::enable_if_t<ConversionType::IsBasicId::value>>
constexpr operator ConversionType()
{
if (statement.fetchType(column) == Type::Integer) {

View File

@@ -15,6 +15,9 @@ namespace Sqlite {
template<auto Type, typename InternalIntegerType = long long>
class BasicId
{
template<auto, auto>
friend class CompoundBasicId;
public:
using IsBasicId = std::true_type;
using DatabaseType = InternalIntegerType;
@@ -97,6 +100,104 @@ protected:
InternalIntegerType id = 0;
};
template<auto Type, auto ContextType>
class CompoundBasicId
{
public:
using IsBasicId = std::true_type;
using DatabaseType = long long;
using MainId = BasicId<Type, int>;
using ContextId = BasicId<ContextType, int>;
constexpr explicit CompoundBasicId() = default;
static constexpr CompoundBasicId create(MainId id, ContextId contextId)
{
CompoundBasicId compoundId;
compoundId.id = (static_cast<long long>(contextId.id) << 32) | static_cast<long long>(id.id);
return compoundId;
}
static constexpr CompoundBasicId create(long long idNumber)
{
CompoundBasicId id;
id.id = idNumber;
return id;
}
constexpr MainId mainId() const { return MainId::create(id); }
constexpr ContextId contextId() const { return ContextId::create(id >> 32); }
friend constexpr bool compareInvalidAreTrue(CompoundBasicId first, CompoundBasicId second)
{
return first.id, second.id;
}
friend constexpr bool operator==(CompoundBasicId first, CompoundBasicId second)
{
return first.id == second.id;
}
friend constexpr bool operator!=(CompoundBasicId first, CompoundBasicId second)
{
return !(first == second);
}
friend constexpr bool operator<(CompoundBasicId first, CompoundBasicId second)
{
return first.id < second.id;
}
friend constexpr bool operator>(CompoundBasicId first, CompoundBasicId second)
{
return first.id > second.id;
}
friend constexpr bool operator<=(CompoundBasicId first, CompoundBasicId second)
{
return first.id <= second.id;
}
friend constexpr bool operator>=(CompoundBasicId first, CompoundBasicId second)
{
return first.id >= second.id;
}
friend constexpr long long operator-(CompoundBasicId first, CompoundBasicId second)
{
return first.id - second.id;
}
constexpr bool isValid() const { return id != 0; }
constexpr bool isNull() const { return id == 0; }
explicit operator bool() const { return isValid(); }
long long internalId() const { return id; }
explicit operator std::size_t() const { return static_cast<std::size_t>(id | 0xFFFFFFFFULL); }
template<typename String>
friend void convertToString(String &string, CompoundBasicId id)
{
convertToString(string, id.id);
convertToString(string, id.contextId);
}
friend bool compareId(CompoundBasicId first, CompoundBasicId second)
{
return first.id == second.id;
}
protected:
long long id = 0;
};
template<typename Container>
auto toIntegers(const Container &container)
{

View File

@@ -15,7 +15,7 @@ enum class BasicIdType {
Type,
PropertyType,
PropertyDeclaration,
Source,
SourceName,
SourceContext,
StorageCacheIndex,
FunctionDeclaration,
@@ -51,10 +51,10 @@ using SourceContextIds = std::vector<SourceContextId>;
template<std::size_t size>
using SmallSourceContextIds = QVarLengthArray<SourceContextId, size>;
using SourceId = Sqlite::BasicId<BasicIdType::Source, int>;
using SourceIds = std::vector<SourceId>;
using SourceNameId = Sqlite::BasicId<BasicIdType::SourceName, int>;
using SourceNameIds = std::vector<SourceNameId>;
template<std::size_t size>
using SmallSourceIds = QVarLengthArray<SourceId, size>;
using SmallSourceNameIds = QVarLengthArray<SourceNameId, size>;
using ModuleId = Sqlite::BasicId<BasicIdType::Module, int>;
using ModuleIds = std::vector<ModuleId>;
@@ -75,4 +75,9 @@ using ExportedTypeNameIds = std::vector<ExportedTypeNameId>;
using ModuleExportedImportId = Sqlite::BasicId<BasicIdType::ModuleExportedImport>;
using ModuleExportedImportIds = std::vector<ModuleExportedImportId>;
using SourceId = Sqlite::CompoundBasicId<BasicIdType::SourceName, BasicIdType::SourceContext>;
using SourceIds = std::vector<SourceId>;
template<std::size_t size>
using SmallSourceIds = QVarLengthArray<SourceId, size>;
} // namespace QmlDesigner

View File

@@ -81,16 +81,14 @@ struct ProjectStorage::Statements
"SELECT sourceContextPath, sourceContextId FROM sourceContexts", database};
Sqlite::WriteStatement<1> insertIntoSourceContextsStatement{
"INSERT INTO sourceContexts(sourceContextPath) VALUES (?)", database};
mutable Sqlite::ReadStatement<1, 2> selectSourceIdFromSourcesBySourceContextIdAndSourceNameStatement{
"SELECT sourceId FROM sources WHERE sourceContextId = ? AND sourceName = ?", database};
mutable Sqlite::ReadStatement<2, 1> selectSourceNameAndSourceContextIdFromSourcesBySourceIdStatement{
"SELECT sourceName, sourceContextId FROM sources WHERE sourceId = ?", database};
mutable Sqlite::ReadStatement<1, 1> selectSourceContextIdFromSourcesBySourceIdStatement{
"SELECT sourceContextId FROM sources WHERE sourceId = ?", database};
Sqlite::WriteStatement<2> insertIntoSourcesStatement{
"INSERT INTO sources(sourceContextId, sourceName) VALUES (?,?)", database};
mutable Sqlite::ReadStatement<3> selectAllSourcesStatement{
"SELECT sourceName, sourceContextId, sourceId FROM sources", database};
mutable Sqlite::ReadStatement<1, 1> selectSourceNameIdFromSourceNamesBySourceNameStatement{
"SELECT sourceNameId FROM sourceNames WHERE sourceName = ?", database};
mutable Sqlite::ReadStatement<1, 1> selectSourceNameFromSourceNamesBySourceNameIdStatement{
"SELECT sourceName FROM sourceNames WHERE sourceNameId = ?", database};
Sqlite::WriteStatement<1> insertIntoSourcesStatement{
"INSERT INTO sourceNames(sourceName) VALUES (?)", database};
mutable Sqlite::ReadStatement<2> selectAllSourcesStatement{
"SELECT sourceName, sourceNameId FROM sourceNames", database};
mutable Sqlite::ReadStatement<8, 1> selectTypeByTypeIdStatement{
"SELECT sourceId, t.name, t.typeId, prototypeId, extensionId, traits, annotationTraits, "
"pd.name "
@@ -621,7 +619,7 @@ struct ProjectStorage::Statements
"ORDER BY itn.kind, etn.majorVersion DESC NULLS FIRST, etn.minorVersion DESC NULLS FIRST "
"LIMIT 1",
database};
Sqlite::WriteStatement<0> deleteAllSourcesStatement{"DELETE FROM sources", database};
Sqlite::WriteStatement<0> deleteAllSourceNamesStatement{"DELETE FROM sourceNames", database};
Sqlite::WriteStatement<0> deleteAllSourceContextsStatement{"DELETE FROM sourceContexts", database};
mutable Sqlite::ReadStatement<6, 1> selectExportedTypesForSourceIdsStatement{
"SELECT moduleId, name, ifnull(majorVersion, -1), ifnull(minorVersion, -1), typeId, "
@@ -897,7 +895,7 @@ public:
if (!isInitialized) {
auto moduleIdColumn = createModulesTable(database);
createSourceContextsTable(database);
createSourcesTable(database);
createSourceNamesTable(database);
createTypesAndePropertyDeclarationsTables(database, moduleIdColumn);
createExportedTypeNamesTable(database, moduleIdColumn);
createImportedTypeNamesTable(database);
@@ -927,22 +925,14 @@ public:
table.initialize(database);
}
void createSourcesTable(Database &database)
void createSourceNamesTable(Database &database)
{
Sqlite::StrictTable table;
table.setUseIfNotExists(true);
table.setName("sources");
table.addColumn("sourceId", Sqlite::StrictColumnType::Integer, {Sqlite::PrimaryKey{}});
const auto &sourceContextIdColumn = table.addColumn(
"sourceContextId",
Sqlite::StrictColumnType::Integer,
{Sqlite::NotNull{},
Sqlite::ForeignKey{"sourceContexts",
"sourceContextId",
Sqlite::ForeignKeyAction::NoAction,
Sqlite::ForeignKeyAction::Cascade}});
table.setName("sourceNames");
table.addColumn("sourceNameId", Sqlite::StrictColumnType::Integer, {Sqlite::PrimaryKey{}});
const auto &sourceNameColumn = table.addColumn("sourceName", Sqlite::StrictColumnType::Text);
table.addUniqueIndex({sourceContextIdColumn, sourceNameColumn});
table.addUniqueIndex({sourceNameColumn});
table.initialize(database);
}
@@ -1217,13 +1207,7 @@ public:
Sqlite::StrictTable table;
table.setUseIfNotExists(true);
table.setName("fileStatuses");
table.addColumn("sourceId",
Sqlite::StrictColumnType::Integer,
{Sqlite::PrimaryKey{},
Sqlite::ForeignKey{"sources",
"sourceId",
Sqlite::ForeignKeyAction::NoAction,
Sqlite::ForeignKeyAction::Cascade}});
table.addColumn("sourceId", Sqlite::StrictColumnType::Integer, {Sqlite::PrimaryKey{}});
table.addColumn("size", Sqlite::StrictColumnType::Integer);
table.addColumn("lastModified", Sqlite::StrictColumnType::Integer);
@@ -2193,89 +2177,66 @@ Cache::SourceContexts ProjectStorage::fetchAllSourceContexts() const
return s->selectAllSourceContextsStatement.valuesWithTransaction<Cache::SourceContext, 128>();
}
SourceId ProjectStorage::fetchSourceId(SourceContextId sourceContextId,
Utils::SmallStringView sourceName)
SourceNameId ProjectStorage::fetchSourceNameId(Utils::SmallStringView sourceName)
{
using NanotraceHR::keyValue;
NanotraceHR::Tracer tracer{"fetch source id"_t,
projectStorageCategory(),
keyValue("source context id", sourceContextId),
keyValue("source name", sourceName)};
auto sourceId = Sqlite::withDeferredTransaction(database, [&] {
return fetchSourceIdUnguarded(sourceContextId, sourceName);
auto sourceNameId = Sqlite::withDeferredTransaction(database, [&] {
return fetchSourceNameIdUnguarded(sourceName);
});
tracer.end(keyValue("source id", sourceId));
tracer.end(keyValue("source name id", sourceNameId));
return sourceId;
return sourceNameId;
}
Cache::SourceNameAndSourceContextId ProjectStorage::fetchSourceNameAndSourceContextId(SourceId sourceId) const
Utils::SmallString ProjectStorage::fetchSourceName(SourceNameId sourceNameId) const
{
using NanotraceHR::keyValue;
NanotraceHR::Tracer tracer{"fetch source name and source context id"_t,
projectStorageCategory(),
keyValue("source id", sourceId)};
keyValue("source name id", sourceNameId)};
auto value = s->selectSourceNameAndSourceContextIdFromSourcesBySourceIdStatement
.valueWithTransaction<Cache::SourceNameAndSourceContextId>(sourceId);
auto sourceName = s->selectSourceNameFromSourceNamesBySourceNameIdStatement
.valueWithTransaction<Utils::SmallString>(sourceNameId);
if (!value.sourceContextId)
throw SourceIdDoesNotExists();
if (sourceName.empty())
throw SourceNameIdDoesNotExists();
tracer.end(keyValue("source name", value.sourceName),
keyValue("source context id", value.sourceContextId));
tracer.end(keyValue("source name", sourceName));
return value;
return sourceName;
}
void ProjectStorage::clearSources()
{
Sqlite::withImmediateTransaction(database, [&] {
s->deleteAllSourceContextsStatement.execute();
s->deleteAllSourcesStatement.execute();
s->deleteAllSourceNamesStatement.execute();
});
}
SourceContextId ProjectStorage::fetchSourceContextId(SourceId sourceId) const
{
using NanotraceHR::keyValue;
NanotraceHR::Tracer tracer{"fetch source context id"_t,
projectStorageCategory(),
keyValue("source id", sourceId)};
auto sourceContextId = s->selectSourceContextIdFromSourcesBySourceIdStatement
.valueWithTransaction<SourceContextId>(sourceId);
if (!sourceContextId)
throw SourceIdDoesNotExists();
tracer.end(keyValue("source context id", sourceContextId));
return sourceContextId;
}
Cache::Sources ProjectStorage::fetchAllSources() const
Cache::SourceNames ProjectStorage::fetchAllSourceNames() const
{
NanotraceHR::Tracer tracer{"fetch all sources"_t, projectStorageCategory()};
return s->selectAllSourcesStatement.valuesWithTransaction<Cache::Source, 1024>();
return s->selectAllSourcesStatement.valuesWithTransaction<Cache::SourceName, 1024>();
}
SourceId ProjectStorage::fetchSourceIdUnguarded(SourceContextId sourceContextId,
Utils::SmallStringView sourceName)
SourceNameId ProjectStorage::fetchSourceNameIdUnguarded(Utils::SmallStringView sourceName)
{
using NanotraceHR::keyValue;
NanotraceHR::Tracer tracer{"fetch source id unguarded"_t,
projectStorageCategory(),
keyValue("source context id", sourceContextId),
keyValue("source name", sourceName)};
auto sourceId = readSourceId(sourceContextId, sourceName);
auto sourceId = readSourceNameId(sourceName);
if (!sourceId)
sourceId = writeSourceId(sourceContextId, sourceName);
sourceId = writeSourceNameId(sourceName);
tracer.end(keyValue("source id", sourceId));
@@ -4908,39 +4869,35 @@ SourceContextId ProjectStorage::writeSourceContextId(Utils::SmallStringView sour
return sourceContextId;
}
SourceId ProjectStorage::writeSourceId(SourceContextId sourceContextId,
Utils::SmallStringView sourceName)
SourceNameId ProjectStorage::writeSourceNameId(Utils::SmallStringView sourceName)
{
using NanotraceHR::keyValue;
NanotraceHR::Tracer tracer{"write source id"_t,
projectStorageCategory(),
keyValue("source context id", sourceContextId),
keyValue("source name", sourceName)};
s->insertIntoSourcesStatement.write(sourceContextId, sourceName);
s->insertIntoSourcesStatement.write(sourceName);
auto sourceId = SourceId::create(static_cast<int>(database.lastInsertedRowId()));
auto sourceNameId = SourceNameId::create(static_cast<int>(database.lastInsertedRowId()));
tracer.end(keyValue("source id", sourceId));
tracer.end(keyValue("source name id", sourceNameId));
return sourceId;
return sourceNameId;
}
SourceId ProjectStorage::readSourceId(SourceContextId sourceContextId,
Utils::SmallStringView sourceName)
SourceNameId ProjectStorage::readSourceNameId(Utils::SmallStringView sourceName)
{
using NanotraceHR::keyValue;
NanotraceHR::Tracer tracer{"read source id"_t,
projectStorageCategory(),
keyValue("source context id", sourceContextId),
keyValue("source name", sourceName)};
auto sourceId = s->selectSourceIdFromSourcesBySourceContextIdAndSourceNameStatement
.value<SourceId>(sourceContextId, sourceName);
auto sourceNameId = s->selectSourceNameIdFromSourceNamesBySourceNameStatement.value<SourceNameId>(
sourceName);
tracer.end(keyValue("source id", sourceId));
tracer.end(keyValue("source id", sourceNameId));
return sourceId;
return sourceNameId;
}
Storage::Synchronization::ExportedTypes ProjectStorage::fetchExportedTypes(TypeId typeId)

View File

@@ -223,18 +223,15 @@ public:
Cache::SourceContexts fetchAllSourceContexts() const;
SourceId fetchSourceId(SourceContextId sourceContextId, Utils::SmallStringView sourceName);
SourceNameId fetchSourceNameId(Utils::SmallStringView sourceName);
Cache::SourceNameAndSourceContextId fetchSourceNameAndSourceContextId(SourceId sourceId) const;
Utils::SmallString fetchSourceName(SourceNameId sourceId) const;
void clearSources();
SourceContextId fetchSourceContextId(SourceId sourceId) const;
Cache::SourceNames fetchAllSourceNames() const;
Cache::Sources fetchAllSources() const;
SourceId fetchSourceIdUnguarded(SourceContextId sourceContextId,
Utils::SmallStringView sourceName);
SourceNameId fetchSourceNameIdUnguarded(Utils::SmallStringView sourceName);
FileStatuses fetchAllFileStatuses() const;
@@ -1009,9 +1006,9 @@ private:
SourceContextId writeSourceContextId(Utils::SmallStringView sourceContextPath);
SourceId writeSourceId(SourceContextId sourceContextId, Utils::SmallStringView sourceName);
SourceNameId writeSourceNameId(Utils::SmallStringView sourceName);
SourceId readSourceId(SourceContextId sourceContextId, Utils::SmallStringView sourceName);
SourceNameId readSourceNameId(Utils::SmallStringView sourceName);
Storage::Synchronization::ExportedTypes fetchExportedTypes(TypeId typeId);

View File

@@ -8,7 +8,7 @@
namespace QmlDesigner {
void ProjectStorageErrorNotifier::typeNameCannotBeResolved(Utils::SmallStringView typeName,
SourceId sourceId)
SourceId sourceId)
{
qDebug() << "Missing type name: " << typeName
<< " in file: " << m_pathCache.sourcePath(sourceId).toStringView();

View File

@@ -47,12 +47,12 @@ const char *SourceContextIdDoesNotExists::what() const noexcept
return "The source context id does not exist in the database!";
}
SourceIdDoesNotExists::SourceIdDoesNotExists()
SourceNameIdDoesNotExists::SourceNameIdDoesNotExists()
{
category().threadEvent("SourceIdDoesNotExists"_t);
category().threadEvent("SourceNameIdDoesNotExists"_t);
}
const char *SourceIdDoesNotExists::what() const noexcept
const char *SourceNameIdDoesNotExists::what() const noexcept
{
return "The source id does not exist in the database!";
}

View File

@@ -55,10 +55,10 @@ public:
const char *what() const noexcept override;
};
class QMLDESIGNERCORE_EXPORT SourceIdDoesNotExists : public ProjectStorageError
class QMLDESIGNERCORE_EXPORT SourceNameIdDoesNotExists : public ProjectStorageError
{
public:
SourceIdDoesNotExists();
SourceNameIdDoesNotExists();
const char *what() const noexcept override;
};

View File

@@ -127,13 +127,16 @@ public:
ids.push_back(id);
outputIterator = std::transform(
idPath.sourceIds.begin(), idPath.sourceIds.end(), outputIterator, [&](SourceId sourceId) {
return WatcherEntry{id,
m_pathCache.sourceContextId(sourceId),
sourceId,
m_fileStatusCache.lastModifiedTime(sourceId)};
});
outputIterator = std::transform(idPath.sourceIds.begin(),
idPath.sourceIds.end(),
outputIterator,
[&](SourceId sourceId) {
return WatcherEntry{id,
sourceId.contextId(),
sourceId,
m_fileStatusCache.lastModifiedTime(
sourceId)};
});
}
std::sort(entries.begin(), entries.end());

View File

@@ -483,7 +483,7 @@ void ProjectStorageUpdater::updateSubdirectories(const Utils::PathString &direct
auto subdirectorySourceIds = m_projectStorage.fetchSubdirectorySourceIds(directorySourceId);
auto subdirectories = Utils::transform<Directories>(
subdirectorySourceIds, [&](SourceId sourceId) -> Directory {
auto sourceContextId = m_pathCache.sourceContextId(sourceId);
auto sourceContextId = sourceId.contextId();
auto subdirectoryPath = m_pathCache.sourceContextPath(sourceContextId);
return {subdirectoryPath, sourceContextId, sourceId};
});
@@ -495,10 +495,9 @@ void ProjectStorageUpdater::updateSubdirectories(const Utils::PathString &direct
|| subdirectory.endsWith("/QtQuick/Scene3D"))
continue;
Utils::PathString subdirectoryPath = subdirectory;
auto [sourceContextId, sourceId] = m_pathCache.sourceContextAndSourceId(
SourcePath{subdirectoryPath + "/."});
subdirectories.emplace_back(subdirectoryPath, sourceContextId, sourceId);
existingSubdirecories.emplace_back(subdirectoryPath, sourceContextId, sourceId);
SourceId sourceId = m_pathCache.sourceId(SourcePath{subdirectoryPath + "/."});
subdirectories.emplace_back(subdirectoryPath, sourceId.contextId(), sourceId);
existingSubdirecories.emplace_back(subdirectoryPath, sourceId.contextId(), sourceId);
}
std::sort(subdirectories.begin(), subdirectories.end());
@@ -828,12 +827,10 @@ void ProjectStorageUpdater::updatePropertyEditorFilePath(
}
namespace {
SourceContextIds filterUniqueSourceContextIds(const SourceIds &sourceIds,
ProjectStorageUpdater::PathCache &pathCache)
SourceContextIds filterUniqueSourceContextIds(const SourceIds &sourceIds)
{
auto sourceContextIds = Utils::transform(sourceIds, [&](SourceId sourceId) {
return pathCache.sourceContextId(sourceId);
});
auto sourceContextIds = Utils::transform(sourceIds,
[](SourceId sourceId) { return sourceId.contextId(); });
std::sort(sourceContextIds.begin(), sourceContextIds.end());
auto newEnd = std::unique(sourceContextIds.begin(), sourceContextIds.end());
@@ -899,7 +896,7 @@ void ProjectStorageUpdater::pathsWithIdsChanged(const std::vector<IdPaths> &chan
}
}
auto directorySourceContextIds = filterUniqueSourceContextIds(directorySourceIds, m_pathCache);
auto directorySourceContextIds = filterUniqueSourceContextIds(directorySourceIds);
for (auto sourceContextId : directorySourceContextIds) {
Utils::PathString directory = m_pathCache.sourceContextPath(sourceContextId);
@@ -911,13 +908,13 @@ void ProjectStorageUpdater::pathsWithIdsChanged(const std::vector<IdPaths> &chan
}
for (SourceId sourceId : filterUniqueSourceIds(qmlDocumentSourceIds)) {
if (!contains(directorySourceContextIds, m_pathCache.sourceContextId(sourceId)))
if (!contains(directorySourceContextIds, sourceId.contextId()))
parseQmlComponent(sourceId, package, notUpdatedSourceIds);
}
try {
for (SourceId sourceId : filterUniqueSourceIds(std::move(qmltypesSourceIds))) {
if (!contains(directorySourceContextIds, m_pathCache.sourceContextId(sourceId))) {
if (!contains(directorySourceContextIds, sourceId.contextId())) {
auto qmltypesPath = m_pathCache.sourcePath(sourceId);
auto directoryInfo = m_projectStorage.fetchDirectoryInfo(sourceId);
if (directoryInfo)

View File

@@ -32,7 +32,7 @@ class SourcePathCache final : public SourcePathCacheInterface
public:
SourcePathCache(ProjectStorage &projectStorage)
: m_sourceContextStorageAdapter{projectStorage}
, m_sourceStorageAdapter{projectStorage}
, m_sourceNameStorageAdapter{projectStorage}
{
populateIfEmpty();
@@ -58,9 +58,9 @@ public:
Utils::SmallStringView sourceName = sourcePath.name();
auto sourceId = m_sourcePathCache.id({sourceName, sourceContextId});
auto sourceId = m_sourcePathCache.id(sourceName);
return {sourceContextId, sourceId};
return {sourceContextId, SourceId::create(sourceId, sourceContextId)};
}
SourceId sourceId(SourcePathView sourcePath) const override
@@ -71,7 +71,9 @@ public:
SourceId sourceId(SourceContextId sourceContextId,
Utils::SmallStringView sourceName) const override
{
return m_sourcePathCache.id({sourceName, sourceContextId});
SourceNameId sourceNameId = m_sourcePathCache.id(sourceName);
return SourceId::create(sourceNameId, sourceContextId);
}
SourceContextId sourceContextId(Utils::SmallStringView sourceContextPath) const override
@@ -88,11 +90,11 @@ public:
if (Q_UNLIKELY(!sourceId.isValid()))
throw NoSourcePathForInvalidSourceId();
auto entry = m_sourcePathCache.value(sourceId);
auto sourceName = m_sourcePathCache.value(sourceId.mainId());
Utils::PathString sourceContextPath = m_sourceContextPathCache.value(entry.sourceContextId);
Utils::PathString sourceContextPath = m_sourceContextPathCache.value(sourceId.contextId());
return SourcePath{sourceContextPath, entry.sourceName};
return SourcePath{sourceContextPath, sourceName};
}
Utils::PathString sourceContextPath(SourceContextId sourceContextId) const override
@@ -103,19 +105,11 @@ public:
return m_sourceContextPathCache.value(sourceContextId);
}
SourceContextId sourceContextId(SourceId sourceId) const override
{
if (Q_UNLIKELY(!sourceId.isValid()))
throw NoSourcePathForInvalidSourceId();
return m_sourcePathCache.value(sourceId).sourceContextId;
}
private:
class SourceContextStorageAdapter
{
public:
auto fetchId(const Utils::SmallStringView sourceContextPath)
auto fetchId(Utils::SmallStringView sourceContextPath)
{
return storage.fetchSourceContextId(sourceContextPath);
}
@@ -127,27 +121,22 @@ private:
ProjectStorage &storage;
};
class SourceStorageAdapter
class SourceNameStorageAdapter
{
public:
auto fetchId(Cache::SourceNameView sourceNameView)
auto fetchId(Utils::SmallStringView sourceNameView)
{
return storage.fetchSourceId(sourceNameView.sourceContextId, sourceNameView.sourceName);
return storage.fetchSourceNameId(sourceNameView);
}
auto fetchValue(SourceId id)
{
auto entry = storage.fetchSourceNameAndSourceContextId(id);
auto fetchValue(SourceNameId id) { return storage.fetchSourceName(id); }
return Cache::SourceNameEntry{std::move(entry.sourceName), entry.sourceContextId};
}
auto fetchAll() { return storage.fetchAllSources(); }
auto fetchAll() { return storage.fetchAllSourceNames(); }
ProjectStorage &storage;
};
static bool sourceContextLess(Utils::SmallStringView first, Utils::SmallStringView second) noexcept
static bool sourceLess(Utils::SmallStringView first, Utils::SmallStringView second) noexcept
{
return std::lexicographical_compare(first.rbegin(),
first.rend(),
@@ -155,31 +144,26 @@ private:
second.rend());
}
static bool sourceLess(Cache::SourceNameView first, Cache::SourceNameView second) noexcept
{
return first < second;
}
using SourceContextPathCache = StorageCache<Utils::PathString,
Utils::SmallStringView,
SourceContextId,
SourceContextStorageAdapter,
Mutex,
sourceContextLess,
sourceLess,
Cache::SourceContext>;
using SourceNameCache = StorageCache<Cache::SourceNameEntry,
Cache::SourceNameView,
SourceId,
SourceStorageAdapter,
using SourceNameCache = StorageCache<Utils::PathString,
Utils::SmallStringView,
SourceNameId,
SourceNameStorageAdapter,
Mutex,
sourceLess,
Cache::Source>;
Cache::SourceName>;
private:
SourceContextStorageAdapter m_sourceContextStorageAdapter;
SourceStorageAdapter m_sourceStorageAdapter;
SourceNameStorageAdapter m_sourceNameStorageAdapter;
mutable SourceContextPathCache m_sourceContextPathCache{m_sourceContextStorageAdapter};
mutable SourceNameCache m_sourcePathCache{m_sourceStorageAdapter};
mutable SourceNameCache m_sourcePathCache{m_sourceNameStorageAdapter};
};
} // namespace QmlDesigner

View File

@@ -36,7 +36,6 @@ public:
virtual SourcePath sourcePath(SourceId sourceId) const = 0;
virtual Utils::PathString sourceContextPath(SourceContextId sourceContextId) const = 0;
virtual SourceContextId sourceContextId(SourceId sourceId) const = 0;
protected:
~SourcePathCacheInterface() = default;

View File

@@ -12,70 +12,6 @@
namespace QmlDesigner::Cache {
class SourceNameView
{
public:
friend bool operator==(const SourceNameView &first, const SourceNameView &second) noexcept
{
return first.sourceContextId == second.sourceContextId
&& first.sourceName == second.sourceName;
}
friend bool operator<(SourceNameView first, SourceNameView second) noexcept
{
return std::tie(first.sourceContextId, first.sourceName)
< std::tie(second.sourceContextId, second.sourceName);
}
public:
Utils::SmallStringView sourceName;
SourceContextId sourceContextId;
};
class SourceNameEntry
{
public:
SourceNameEntry() = default;
SourceNameEntry(Utils::SmallStringView sourceName, SourceContextId sourceContextId)
: sourceName(sourceName)
, sourceContextId(sourceContextId)
{}
SourceNameEntry(SourceNameView view)
: sourceName(view.sourceName)
, sourceContextId(view.sourceContextId)
{}
friend bool operator==(const SourceNameEntry &first, const SourceNameEntry &second) noexcept
{
return first.sourceContextId == second.sourceContextId
&& first.sourceName == second.sourceName;
}
friend bool operator!=(const SourceNameEntry &first, const SourceNameEntry &second) noexcept
{
return !(first == second);
}
friend bool operator==(const SourceNameEntry &first, const SourceNameView &second) noexcept
{
return first.sourceContextId == second.sourceContextId
&& first.sourceName == second.sourceName;
}
friend bool operator!=(const SourceNameEntry &first, const SourceNameView &second) noexcept
{
return !(first == second);
}
operator SourceNameView() const noexcept { return {sourceName, sourceContextId}; }
operator Utils::SmallString() &&noexcept { return std::move(sourceName); }
public:
Utils::SmallString sourceName;
SourceContextId sourceContextId;
};
class SourceContext
: public StorageCacheEntry<Utils::PathString, Utils::SmallStringView, SourceContextId>
@@ -93,38 +29,19 @@ public:
using SourceContexts = std::vector<SourceContext>;
class Source : public StorageCacheEntry<SourceNameEntry, SourceNameView, SourceId>
class SourceName : public StorageCacheEntry<Utils::PathString, Utils::SmallStringView, SourceNameId>
{
using Base = StorageCacheEntry<SourceNameEntry, SourceNameView, SourceId>;
using Base = StorageCacheEntry<Utils::PathString, Utils::SmallStringView, SourceNameId>;
public:
using Base::Base;
Source(Utils::SmallStringView sourceName, SourceContextId sourceContextId, SourceId sourceId)
: Base{{sourceName, sourceContextId}, sourceId}
{}
friend bool operator==(const Source &first, const Source &second)
friend bool operator==(const SourceName &first, const SourceName &second)
{
return first.id == second.id && first.value == second.value;
}
};
using Sources = std::vector<Source>;
class SourceNameAndSourceContextId
{
public:
constexpr SourceNameAndSourceContextId() = default;
SourceNameAndSourceContextId(Utils::SmallStringView sourceName, SourceContextId sourceContextId)
: sourceName{sourceName}
, sourceContextId{sourceContextId}
{}
Utils::SmallString sourceName;
SourceContextId sourceContextId;
};
using SourceNameAndSourceContextIds = std::vector<SourceNameAndSourceContextId>;
using SourceNames = std::vector<SourceName>;
} // namespace QmlDesigner::Cache

View File

@@ -324,26 +324,21 @@ public:
fetchSourceContextId,
(::Utils::SmallStringView SourceContextPath),
());
MOCK_METHOD(QmlDesigner::SourceId,
fetchSourceId,
(QmlDesigner::SourceContextId SourceContextId, ::Utils::SmallStringView sourceName),
());
MOCK_METHOD(QmlDesigner::SourceNameId, fetchSourceNameId, (::Utils::SmallStringView sourceName), ());
MOCK_METHOD(QmlDesigner::SourceContextId,
fetchSourceContextIdUnguarded,
(::Utils::SmallStringView SourceContextPath),
(::Utils::SmallStringView sourceContextPath),
());
MOCK_METHOD(QmlDesigner::SourceId,
fetchSourceIdUnguarded,
(QmlDesigner::SourceContextId SourceContextId, ::Utils::SmallStringView sourceName),
MOCK_METHOD(QmlDesigner::SourceNameId,
fetchSourceNameIdUnguarded,
(::Utils::SmallStringView sourceName),
());
MOCK_METHOD(::Utils::PathString,
fetchSourceContextPath,
(QmlDesigner::SourceContextId sourceContextId));
MOCK_METHOD(QmlDesigner::Cache::SourceNameAndSourceContextId,
fetchSourceNameAndSourceContextId,
(QmlDesigner::SourceId sourceId));
MOCK_METHOD(Utils::SmallString, fetchSourceName, (QmlDesigner::SourceNameId sourceId));
MOCK_METHOD(std::vector<QmlDesigner::Cache::SourceContext>, fetchAllSourceContexts, (), ());
MOCK_METHOD(std::vector<QmlDesigner::Cache::Source>, fetchAllSources, (), ());
MOCK_METHOD(std::vector<QmlDesigner::Cache::SourceName>, fetchAllSourceNames, (), ());
MOCK_METHOD(QmlDesigner::SourceId,
propertyEditorPathId,

View File

@@ -41,10 +41,6 @@ public:
sourceContextPath,
(QmlDesigner::SourceContextId directoryPathId),
(const, override));
MOCK_METHOD(QmlDesigner::SourceContextId,
sourceContextId,
(QmlDesigner::SourceId sourceId),
(const, override));
MOCK_METHOD(void, populateIfEmpty, (), (override));
};

View File

@@ -69,11 +69,10 @@ public:
(std::size_t),
());
MOCK_METHOD(std::vector<QmlDesigner::Cache::Source>, valuesReturnCacheSources, (std::size_t), ());
MOCK_METHOD(QmlDesigner::Cache::SourceNameAndSourceContextId,
valueReturnCacheSourceNameAndSourceContextId,
(int) );
MOCK_METHOD(std::vector<QmlDesigner::Cache::SourceName>,
valuesReturnCacheSourceNames,
(std::size_t),
());
MOCK_METHOD(Sqlite::TimeStamp, valueWithTransactionReturnsTimeStamp, (Utils::SmallStringView), ());
MOCK_METHOD(int, valueWithTransactionReturnsInt, (Utils::SmallStringView), ());
@@ -162,8 +161,6 @@ public:
else if constexpr (std::is_same_v<ResultType,
std::tuple<QmlDesigner::PropertyDeclarationId, QmlDesigner::TypeId>>)
return valueReturnsPropertyDeclaration(queryValues...);
else if constexpr (std::is_same_v<ResultType, QmlDesigner::Cache::SourceNameAndSourceContextId>)
return valueReturnCacheSourceNameAndSourceContextId(queryValues...);
else if constexpr (std::is_same_v<ResultType, QmlDesigner::SourceContextId>)
return valueReturnsSourceContextId(queryValues...);
else if constexpr (std::is_same_v<ResultType, QmlDesigner::SourceId>)
@@ -212,8 +209,8 @@ public:
return valuesReturnRowIds(reserveSize);
else if constexpr (std::is_same_v<ResultType, QmlDesigner::Cache::SourceContext>)
return valuesReturnCacheSourceContexts(reserveSize);
else if constexpr (std::is_same_v<ResultType, QmlDesigner::Cache::Source>)
return valuesReturnCacheSources(reserveSize);
else if constexpr (std::is_same_v<ResultType, QmlDesigner::Cache::SourceName>)
return valuesReturnCacheSourceNames(reserveSize);
else if constexpr (std::is_same_v<ResultType, QmlDesigner::Storage::Synchronization::Type>)
return valuesReturnsStorageTypes(reserveSize, queryValues...);
else if constexpr (std::is_same_v<ResultType, QmlDesigner::Storage::Synchronization::ExportedType>)

View File

@@ -23,6 +23,8 @@ enum class LockingMode : char;
class TimeStamp;
template<auto Type, typename InternalIntegerType>
class BasicId;
template<auto Type, auto ContextType>
class CompoundBasicId;
std::ostream &operator<<(std::ostream &out, const Value &value);
std::ostream &operator<<(std::ostream &out, const ValueView &value);
@@ -37,6 +39,12 @@ std::ostream &operator<<(std::ostream &out, const BasicId<Type, InternalIntegerT
return out << "id=" << id.internalId();
}
template<auto Type, auto ContextType>
std::ostream &operator<<(std::ostream &out, const CompoundBasicId<Type, ContextType> &id)
{
return out << "id=(" << id.mainId().internalId() << ", " << id.contextId().internalId() << ")";
}
namespace SessionChangeSetInternal {
class ConstIterator;
class ConstTupleIterator;

View File

@@ -19,8 +19,8 @@
namespace {
using QmlDesigner::Cache::Source;
using QmlDesigner::Cache::SourceContext;
using QmlDesigner::Cache::SourceName;
using QmlDesigner::FileStatus;
using QmlDesigner::FileStatuses;
using QmlDesigner::FlagIs;
@@ -29,6 +29,7 @@ using QmlDesigner::PropertyDeclarationId;
using QmlDesigner::SourceContextId;
using QmlDesigner::SourceId;
using QmlDesigner::SourceIds;
using QmlDesigner::SourceNameId;
using QmlDesigner::Storage::ModuleKind;
using QmlDesigner::Storage::Synchronization::SynchronizationPackage;
using QmlDesigner::Storage::Synchronization::TypeAnnotations;
@@ -66,18 +67,6 @@ MATCHER_P2(IsSourceContext,
return sourceContext.id == id && sourceContext.value == value;
}
MATCHER_P2(IsSourceNameAndSourceContextId,
name,
id,
std::string(negation ? "isn't " : "is ")
+ PrintToString(QmlDesigner::Cache::SourceNameAndSourceContextId{name, id}))
{
const QmlDesigner::Cache::SourceNameAndSourceContextId &sourceNameAndSourceContextId = arg;
return sourceNameAndSourceContextId.sourceName == name
&& sourceNameAndSourceContextId.sourceContextId == id;
}
MATCHER_P4(IsStorageType,
sourceId,
typeName,
@@ -352,18 +341,14 @@ protected:
void addSomeDummyData()
{
auto sourceContextId1 = storage.fetchSourceContextId("/path/dummy");
auto sourceContextId2 = storage.fetchSourceContextId("/path/dummy2");
auto sourceContextId3 = storage.fetchSourceContextId("/path/");
storage.fetchSourceContextId("/path/dummy");
storage.fetchSourceContextId("/path/dummy2");
storage.fetchSourceContextId("/path/");
storage.fetchSourceId(sourceContextId1, "foo");
storage.fetchSourceId(sourceContextId1, "dummy");
storage.fetchSourceId(sourceContextId2, "foo");
storage.fetchSourceId(sourceContextId2, "bar");
storage.fetchSourceId(sourceContextId3, "foo");
storage.fetchSourceId(sourceContextId3, "bar");
storage.fetchSourceId(sourceContextId1, "bar");
storage.fetchSourceId(sourceContextId3, "bar");
storage.fetchSourceNameId("foo");
storage.fetchSourceNameId("dummy");
storage.fetchSourceNameId("bar");
storage.fetchSourceNameId("bar");
}
auto createVerySimpleSynchronizationPackage()
@@ -1342,92 +1327,53 @@ TEST_F(ProjectStorage, fetch_all_source_contexts)
TEST_F(ProjectStorage, fetch_source_id_first_time)
{
addSomeDummyData();
auto sourceContextId = storage.fetchSourceContextId("/path/to");
auto sourceId = storage.fetchSourceId(sourceContextId, "foo");
auto sourceNameId = storage.fetchSourceNameId("foo");
ASSERT_TRUE(sourceId.isValid());
ASSERT_TRUE(sourceNameId.isValid());
}
TEST_F(ProjectStorage, fetch_existing_source_id)
{
addSomeDummyData();
auto sourceContextId = storage.fetchSourceContextId("/path/to");
auto createdSourceId = storage.fetchSourceId(sourceContextId, "foo");
auto createdSourceNameId = storage.fetchSourceNameId("foo");
auto sourceId = storage.fetchSourceId(sourceContextId, "foo");
auto sourceNameId = storage.fetchSourceNameId("foo");
ASSERT_THAT(sourceId, createdSourceId);
}
TEST_F(ProjectStorage, fetch_source_id_with_different_context_id_are_not_equal)
{
addSomeDummyData();
auto sourceContextId = storage.fetchSourceContextId("/path/to");
auto sourceContextId2 = storage.fetchSourceContextId("/path/to2");
auto sourceId2 = storage.fetchSourceId(sourceContextId2, "foo");
auto sourceId = storage.fetchSourceId(sourceContextId, "foo");
ASSERT_THAT(sourceId, Ne(sourceId2));
ASSERT_THAT(sourceNameId, createdSourceNameId);
}
TEST_F(ProjectStorage, fetch_source_id_with_different_name_are_not_equal)
{
addSomeDummyData();
auto sourceContextId = storage.fetchSourceContextId("/path/to");
auto sourceId2 = storage.fetchSourceId(sourceContextId, "foo");
auto sourceNameId2 = storage.fetchSourceNameId("foo");
auto sourceId = storage.fetchSourceId(sourceContextId, "foo2");
auto sourceNameId = storage.fetchSourceNameId("foo2");
ASSERT_THAT(sourceId, Ne(sourceId2));
}
TEST_F(ProjectStorage, fetch_source_id_with_non_existing_source_context_id_throws)
{
ASSERT_THROW(storage.fetchSourceId(SourceContextId::create(42), "foo"),
Sqlite::ConstraintPreventsModification);
ASSERT_THAT(sourceNameId, Ne(sourceNameId2));
}
TEST_F(ProjectStorage, fetch_source_name_and_source_context_id_for_non_existing_source_id)
{
ASSERT_THROW(storage.fetchSourceNameAndSourceContextId(SourceId::create(212)),
QmlDesigner::SourceIdDoesNotExists);
ASSERT_THROW(storage.fetchSourceName(SourceNameId::create(212)),
QmlDesigner::SourceNameIdDoesNotExists);
}
TEST_F(ProjectStorage, fetch_source_name_and_source_context_id_for_non_existing_entry)
TEST_F(ProjectStorage, fetch_source_name_for_non_existing_entry)
{
addSomeDummyData();
auto sourceContextId = storage.fetchSourceContextId("/path/to");
auto sourceId = storage.fetchSourceId(sourceContextId, "foo");
auto sourceNameId = storage.fetchSourceNameId("foo");
auto sourceNameAndSourceContextId = storage.fetchSourceNameAndSourceContextId(sourceId);
auto sourceName = storage.fetchSourceName(sourceNameId);
ASSERT_THAT(sourceNameAndSourceContextId, IsSourceNameAndSourceContextId("foo", sourceContextId));
}
TEST_F(ProjectStorage, fetch_source_context_id_for_non_existing_source_id)
{
ASSERT_THROW(storage.fetchSourceContextId(SourceId::create(212)),
QmlDesigner::SourceIdDoesNotExists);
}
TEST_F(ProjectStorage, fetch_source_context_id_for_existing_source_id)
{
addSomeDummyData();
auto originalSourceContextId = storage.fetchSourceContextId("/path/to3");
auto sourceId = storage.fetchSourceId(originalSourceContextId, "foo");
auto sourceContextId = storage.fetchSourceContextId(sourceId);
ASSERT_THAT(sourceContextId, Eq(originalSourceContextId));
ASSERT_THAT(sourceName, Eq("foo"));
}
TEST_F(ProjectStorage, fetch_all_sources)
{
storage.clearSources();
auto sources = storage.fetchAllSources();
auto sources = storage.fetchAllSourceNames();
ASSERT_THAT(toValues(sources), IsEmpty());
}
@@ -1435,10 +1381,9 @@ TEST_F(ProjectStorage, fetch_all_sources)
TEST_F(ProjectStorage, fetch_source_id_unguarded_first_time)
{
addSomeDummyData();
auto sourceContextId = storage.fetchSourceContextId("/path/to");
std::lock_guard lock{database};
auto sourceId = storage.fetchSourceIdUnguarded(sourceContextId, "foo");
auto sourceId = storage.fetchSourceNameIdUnguarded("foo");
ASSERT_TRUE(sourceId.isValid());
}
@@ -1446,48 +1391,25 @@ TEST_F(ProjectStorage, fetch_source_id_unguarded_first_time)
TEST_F(ProjectStorage, fetch_existing_source_id_unguarded)
{
addSomeDummyData();
auto sourceContextId = storage.fetchSourceContextId("/path/to");
std::lock_guard lock{database};
auto createdSourceId = storage.fetchSourceIdUnguarded(sourceContextId, "foo");
auto createdSourceId = storage.fetchSourceNameIdUnguarded("foo");
auto sourceId = storage.fetchSourceIdUnguarded(sourceContextId, "foo");
auto sourceId = storage.fetchSourceNameIdUnguarded("foo");
ASSERT_THAT(sourceId, createdSourceId);
}
TEST_F(ProjectStorage, fetch_source_id_unguarded_with_different_context_id_are_not_equal)
{
addSomeDummyData();
auto sourceContextId = storage.fetchSourceContextId("/path/to");
auto sourceContextId2 = storage.fetchSourceContextId("/path/to2");
std::lock_guard lock{database};
auto sourceId2 = storage.fetchSourceIdUnguarded(sourceContextId2, "foo");
auto sourceId = storage.fetchSourceIdUnguarded(sourceContextId, "foo");
ASSERT_THAT(sourceId, Ne(sourceId2));
}
TEST_F(ProjectStorage, fetch_source_id_unguarded_with_different_name_are_not_equal)
{
addSomeDummyData();
auto sourceContextId = storage.fetchSourceContextId("/path/to");
std::lock_guard lock{database};
auto sourceId2 = storage.fetchSourceIdUnguarded(sourceContextId, "foo");
auto sourceId2 = storage.fetchSourceNameIdUnguarded("foo");
auto sourceId = storage.fetchSourceIdUnguarded(sourceContextId, "foo2");
auto sourceId = storage.fetchSourceNameIdUnguarded("foo2");
ASSERT_THAT(sourceId, Ne(sourceId2));
}
TEST_F(ProjectStorage, fetch_source_id_unguarded_with_non_existing_source_context_id_throws)
{
std::lock_guard lock{database};
ASSERT_THROW(storage.fetchSourceIdUnguarded(SourceContextId::create(42), "foo"),
Sqlite::ConstraintPreventsModification);
}
TEST_F(ProjectStorage, synchronize_types_adds_new_types)
{
auto package{createSimpleSynchronizationPackage()};

View File

@@ -104,9 +104,9 @@ protected:
pathCache.sourceId(path3),
pathCache.sourceId(path4),
pathCache.sourceId(path5)};
SourceContextIds sourceContextIds = {pathCache.sourceContextId(sourceIds[0]),
pathCache.sourceContextId(sourceIds[2]),
pathCache.sourceContextId(sourceIds[4])};
SourceContextIds sourceContextIds = {sourceIds[0].contextId(),
sourceIds[2].contextId(),
sourceIds[4].contextId()};
ProjectChunkIds ids{projectChunkId1, projectChunkId2, projectChunkId3};
WatcherEntry watcherEntry1{projectChunkId1, sourceContextIds[0], sourceIds[0]};
WatcherEntry watcherEntry2{projectChunkId2, sourceContextIds[0], sourceIds[0]};
@@ -366,10 +366,9 @@ TEST_F(ProjectStoragePathWatcher, two_notify_file_changes)
.WillByDefault(Return(FileStatus{sourceIds[3], 1, 2}));
EXPECT_CALL(notifier,
pathsWithIdsChanged(ElementsAre(
IdPaths{projectChunkId1, {SourceId::create(1), SourceId::create(2)}},
IdPaths{projectChunkId2,
{SourceId::create(1), SourceId::create(2), SourceId::create(4)}})));
pathsWithIdsChanged(
ElementsAre(IdPaths{projectChunkId1, {sourceIds[0], sourceIds[1]}},
IdPaths{projectChunkId2, {sourceIds[0], sourceIds[1], sourceIds[3]}})));
mockQFileSytemWatcher.directoryChanged(sourceContextPath);
mockQFileSytemWatcher.directoryChanged(sourceContextPath2);

View File

@@ -2413,7 +2413,7 @@ TEST_F(ProjectStorageUpdater, watcher_watches_directories_after_directory_change
setContent(u"/path/qmldir", qmldir);
setFilesChanged({directoryPathSourceId});
setFilesDontChanged({qmlDirPathSourceId});
auto directorySourceContextId = sourcePathCache.sourceContextId(directoryPathSourceId);
auto directorySourceContextId = directoryPathSourceId.contextId();
EXPECT_CALL(patchWatcherMock,
updateContextIdPaths(
@@ -2526,7 +2526,7 @@ TEST_F(ProjectStorageUpdater, watcher_watches_directories_after_qmldir_changes)
FirstType 2.2 First2.qml
SecondType 2.2 Second.qml)"};
setContent(u"/path/qmldir", qmldir);
auto directorySourceContextId = sourcePathCache.sourceContextId(qmlDirPathSourceId);
auto directorySourceContextId = qmlDirPathSourceId.contextId();
EXPECT_CALL(patchWatcherMock,
updateContextIdPaths(

View File

@@ -156,7 +156,7 @@ protected:
QmlDesigner::QmlDocumentParser parser{storage, sourcePathCache};
Storage::Imports imports;
SourceId qmlFileSourceId{sourcePathCache.sourceId("/path/to/qmlfile.qml")};
SourceContextId qmlFileSourceContextId{sourcePathCache.sourceContextId(qmlFileSourceId)};
SourceContextId qmlFileSourceContextId{qmlFileSourceId.contextId()};
Utils::PathString directoryPath{sourcePathCache.sourceContextPath(qmlFileSourceContextId)};
ModuleId directoryModuleId{storage.moduleId(directoryPath, ModuleKind::PathLibrary)};
};

View File

@@ -184,7 +184,7 @@ protected:
qmltypesFileSourceId,
qtQmlNativeModuleId,
Synchronization::FileType::QmlTypes};
SourceContextId qmltypesFileSourceContextId{sourcePathCache.sourceContextId(qmltypesFileSourceId)};
SourceContextId qmltypesFileSourceContextId{qmltypesFileSourceId.contextId()};
};
TEST_F(QmlTypesParser, imports)

View File

@@ -13,48 +13,44 @@ namespace {
using QmlDesigner::SourceContextId;
using QmlDesigner::SourceId;
using QmlDesigner::SourceIds;
using QmlDesigner::SourceNameId;
using Cache = QmlDesigner::SourcePathCache<NiceMock<ProjectStorageMock>>;
using NFP = QmlDesigner::SourcePath;
using QmlDesigner::Cache::SourceName;
using QmlDesigner::SourcePathView;
using QmlDesigner::SourcePathViews;
using QmlDesigner::Cache::SourceNameAndSourceContextId;
class SourcePathCache : public testing::Test
{
protected:
SourcePathCache()
{
ON_CALL(storageMock, fetchSourceContextId(Eq("/path/to")))
.WillByDefault(Return(SourceContextId::create(5)));
ON_CALL(storageMock, fetchSourceContextId(Eq("/path2/to")))
.WillByDefault(Return(SourceContextId::create(6)));
ON_CALL(storageMock, fetchSourceId(SourceContextId::create(5), Eq("file.cpp")))
.WillByDefault(Return(SourceId::create(42)));
ON_CALL(storageMock, fetchSourceId(SourceContextId::create(5), Eq("file2.cpp")))
.WillByDefault(Return(SourceId::create(63)));
ON_CALL(storageMock, fetchSourceId(SourceContextId::create(6), Eq("file.cpp")))
.WillByDefault(Return(SourceId::create(72)));
ON_CALL(storageMock, fetchSourceContextPath(SourceContextId::create(5)))
ON_CALL(storageMock, fetchSourceContextId(Eq("/path/to"))).WillByDefault(Return(sourceContextId5));
ON_CALL(storageMock, fetchSourceContextId(Eq("/path2/to"))).WillByDefault(Return(sourceContextId6));
ON_CALL(storageMock, fetchSourceNameId(Eq("file.cpp"))).WillByDefault(Return(sourceNameId42));
ON_CALL(storageMock, fetchSourceNameId(Eq("file2.cpp"))).WillByDefault(Return(sourceNameId63));
ON_CALL(storageMock, fetchSourceContextPath(sourceContextId5))
.WillByDefault(Return(Utils::PathString("/path/to")));
ON_CALL(storageMock, fetchSourceNameAndSourceContextId(SourceId::create(42)))
.WillByDefault(
Return(SourceNameAndSourceContextId("file.cpp", SourceContextId::create(5))));
ON_CALL(storageMockFilled, fetchAllSources())
.WillByDefault(Return(std::vector<QmlDesigner::Cache::Source>({
{"file.cpp", SourceContextId::create(6), SourceId::create(72)},
{"file2.cpp", SourceContextId::create(5), SourceId::create(63)},
{"file.cpp", SourceContextId::create(5), SourceId::create(42)},
})));
ON_CALL(storageMock, fetchSourceName(sourceNameId42)).WillByDefault(Return("file.cpp"));
ON_CALL(storageMockFilled, fetchAllSourceNames())
.WillByDefault(Return(std::vector<QmlDesigner::Cache::SourceName>(
{{"file.cpp", sourceNameId42}, {"file2.cpp", sourceNameId63}})));
ON_CALL(storageMockFilled, fetchAllSourceContexts())
.WillByDefault(Return(std::vector<QmlDesigner::Cache::SourceContext>(
{{"/path2/to", SourceContextId::create(6)}, {"/path/to", SourceContextId::create(5)}})));
{{"/path2/to", sourceContextId6}, {"/path/to", sourceContextId5}})));
ON_CALL(storageMockFilled, fetchSourceContextId(Eq("/path/to")))
.WillByDefault(Return(SourceContextId::create(5)));
ON_CALL(storageMockFilled, fetchSourceId(SourceContextId::create(5), Eq("file.cpp")))
.WillByDefault(Return(SourceId::create(42)));
.WillByDefault(Return(sourceContextId5));
ON_CALL(storageMockFilled, fetchSourceNameId(Eq("file.cpp"))).WillByDefault(Return(sourceNameId42));
}
protected:
SourceNameId sourceNameId42 = SourceNameId::create(42);
SourceNameId sourceNameId63 = SourceNameId::create(63);
SourceContextId sourceContextId5 = SourceContextId::create(5);
SourceContextId sourceContextId6 = SourceContextId::create(6);
SourceId sourceId542 = SourceId::create(sourceNameId42, sourceContextId5);
SourceId sourceId563 = SourceId::create(sourceNameId63, sourceContextId5);
SourceId sourceId642 = SourceId::create(sourceNameId42, sourceContextId6);
NiceMock<ProjectStorageMock> storageMock;
Cache cache{storageMock};
NiceMock<ProjectStorageMock> storageMockFilled;
@@ -70,7 +66,7 @@ TEST_F(SourcePathCache, source_id_with_out_any_entry_call_source_context_id)
TEST_F(SourcePathCache, source_id_with_out_any_entry_calls)
{
EXPECT_CALL(storageMock, fetchSourceId(SourceContextId::create(5), Eq("file.cpp")));
EXPECT_CALL(storageMock, fetchSourceNameId(Eq("file.cpp")));
cache.sourceId(SourcePathView("/path/to/file.cpp"));
}
@@ -79,7 +75,7 @@ TEST_F(SourcePathCache, source_id_of_source_id_with_out_any_entry)
{
auto sourceId = cache.sourceId(SourcePathView("/path/to/file.cpp"));
ASSERT_THAT(sourceId, SourceId::create(42));
ASSERT_THAT(sourceId, sourceId542);
}
TEST_F(SourcePathCache, source_id_with_source_context_id_and_source_name)
@@ -88,7 +84,7 @@ TEST_F(SourcePathCache, source_id_with_source_context_id_and_source_name)
auto sourceId = cache.sourceId(sourceContextId, "file.cpp"_sv);
ASSERT_THAT(sourceId, SourceId::create(42));
ASSERT_THAT(sourceId, sourceId542);
}
TEST_F(SourcePathCache, if_entry_exists_dont_call_in_strorage)
@@ -96,7 +92,7 @@ TEST_F(SourcePathCache, if_entry_exists_dont_call_in_strorage)
cache.sourceId(SourcePathView("/path/to/file.cpp"));
EXPECT_CALL(storageMock, fetchSourceContextId(Eq("/path/to"))).Times(0);
EXPECT_CALL(storageMock, fetchSourceId(SourceContextId::create(5), Eq("file.cpp"))).Times(0);
EXPECT_CALL(storageMock, fetchSourceNameId(Eq("file.cpp"))).Times(0);
cache.sourceId(SourcePathView("/path/to/file.cpp"));
}
@@ -106,7 +102,7 @@ TEST_F(SourcePathCache, if_directory_entry_exists_dont_call_fetch_source_context
cache.sourceId(SourcePathView("/path/to/file2.cpp"));
EXPECT_CALL(storageMock, fetchSourceContextId(Eq("/path/to"))).Times(0);
EXPECT_CALL(storageMock, fetchSourceId(SourceContextId::create(5), Eq("file.cpp")));
EXPECT_CALL(storageMock, fetchSourceNameId(Eq("file.cpp")));
cache.sourceId(SourcePathView("/path/to/file.cpp"));
}
@@ -117,7 +113,7 @@ TEST_F(SourcePathCache, get_source_id_with_cached_value)
auto sourceId = cache.sourceId(SourcePathView("/path/to/file.cpp"));
ASSERT_THAT(sourceId, SourceId::create(42));
ASSERT_THAT(sourceId, sourceId542);
}
TEST_F(SourcePathCache, get_source_id_with_source_context_id_cached)
@@ -126,7 +122,7 @@ TEST_F(SourcePathCache, get_source_id_with_source_context_id_cached)
auto sourceId = cache.sourceId(SourcePathView("/path/to/file2.cpp"));
ASSERT_THAT(sourceId, SourceId::create(63));
ASSERT_THAT(sourceId, sourceId563);
}
TEST_F(SourcePathCache, throw_for_getting_a_file_path_with_an_invalid_id)
@@ -147,9 +143,7 @@ TEST_F(SourcePathCache, get_a_file_path)
TEST_F(SourcePathCache, get_a_file_path_with_cached_source_id)
{
SourceId sourceId{SourceId::create(42)};
auto sourcePath = cache.sourcePath(sourceId);
auto sourcePath = cache.sourcePath(sourceId542);
ASSERT_THAT(sourcePath, Eq(SourcePathView{"/path/to/file.cpp"}));
}
@@ -199,7 +193,7 @@ TEST_F(SourcePathCache, source_context_id)
{
auto id = cache.sourceContextId(Utils::SmallString("/path/to"));
ASSERT_THAT(id, Eq(SourceContextId::create(5)));
ASSERT_THAT(id, Eq(sourceContextId5));
}
TEST_F(SourcePathCache, source_context_id_is_already_in_cache)
@@ -248,7 +242,7 @@ TEST_F(SourcePathCache, throw_for_getting_a_directory_path_with_an_invalid_id)
TEST_F(SourcePathCache, get_a_directory_path)
{
SourceContextId sourceContextId{SourceContextId::create(5)};
SourceContextId sourceContextId{sourceContextId5};
auto sourceContextPath = cache.sourceContextPath(sourceContextId);
@@ -257,7 +251,7 @@ TEST_F(SourcePathCache, get_a_directory_path)
TEST_F(SourcePathCache, get_a_directory_path_with_cached_source_context_id)
{
SourceContextId sourceContextId{SourceContextId::create(5)};
SourceContextId sourceContextId{sourceContextId5};
cache.sourceContextPath(sourceContextId);
auto sourceContextPath = cache.sourceContextPath(sourceContextId);
@@ -267,65 +261,40 @@ TEST_F(SourcePathCache, get_a_directory_path_with_cached_source_context_id)
TEST_F(SourcePathCache, directory_path_calls_fetch_directory_path)
{
EXPECT_CALL(storageMock, fetchSourceContextPath(Eq(SourceContextId::create(5))));
EXPECT_CALL(storageMock, fetchSourceContextPath(Eq(sourceContextId5)));
cache.sourceContextPath(SourceContextId::create(5));
cache.sourceContextPath(sourceContextId5);
}
TEST_F(SourcePathCache, second_directory_path_calls_not_fetch_directory_path)
{
cache.sourceContextPath(SourceContextId::create(5));
cache.sourceContextPath(sourceContextId5);
EXPECT_CALL(storageMock, fetchSourceContextPath(_)).Times(0);
cache.sourceContextPath(SourceContextId::create(5));
cache.sourceContextPath(sourceContextId5);
}
TEST_F(SourcePathCache, throw_for_getting_a_source_context_id_with_an_invalid_source_id)
TEST_F(SourcePathCache, fetch_source_context_from_source_id)
{
SourceId sourceId;
auto sourceContextId = sourceId542.contextId();
ASSERT_THROW(cache.sourceContextId(sourceId), QmlDesigner::NoSourcePathForInvalidSourceId);
}
TEST_F(SourcePathCache, fetch_source_context_id_by_source_id)
{
auto sourceContextId = cache.sourceContextId(SourceId::create(42));
ASSERT_THAT(sourceContextId, Eq(SourceContextId::create(5)));
}
TEST_F(SourcePathCache, fetch_source_context_id_by_source_id_cached)
{
cache.sourceContextId(SourceId::create(42));
auto sourceContextId = cache.sourceContextId(SourceId::create(42));
ASSERT_THAT(sourceContextId, Eq(SourceContextId::create(5)));
}
TEST_F(SourcePathCache, fetch_file_path_after_fetching_source_context_id_by_source_id)
{
cache.sourceContextId(SourceId::create(42));
auto sourcePath = cache.sourcePath(SourceId::create(42));
ASSERT_THAT(sourcePath, Eq("/path/to/file.cpp"));
ASSERT_THAT(sourceContextId, Eq(sourceContextId5));
}
TEST_F(SourcePathCache, fetch_source_context_id_after_fetching_file_path_by_source_id)
{
cache.sourcePath(SourceId::create(42));
cache.sourcePath(sourceId542);
auto sourceContextId = cache.sourceContextId(SourceId::create(42));
auto sourceContextId = sourceId542.contextId();
ASSERT_THAT(sourceContextId, Eq(SourceContextId::create(5)));
ASSERT_THAT(sourceContextId, Eq(sourceContextId5));
}
TEST_F(SourcePathCache, fetch_all_source_contexts_and_sources_at_creation)
{
EXPECT_CALL(storageMock, fetchAllSourceContexts());
EXPECT_CALL(storageMock, fetchAllSources());
EXPECT_CALL(storageMock, fetchAllSourceNames());
Cache cache{storageMock};
}
@@ -336,23 +305,23 @@ TEST_F(SourcePathCache, get_file_id_in_filled_cache)
auto id = cacheFilled.sourceId("/path2/to/file.cpp");
ASSERT_THAT(id, Eq(SourceId::create(72)));
ASSERT_THAT(id, Eq(sourceId642));
}
TEST_F(SourcePathCache, get_source_context_id_in_filled_cache)
{
Cache cacheFilled{storageMockFilled};
auto id = cacheFilled.sourceContextId(SourceId::create(42));
auto id = sourceId542.contextId();
ASSERT_THAT(id, Eq(SourceContextId::create(5)));
ASSERT_THAT(id, Eq(sourceContextId5));
}
TEST_F(SourcePathCache, get_directory_path_in_filled_cache)
{
Cache cacheFilled{storageMockFilled};
auto path = cacheFilled.sourceContextPath(SourceContextId::create(5));
auto path = cacheFilled.sourceContextPath(sourceContextId5);
ASSERT_THAT(path, Eq("/path/to"));
}
@@ -361,7 +330,7 @@ TEST_F(SourcePathCache, get_file_path_in_filled_cache)
{
Cache cacheFilled{storageMockFilled};
auto path = cacheFilled.sourcePath(SourceId::create(42));
auto path = cacheFilled.sourcePath(sourceId542);
ASSERT_THAT(path, Eq("/path/to/file.cpp"));
}
@@ -372,7 +341,7 @@ TEST_F(SourcePathCache, get_file_id_in_after_populate_if_empty)
auto id = cacheNotFilled.sourceId("/path2/to/file.cpp");
ASSERT_THAT(id, Eq(SourceId::create(72)));
ASSERT_THAT(id, Eq(sourceId642));
}
TEST_F(SourcePathCache, dont_populate_if_not_empty)
@@ -380,25 +349,16 @@ TEST_F(SourcePathCache, dont_populate_if_not_empty)
cacheNotFilled.sourceId("/path/to/file.cpp");
EXPECT_CALL(storageMockFilled, fetchAllSourceContexts()).Times(0);
EXPECT_CALL(storageMockFilled, fetchAllSources()).Times(0);
EXPECT_CALL(storageMockFilled, fetchAllSourceNames()).Times(0);
cacheNotFilled.populateIfEmpty();
}
TEST_F(SourcePathCache, get_source_context_id_after_populate_if_empty)
{
cacheNotFilled.populateIfEmpty();
auto id = cacheNotFilled.sourceContextId(SourceId::create(42));
ASSERT_THAT(id, Eq(SourceContextId::create(5)));
}
TEST_F(SourcePathCache, get_directory_path_after_populate_if_empty)
{
cacheNotFilled.populateIfEmpty();
auto path = cacheNotFilled.sourceContextPath(SourceContextId::create(5));
auto path = cacheNotFilled.sourceContextPath(sourceContextId5);
ASSERT_THAT(path, Eq("/path/to"));
}
@@ -407,7 +367,7 @@ TEST_F(SourcePathCache, get_file_path_after_populate_if_empty)
{
cacheNotFilled.populateIfEmpty();
auto path = cacheNotFilled.sourcePath(SourceId::create(42));
auto path = cacheNotFilled.sourcePath(sourceId542);
ASSERT_THAT(path, Eq("/path/to/file.cpp"));
}
@@ -421,17 +381,18 @@ TEST_F(SourcePathCache, source_context_and_source_id_with_out_any_entry_call_sou
TEST_F(SourcePathCache, source_context_and_source_id_with_out_any_entry_calls)
{
EXPECT_CALL(storageMock, fetchSourceId(SourceContextId::create(5), Eq("file.cpp")));
EXPECT_CALL(storageMock, fetchSourceNameId(Eq("file.cpp")));
cache.sourceContextAndSourceId(SourcePathView("/path/to/file.cpp"));
}
TEST_F(SourcePathCache, source_context_and_source_id_of_source_id_with_out_any_entry)
{
auto sourceContextAndSourceId = cache.sourceContextAndSourceId(
SourcePathView("/path/to/file.cpp"));
SourcePathView path("/path/to/file.cpp");
ASSERT_THAT(sourceContextAndSourceId, Pair(SourceContextId::create(5), SourceId::create(42)));
auto sourceId = cache.sourceId(path);
ASSERT_THAT(sourceId.contextId(), sourceContextId5);
}
TEST_F(SourcePathCache, source_context_and_source_id_if_entry_exists_dont_call_in_strorage)
@@ -439,7 +400,7 @@ TEST_F(SourcePathCache, source_context_and_source_id_if_entry_exists_dont_call_i
cache.sourceContextAndSourceId(SourcePathView("/path/to/file.cpp"));
EXPECT_CALL(storageMock, fetchSourceContextId(Eq("/path/to"))).Times(0);
EXPECT_CALL(storageMock, fetchSourceId(SourceContextId::create(5), Eq("file.cpp"))).Times(0);
EXPECT_CALL(storageMock, fetchSourceNameId(Eq("file.cpp"))).Times(0);
cache.sourceContextAndSourceId(SourcePathView("/path/to/file.cpp"));
}
@@ -450,7 +411,7 @@ TEST_F(SourcePathCache,
cache.sourceContextAndSourceId(SourcePathView("/path/to/file2.cpp"));
EXPECT_CALL(storageMock, fetchSourceContextId(Eq("/path/to"))).Times(0);
EXPECT_CALL(storageMock, fetchSourceId(SourceContextId::create(5), Eq("file.cpp")));
EXPECT_CALL(storageMock, fetchSourceNameId(Eq("file.cpp")));
cache.sourceContextAndSourceId(SourcePathView("/path/to/file.cpp"));
}
@@ -461,7 +422,7 @@ TEST_F(SourcePathCache, source_context_and_source_id_get_source_id_with_cached_v
auto sourceId = cache.sourceContextAndSourceId(SourcePathView("/path/to/file.cpp"));
ASSERT_THAT(sourceId, Pair(SourceContextId::create(5), SourceId::create(42)));
ASSERT_THAT(sourceId, Pair(sourceContextId5, sourceId542));
}
TEST_F(SourcePathCache, get_source_context_and_source_id_with_source_context_id_cached)
@@ -471,7 +432,7 @@ TEST_F(SourcePathCache, get_source_context_and_source_id_with_source_context_id_
auto sourceContextAndSourceId = cache.sourceContextAndSourceId(
SourcePathView("/path/to/file2.cpp"));
ASSERT_THAT(sourceContextAndSourceId, Pair(SourceContextId::create(5), SourceId::create(63)));
ASSERT_THAT(sourceContextAndSourceId, Pair(sourceContextId5, sourceId563));
}
TEST_F(SourcePathCache, get_source_context_and_source_id_file_names_are_unique_for_every_directory)

View File

@@ -33,10 +33,13 @@ using Sqlite::ReadWriteStatement;
using Sqlite::Value;
using Sqlite::WriteStatement;
enum class BasicIdEnumeration { TestId };
enum class BasicIdEnumeration { TestId, TestId2 };
using TestLongLongId = Sqlite::BasicId<BasicIdEnumeration::TestId, long long>;
using TestIntId = Sqlite::BasicId<BasicIdEnumeration::TestId, int>;
using TestIntId2 = Sqlite::BasicId<BasicIdEnumeration::TestId2, int>;
using CompoundId = Sqlite::CompoundBasicId<BasicIdEnumeration::TestId, BasicIdEnumeration::TestId2>;
template<typename Type>
bool compareValue(SqliteTestStatement<2, 1> &statement, Type value, int column)
@@ -255,6 +258,19 @@ TEST_F(SqliteStatement, bind_invalid_int_id_to_null)
ASSERT_THAT(readStatement.fetchType(0), Sqlite::Type::Null);
}
TEST_F(SqliteStatement, bind_invalid_compound_id_to_null)
{
CompoundId id;
SqliteTestStatement<0, 1> statement("INSERT INTO test VALUES ('id', 323, ?)", database);
statement.bind(1, id);
statement.next();
SqliteTestStatement<1, 1> readStatement("SELECT value FROM test WHERE name='id'", database);
readStatement.next();
ASSERT_THAT(readStatement.fetchType(0), Sqlite::Type::Null);
}
TEST_F(SqliteStatement, bind_int_id)
{
TestIntId id{TestIntId::create(42)};
@@ -269,6 +285,20 @@ TEST_F(SqliteStatement, bind_int_id)
ASSERT_THAT(readStatement.fetchIntValue(0), 42);
}
TEST_F(SqliteStatement, bind_compound_id)
{
CompoundId id = CompoundId::create(42);
SqliteTestStatement<0, 1> statement("INSERT INTO test VALUES ('id', 323, ?)", database);
statement.bind(1, id);
statement.next();
SqliteTestStatement<1, 1> readStatement("SELECT value FROM test WHERE name='id'", database);
readStatement.next();
ASSERT_THAT(readStatement.fetchType(0), Sqlite::Type::Integer);
ASSERT_THAT(readStatement.fetchIntValue(0), 42);
}
TEST_F(SqliteStatement, bind_special_state_id)
{
enum class SpecialIdState { Unresolved = -1 };
@@ -1271,6 +1301,30 @@ TEST_F(SqliteStatement, get_single_int_id)
ASSERT_THAT(value.internalId(), Eq(42));
}
TEST_F(SqliteStatement, get_single_invalid_compound_id)
{
CompoundId id;
WriteStatement<1>("INSERT INTO test VALUES ('id', 323, ?)", database).write(id);
ReadStatement<1, 0> statement("SELECT value FROM test WHERE name='id'", database);
auto value = statement.value<CompoundId>();
ASSERT_FALSE(value.isValid());
}
TEST_F(SqliteStatement, get_single_compound_id)
{
TestIntId testId = TestIntId::create(42);
TestIntId2 testId2 = TestIntId2::create(23);
CompoundId id = CompoundId::create(testId, testId2);
WriteStatement<1>("INSERT INTO test VALUES ('id', 323, ?)", database).write(id);
ReadStatement<1, 0> statement("SELECT value FROM test WHERE name='id'", database);
auto value = statement.value<CompoundId>();
ASSERT_THAT(value, Eq(id));
}
TEST_F(SqliteStatement, get_value_calls_reset)
{
struct Value