diff options
Diffstat (limited to 'src/plugins/qmldesigner/designercore/projectstorage')
9 files changed, 3965 insertions, 3609 deletions
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/filesystem.h b/src/plugins/qmldesigner/designercore/projectstorage/filesystem.h index 078fd1ee98..28754a8560 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/filesystem.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/filesystem.h @@ -6,6 +6,7 @@ #include "filestatuscache.h" #include "filesysteminterface.h" #include "nonlockingmutex.h" +#include "projectstoragefwd.h" namespace Sqlite { class Database; @@ -16,12 +17,9 @@ namespace QmlDesigner { template<typename ProjectStorage, typename Mutex> class SourcePathCache; -template<typename Database> -class ProjectStorage; - class FileSystem : public FileSystemInterface { - using PathCache = SourcePathCache<ProjectStorage<Sqlite::Database>, NonLockingMutex>; + using PathCache = SourcePathCache<ProjectStorage, NonLockingMutex>; public: FileSystem(PathCache &sourcePathCache) diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.cpp b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.cpp index 2bef2244d7..a037ddae9a 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.cpp +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.cpp @@ -5,4 +5,3776 @@ #include <sqlitedatabase.h> -template class QmlDesigner::ProjectStorage<Sqlite::Database>; +namespace QmlDesigner { + +class ProjectStorage::Initializer +{ +public: + Initializer(Database &database, bool isInitialized) + { + if (!isInitialized) { + auto moduleIdColumn = createModulesTable(database); + createSourceContextsTable(database); + createSourcesTable(database); + createTypesAndePropertyDeclarationsTables(database, moduleIdColumn); + createExportedTypeNamesTable(database, moduleIdColumn); + createImportedTypeNamesTable(database); + createEnumerationsTable(database); + createFunctionsTable(database); + createSignalsTable(database); + createModuleExportedImportsTable(database, moduleIdColumn); + createDocumentImportsTable(database, moduleIdColumn); + createFileStatusesTable(database); + createProjectDatasTable(database); + createPropertyEditorPathsTable(database); + createTypeAnnotionsTable(database); + } + database.setIsInitialized(true); + } + + void createSourceContextsTable(Database &database) + { + Sqlite::Table table; + table.setUseIfNotExists(true); + table.setName("sourceContexts"); + table.addColumn("sourceContextId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}}); + const Sqlite::Column &sourceContextPathColumn = table.addColumn("sourceContextPath"); + + table.addUniqueIndex({sourceContextPathColumn}); + + table.initialize(database); + } + + void createSourcesTable(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}}); + const auto &sourceNameColumn = table.addColumn("sourceName", Sqlite::StrictColumnType::Text); + table.addUniqueIndex({sourceContextIdColumn, sourceNameColumn}); + + table.initialize(database); + } + + void createTypesAndePropertyDeclarationsTables( + Database &database, [[maybe_unused]] const Sqlite::StrictColumn &foreignModuleIdColumn) + { + Sqlite::StrictTable typesTable; + typesTable.setUseIfNotExists(true); + typesTable.setName("types"); + typesTable.addColumn("typeId", Sqlite::StrictColumnType::Integer, {Sqlite::PrimaryKey{}}); + auto &sourceIdColumn = typesTable.addColumn("sourceId", Sqlite::StrictColumnType::Integer); + auto &typesNameColumn = typesTable.addColumn("name", Sqlite::StrictColumnType::Text); + typesTable.addColumn("traits", Sqlite::StrictColumnType::Integer); + auto &prototypeIdColumn = typesTable.addForeignKeyColumn("prototypeId", + typesTable, + Sqlite::ForeignKeyAction::NoAction, + Sqlite::ForeignKeyAction::Restrict); + typesTable.addColumn("prototypeNameId", Sqlite::StrictColumnType::Integer); + auto &extensionIdColumn = typesTable.addForeignKeyColumn("extensionId", + typesTable, + Sqlite::ForeignKeyAction::NoAction, + Sqlite::ForeignKeyAction::Restrict); + typesTable.addColumn("extensionNameId", Sqlite::StrictColumnType::Integer); + auto &defaultPropertyIdColumn = typesTable.addColumn("defaultPropertyId", + Sqlite::StrictColumnType::Integer); + typesTable.addColumn("annotationTraits", Sqlite::StrictColumnType::Integer); + typesTable.addUniqueIndex({sourceIdColumn, typesNameColumn}); + typesTable.addIndex({defaultPropertyIdColumn}); + typesTable.addIndex({prototypeIdColumn}); + typesTable.addIndex({extensionIdColumn}); + + typesTable.initialize(database); + + { + Sqlite::StrictTable propertyDeclarationTable; + propertyDeclarationTable.setUseIfNotExists(true); + propertyDeclarationTable.setName("propertyDeclarations"); + propertyDeclarationTable.addColumn("propertyDeclarationId", + Sqlite::StrictColumnType::Integer, + {Sqlite::PrimaryKey{}}); + auto &typeIdColumn = propertyDeclarationTable.addColumn("typeId"); + auto &nameColumn = propertyDeclarationTable.addColumn("name"); + auto &propertyTypeIdColumn = propertyDeclarationTable.addForeignKeyColumn( + "propertyTypeId", + typesTable, + Sqlite::ForeignKeyAction::NoAction, + Sqlite::ForeignKeyAction::Restrict); + propertyDeclarationTable.addColumn("propertyTraits", Sqlite::StrictColumnType::Integer); + propertyDeclarationTable.addColumn("propertyImportedTypeNameId", + Sqlite::StrictColumnType::Integer); + auto &aliasPropertyDeclarationIdColumn = propertyDeclarationTable.addForeignKeyColumn( + "aliasPropertyDeclarationId", + propertyDeclarationTable, + Sqlite::ForeignKeyAction::NoAction, + Sqlite::ForeignKeyAction::Restrict); + auto &aliasPropertyDeclarationTailIdColumn = propertyDeclarationTable.addForeignKeyColumn( + "aliasPropertyDeclarationTailId", + propertyDeclarationTable, + Sqlite::ForeignKeyAction::NoAction, + Sqlite::ForeignKeyAction::Restrict); + + propertyDeclarationTable.addUniqueIndex({typeIdColumn, nameColumn}); + propertyDeclarationTable.addIndex({propertyTypeIdColumn}); + propertyDeclarationTable.addIndex({aliasPropertyDeclarationIdColumn}, + "aliasPropertyDeclarationId IS NOT NULL"); + propertyDeclarationTable.addIndex({aliasPropertyDeclarationTailIdColumn}, + "aliasPropertyDeclarationTailId IS NOT NULL"); + + propertyDeclarationTable.initialize(database); + } + } + + void createExportedTypeNamesTable(Database &database, + const Sqlite::StrictColumn &foreignModuleIdColumn) + { + Sqlite::StrictTable table; + table.setUseIfNotExists(true); + table.setName("exportedTypeNames"); + table.addColumn("exportedTypeNameId", + Sqlite::StrictColumnType::Integer, + {Sqlite::PrimaryKey{}}); + auto &moduleIdColumn = table.addForeignKeyColumn("moduleId", + foreignModuleIdColumn, + Sqlite::ForeignKeyAction::NoAction, + Sqlite::ForeignKeyAction::NoAction); + auto &nameColumn = table.addColumn("name", Sqlite::StrictColumnType::Text); + auto &typeIdColumn = table.addColumn("typeId", Sqlite::StrictColumnType::Integer); + auto &majorVersionColumn = table.addColumn("majorVersion", Sqlite::StrictColumnType::Integer); + auto &minorVersionColumn = table.addColumn("minorVersion", Sqlite::StrictColumnType::Integer); + + table.addUniqueIndex({moduleIdColumn, nameColumn}, + "majorVersion IS NULL AND minorVersion IS NULL"); + table.addUniqueIndex({moduleIdColumn, nameColumn, majorVersionColumn}, + "majorVersion IS NOT NULL AND minorVersion IS NULL"); + table.addUniqueIndex({moduleIdColumn, nameColumn, majorVersionColumn, minorVersionColumn}, + "majorVersion IS NOT NULL AND minorVersion IS NOT NULL"); + + table.addIndex({typeIdColumn}); + table.addIndex({moduleIdColumn, nameColumn}); + + table.initialize(database); + } + + void createImportedTypeNamesTable(Database &database) + { + Sqlite::StrictTable table; + table.setUseIfNotExists(true); + table.setName("importedTypeNames"); + table.addColumn("importedTypeNameId", + Sqlite::StrictColumnType::Integer, + {Sqlite::PrimaryKey{}}); + auto &importOrSourceIdColumn = table.addColumn("importOrSourceId"); + auto &nameColumn = table.addColumn("name", Sqlite::StrictColumnType::Text); + auto &kindColumn = table.addColumn("kind", Sqlite::StrictColumnType::Integer); + + table.addUniqueIndex({kindColumn, importOrSourceIdColumn, nameColumn}); + table.addIndex({nameColumn}); + + table.initialize(database); + } + + void createEnumerationsTable(Database &database) + { + Sqlite::StrictTable table; + table.setUseIfNotExists(true); + table.setName("enumerationDeclarations"); + table.addColumn("enumerationDeclarationId", + Sqlite::StrictColumnType::Integer, + {Sqlite::PrimaryKey{}}); + auto &typeIdColumn = table.addColumn("typeId", Sqlite::StrictColumnType::Integer); + auto &nameColumn = table.addColumn("name", Sqlite::StrictColumnType::Text); + table.addColumn("enumeratorDeclarations", Sqlite::StrictColumnType::Text); + + table.addUniqueIndex({typeIdColumn, nameColumn}); + + table.initialize(database); + } + + void createFunctionsTable(Database &database) + { + Sqlite::StrictTable table; + table.setUseIfNotExists(true); + table.setName("functionDeclarations"); + table.addColumn("functionDeclarationId", + Sqlite::StrictColumnType::Integer, + {Sqlite::PrimaryKey{}}); + auto &typeIdColumn = table.addColumn("typeId", Sqlite::StrictColumnType::Integer); + auto &nameColumn = table.addColumn("name", Sqlite::StrictColumnType::Text); + auto &signatureColumn = table.addColumn("signature", Sqlite::StrictColumnType::Text); + table.addColumn("returnTypeName"); + + table.addUniqueIndex({typeIdColumn, nameColumn, signatureColumn}); + + table.initialize(database); + } + + void createSignalsTable(Database &database) + { + Sqlite::StrictTable table; + table.setUseIfNotExists(true); + table.setName("signalDeclarations"); + table.addColumn("signalDeclarationId", + Sqlite::StrictColumnType::Integer, + {Sqlite::PrimaryKey{}}); + auto &typeIdColumn = table.addColumn("typeId", Sqlite::StrictColumnType::Integer); + auto &nameColumn = table.addColumn("name", Sqlite::StrictColumnType::Text); + auto &signatureColumn = table.addColumn("signature", Sqlite::StrictColumnType::Text); + + table.addUniqueIndex({typeIdColumn, nameColumn, signatureColumn}); + + table.initialize(database); + } + + Sqlite::StrictColumn createModulesTable(Database &database) + { + Sqlite::StrictTable table; + table.setUseIfNotExists(true); + table.setName("modules"); + auto &modelIdColumn = table.addColumn("moduleId", + Sqlite::StrictColumnType::Integer, + {Sqlite::PrimaryKey{}}); + auto &nameColumn = table.addColumn("name", Sqlite::StrictColumnType::Text); + + table.addUniqueIndex({nameColumn}); + + table.initialize(database); + + return std::move(modelIdColumn); + } + + void createModuleExportedImportsTable(Database &database, + const Sqlite::StrictColumn &foreignModuleIdColumn) + { + Sqlite::StrictTable table; + table.setUseIfNotExists(true); + table.setName("moduleExportedImports"); + table.addColumn("moduleExportedImportId", + Sqlite::StrictColumnType::Integer, + {Sqlite::PrimaryKey{}}); + auto &moduleIdColumn = table.addForeignKeyColumn("moduleId", + foreignModuleIdColumn, + Sqlite::ForeignKeyAction::NoAction, + Sqlite::ForeignKeyAction::Cascade, + Sqlite::Enforment::Immediate); + auto &sourceIdColumn = table.addColumn("exportedModuleId", Sqlite::StrictColumnType::Integer); + table.addColumn("isAutoVersion", Sqlite::StrictColumnType::Integer); + table.addColumn("majorVersion", Sqlite::StrictColumnType::Integer); + table.addColumn("minorVersion", Sqlite::StrictColumnType::Integer); + + table.addUniqueIndex({sourceIdColumn, moduleIdColumn}); + + table.initialize(database); + } + + void createDocumentImportsTable(Database &database, + const Sqlite::StrictColumn &foreignModuleIdColumn) + { + Sqlite::StrictTable table; + table.setUseIfNotExists(true); + table.setName("documentImports"); + table.addColumn("importId", Sqlite::StrictColumnType::Integer, {Sqlite::PrimaryKey{}}); + auto &sourceIdColumn = table.addColumn("sourceId", Sqlite::StrictColumnType::Integer); + auto &moduleIdColumn = table.addForeignKeyColumn("moduleId", + foreignModuleIdColumn, + Sqlite::ForeignKeyAction::NoAction, + Sqlite::ForeignKeyAction::Cascade, + Sqlite::Enforment::Immediate); + auto &sourceModuleIdColumn = table.addForeignKeyColumn("sourceModuleId", + foreignModuleIdColumn, + Sqlite::ForeignKeyAction::NoAction, + Sqlite::ForeignKeyAction::Cascade, + Sqlite::Enforment::Immediate); + auto &kindColumn = table.addColumn("kind", Sqlite::StrictColumnType::Integer); + auto &majorVersionColumn = table.addColumn("majorVersion", Sqlite::StrictColumnType::Integer); + auto &minorVersionColumn = table.addColumn("minorVersion", Sqlite::StrictColumnType::Integer); + auto &parentImportIdColumn = table.addColumn("parentImportId", + Sqlite::StrictColumnType::Integer); + + table.addUniqueIndex( + {sourceIdColumn, moduleIdColumn, kindColumn, sourceModuleIdColumn, parentImportIdColumn}, + "majorVersion IS NULL AND minorVersion IS NULL"); + table.addUniqueIndex({sourceIdColumn, + moduleIdColumn, + kindColumn, + sourceModuleIdColumn, + majorVersionColumn, + parentImportIdColumn}, + "majorVersion IS NOT NULL AND minorVersion IS NULL"); + table.addUniqueIndex({sourceIdColumn, + moduleIdColumn, + kindColumn, + sourceModuleIdColumn, + majorVersionColumn, + minorVersionColumn, + parentImportIdColumn}, + "majorVersion IS NOT NULL AND minorVersion IS NOT NULL"); + + table.addIndex({sourceIdColumn, kindColumn}); + + table.initialize(database); + } + + void createFileStatusesTable(Database &database) + { + 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("size", Sqlite::StrictColumnType::Integer); + table.addColumn("lastModified", Sqlite::StrictColumnType::Integer); + + table.initialize(database); + } + + void createProjectDatasTable(Database &database) + { + Sqlite::StrictTable table; + table.setUseIfNotExists(true); + table.setUseWithoutRowId(true); + table.setName("projectDatas"); + auto &projectSourceIdColumn = table.addColumn("projectSourceId", + Sqlite::StrictColumnType::Integer); + auto &sourceIdColumn = table.addColumn("sourceId", Sqlite::StrictColumnType::Integer); + table.addColumn("moduleId", Sqlite::StrictColumnType::Integer); + table.addColumn("fileType", Sqlite::StrictColumnType::Integer); + + table.addPrimaryKeyContraint({projectSourceIdColumn, sourceIdColumn}); + table.addUniqueIndex({sourceIdColumn}); + + table.initialize(database); + } + + void createPropertyEditorPathsTable(Database &database) + { + Sqlite::StrictTable table; + table.setUseIfNotExists(true); + table.setUseWithoutRowId(true); + table.setName("propertyEditorPaths"); + table.addColumn("typeId", Sqlite::StrictColumnType::Integer, {Sqlite::PrimaryKey{}}); + table.addColumn("pathSourceId", Sqlite::StrictColumnType::Integer); + auto &directoryIdColumn = table.addColumn("directoryId", Sqlite::StrictColumnType::Integer); + + table.addIndex({directoryIdColumn}); + + table.initialize(database); + } + + void createTypeAnnotionsTable(Database &database) + { + Sqlite::StrictTable table; + table.setUseIfNotExists(true); + table.setUseWithoutRowId(true); + table.setName("typeAnnotations"); + auto &typeIdColumn = table.addColumn("typeId", + Sqlite::StrictColumnType::Integer, + {Sqlite::PrimaryKey{}}); + auto &sourceIdColumn = table.addColumn("sourceId", Sqlite::StrictColumnType::Integer); + auto &directorySourceIdColumn = table.addColumn("directorySourceId", + Sqlite::StrictColumnType::Integer); + + table.addColumn("iconPath", Sqlite::StrictColumnType::Text); + table.addColumn("itemLibrary", Sqlite::StrictColumnType::Text); + table.addColumn("hints", Sqlite::StrictColumnType::Text); + + table.addUniqueIndex({sourceIdColumn, typeIdColumn}); + table.addIndex({directorySourceIdColumn}); + + table.initialize(database); + } +}; + +ProjectStorage::ProjectStorage(Database &database, bool isInitialized) + : database{database} + , exclusiveTransaction{database} + , initializer{std::make_unique<ProjectStorage::Initializer>(database, isInitialized)} + , moduleCache{ModuleStorageAdapter{*this}} +{ + NanotraceHR::Tracer tracer{"initialize"_t, projectStorageCategory()}; + + exclusiveTransaction.commit(); + + database.walCheckpointFull(); + + moduleCache.populate(); +} + +ProjectStorage::~ProjectStorage() = default; + +void ProjectStorage::synchronize(Storage::Synchronization::SynchronizationPackage package) +{ + NanotraceHR::Tracer tracer{"synchronize"_t, projectStorageCategory()}; + + TypeIds deletedTypeIds; + Sqlite::withImmediateTransaction(database, [&] { + AliasPropertyDeclarations insertedAliasPropertyDeclarations; + AliasPropertyDeclarations updatedAliasPropertyDeclarations; + + AliasPropertyDeclarations relinkableAliasPropertyDeclarations; + PropertyDeclarations relinkablePropertyDeclarations; + Prototypes relinkablePrototypes; + Prototypes relinkableExtensions; + + TypeIds updatedTypeIds; + updatedTypeIds.reserve(package.types.size()); + + TypeIds typeIdsToBeDeleted; + + std::sort(package.updatedSourceIds.begin(), package.updatedSourceIds.end()); + + synchronizeFileStatuses(package.fileStatuses, package.updatedFileStatusSourceIds); + synchronizeImports(package.imports, + package.updatedSourceIds, + package.moduleDependencies, + package.updatedModuleDependencySourceIds, + package.moduleExportedImports, + package.updatedModuleIds); + synchronizeTypes(package.types, + updatedTypeIds, + insertedAliasPropertyDeclarations, + updatedAliasPropertyDeclarations, + relinkableAliasPropertyDeclarations, + relinkablePropertyDeclarations, + relinkablePrototypes, + relinkableExtensions, + package.updatedSourceIds); + synchronizeTypeAnnotations(package.typeAnnotations, package.updatedTypeAnnotationSourceIds); + synchronizePropertyEditorQmlPaths(package.propertyEditorQmlPaths, + package.updatedPropertyEditorQmlPathSourceIds); + + deleteNotUpdatedTypes(updatedTypeIds, + package.updatedSourceIds, + typeIdsToBeDeleted, + relinkableAliasPropertyDeclarations, + relinkablePropertyDeclarations, + relinkablePrototypes, + relinkableExtensions, + deletedTypeIds); + + relink(relinkableAliasPropertyDeclarations, + relinkablePropertyDeclarations, + relinkablePrototypes, + relinkableExtensions, + deletedTypeIds); + + linkAliases(insertedAliasPropertyDeclarations, updatedAliasPropertyDeclarations); + + synchronizeProjectDatas(package.projectDatas, package.updatedProjectSourceIds); + + commonTypeCache_.resetTypeIds(); + }); + + callRefreshMetaInfoCallback(deletedTypeIds); +} + +void ProjectStorage::synchronizeDocumentImports(Storage::Imports imports, SourceId sourceId) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"synchronize document imports"_t, + projectStorageCategory(), + keyValue("imports", imports), + keyValue("source id", sourceId)}; + + Sqlite::withImmediateTransaction(database, [&] { + synchronizeDocumentImports(imports, {sourceId}, Storage::Synchronization::ImportKind::Import); + }); +} + +void ProjectStorage::addObserver(ProjectStorageObserver *observer) +{ + NanotraceHR::Tracer tracer{"add observer"_t, projectStorageCategory()}; + observers.push_back(observer); +} + +void ProjectStorage::removeObserver(ProjectStorageObserver *observer) +{ + NanotraceHR::Tracer tracer{"remove observer"_t, projectStorageCategory()}; + observers.removeOne(observer); +} + +ModuleId ProjectStorage::moduleId(Utils::SmallStringView moduleName) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get module id"_t, + projectStorageCategory(), + keyValue("module name", moduleName)}; + + auto moduleId = moduleCache.id(moduleName); + + tracer.end(keyValue("module id", moduleId)); + + return moduleId; +} + +Utils::SmallString ProjectStorage::moduleName(ModuleId moduleId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get module name"_t, + projectStorageCategory(), + keyValue("module id", moduleId)}; + + if (!moduleId) + throw ModuleDoesNotExists{}; + + auto moduleName = moduleCache.value(moduleId); + + tracer.end(keyValue("module name", moduleName)); + + return moduleName; +} + +TypeId ProjectStorage::typeId(ModuleId moduleId, + Utils::SmallStringView exportedTypeName, + Storage::Version version) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get type id by exported name"_t, + projectStorageCategory(), + keyValue("module id", moduleId), + keyValue("exported type name", exportedTypeName), + keyValue("version", version)}; + + TypeId typeId; + + if (version.minor) { + typeId = selectTypeIdByModuleIdAndExportedNameAndVersionStatement.valueWithTransaction<TypeId>( + moduleId, exportedTypeName, version.major.value, version.minor.value); + + } else if (version.major) { + typeId = selectTypeIdByModuleIdAndExportedNameAndMajorVersionStatement + .valueWithTransaction<TypeId>(moduleId, exportedTypeName, version.major.value); + + } else { + typeId = selectTypeIdByModuleIdAndExportedNameStatement + .valueWithTransaction<TypeId>(moduleId, exportedTypeName); + } + + tracer.end(keyValue("type id", typeId)); + + return typeId; +} + +TypeId ProjectStorage::typeId(ImportedTypeNameId typeNameId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get type id by imported type name"_t, + projectStorageCategory(), + keyValue("imported type name id", typeNameId)}; + + auto typeId = Sqlite::withDeferredTransaction(database, [&] { return fetchTypeId(typeNameId); }); + + tracer.end(keyValue("type id", typeId)); + + return typeId; +} + +QVarLengthArray<TypeId, 256> ProjectStorage::typeIds(ModuleId moduleId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get type ids by module id"_t, + projectStorageCategory(), + keyValue("module id", moduleId)}; + + auto typeIds = selectTypeIdsByModuleIdStatement.valuesWithTransaction<QVarLengthArray<TypeId, 256>>( + moduleId); + + tracer.end(keyValue("type ids", typeIds)); + + return typeIds; +} + +Storage::Info::ExportedTypeNames ProjectStorage::exportedTypeNames(TypeId typeId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get exported type names by type id"_t, + projectStorageCategory(), + keyValue("type id", typeId)}; + + auto exportedTypenames = selectExportedTypesByTypeIdStatement + .valuesWithTransaction<Storage::Info::ExportedTypeName, 4>(typeId); + + tracer.end(keyValue("exported type names", exportedTypenames)); + + return exportedTypenames; +} + +Storage::Info::ExportedTypeNames ProjectStorage::exportedTypeNames(TypeId typeId, SourceId sourceId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get exported type names by source id"_t, + projectStorageCategory(), + keyValue("type id", typeId), + keyValue("source id", sourceId)}; + + auto exportedTypenames = selectExportedTypesByTypeIdAndSourceIdStatement + .valuesWithTransaction<Storage::Info::ExportedTypeName, 4>(typeId, + sourceId); + + tracer.end(keyValue("exported type names", exportedTypenames)); + + return exportedTypenames; +} + +ImportId ProjectStorage::importId(const Storage::Import &import) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get import id by import"_t, + projectStorageCategory(), + keyValue("import", import)}; + + auto importId = Sqlite::withDeferredTransaction(database, [&] { + return fetchImportId(import.sourceId, import); + }); + + tracer.end(keyValue("import id", importId)); + + return importId; +} + +ImportedTypeNameId ProjectStorage::importedTypeNameId(ImportId importId, + Utils::SmallStringView typeName) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get imported type name id by import id"_t, + projectStorageCategory(), + keyValue("import id", importId), + keyValue("imported type name", typeName)}; + + auto importedTypeNameId = Sqlite::withDeferredTransaction(database, [&] { + return fetchImportedTypeNameId(Storage::Synchronization::TypeNameKind::QualifiedExported, + importId, + typeName); + }); + + tracer.end(keyValue("imported type name id", importedTypeNameId)); + + return importedTypeNameId; +} + +ImportedTypeNameId ProjectStorage::importedTypeNameId(SourceId sourceId, + Utils::SmallStringView typeName) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get imported type name id by source id"_t, + projectStorageCategory(), + keyValue("source id", sourceId), + keyValue("imported type name", typeName)}; + + auto importedTypeNameId = Sqlite::withDeferredTransaction(database, [&] { + return fetchImportedTypeNameId(Storage::Synchronization::TypeNameKind::Exported, + sourceId, + typeName); + }); + + tracer.end(keyValue("imported type name id", importedTypeNameId)); + + return importedTypeNameId; +} + +QVarLengthArray<PropertyDeclarationId, 128> ProjectStorage::propertyDeclarationIds(TypeId typeId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get property declaration ids"_t, + projectStorageCategory(), + keyValue("type id", typeId)}; + + auto propertyDeclarationIds = Sqlite::withDeferredTransaction(database, [&] { + return fetchPropertyDeclarationIds(typeId); + }); + + std::sort(propertyDeclarationIds.begin(), propertyDeclarationIds.end()); + + tracer.end(keyValue("property declaration ids", propertyDeclarationIds)); + + return propertyDeclarationIds; +} + +QVarLengthArray<PropertyDeclarationId, 128> ProjectStorage::localPropertyDeclarationIds(TypeId typeId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get local property declaration ids"_t, + projectStorageCategory(), + keyValue("type id", typeId)}; + + auto propertyDeclarationIds = selectLocalPropertyDeclarationIdsForTypeStatement + .valuesWithTransaction<QVarLengthArray<PropertyDeclarationId, 128>>( + typeId); + + tracer.end(keyValue("property declaration ids", propertyDeclarationIds)); + + return propertyDeclarationIds; +} + +PropertyDeclarationId ProjectStorage::propertyDeclarationId(TypeId typeId, + Utils::SmallStringView propertyName) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get property declaration id"_t, + projectStorageCategory(), + keyValue("type id", typeId), + keyValue("property name", propertyName)}; + + auto propertyDeclarationId = Sqlite::withDeferredTransaction(database, [&] { + return fetchPropertyDeclarationId(typeId, propertyName); + }); + + tracer.end(keyValue("property declaration id", propertyDeclarationId)); + + return propertyDeclarationId; +} + +PropertyDeclarationId ProjectStorage::localPropertyDeclarationId(TypeId typeId, + Utils::SmallStringView propertyName) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get local property declaration id"_t, + projectStorageCategory(), + keyValue("type id", typeId), + keyValue("property name", propertyName)}; + + auto propertyDeclarationId = selectLocalPropertyDeclarationIdForTypeAndPropertyNameStatement + .valueWithTransaction<PropertyDeclarationId>(typeId, + propertyName); + + tracer.end(keyValue("property declaration id", propertyDeclarationId)); + + return propertyDeclarationId; +} + +PropertyDeclarationId ProjectStorage::defaultPropertyDeclarationId(TypeId typeId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get default property declaration id"_t, + projectStorageCategory(), + keyValue("type id", typeId)}; + + auto propertyDeclarationId = Sqlite::withDeferredTransaction(database, [&] { + return fetchDefaultPropertyDeclarationId(typeId); + }); + + tracer.end(keyValue("property declaration id", propertyDeclarationId)); + + return propertyDeclarationId; +} + +std::optional<Storage::Info::PropertyDeclaration> ProjectStorage::propertyDeclaration( + PropertyDeclarationId propertyDeclarationId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get property declaration"_t, + projectStorageCategory(), + keyValue("property declaration id", propertyDeclarationId)}; + + auto propertyDeclaration = selectPropertyDeclarationForPropertyDeclarationIdStatement + .optionalValueWithTransaction<Storage::Info::PropertyDeclaration>( + propertyDeclarationId); + + tracer.end(keyValue("property declaration", propertyDeclaration)); + + return propertyDeclaration; +} + +std::optional<Storage::Info::Type> ProjectStorage::type(TypeId typeId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get type"_t, projectStorageCategory(), keyValue("type id", typeId)}; + + auto type = selectInfoTypeByTypeIdStatement.optionalValueWithTransaction<Storage::Info::Type>( + typeId); + + tracer.end(keyValue("type", type)); + + return type; +} + +Utils::PathString ProjectStorage::typeIconPath(TypeId typeId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get type icon path"_t, + projectStorageCategory(), + keyValue("type id", typeId)}; + + auto typeIconPath = selectTypeIconPathStatement.valueWithTransaction<Utils::PathString>(typeId); + + tracer.end(keyValue("type icon path", typeIconPath)); + + return typeIconPath; +} + +Storage::Info::TypeHints ProjectStorage::typeHints(TypeId typeId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get type hints"_t, + projectStorageCategory(), + keyValue("type id", typeId)}; + + auto typeHints = selectTypeHintsStatement.valuesWithTransaction<Storage::Info::TypeHints, 4>( + typeId); + + tracer.end(keyValue("type hints", typeHints)); + + return typeHints; +} + +SmallSourceIds<4> ProjectStorage::typeAnnotationSourceIds(SourceId directoryId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get type annotaion source ids"_t, + projectStorageCategory(), + keyValue("source id", directoryId)}; + + auto sourceIds = selectTypeAnnotationSourceIdsStatement.valuesWithTransaction<SmallSourceIds<4>>( + directoryId); + + tracer.end(keyValue("source ids", sourceIds)); + + return sourceIds; +} + +SmallSourceIds<64> ProjectStorage::typeAnnotationDirectorySourceIds() const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get type annotaion source ids"_t, projectStorageCategory()}; + + auto sourceIds = selectTypeAnnotationDirectorySourceIdsStatement + .valuesWithTransaction<SmallSourceIds<64>>(); + + tracer.end(keyValue("source ids", sourceIds)); + + return sourceIds; +} + +Storage::Info::ItemLibraryEntries ProjectStorage::itemLibraryEntries(TypeId typeId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get item library entries by type id"_t, + projectStorageCategory(), + keyValue("type id", typeId)}; + + using Storage::Info::ItemLibraryProperties; + Storage::Info::ItemLibraryEntries entries; + + auto callback = [&](TypeId typeId_, + Utils::SmallStringView name, + Utils::SmallStringView iconPath, + Utils::SmallStringView category, + Utils::SmallStringView import, + Utils::SmallStringView toolTip, + Utils::SmallStringView properties, + Utils::SmallStringView extraFilePaths, + Utils::SmallStringView templatePath) { + auto &last = entries.emplace_back(typeId_, name, iconPath, category, import, toolTip, templatePath); + if (properties.size()) + selectItemLibraryPropertiesStatement.readTo(last.properties, properties); + if (extraFilePaths.size()) + selectItemLibraryExtraFilePathsStatement.readTo(last.extraFilePaths, extraFilePaths); + }; + + selectItemLibraryEntriesByTypeIdStatement.readCallbackWithTransaction(callback, typeId); + + tracer.end(keyValue("item library entries", entries)); + + return entries; +} + +Storage::Info::ItemLibraryEntries ProjectStorage::itemLibraryEntries(ImportId importId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get item library entries by import id"_t, + projectStorageCategory(), + keyValue("import id", importId)}; + + using Storage::Info::ItemLibraryProperties; + Storage::Info::ItemLibraryEntries entries; + + auto callback = [&](TypeId typeId_, + Utils::SmallStringView name, + Utils::SmallStringView iconPath, + Utils::SmallStringView category, + Utils::SmallStringView import, + Utils::SmallStringView toolTip, + Utils::SmallStringView properties, + Utils::SmallStringView extraFilePaths, + Utils::SmallStringView templatePath) { + auto &last = entries.emplace_back(typeId_, name, iconPath, category, import, toolTip, templatePath); + if (properties.size()) + selectItemLibraryPropertiesStatement.readTo(last.properties, properties); + if (extraFilePaths.size()) + selectItemLibraryExtraFilePathsStatement.readTo(last.extraFilePaths, extraFilePaths); + }; + + selectItemLibraryEntriesByTypeIdStatement.readCallbackWithTransaction(callback, importId); + + tracer.end(keyValue("item library entries", entries)); + + return entries; +} + +Storage::Info::ItemLibraryEntries ProjectStorage::itemLibraryEntries(SourceId sourceId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get item library entries by source id"_t, + projectStorageCategory(), + keyValue("source id", sourceId)}; + + using Storage::Info::ItemLibraryProperties; + Storage::Info::ItemLibraryEntries entries; + + auto callback = [&](TypeId typeId, + Utils::SmallStringView name, + Utils::SmallStringView iconPath, + Utils::SmallStringView category, + Utils::SmallStringView import, + Utils::SmallStringView toolTip, + Utils::SmallStringView properties, + Utils::SmallStringView extraFilePaths, + Utils::SmallStringView templatePath) { + auto &last = entries.emplace_back(typeId, name, iconPath, category, import, toolTip, templatePath); + if (properties.size()) + selectItemLibraryPropertiesStatement.readTo(last.properties, properties); + if (extraFilePaths.size()) + selectItemLibraryExtraFilePathsStatement.readTo(last.extraFilePaths, extraFilePaths); + }; + + selectItemLibraryEntriesBySourceIdStatement.readCallbackWithTransaction(callback, sourceId); + + tracer.end(keyValue("item library entries", entries)); + + return entries; +} + +Storage::Info::ItemLibraryEntries ProjectStorage::allItemLibraryEntries() const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get all item library entries"_t, projectStorageCategory()}; + + using Storage::Info::ItemLibraryProperties; + Storage::Info::ItemLibraryEntries entries; + + auto callback = [&](TypeId typeId, + Utils::SmallStringView name, + Utils::SmallStringView iconPath, + Utils::SmallStringView category, + Utils::SmallStringView import, + Utils::SmallStringView toolTip, + Utils::SmallStringView properties, + Utils::SmallStringView extraFilePaths, + Utils::SmallStringView templatePath) { + auto &last = entries.emplace_back(typeId, name, iconPath, category, import, toolTip, templatePath); + if (properties.size()) + selectItemLibraryPropertiesStatement.readTo(last.properties, properties); + if (extraFilePaths.size()) + selectItemLibraryExtraFilePathsStatement.readTo(last.extraFilePaths, extraFilePaths); + }; + + selectItemLibraryEntriesStatement.readCallbackWithTransaction(callback); + + tracer.end(keyValue("item library entries", entries)); + + return entries; +} + +std::vector<Utils::SmallString> ProjectStorage::signalDeclarationNames(TypeId typeId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get signal names"_t, + projectStorageCategory(), + keyValue("type id", typeId)}; + + auto signalDeclarationNames = selectSignalDeclarationNamesForTypeStatement + .valuesWithTransaction<Utils::SmallString, 32>(typeId); + + tracer.end(keyValue("signal names", signalDeclarationNames)); + + return signalDeclarationNames; +} + +std::vector<Utils::SmallString> ProjectStorage::functionDeclarationNames(TypeId typeId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get function names"_t, + projectStorageCategory(), + keyValue("type id", typeId)}; + + auto functionDeclarationNames = selectFuncionDeclarationNamesForTypeStatement + .valuesWithTransaction<Utils::SmallString, 32>(typeId); + + tracer.end(keyValue("function names", functionDeclarationNames)); + + return functionDeclarationNames; +} + +std::optional<Utils::SmallString> ProjectStorage::propertyName( + PropertyDeclarationId propertyDeclarationId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get property name"_t, + projectStorageCategory(), + keyValue("property declaration id", propertyDeclarationId)}; + + auto propertyName = selectPropertyNameStatement.optionalValueWithTransaction<Utils::SmallString>( + propertyDeclarationId); + + tracer.end(keyValue("property name", propertyName)); + + return propertyName; +} + +SmallTypeIds<16> ProjectStorage::prototypeIds(TypeId type) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get prototypes"_t, projectStorageCategory(), keyValue("type id", type)}; + + auto prototypeIds = selectPrototypeAndExtensionIdsStatement.valuesWithTransaction<SmallTypeIds<16>>( + type); + + tracer.end(keyValue("type ids", prototypeIds)); + + return prototypeIds; +} + +SmallTypeIds<16> ProjectStorage::prototypeAndSelfIds(TypeId typeId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get prototypes and self"_t, projectStorageCategory()}; + + SmallTypeIds<16> prototypeAndSelfIds; + prototypeAndSelfIds.push_back(typeId); + + selectPrototypeAndExtensionIdsStatement.readToWithTransaction(prototypeAndSelfIds, typeId); + + tracer.end(keyValue("type ids", prototypeAndSelfIds)); + + return prototypeAndSelfIds; +} + +SmallTypeIds<64> ProjectStorage::heirIds(TypeId typeId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get heirs"_t, projectStorageCategory()}; + + auto heirIds = selectHeirTypeIdsStatement.valuesWithTransaction<SmallTypeIds<64>>(typeId); + + tracer.end(keyValue("type ids", heirIds)); + + return heirIds; +} + +bool ProjectStorage::isBasedOn(TypeId) const +{ + return false; +} + +bool ProjectStorage::isBasedOn(TypeId typeId, TypeId id1) const +{ + return isBasedOn_(typeId, id1); +} + +bool ProjectStorage::isBasedOn(TypeId typeId, TypeId id1, TypeId id2) const +{ + return isBasedOn_(typeId, id1, id2); +} + +bool ProjectStorage::isBasedOn(TypeId typeId, TypeId id1, TypeId id2, TypeId id3) const +{ + return isBasedOn_(typeId, id1, id2, id3); +} + +bool ProjectStorage::isBasedOn(TypeId typeId, TypeId id1, TypeId id2, TypeId id3, TypeId id4) const +{ + return isBasedOn_(typeId, id1, id2, id3, id4); +} + +bool ProjectStorage::isBasedOn(TypeId typeId, TypeId id1, TypeId id2, TypeId id3, TypeId id4, TypeId id5) const +{ + return isBasedOn_(typeId, id1, id2, id3, id4, id5); +} + +bool ProjectStorage::isBasedOn( + TypeId typeId, TypeId id1, TypeId id2, TypeId id3, TypeId id4, TypeId id5, TypeId id6) const +{ + return isBasedOn_(typeId, id1, id2, id3, id4, id5, id6); +} + +bool ProjectStorage::isBasedOn( + TypeId typeId, TypeId id1, TypeId id2, TypeId id3, TypeId id4, TypeId id5, TypeId id6, TypeId id7) const +{ + return isBasedOn_(typeId, id1, id2, id3, id4, id5, id6, id7); +} + +TypeId ProjectStorage::fetchTypeIdByExportedName(Utils::SmallStringView name) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is based on"_t, + projectStorageCategory(), + keyValue("exported type name", name)}; + + auto typeId = selectTypeIdByExportedNameStatement.valueWithTransaction<TypeId>(name); + + tracer.end(keyValue("type id", typeId)); + + return typeId; +} + +TypeId ProjectStorage::fetchTypeIdByModuleIdsAndExportedName(ModuleIds moduleIds, + Utils::SmallStringView name) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch type id by module ids and exported name"_t, + projectStorageCategory(), + keyValue("module ids", NanotraceHR::array(moduleIds)), + keyValue("exported type name", name)}; + auto typeId = selectTypeIdByModuleIdsAndExportedNameStatement.valueWithTransaction<TypeId>( + static_cast<void *>(moduleIds.data()), static_cast<long long>(moduleIds.size()), name); + + tracer.end(keyValue("type id", typeId)); + + return typeId; +} + +TypeId ProjectStorage::fetchTypeIdByName(SourceId sourceId, Utils::SmallStringView name) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch type id by name"_t, + projectStorageCategory(), + keyValue("source id", sourceId), + keyValue("internal type name", name)}; + + auto typeId = selectTypeIdBySourceIdAndNameStatement.valueWithTransaction<TypeId>(sourceId, name); + + tracer.end(keyValue("type id", typeId)); + + return typeId; +} + +Storage::Synchronization::Type ProjectStorage::fetchTypeByTypeId(TypeId typeId) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch type by type id"_t, + projectStorageCategory(), + keyValue("type id", typeId)}; + + auto type = Sqlite::withDeferredTransaction(database, [&] { + auto type = selectTypeByTypeIdStatement.value<Storage::Synchronization::Type>(typeId); + + type.exportedTypes = fetchExportedTypes(typeId); + type.propertyDeclarations = fetchPropertyDeclarations(type.typeId); + type.functionDeclarations = fetchFunctionDeclarations(type.typeId); + type.signalDeclarations = fetchSignalDeclarations(type.typeId); + type.enumerationDeclarations = fetchEnumerationDeclarations(type.typeId); + + return type; + }); + + tracer.end(keyValue("type", type)); + + return type; +} + +Storage::Synchronization::Types ProjectStorage::fetchTypes() +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch types"_t, projectStorageCategory()}; + + auto types = Sqlite::withDeferredTransaction(database, [&] { + auto types = selectTypesStatement.values<Storage::Synchronization::Type, 64>(); + + for (Storage::Synchronization::Type &type : types) { + type.exportedTypes = fetchExportedTypes(type.typeId); + type.propertyDeclarations = fetchPropertyDeclarations(type.typeId); + type.functionDeclarations = fetchFunctionDeclarations(type.typeId); + type.signalDeclarations = fetchSignalDeclarations(type.typeId); + type.enumerationDeclarations = fetchEnumerationDeclarations(type.typeId); + } + + return types; + }); + + tracer.end(keyValue("type", types)); + + return types; +} + +SourceContextId ProjectStorage::fetchSourceContextIdUnguarded(Utils::SmallStringView sourceContextPath) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch source context id unguarded"_t, projectStorageCategory()}; + + auto sourceContextId = readSourceContextId(sourceContextPath); + + return sourceContextId ? sourceContextId : writeSourceContextId(sourceContextPath); +} + +SourceContextId ProjectStorage::fetchSourceContextId(Utils::SmallStringView sourceContextPath) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch source context id"_t, + projectStorageCategory(), + keyValue("source context path", sourceContextPath)}; + + SourceContextId sourceContextId; + try { + sourceContextId = Sqlite::withDeferredTransaction(database, [&] { + return fetchSourceContextIdUnguarded(sourceContextPath); + }); + } catch (const Sqlite::ConstraintPreventsModification &) { + sourceContextId = fetchSourceContextId(sourceContextPath); + } + + tracer.end(keyValue("source context id", sourceContextId)); + + return sourceContextId; +} + +Utils::PathString ProjectStorage::fetchSourceContextPath(SourceContextId sourceContextId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch source context path"_t, + projectStorageCategory(), + keyValue("source context id", sourceContextId)}; + + auto path = Sqlite::withDeferredTransaction(database, [&] { + auto optionalSourceContextPath = selectSourceContextPathFromSourceContextsBySourceContextIdStatement + .optionalValue<Utils::PathString>(sourceContextId); + + if (!optionalSourceContextPath) + throw SourceContextIdDoesNotExists(); + + return std::move(*optionalSourceContextPath); + }); + + tracer.end(keyValue("source context path", path)); + + return path; +} + +Cache::SourceContexts ProjectStorage::fetchAllSourceContexts() const +{ + NanotraceHR::Tracer tracer{"fetch all source contexts"_t, projectStorageCategory()}; + + return selectAllSourceContextsStatement.valuesWithTransaction<Cache::SourceContext, 128>(); +} + +SourceId ProjectStorage::fetchSourceId(SourceContextId sourceContextId, + 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); + }); + + tracer.end(keyValue("source id", sourceId)); + + return sourceId; +} + +Cache::SourceNameAndSourceContextId ProjectStorage::fetchSourceNameAndSourceContextId(SourceId sourceId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch source name and source context id"_t, + projectStorageCategory(), + keyValue("source id", sourceId)}; + + auto value = selectSourceNameAndSourceContextIdFromSourcesBySourceIdStatement + .valueWithTransaction<Cache::SourceNameAndSourceContextId>(sourceId); + + if (!value.sourceContextId) + throw SourceIdDoesNotExists(); + + tracer.end(keyValue("source name", value.sourceName), + keyValue("source context id", value.sourceContextId)); + + return value; +} + +void ProjectStorage::clearSources() +{ + Sqlite::withImmediateTransaction(database, [&] { + deleteAllSourceContextsStatement.execute(); + deleteAllSourcesStatement.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 = selectSourceContextIdFromSourcesBySourceIdStatement + .valueWithTransaction<SourceContextId>(sourceId); + + if (!sourceContextId) + throw SourceIdDoesNotExists(); + + tracer.end(keyValue("source context id", sourceContextId)); + + return sourceContextId; +} + +Cache::Sources ProjectStorage::fetchAllSources() const +{ + NanotraceHR::Tracer tracer{"fetch all sources"_t, projectStorageCategory()}; + + return selectAllSourcesStatement.valuesWithTransaction<Cache::Source, 1024>(); +} + +SourceId ProjectStorage::fetchSourceIdUnguarded(SourceContextId sourceContextId, + 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); + + if (!sourceId) + sourceId = writeSourceId(sourceContextId, sourceName); + + tracer.end(keyValue("source id", sourceId)); + + return sourceId; +} + +FileStatus ProjectStorage::fetchFileStatus(SourceId sourceId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch file status"_t, + projectStorageCategory(), + keyValue("source id", sourceId)}; + + auto fileStatus = selectFileStatusesForSourceIdStatement.valueWithTransaction<FileStatus>(sourceId); + + tracer.end(keyValue("file status", fileStatus)); + + return fileStatus; +} + +std::optional<Storage::Synchronization::ProjectData> ProjectStorage::fetchProjectData(SourceId sourceId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch project data"_t, + projectStorageCategory(), + keyValue("source id", sourceId)}; + + auto projectData = selectProjectDataForSourceIdStatement + .optionalValueWithTransaction<Storage::Synchronization::ProjectData>( + sourceId); + + tracer.end(keyValue("project data", projectData)); + + return projectData; +} + +Storage::Synchronization::ProjectDatas ProjectStorage::fetchProjectDatas(SourceId projectSourceId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch project datas by source id"_t, + projectStorageCategory(), + keyValue("source id", projectSourceId)}; + + auto projectDatas = selectProjectDatasForSourceIdStatement + .valuesWithTransaction<Storage::Synchronization::ProjectData, 1024>( + projectSourceId); + + tracer.end(keyValue("project datas", projectDatas)); + + return projectDatas; +} + +Storage::Synchronization::ProjectDatas ProjectStorage::fetchProjectDatas( + const SourceIds &projectSourceIds) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch project datas by source ids"_t, + projectStorageCategory(), + keyValue("source ids", projectSourceIds)}; + + auto projectDatas = selectProjectDatasForSourceIdsStatement + .valuesWithTransaction<Storage::Synchronization::ProjectData, 64>( + toIntegers(projectSourceIds)); + + tracer.end(keyValue("project datas", projectDatas)); + + return projectDatas; +} + +void ProjectStorage::setPropertyEditorPathId(TypeId typeId, SourceId pathId) +{ + Sqlite::ImmediateSessionTransaction transaction{database}; + + upsertPropertyEditorPathIdStatement.write(typeId, pathId); + + transaction.commit(); +} + +SourceId ProjectStorage::propertyEditorPathId(TypeId typeId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"property editor path id"_t, + projectStorageCategory(), + keyValue("type id", typeId)}; + + auto sourceId = selectPropertyEditorPathIdStatement.valueWithTransaction<SourceId>(typeId); + + tracer.end(keyValue("source id", sourceId)); + + return sourceId; +} + +Storage::Imports ProjectStorage::fetchDocumentImports() const +{ + NanotraceHR::Tracer tracer{"fetch document imports"_t, projectStorageCategory()}; + + return selectAllDocumentImportForSourceIdStatement.valuesWithTransaction<Storage::Imports>(); +} + +void ProjectStorage::resetForTestsOnly() +{ + database.clearAllTablesForTestsOnly(); + commonTypeCache_.clearForTestsOnly(); + moduleCache.clearForTestOnly(); +} + +bool ProjectStorage::moduleNameLess(Utils::SmallStringView first, Utils::SmallStringView second) noexcept +{ + return first < second; +} + +ModuleId ProjectStorage::fetchModuleId(Utils::SmallStringView moduleName) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch module id"_t, + projectStorageCategory(), + keyValue("module name", moduleName)}; + + auto moduleId = Sqlite::withDeferredTransaction(database, [&] { + return fetchModuleIdUnguarded(moduleName); + }); + + tracer.end(keyValue("module id", moduleId)); + + return moduleId; +} + +Utils::PathString ProjectStorage::fetchModuleName(ModuleId id) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch module name"_t, + projectStorageCategory(), + keyValue("module id", id)}; + + auto moduleName = Sqlite::withDeferredTransaction(database, + [&] { return fetchModuleNameUnguarded(id); }); + + tracer.end(keyValue("module name", moduleName)); + + return moduleName; +} + +ProjectStorage::Modules ProjectStorage::fetchAllModules() const +{ + NanotraceHR::Tracer tracer{"fetch all modules"_t, projectStorageCategory()}; + + return selectAllModulesStatement.valuesWithTransaction<Module, 128>(); +} + +void ProjectStorage::callRefreshMetaInfoCallback(const TypeIds &deletedTypeIds) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"call refresh meta info callback"_t, + projectStorageCategory(), + keyValue("type ids", deletedTypeIds)}; + + if (deletedTypeIds.size()) { + for (ProjectStorageObserver *observer : observers) + observer->removedTypeIds(deletedTypeIds); + } +} + +SourceIds ProjectStorage::filterSourceIdsWithoutType(const SourceIds &updatedSourceIds, + SourceIds &sourceIdsOfTypes) +{ + std::sort(sourceIdsOfTypes.begin(), sourceIdsOfTypes.end()); + + SourceIds sourceIdsWithoutTypeSourceIds; + sourceIdsWithoutTypeSourceIds.reserve(updatedSourceIds.size()); + std::set_difference(updatedSourceIds.begin(), + updatedSourceIds.end(), + sourceIdsOfTypes.begin(), + sourceIdsOfTypes.end(), + std::back_inserter(sourceIdsWithoutTypeSourceIds)); + + return sourceIdsWithoutTypeSourceIds; +} + +TypeIds ProjectStorage::fetchTypeIds(const SourceIds &sourceIds) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch type ids"_t, + projectStorageCategory(), + keyValue("source ids", sourceIds)}; + + return selectTypeIdsForSourceIdsStatement.values<TypeId, 128>(toIntegers(sourceIds)); +} + +void ProjectStorage::unique(SourceIds &sourceIds) +{ + std::sort(sourceIds.begin(), sourceIds.end()); + auto newEnd = std::unique(sourceIds.begin(), sourceIds.end()); + sourceIds.erase(newEnd, sourceIds.end()); +} + +void ProjectStorage::synchronizeTypeTraits(TypeId typeId, Storage::TypeTraits traits) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"synchronize type traits"_t, + projectStorageCategory(), + keyValue("type id", typeId), + keyValue("type traits", traits)}; + + updateTypeAnnotationTraitStatement.write(typeId, traits.annotation); +} + +void ProjectStorage::updateTypeIdInTypeAnnotations(Storage::Synchronization::TypeAnnotations &typeAnnotations) +{ + NanotraceHR::Tracer tracer{"update type id in type annotations"_t, projectStorageCategory()}; + + for (auto &annotation : typeAnnotations) { + annotation.typeId = fetchTypeIdByModuleIdAndExportedName(annotation.moduleId, + annotation.typeName); + } + + for (auto &annotation : typeAnnotations) { + if (!annotation.typeId) + qWarning() << moduleName(annotation.moduleId).toQString() + << annotation.typeName.toQString(); + } + + typeAnnotations.erase(std::remove_if(typeAnnotations.begin(), + typeAnnotations.end(), + [](const auto &annotation) { return !annotation.typeId; }), + typeAnnotations.end()); +} + +void ProjectStorage::synchronizeTypeAnnotations(Storage::Synchronization::TypeAnnotations &typeAnnotations, + const SourceIds &updatedTypeAnnotationSourceIds) +{ + NanotraceHR::Tracer tracer{"synchronize type annotations"_t, projectStorageCategory()}; + + using Storage::Synchronization::TypeAnnotation; + + updateTypeIdInTypeAnnotations(typeAnnotations); + + auto compareKey = [](auto &&first, auto &&second) { return first.typeId - second.typeId; }; + + std::sort(typeAnnotations.begin(), typeAnnotations.end(), [&](auto &&first, auto &&second) { + return first.typeId < second.typeId; + }); + + auto range = selectTypeAnnotationsForSourceIdsStatement.range<TypeAnnotationView>( + toIntegers(updatedTypeAnnotationSourceIds)); + + auto insert = [&](const TypeAnnotation &annotation) { + if (!annotation.sourceId) + throw TypeAnnotationHasInvalidSourceId{}; + + synchronizeTypeTraits(annotation.typeId, annotation.traits); + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"insert type annotations"_t, + projectStorageCategory(), + keyValue("type annotation", annotation)}; + + insertTypeAnnotationStatement.write(annotation.typeId, + annotation.sourceId, + annotation.directorySourceId, + annotation.iconPath, + createEmptyAsNull(annotation.itemLibraryJson), + createEmptyAsNull(annotation.hintsJson)); + }; + + auto update = [&](const TypeAnnotationView &annotationFromDatabase, + const TypeAnnotation &annotation) { + synchronizeTypeTraits(annotation.typeId, annotation.traits); + + if (annotationFromDatabase.iconPath != annotation.iconPath + || annotationFromDatabase.itemLibraryJson != annotation.itemLibraryJson + || annotationFromDatabase.hintsJson != annotation.hintsJson) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"update type annotations"_t, + projectStorageCategory(), + keyValue("type annotation from database", + annotationFromDatabase), + keyValue("type annotation", annotation)}; + + updateTypeAnnotationStatement.write(annotation.typeId, + annotation.iconPath, + createEmptyAsNull(annotation.itemLibraryJson), + createEmptyAsNull(annotation.hintsJson)); + return Sqlite::UpdateChange::Update; + } + + return Sqlite::UpdateChange::No; + }; + + auto remove = [&](const TypeAnnotationView &annotationFromDatabase) { + synchronizeTypeTraits(annotationFromDatabase.typeId, Storage::TypeTraits{}); + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"remove type annotations"_t, + projectStorageCategory(), + keyValue("type annotation", annotationFromDatabase)}; + + deleteTypeAnnotationStatement.write(annotationFromDatabase.typeId); + }; + + Sqlite::insertUpdateDelete(range, typeAnnotations, compareKey, insert, update, remove); +} + +void ProjectStorage::synchronizeTypeTrait(const Storage::Synchronization::Type &type) +{ + updateTypeTraitStatement.write(type.typeId, type.traits.type); +} + +void ProjectStorage::synchronizeTypes(Storage::Synchronization::Types &types, + TypeIds &updatedTypeIds, + AliasPropertyDeclarations &insertedAliasPropertyDeclarations, + AliasPropertyDeclarations &updatedAliasPropertyDeclarations, + AliasPropertyDeclarations &relinkableAliasPropertyDeclarations, + PropertyDeclarations &relinkablePropertyDeclarations, + Prototypes &relinkablePrototypes, + Prototypes &relinkableExtensions, + const SourceIds &updatedSourceIds) +{ + NanotraceHR::Tracer tracer{"synchronize types"_t, projectStorageCategory()}; + + Storage::Synchronization::ExportedTypes exportedTypes; + exportedTypes.reserve(types.size() * 3); + SourceIds sourceIdsOfTypes; + sourceIdsOfTypes.reserve(updatedSourceIds.size()); + SourceIds notUpdatedExportedSourceIds; + notUpdatedExportedSourceIds.reserve(updatedSourceIds.size()); + SourceIds exportedSourceIds; + exportedSourceIds.reserve(types.size()); + + for (auto &type : types) { + if (!type.sourceId) + throw TypeHasInvalidSourceId{}; + + TypeId typeId = declareType(type); + synchronizeTypeTrait(type); + sourceIdsOfTypes.push_back(type.sourceId); + updatedTypeIds.push_back(typeId); + if (type.changeLevel != Storage::Synchronization::ChangeLevel::ExcludeExportedTypes) { + exportedSourceIds.push_back(type.sourceId); + extractExportedTypes(typeId, type, exportedTypes); + } + } + + std::sort(types.begin(), types.end(), [](const auto &first, const auto &second) { + return first.typeId < second.typeId; + }); + + unique(exportedSourceIds); + + SourceIds sourceIdsWithoutType = filterSourceIdsWithoutType(updatedSourceIds, sourceIdsOfTypes); + exportedSourceIds.insert(exportedSourceIds.end(), + sourceIdsWithoutType.begin(), + sourceIdsWithoutType.end()); + TypeIds exportedTypeIds = fetchTypeIds(exportedSourceIds); + synchronizeExportedTypes(exportedTypeIds, + exportedTypes, + relinkableAliasPropertyDeclarations, + relinkablePropertyDeclarations, + relinkablePrototypes, + relinkableExtensions); + + syncPrototypesAndExtensions(types, relinkablePrototypes, relinkableExtensions); + resetDefaultPropertiesIfChanged(types); + resetRemovedAliasPropertyDeclarationsToNull(types, relinkableAliasPropertyDeclarations); + syncDeclarations(types, + insertedAliasPropertyDeclarations, + updatedAliasPropertyDeclarations, + relinkablePropertyDeclarations); + syncDefaultProperties(types); +} + +void ProjectStorage::synchronizeProjectDatas(Storage::Synchronization::ProjectDatas &projectDatas, + const SourceIds &updatedProjectSourceIds) +{ + NanotraceHR::Tracer tracer{"synchronize project datas"_t, projectStorageCategory()}; + + auto compareKey = [](auto &&first, auto &&second) { + auto projectSourceIdDifference = first.projectSourceId - second.projectSourceId; + if (projectSourceIdDifference != 0) + return projectSourceIdDifference; + + return first.sourceId - second.sourceId; + }; + + std::sort(projectDatas.begin(), projectDatas.end(), [&](auto &&first, auto &&second) { + return std::tie(first.projectSourceId, first.sourceId) + < std::tie(second.projectSourceId, second.sourceId); + }); + + auto range = selectProjectDatasForSourceIdsStatement.range<Storage::Synchronization::ProjectData>( + toIntegers(updatedProjectSourceIds)); + + auto insert = [&](const Storage::Synchronization::ProjectData &projectData) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"insert project data"_t, + projectStorageCategory(), + keyValue("project data", projectData)}; + + if (!projectData.projectSourceId) + throw ProjectDataHasInvalidProjectSourceId{}; + if (!projectData.sourceId) + throw ProjectDataHasInvalidSourceId{}; + + insertProjectDataStatement.write(projectData.projectSourceId, + projectData.sourceId, + projectData.moduleId, + projectData.fileType); + }; + + auto update = [&](const Storage::Synchronization::ProjectData &projectDataFromDatabase, + const Storage::Synchronization::ProjectData &projectData) { + if (projectDataFromDatabase.fileType != projectData.fileType + || !compareInvalidAreTrue(projectDataFromDatabase.moduleId, projectData.moduleId)) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"update project data"_t, + projectStorageCategory(), + keyValue("project data", projectData), + keyValue("project data from database", projectDataFromDatabase)}; + + updateProjectDataStatement.write(projectData.projectSourceId, + projectData.sourceId, + projectData.moduleId, + projectData.fileType); + return Sqlite::UpdateChange::Update; + } + + return Sqlite::UpdateChange::No; + }; + + auto remove = [&](const Storage::Synchronization::ProjectData &projectData) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"remove project data"_t, + projectStorageCategory(), + keyValue("project data", projectData)}; + + deleteProjectDataStatement.write(projectData.projectSourceId, projectData.sourceId); + }; + + Sqlite::insertUpdateDelete(range, projectDatas, compareKey, insert, update, remove); +} + +void ProjectStorage::synchronizeFileStatuses(FileStatuses &fileStatuses, + const SourceIds &updatedSourceIds) +{ + NanotraceHR::Tracer tracer{"synchronize file statuses"_t, projectStorageCategory()}; + + auto compareKey = [](auto &&first, auto &&second) { return first.sourceId - second.sourceId; }; + + std::sort(fileStatuses.begin(), fileStatuses.end(), [&](auto &&first, auto &&second) { + return first.sourceId < second.sourceId; + }); + + auto range = selectFileStatusesForSourceIdsStatement.range<FileStatus>( + toIntegers(updatedSourceIds)); + + auto insert = [&](const FileStatus &fileStatus) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"insert file status"_t, + projectStorageCategory(), + keyValue("file status", fileStatus)}; + + if (!fileStatus.sourceId) + throw FileStatusHasInvalidSourceId{}; + insertFileStatusStatement.write(fileStatus.sourceId, fileStatus.size, fileStatus.lastModified); + }; + + auto update = [&](const FileStatus &fileStatusFromDatabase, const FileStatus &fileStatus) { + if (fileStatusFromDatabase.lastModified != fileStatus.lastModified + || fileStatusFromDatabase.size != fileStatus.size) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"update file status"_t, + projectStorageCategory(), + keyValue("file status", fileStatus), + keyValue("file status from database", fileStatusFromDatabase)}; + + updateFileStatusStatement.write(fileStatus.sourceId, + fileStatus.size, + fileStatus.lastModified); + return Sqlite::UpdateChange::Update; + } + + return Sqlite::UpdateChange::No; + }; + + auto remove = [&](const FileStatus &fileStatus) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"remove file status"_t, + projectStorageCategory(), + keyValue("file status", fileStatus)}; + + deleteFileStatusStatement.write(fileStatus.sourceId); + }; + + Sqlite::insertUpdateDelete(range, fileStatuses, compareKey, insert, update, remove); +} + +void ProjectStorage::synchronizeImports(Storage::Imports &imports, + const SourceIds &updatedSourceIds, + Storage::Imports &moduleDependencies, + const SourceIds &updatedModuleDependencySourceIds, + Storage::Synchronization::ModuleExportedImports &moduleExportedImports, + const ModuleIds &updatedModuleIds) +{ + NanotraceHR::Tracer tracer{"synchronize imports"_t, projectStorageCategory()}; + + synchromizeModuleExportedImports(moduleExportedImports, updatedModuleIds); + NanotraceHR::Tracer importTracer{"synchronize qml document imports"_t, projectStorageCategory()}; + synchronizeDocumentImports(imports, updatedSourceIds, Storage::Synchronization::ImportKind::Import); + importTracer.end(); + NanotraceHR::Tracer moduleDependenciesTracer{"synchronize module depdencies"_t, + projectStorageCategory()}; + synchronizeDocumentImports(moduleDependencies, + updatedModuleDependencySourceIds, + Storage::Synchronization::ImportKind::ModuleDependency); + moduleDependenciesTracer.end(); +} + +void ProjectStorage::synchromizeModuleExportedImports( + Storage::Synchronization::ModuleExportedImports &moduleExportedImports, + const ModuleIds &updatedModuleIds) +{ + NanotraceHR::Tracer tracer{"synchronize module exported imports"_t, projectStorageCategory()}; + std::sort(moduleExportedImports.begin(), + moduleExportedImports.end(), + [](auto &&first, auto &&second) { + return std::tie(first.moduleId, first.exportedModuleId) + < std::tie(second.moduleId, second.exportedModuleId); + }); + + auto range = selectModuleExportedImportsForSourceIdStatement + .range<Storage::Synchronization::ModuleExportedImportView>( + toIntegers(updatedModuleIds)); + + auto compareKey = [](const Storage::Synchronization::ModuleExportedImportView &view, + const Storage::Synchronization::ModuleExportedImport &import) -> long long { + auto moduleIdDifference = view.moduleId - import.moduleId; + if (moduleIdDifference != 0) + return moduleIdDifference; + + return view.exportedModuleId - import.exportedModuleId; + }; + + auto insert = [&](const Storage::Synchronization::ModuleExportedImport &import) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"insert module exported import"_t, + projectStorageCategory(), + keyValue("module exported import", import), + keyValue("module id", import.moduleId)}; + tracer.tick("exported module"_t, keyValue("module id", import.exportedModuleId)); + + if (import.version.minor) { + insertModuleExportedImportWithVersionStatement.write(import.moduleId, + import.exportedModuleId, + import.isAutoVersion, + import.version.major.value, + import.version.minor.value); + } else if (import.version.major) { + insertModuleExportedImportWithMajorVersionStatement.write(import.moduleId, + import.exportedModuleId, + import.isAutoVersion, + import.version.major.value); + } else { + insertModuleExportedImportWithoutVersionStatement.write(import.moduleId, + import.exportedModuleId, + import.isAutoVersion); + } + }; + + auto update = [](const Storage::Synchronization::ModuleExportedImportView &, + const Storage::Synchronization::ModuleExportedImport &) { + return Sqlite::UpdateChange::No; + }; + + auto remove = [&](const Storage::Synchronization::ModuleExportedImportView &view) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"remove module exported import"_t, + projectStorageCategory(), + keyValue("module exported import view", view), + keyValue("module id", view.moduleId)}; + tracer.tick("exported module"_t, keyValue("module id", view.exportedModuleId)); + + deleteModuleExportedImportStatement.write(view.moduleExportedImportId); + }; + + Sqlite::insertUpdateDelete(range, moduleExportedImports, compareKey, insert, update, remove); +} + +ModuleId ProjectStorage::fetchModuleIdUnguarded(Utils::SmallStringView name) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch module id ungarded"_t, + projectStorageCategory(), + keyValue("module name", name)}; + + auto moduleId = selectModuleIdByNameStatement.value<ModuleId>(name); + + if (!moduleId) + moduleId = insertModuleNameStatement.value<ModuleId>(name); + + tracer.end(keyValue("module id", moduleId)); + + return moduleId; +} + +Utils::PathString ProjectStorage::fetchModuleNameUnguarded(ModuleId id) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch module name ungarded"_t, + projectStorageCategory(), + keyValue("module id", id)}; + + auto moduleName = selectModuleNameStatement.value<Utils::PathString>(id); + + if (moduleName.empty()) + throw ModuleDoesNotExists{}; + + tracer.end(keyValue("module name", moduleName)); + + return moduleName; +} + +void ProjectStorage::handleAliasPropertyDeclarationsWithPropertyType( + TypeId typeId, AliasPropertyDeclarations &relinkableAliasPropertyDeclarations) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"handle alias property declarations with property type"_t, + projectStorageCategory(), + keyValue("type id", typeId), + keyValue("relinkable alias property declarations", + relinkableAliasPropertyDeclarations)}; + + auto callback = [&](TypeId typeId_, + PropertyDeclarationId propertyDeclarationId, + ImportedTypeNameId propertyImportedTypeNameId, + PropertyDeclarationId aliasPropertyDeclarationId, + PropertyDeclarationId aliasPropertyDeclarationTailId) { + auto aliasPropertyName = selectPropertyNameStatement.value<Utils::SmallString>( + aliasPropertyDeclarationId); + Utils::SmallString aliasPropertyNameTail; + if (aliasPropertyDeclarationTailId) + aliasPropertyNameTail = selectPropertyNameStatement.value<Utils::SmallString>( + aliasPropertyDeclarationTailId); + + relinkableAliasPropertyDeclarations.emplace_back(TypeId{typeId_}, + PropertyDeclarationId{propertyDeclarationId}, + ImportedTypeNameId{propertyImportedTypeNameId}, + std::move(aliasPropertyName), + std::move(aliasPropertyNameTail)); + + updateAliasPropertyDeclarationToNullStatement.write(propertyDeclarationId); + }; + + selectAliasPropertiesDeclarationForPropertiesWithTypeIdStatement.readCallback(callback, typeId); +} + +void ProjectStorage::handlePropertyDeclarationWithPropertyType( + TypeId typeId, PropertyDeclarations &relinkablePropertyDeclarations) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"handle property declarations with property type"_t, + projectStorageCategory(), + keyValue("type id", typeId), + keyValue("relinkable property declarations", + relinkablePropertyDeclarations)}; + + updatesPropertyDeclarationPropertyTypeToNullStatement.readTo(relinkablePropertyDeclarations, + typeId); +} + +void ProjectStorage::handlePrototypes(TypeId prototypeId, Prototypes &relinkablePrototypes) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"handle prototypes"_t, + projectStorageCategory(), + keyValue("type id", prototypeId), + keyValue("relinkable prototypes", relinkablePrototypes)}; + + auto callback = [&](TypeId typeId, ImportedTypeNameId prototypeNameId) { + relinkablePrototypes.emplace_back(typeId, prototypeNameId); + }; + + updatePrototypeIdToNullStatement.readCallback(callback, prototypeId); +} + +void ProjectStorage::handleExtensions(TypeId extensionId, Prototypes &relinkableExtensions) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"handle extension"_t, + projectStorageCategory(), + keyValue("type id", extensionId), + keyValue("relinkable extensions", relinkableExtensions)}; + + auto callback = [&](TypeId typeId, ImportedTypeNameId extensionNameId) { + relinkableExtensions.emplace_back(typeId, extensionNameId); + }; + + updateExtensionIdToNullStatement.readCallback(callback, extensionId); +} + +void ProjectStorage::deleteType(TypeId typeId, + AliasPropertyDeclarations &relinkableAliasPropertyDeclarations, + PropertyDeclarations &relinkablePropertyDeclarations, + Prototypes &relinkablePrototypes, + Prototypes &relinkableExtensions) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"delete type"_t, projectStorageCategory(), keyValue("type id", typeId)}; + + handlePropertyDeclarationWithPropertyType(typeId, relinkablePropertyDeclarations); + handleAliasPropertyDeclarationsWithPropertyType(typeId, relinkableAliasPropertyDeclarations); + handlePrototypes(typeId, relinkablePrototypes); + handleExtensions(typeId, relinkableExtensions); + deleteTypeNamesByTypeIdStatement.write(typeId); + deleteEnumerationDeclarationByTypeIdStatement.write(typeId); + deletePropertyDeclarationByTypeIdStatement.write(typeId); + deleteFunctionDeclarationByTypeIdStatement.write(typeId); + deleteSignalDeclarationByTypeIdStatement.write(typeId); + deleteTypeStatement.write(typeId); +} + +void ProjectStorage::relinkAliasPropertyDeclarations(AliasPropertyDeclarations &aliasPropertyDeclarations, + const TypeIds &deletedTypeIds) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"relink alias properties"_t, + projectStorageCategory(), + keyValue("alias property declarations", aliasPropertyDeclarations), + keyValue("deleted type ids", deletedTypeIds)}; + + std::sort(aliasPropertyDeclarations.begin(), aliasPropertyDeclarations.end()); + + Utils::set_greedy_difference( + aliasPropertyDeclarations.cbegin(), + aliasPropertyDeclarations.cend(), + deletedTypeIds.begin(), + deletedTypeIds.end(), + [&](const AliasPropertyDeclaration &alias) { + auto typeId = fetchTypeId(alias.aliasImportedTypeNameId); + + if (!typeId) + throw TypeNameDoesNotExists{fetchImportedTypeName(alias.aliasImportedTypeNameId)}; + + auto [propertyTypeId, aliasId, propertyTraits] = fetchPropertyDeclarationByTypeIdAndNameUngarded( + typeId, alias.aliasPropertyName); + + updatePropertyDeclarationWithAliasAndTypeStatement.write(alias.propertyDeclarationId, + propertyTypeId, + propertyTraits, + alias.aliasImportedTypeNameId, + aliasId); + }, + TypeCompare<AliasPropertyDeclaration>{}); +} + +void ProjectStorage::relinkPropertyDeclarations(PropertyDeclarations &relinkablePropertyDeclaration, + const TypeIds &deletedTypeIds) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"relink property declarations"_t, + projectStorageCategory(), + keyValue("relinkable property declarations", + relinkablePropertyDeclaration), + keyValue("deleted type ids", deletedTypeIds)}; + + std::sort(relinkablePropertyDeclaration.begin(), relinkablePropertyDeclaration.end()); + + Utils::set_greedy_difference( + relinkablePropertyDeclaration.cbegin(), + relinkablePropertyDeclaration.cend(), + deletedTypeIds.begin(), + deletedTypeIds.end(), + [&](const PropertyDeclaration &property) { + TypeId propertyTypeId = fetchTypeId(property.importedTypeNameId); + + if (!propertyTypeId) + throw TypeNameDoesNotExists{fetchImportedTypeName(property.importedTypeNameId)}; + + updatePropertyDeclarationTypeStatement.write(property.propertyDeclarationId, + propertyTypeId); + }, + TypeCompare<PropertyDeclaration>{}); +} + +void ProjectStorage::deleteNotUpdatedTypes(const TypeIds &updatedTypeIds, + const SourceIds &updatedSourceIds, + const TypeIds &typeIdsToBeDeleted, + AliasPropertyDeclarations &relinkableAliasPropertyDeclarations, + PropertyDeclarations &relinkablePropertyDeclarations, + Prototypes &relinkablePrototypes, + Prototypes &relinkableExtensions, + TypeIds &deletedTypeIds) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"delete not updated types"_t, + projectStorageCategory(), + keyValue("updated type ids", updatedTypeIds), + keyValue("updated source ids", updatedSourceIds), + keyValue("type ids to be deleted", typeIdsToBeDeleted)}; + + auto callback = [&](TypeId typeId) { + deletedTypeIds.push_back(typeId); + deleteType(typeId, + relinkableAliasPropertyDeclarations, + relinkablePropertyDeclarations, + relinkablePrototypes, + relinkableExtensions); + }; + + selectNotUpdatedTypesInSourcesStatement.readCallback(callback, + toIntegers(updatedSourceIds), + toIntegers(updatedTypeIds)); + for (TypeId typeIdToBeDeleted : typeIdsToBeDeleted) + callback(typeIdToBeDeleted); +} + +void ProjectStorage::relink(AliasPropertyDeclarations &relinkableAliasPropertyDeclarations, + PropertyDeclarations &relinkablePropertyDeclarations, + Prototypes &relinkablePrototypes, + Prototypes &relinkableExtensions, + TypeIds &deletedTypeIds) +{ + NanotraceHR::Tracer tracer{"relink"_t, projectStorageCategory()}; + + std::sort(deletedTypeIds.begin(), deletedTypeIds.end()); + + relinkPrototypes(relinkablePrototypes, deletedTypeIds, [&](TypeId typeId, TypeId prototypeId) { + updateTypePrototypeStatement.write(typeId, prototypeId); + }); + relinkPrototypes(relinkableExtensions, deletedTypeIds, [&](TypeId typeId, TypeId prototypeId) { + updateTypeExtensionStatement.write(typeId, prototypeId); + }); + relinkPropertyDeclarations(relinkablePropertyDeclarations, deletedTypeIds); + relinkAliasPropertyDeclarations(relinkableAliasPropertyDeclarations, deletedTypeIds); +} + +PropertyDeclarationId ProjectStorage::fetchAliasId(TypeId aliasTypeId, + Utils::SmallStringView aliasPropertyName, + Utils::SmallStringView aliasPropertyNameTail) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch alias id"_t, + projectStorageCategory(), + keyValue("alias type id", aliasTypeId), + keyValue("alias property name", aliasPropertyName), + keyValue("alias property name tail", aliasPropertyNameTail)}; + + if (aliasPropertyNameTail.empty()) + return fetchPropertyDeclarationIdByTypeIdAndNameUngarded(aliasTypeId, aliasPropertyName); + + auto stemAlias = fetchPropertyDeclarationByTypeIdAndNameUngarded(aliasTypeId, aliasPropertyName); + + return fetchPropertyDeclarationIdByTypeIdAndNameUngarded(stemAlias.propertyTypeId, + aliasPropertyNameTail); +} + +void ProjectStorage::linkAliasPropertyDeclarationAliasIds(const AliasPropertyDeclarations &aliasDeclarations) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"link alias property declarations alias ids"_t, + projectStorageCategory(), + keyValue("alias property declarations", aliasDeclarations)}; + + for (const auto &aliasDeclaration : aliasDeclarations) { + auto aliasTypeId = fetchTypeId(aliasDeclaration.aliasImportedTypeNameId); + + if (!aliasTypeId) { + throw TypeNameDoesNotExists{ + fetchImportedTypeName(aliasDeclaration.aliasImportedTypeNameId)}; + } + + auto aliasId = fetchAliasId(aliasTypeId, + aliasDeclaration.aliasPropertyName, + aliasDeclaration.aliasPropertyNameTail); + + updatePropertyDeclarationAliasIdAndTypeNameIdStatement.write( + aliasDeclaration.propertyDeclarationId, aliasId, aliasDeclaration.aliasImportedTypeNameId); + } +} + +void ProjectStorage::updateAliasPropertyDeclarationValues(const AliasPropertyDeclarations &aliasDeclarations) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"update alias property declarations"_t, + projectStorageCategory(), + keyValue("alias property declarations", aliasDeclarations)}; + + for (const auto &aliasDeclaration : aliasDeclarations) { + updatetPropertiesDeclarationValuesOfAliasStatement.write( + aliasDeclaration.propertyDeclarationId); + updatePropertyAliasDeclarationRecursivelyStatement.write( + aliasDeclaration.propertyDeclarationId); + } +} + +void ProjectStorage::checkAliasPropertyDeclarationCycles(const AliasPropertyDeclarations &aliasDeclarations) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"check alias property declarations cycles"_t, + projectStorageCategory(), + keyValue("alias property declarations", aliasDeclarations)}; + for (const auto &aliasDeclaration : aliasDeclarations) + checkForAliasChainCycle(aliasDeclaration.propertyDeclarationId); +} + +void ProjectStorage::linkAliases(const AliasPropertyDeclarations &insertedAliasPropertyDeclarations, + const AliasPropertyDeclarations &updatedAliasPropertyDeclarations) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"link aliases"_t, projectStorageCategory()}; + + linkAliasPropertyDeclarationAliasIds(insertedAliasPropertyDeclarations); + linkAliasPropertyDeclarationAliasIds(updatedAliasPropertyDeclarations); + + checkAliasPropertyDeclarationCycles(insertedAliasPropertyDeclarations); + checkAliasPropertyDeclarationCycles(updatedAliasPropertyDeclarations); + + updateAliasPropertyDeclarationValues(insertedAliasPropertyDeclarations); + updateAliasPropertyDeclarationValues(updatedAliasPropertyDeclarations); +} + +void ProjectStorage::synchronizeExportedTypes(const TypeIds &updatedTypeIds, + Storage::Synchronization::ExportedTypes &exportedTypes, + AliasPropertyDeclarations &relinkableAliasPropertyDeclarations, + PropertyDeclarations &relinkablePropertyDeclarations, + Prototypes &relinkablePrototypes, + Prototypes &relinkableExtensions) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"synchronize exported types"_t, projectStorageCategory()}; + + std::sort(exportedTypes.begin(), exportedTypes.end(), [](auto &&first, auto &&second) { + if (first.moduleId < second.moduleId) + return true; + else if (first.moduleId > second.moduleId) + return false; + + auto nameCompare = Sqlite::compare(first.name, second.name); + + if (nameCompare < 0) + return true; + else if (nameCompare > 0) + return false; + + return first.version < second.version; + }); + + auto range = selectExportedTypesForSourceIdsStatement + .range<Storage::Synchronization::ExportedTypeView>(toIntegers(updatedTypeIds)); + + auto compareKey = [](const Storage::Synchronization::ExportedTypeView &view, + const Storage::Synchronization::ExportedType &type) -> long long { + auto moduleIdDifference = view.moduleId - type.moduleId; + if (moduleIdDifference != 0) + return moduleIdDifference; + + auto nameDifference = Sqlite::compare(view.name, type.name); + if (nameDifference != 0) + return nameDifference; + + auto versionDifference = view.version.major.value - type.version.major.value; + if (versionDifference != 0) + return versionDifference; + + return view.version.minor.value - type.version.minor.value; + }; + + auto insert = [&](const Storage::Synchronization::ExportedType &type) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"insert exported type"_t, + projectStorageCategory(), + keyValue("exported type", type), + keyValue("type id", type.typeId), + keyValue("module id", type.moduleId)}; + if (!type.moduleId) + throw QmlDesigner::ModuleDoesNotExists{}; + + try { + if (type.version) { + insertExportedTypeNamesWithVersionStatement.write(type.moduleId, + type.name, + type.version.major.value, + type.version.minor.value, + type.typeId); + + } else if (type.version.major) { + insertExportedTypeNamesWithMajorVersionStatement.write(type.moduleId, + type.name, + type.version.major.value, + type.typeId); + } else { + insertExportedTypeNamesWithoutVersionStatement.write(type.moduleId, + type.name, + type.typeId); + } + } catch (const Sqlite::ConstraintPreventsModification &) { + throw QmlDesigner::ExportedTypeCannotBeInserted{type.name}; + } + }; + + auto update = [&](const Storage::Synchronization::ExportedTypeView &view, + const Storage::Synchronization::ExportedType &type) { + if (view.typeId != type.typeId) { + NanotraceHR::Tracer tracer{"update exported type"_t, + projectStorageCategory(), + keyValue("exported type", type), + keyValue("exported type view", view), + keyValue("type id", type.typeId), + keyValue("module id", type.typeId)}; + + handlePropertyDeclarationWithPropertyType(view.typeId, relinkablePropertyDeclarations); + handleAliasPropertyDeclarationsWithPropertyType(view.typeId, + relinkableAliasPropertyDeclarations); + handlePrototypes(view.typeId, relinkablePrototypes); + handleExtensions(view.typeId, relinkableExtensions); + updateExportedTypeNameTypeIdStatement.write(view.exportedTypeNameId, type.typeId); + return Sqlite::UpdateChange::Update; + } + return Sqlite::UpdateChange::No; + }; + + auto remove = [&](const Storage::Synchronization::ExportedTypeView &view) { + NanotraceHR::Tracer tracer{"remove exported type"_t, + projectStorageCategory(), + keyValue("exported type", view), + keyValue("type id", view.typeId), + keyValue("module id", view.moduleId)}; + + handlePropertyDeclarationWithPropertyType(view.typeId, relinkablePropertyDeclarations); + handleAliasPropertyDeclarationsWithPropertyType(view.typeId, + relinkableAliasPropertyDeclarations); + handlePrototypes(view.typeId, relinkablePrototypes); + handleExtensions(view.typeId, relinkableExtensions); + deleteExportedTypeNameStatement.write(view.exportedTypeNameId); + }; + + Sqlite::insertUpdateDelete(range, exportedTypes, compareKey, insert, update, remove); +} + +void ProjectStorage::synchronizePropertyDeclarationsInsertAlias( + AliasPropertyDeclarations &insertedAliasPropertyDeclarations, + const Storage::Synchronization::PropertyDeclaration &value, + SourceId sourceId, + TypeId typeId) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"insert property declaration to alias"_t, + projectStorageCategory(), + keyValue("property declaration", value)}; + + auto callback = [&](PropertyDeclarationId propertyDeclarationId) { + insertedAliasPropertyDeclarations.emplace_back(typeId, + propertyDeclarationId, + fetchImportedTypeNameId(value.typeName, + sourceId), + value.aliasPropertyName, + value.aliasPropertyNameTail); + return Sqlite::CallbackControl::Abort; + }; + + insertAliasPropertyDeclarationStatement.readCallback(callback, typeId, value.name); +} + +QVarLengthArray<PropertyDeclarationId, 128> ProjectStorage::fetchPropertyDeclarationIds( + TypeId baseTypeId) const +{ + QVarLengthArray<PropertyDeclarationId, 128> propertyDeclarationIds; + + selectLocalPropertyDeclarationIdsForTypeStatement.readTo(propertyDeclarationIds, baseTypeId); + + auto range = selectPrototypeAndExtensionIdsStatement.range<TypeId>(baseTypeId); + + for (TypeId prototype : range) { + selectLocalPropertyDeclarationIdsForTypeStatement.readTo(propertyDeclarationIds, prototype); + } + + return propertyDeclarationIds; +} + +PropertyDeclarationId ProjectStorage::fetchNextPropertyDeclarationId( + TypeId baseTypeId, Utils::SmallStringView propertyName) const +{ + auto range = selectPrototypeAndExtensionIdsStatement.range<TypeId>(baseTypeId); + + for (TypeId prototype : range) { + auto propertyDeclarationId = selectPropertyDeclarationIdByTypeIdAndNameStatement + .value<PropertyDeclarationId>(prototype, propertyName); + + if (propertyDeclarationId) + return propertyDeclarationId; + } + + return PropertyDeclarationId{}; +} + +PropertyDeclarationId ProjectStorage::fetchPropertyDeclarationId(TypeId typeId, + Utils::SmallStringView propertyName) const +{ + auto propertyDeclarationId = selectPropertyDeclarationIdByTypeIdAndNameStatement + .value<PropertyDeclarationId>(typeId, propertyName); + + if (propertyDeclarationId) + return propertyDeclarationId; + + return fetchNextPropertyDeclarationId(typeId, propertyName); +} + +PropertyDeclarationId ProjectStorage::fetchNextDefaultPropertyDeclarationId(TypeId baseTypeId) const +{ + auto range = selectPrototypeAndExtensionIdsStatement.range<TypeId>(baseTypeId); + + for (TypeId prototype : range) { + auto propertyDeclarationId = selectDefaultPropertyDeclarationIdStatement + .value<PropertyDeclarationId>(prototype); + + if (propertyDeclarationId) + return propertyDeclarationId; + } + + return PropertyDeclarationId{}; +} + +PropertyDeclarationId ProjectStorage::fetchDefaultPropertyDeclarationId(TypeId typeId) const +{ + auto propertyDeclarationId = selectDefaultPropertyDeclarationIdStatement.value<PropertyDeclarationId>( + typeId); + + if (propertyDeclarationId) + return propertyDeclarationId; + + return fetchNextDefaultPropertyDeclarationId(typeId); +} + +void ProjectStorage::synchronizePropertyDeclarationsInsertProperty( + const Storage::Synchronization::PropertyDeclaration &value, SourceId sourceId, TypeId typeId) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"insert property declaration"_t, + projectStorageCategory(), + keyValue("property declaration", value)}; + + auto propertyImportedTypeNameId = fetchImportedTypeNameId(value.typeName, sourceId); + auto propertyTypeId = fetchTypeId(propertyImportedTypeNameId); + + if (!propertyTypeId) + throw TypeNameDoesNotExists{fetchImportedTypeName(propertyImportedTypeNameId), sourceId}; + + auto propertyDeclarationId = insertPropertyDeclarationStatement.value<PropertyDeclarationId>( + typeId, value.name, propertyTypeId, value.traits, propertyImportedTypeNameId); + + auto nextPropertyDeclarationId = fetchNextPropertyDeclarationId(typeId, value.name); + if (nextPropertyDeclarationId) { + updateAliasIdPropertyDeclarationStatement.write(nextPropertyDeclarationId, + propertyDeclarationId); + updatePropertyAliasDeclarationRecursivelyWithTypeAndTraitsStatement.write(propertyDeclarationId, + propertyTypeId, + value.traits); + } +} + +void ProjectStorage::synchronizePropertyDeclarationsUpdateAlias( + AliasPropertyDeclarations &updatedAliasPropertyDeclarations, + const Storage::Synchronization::PropertyDeclarationView &view, + const Storage::Synchronization::PropertyDeclaration &value, + SourceId sourceId) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"update property declaration to alias"_t, + projectStorageCategory(), + keyValue("property declaration", value), + keyValue("property declaration view", view)}; + + updatedAliasPropertyDeclarations.emplace_back(view.typeId, + view.id, + fetchImportedTypeNameId(value.typeName, sourceId), + value.aliasPropertyName, + value.aliasPropertyNameTail, + view.aliasId); +} + +Sqlite::UpdateChange ProjectStorage::synchronizePropertyDeclarationsUpdateProperty( + const Storage::Synchronization::PropertyDeclarationView &view, + const Storage::Synchronization::PropertyDeclaration &value, + SourceId sourceId, + PropertyDeclarationIds &propertyDeclarationIds) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"update property declaration"_t, + projectStorageCategory(), + keyValue("property declaration", value), + keyValue("property declaration view", view)}; + + auto propertyImportedTypeNameId = fetchImportedTypeNameId(value.typeName, sourceId); + + auto propertyTypeId = fetchTypeId(propertyImportedTypeNameId); + + if (!propertyTypeId) + throw TypeNameDoesNotExists{fetchImportedTypeName(propertyImportedTypeNameId), sourceId}; + + if (view.traits == value.traits && propertyTypeId == view.typeId + && propertyImportedTypeNameId == view.typeNameId) + return Sqlite::UpdateChange::No; + + updatePropertyDeclarationStatement.write(view.id, + propertyTypeId, + value.traits, + propertyImportedTypeNameId); + updatePropertyAliasDeclarationRecursivelyWithTypeAndTraitsStatement.write(view.id, + propertyTypeId, + value.traits); + propertyDeclarationIds.push_back(view.id); + + tracer.end(keyValue("updated", "yes")); + + return Sqlite::UpdateChange::Update; +} + +void ProjectStorage::synchronizePropertyDeclarations( + TypeId typeId, + Storage::Synchronization::PropertyDeclarations &propertyDeclarations, + SourceId sourceId, + AliasPropertyDeclarations &insertedAliasPropertyDeclarations, + AliasPropertyDeclarations &updatedAliasPropertyDeclarations, + PropertyDeclarationIds &propertyDeclarationIds) +{ + NanotraceHR::Tracer tracer{"synchronize property declaration"_t, projectStorageCategory()}; + + std::sort(propertyDeclarations.begin(), propertyDeclarations.end(), [](auto &&first, auto &&second) { + return Sqlite::compare(first.name, second.name) < 0; + }); + + auto range = selectPropertyDeclarationsForTypeIdStatement + .range<Storage::Synchronization::PropertyDeclarationView>(typeId); + + auto compareKey = [](const Storage::Synchronization::PropertyDeclarationView &view, + const Storage::Synchronization::PropertyDeclaration &value) { + return Sqlite::compare(view.name, value.name); + }; + + auto insert = [&](const Storage::Synchronization::PropertyDeclaration &value) { + if (value.kind == Storage::Synchronization::PropertyKind::Alias) { + synchronizePropertyDeclarationsInsertAlias(insertedAliasPropertyDeclarations, + value, + sourceId, + typeId); + } else { + synchronizePropertyDeclarationsInsertProperty(value, sourceId, typeId); + } + }; + + auto update = [&](const Storage::Synchronization::PropertyDeclarationView &view, + const Storage::Synchronization::PropertyDeclaration &value) { + if (value.kind == Storage::Synchronization::PropertyKind::Alias) { + synchronizePropertyDeclarationsUpdateAlias(updatedAliasPropertyDeclarations, + view, + value, + sourceId); + propertyDeclarationIds.push_back(view.id); + } else { + return synchronizePropertyDeclarationsUpdateProperty(view, + value, + sourceId, + propertyDeclarationIds); + } + + return Sqlite::UpdateChange::No; + }; + + auto remove = [&](const Storage::Synchronization::PropertyDeclarationView &view) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"remove property declaration"_t, + projectStorageCategory(), + keyValue("property declaratio viewn", view)}; + + auto nextPropertyDeclarationId = fetchNextPropertyDeclarationId(typeId, view.name); + + if (nextPropertyDeclarationId) { + updateAliasPropertyDeclarationByAliasPropertyDeclarationIdStatement + .write(nextPropertyDeclarationId, view.id); + } + + updateDefaultPropertyIdToNullStatement.write(view.id); + deletePropertyDeclarationStatement.write(view.id); + propertyDeclarationIds.push_back(view.id); + }; + + Sqlite::insertUpdateDelete(range, propertyDeclarations, compareKey, insert, update, remove); +} + +void ProjectStorage::resetRemovedAliasPropertyDeclarationsToNull( + Storage::Synchronization::Type &type, PropertyDeclarationIds &propertyDeclarationIds) +{ + NanotraceHR::Tracer tracer{"reset removed alias property declaration to null"_t, + projectStorageCategory()}; + + if (type.changeLevel == Storage::Synchronization::ChangeLevel::Minimal) + return; + + Storage::Synchronization::PropertyDeclarations &aliasDeclarations = type.propertyDeclarations; + + std::sort(aliasDeclarations.begin(), aliasDeclarations.end(), [](auto &&first, auto &&second) { + return Sqlite::compare(first.name, second.name) < 0; + }); + + auto range = selectPropertyDeclarationsWithAliasForTypeIdStatement + .range<AliasPropertyDeclarationView>(type.typeId); + + auto compareKey = [](const AliasPropertyDeclarationView &view, + const Storage::Synchronization::PropertyDeclaration &value) { + return Sqlite::compare(view.name, value.name); + }; + + auto insert = [&](const Storage::Synchronization::PropertyDeclaration &) {}; + + auto update = [&](const AliasPropertyDeclarationView &, + const Storage::Synchronization::PropertyDeclaration &) { + return Sqlite::UpdateChange::No; + }; + + auto remove = [&](const AliasPropertyDeclarationView &view) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"reset removed alias property declaration to null"_t, + projectStorageCategory(), + keyValue("alias property declaration view", view)}; + + updatePropertyDeclarationAliasIdToNullStatement.write(view.id); + propertyDeclarationIds.push_back(view.id); + }; + + Sqlite::insertUpdateDelete(range, aliasDeclarations, compareKey, insert, update, remove); +} + +void ProjectStorage::resetRemovedAliasPropertyDeclarationsToNull( + Storage::Synchronization::Types &types, + AliasPropertyDeclarations &relinkableAliasPropertyDeclarations) +{ + NanotraceHR::Tracer tracer{"reset removed alias properties to null"_t, projectStorageCategory()}; + + PropertyDeclarationIds propertyDeclarationIds; + propertyDeclarationIds.reserve(types.size()); + + for (auto &&type : types) + resetRemovedAliasPropertyDeclarationsToNull(type, propertyDeclarationIds); + + removeRelinkableEntries(relinkableAliasPropertyDeclarations, + propertyDeclarationIds, + PropertyCompare<AliasPropertyDeclaration>{}); +} + +ImportId ProjectStorage::insertDocumentImport(const Storage::Import &import, + Storage::Synchronization::ImportKind importKind, + ModuleId sourceModuleId, + ImportId parentImportId) +{ + if (import.version.minor) { + return insertDocumentImportWithVersionStatement.value<ImportId>(import.sourceId, + import.moduleId, + sourceModuleId, + importKind, + import.version.major.value, + import.version.minor.value, + parentImportId); + } else if (import.version.major) { + return insertDocumentImportWithMajorVersionStatement.value<ImportId>(import.sourceId, + import.moduleId, + sourceModuleId, + importKind, + import.version.major.value, + parentImportId); + } else { + return insertDocumentImportWithoutVersionStatement.value<ImportId>(import.sourceId, + import.moduleId, + sourceModuleId, + importKind, + parentImportId); + } +} + +void ProjectStorage::synchronizeDocumentImports(Storage::Imports &imports, + const SourceIds &updatedSourceIds, + Storage::Synchronization::ImportKind importKind) +{ + std::sort(imports.begin(), imports.end(), [](auto &&first, auto &&second) { + return std::tie(first.sourceId, first.moduleId, first.version) + < std::tie(second.sourceId, second.moduleId, second.version); + }); + + auto range = selectDocumentImportForSourceIdStatement.range<Storage::Synchronization::ImportView>( + toIntegers(updatedSourceIds), importKind); + + auto compareKey = [](const Storage::Synchronization::ImportView &view, + const Storage::Import &import) -> long long { + auto sourceIdDifference = view.sourceId - import.sourceId; + if (sourceIdDifference != 0) + return sourceIdDifference; + + auto moduleIdDifference = view.moduleId - import.moduleId; + if (moduleIdDifference != 0) + return moduleIdDifference; + + auto versionDifference = view.version.major.value - import.version.major.value; + if (versionDifference != 0) + return versionDifference; + + return view.version.minor.value - import.version.minor.value; + }; + + auto insert = [&](const Storage::Import &import) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"insert import"_t, + projectStorageCategory(), + keyValue("import", import), + keyValue("import kind", importKind), + keyValue("source id", import.sourceId), + keyValue("module id", import.moduleId)}; + + auto importId = insertDocumentImport(import, importKind, import.moduleId, ImportId{}); + auto callback = [&](ModuleId exportedModuleId, int majorVersion, int minorVersion) { + Storage::Import additionImport{exportedModuleId, + Storage::Version{majorVersion, minorVersion}, + import.sourceId}; + + auto exportedImportKind = importKind == Storage::Synchronization::ImportKind::Import + ? Storage::Synchronization::ImportKind::ModuleExportedImport + : Storage::Synchronization::ImportKind::ModuleExportedModuleDependency; + + NanotraceHR::Tracer tracer{"insert indirect import"_t, + projectStorageCategory(), + keyValue("import", import), + keyValue("import kind", exportedImportKind), + keyValue("source id", import.sourceId), + keyValue("module id", import.moduleId)}; + + auto indirectImportId = insertDocumentImport(additionImport, + exportedImportKind, + import.moduleId, + importId); + + tracer.end(keyValue("import id", indirectImportId)); + }; + + selectModuleExportedImportsForModuleIdStatement.readCallback(callback, + import.moduleId, + import.version.major.value, + import.version.minor.value); + tracer.end(keyValue("import id", importId)); + }; + + auto update = [](const Storage::Synchronization::ImportView &, const Storage::Import &) { + return Sqlite::UpdateChange::No; + }; + + auto remove = [&](const Storage::Synchronization::ImportView &view) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"remove import"_t, + projectStorageCategory(), + keyValue("import", view), + keyValue("import id", view.importId), + keyValue("source id", view.sourceId), + keyValue("module id", view.moduleId)}; + + deleteDocumentImportStatement.write(view.importId); + deleteDocumentImportsWithParentImportIdStatement.write(view.sourceId, view.importId); + }; + + Sqlite::insertUpdateDelete(range, imports, compareKey, insert, update, remove); +} + +Utils::PathString ProjectStorage::createJson(const Storage::Synchronization::ParameterDeclarations ¶meters) +{ + NanotraceHR::Tracer tracer{"create json from parameter declarations"_t, projectStorageCategory()}; + + Utils::PathString json; + json.append("["); + + Utils::SmallStringView comma{""}; + + for (const auto ¶meter : parameters) { + json.append(comma); + comma = ","; + json.append(R"({"n":")"); + json.append(parameter.name); + json.append(R"(","tn":")"); + json.append(parameter.typeName); + if (parameter.traits == Storage::PropertyDeclarationTraits::None) { + json.append("\"}"); + } else { + json.append(R"(","tr":)"); + json.append(Utils::SmallString::number(to_underlying(parameter.traits))); + json.append("}"); + } + } + + json.append("]"); + + return json; +} + +TypeId ProjectStorage::fetchTypeIdByModuleIdAndExportedName(ModuleId moduleId, + Utils::SmallStringView name) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch type id by module id and exported name"_t, + projectStorageCategory(), + keyValue("module id", moduleId), + keyValue("exported name", name)}; + + return selectTypeIdByModuleIdAndExportedNameStatement.value<TypeId>(moduleId, name); +} + +void ProjectStorage::addTypeIdToPropertyEditorQmlPaths( + Storage::Synchronization::PropertyEditorQmlPaths &paths) +{ + NanotraceHR::Tracer tracer{"add type id to property editor qml paths"_t, projectStorageCategory()}; + + for (auto &path : paths) + path.typeId = fetchTypeIdByModuleIdAndExportedName(path.moduleId, path.typeName); +} + +void ProjectStorage::synchronizePropertyEditorPaths(Storage::Synchronization::PropertyEditorQmlPaths &paths, + SourceIds updatedPropertyEditorQmlPathsSourceIds) +{ + using Storage::Synchronization::PropertyEditorQmlPath; + std::sort(paths.begin(), paths.end(), [](auto &&first, auto &&second) { + return first.typeId < second.typeId; + }); + + auto range = selectPropertyEditorPathsForForSourceIdsStatement.range<PropertyEditorQmlPathView>( + toIntegers(updatedPropertyEditorQmlPathsSourceIds)); + + auto compareKey = [](const PropertyEditorQmlPathView &view, + const PropertyEditorQmlPath &value) -> long long { + return view.typeId - value.typeId; + }; + + auto insert = [&](const PropertyEditorQmlPath &path) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"insert property editor paths"_t, + projectStorageCategory(), + keyValue("property editor qml path", path)}; + + if (path.typeId) + insertPropertyEditorPathStatement.write(path.typeId, path.pathId, path.directoryId); + }; + + auto update = [&](const PropertyEditorQmlPathView &view, const PropertyEditorQmlPath &value) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"update property editor paths"_t, + projectStorageCategory(), + keyValue("property editor qml path", value), + keyValue("property editor qml path view", view)}; + + if (value.pathId != view.pathId || value.directoryId != view.directoryId) { + updatePropertyEditorPathsStatement.write(value.typeId, value.pathId, value.directoryId); + + tracer.end(keyValue("updated", "yes")); + + return Sqlite::UpdateChange::Update; + } + return Sqlite::UpdateChange::No; + }; + + auto remove = [&](const PropertyEditorQmlPathView &view) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"remove property editor paths"_t, + projectStorageCategory(), + keyValue("property editor qml path view", view)}; + + deletePropertyEditorPathStatement.write(view.typeId); + }; + + Sqlite::insertUpdateDelete(range, paths, compareKey, insert, update, remove); +} + +void ProjectStorage::synchronizePropertyEditorQmlPaths( + Storage::Synchronization::PropertyEditorQmlPaths &paths, + SourceIds updatedPropertyEditorQmlPathsSourceIds) +{ + NanotraceHR::Tracer tracer{"synchronize property editor qml paths"_t, projectStorageCategory()}; + + addTypeIdToPropertyEditorQmlPaths(paths); + synchronizePropertyEditorPaths(paths, updatedPropertyEditorQmlPathsSourceIds); +} + +void ProjectStorage::synchronizeFunctionDeclarations( + TypeId typeId, Storage::Synchronization::FunctionDeclarations &functionsDeclarations) +{ + NanotraceHR::Tracer tracer{"synchronize function declaration"_t, projectStorageCategory()}; + + std::sort(functionsDeclarations.begin(), + functionsDeclarations.end(), + [](auto &&first, auto &&second) { + auto compare = Sqlite::compare(first.name, second.name); + + if (compare == 0) { + Utils::PathString firstSignature{createJson(first.parameters)}; + Utils::PathString secondSignature{createJson(second.parameters)}; + + return Sqlite::compare(firstSignature, secondSignature) < 0; + } + + return compare < 0; + }); + + auto range = selectFunctionDeclarationsForTypeIdStatement + .range<Storage::Synchronization::FunctionDeclarationView>(typeId); + + auto compareKey = [](const Storage::Synchronization::FunctionDeclarationView &view, + const Storage::Synchronization::FunctionDeclaration &value) { + auto nameKey = Sqlite::compare(view.name, value.name); + if (nameKey != 0) + return nameKey; + + Utils::PathString valueSignature{createJson(value.parameters)}; + + return Sqlite::compare(view.signature, valueSignature); + }; + + auto insert = [&](const Storage::Synchronization::FunctionDeclaration &value) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"insert function declaration"_t, + projectStorageCategory(), + keyValue("function declaration", value)}; + + Utils::PathString signature{createJson(value.parameters)}; + + insertFunctionDeclarationStatement.write(typeId, value.name, value.returnTypeName, signature); + }; + + auto update = [&](const Storage::Synchronization::FunctionDeclarationView &view, + const Storage::Synchronization::FunctionDeclaration &value) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"update function declaration"_t, + projectStorageCategory(), + keyValue("function declaration", value), + keyValue("function declaration view", view)}; + + Utils::PathString signature{createJson(value.parameters)}; + + if (value.returnTypeName == view.returnTypeName && signature == view.signature) + return Sqlite::UpdateChange::No; + + updateFunctionDeclarationStatement.write(view.id, value.returnTypeName, signature); + + tracer.end(keyValue("updated", "yes")); + + return Sqlite::UpdateChange::Update; + }; + + auto remove = [&](const Storage::Synchronization::FunctionDeclarationView &view) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"remove function declaration"_t, + projectStorageCategory(), + keyValue("function declaration view", view)}; + + deleteFunctionDeclarationStatement.write(view.id); + }; + + Sqlite::insertUpdateDelete(range, functionsDeclarations, compareKey, insert, update, remove); +} + +void ProjectStorage::synchronizeSignalDeclarations( + TypeId typeId, Storage::Synchronization::SignalDeclarations &signalDeclarations) +{ + NanotraceHR::Tracer tracer{"synchronize signal declaration"_t, projectStorageCategory()}; + + std::sort(signalDeclarations.begin(), signalDeclarations.end(), [](auto &&first, auto &&second) { + auto compare = Sqlite::compare(first.name, second.name); + + if (compare == 0) { + Utils::PathString firstSignature{createJson(first.parameters)}; + Utils::PathString secondSignature{createJson(second.parameters)}; + + return Sqlite::compare(firstSignature, secondSignature) < 0; + } + + return compare < 0; + }); + + auto range = selectSignalDeclarationsForTypeIdStatement + .range<Storage::Synchronization::SignalDeclarationView>(typeId); + + auto compareKey = [](const Storage::Synchronization::SignalDeclarationView &view, + const Storage::Synchronization::SignalDeclaration &value) { + auto nameKey = Sqlite::compare(view.name, value.name); + if (nameKey != 0) + return nameKey; + + Utils::PathString valueSignature{createJson(value.parameters)}; + + return Sqlite::compare(view.signature, valueSignature); + }; + + auto insert = [&](const Storage::Synchronization::SignalDeclaration &value) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"insert signal declaration"_t, + projectStorageCategory(), + keyValue("signal declaration", value)}; + + Utils::PathString signature{createJson(value.parameters)}; + + insertSignalDeclarationStatement.write(typeId, value.name, signature); + }; + + auto update = [&]([[maybe_unused]] const Storage::Synchronization::SignalDeclarationView &view, + [[maybe_unused]] const Storage::Synchronization::SignalDeclaration &value) { + return Sqlite::UpdateChange::No; + }; + + auto remove = [&](const Storage::Synchronization::SignalDeclarationView &view) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"remove signal declaration"_t, + projectStorageCategory(), + keyValue("signal declaration view", view)}; + + deleteSignalDeclarationStatement.write(view.id); + }; + + Sqlite::insertUpdateDelete(range, signalDeclarations, compareKey, insert, update, remove); +} + +Utils::PathString ProjectStorage::createJson( + const Storage::Synchronization::EnumeratorDeclarations &enumeratorDeclarations) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"create json from enumerator declarations"_t, projectStorageCategory()}; + + Utils::PathString json; + json.append("{"); + + Utils::SmallStringView comma{"\""}; + + for (const auto &enumerator : enumeratorDeclarations) { + json.append(comma); + comma = ",\""; + json.append(enumerator.name); + if (enumerator.hasValue) { + json.append("\":\""); + json.append(Utils::SmallString::number(enumerator.value)); + json.append("\""); + } else { + json.append("\":null"); + } + } + + json.append("}"); + + return json; +} + +void ProjectStorage::synchronizeEnumerationDeclarations( + TypeId typeId, Storage::Synchronization::EnumerationDeclarations &enumerationDeclarations) +{ + NanotraceHR::Tracer tracer{"synchronize enumeration declaration"_t, projectStorageCategory()}; + + std::sort(enumerationDeclarations.begin(), + enumerationDeclarations.end(), + [](auto &&first, auto &&second) { + return Sqlite::compare(first.name, second.name) < 0; + }); + + auto range = selectEnumerationDeclarationsForTypeIdStatement + .range<Storage::Synchronization::EnumerationDeclarationView>(typeId); + + auto compareKey = [](const Storage::Synchronization::EnumerationDeclarationView &view, + const Storage::Synchronization::EnumerationDeclaration &value) { + return Sqlite::compare(view.name, value.name); + }; + + auto insert = [&](const Storage::Synchronization::EnumerationDeclaration &value) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"insert enumeration declaration"_t, + projectStorageCategory(), + keyValue("enumeration declaration", value)}; + + Utils::PathString signature{createJson(value.enumeratorDeclarations)}; + + insertEnumerationDeclarationStatement.write(typeId, value.name, signature); + }; + + auto update = [&](const Storage::Synchronization::EnumerationDeclarationView &view, + const Storage::Synchronization::EnumerationDeclaration &value) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"update enumeration declaration"_t, + projectStorageCategory(), + keyValue("enumeration declaration", value), + keyValue("enumeration declaration view", view)}; + + Utils::PathString enumeratorDeclarations{createJson(value.enumeratorDeclarations)}; + + if (enumeratorDeclarations == view.enumeratorDeclarations) + return Sqlite::UpdateChange::No; + + updateEnumerationDeclarationStatement.write(view.id, enumeratorDeclarations); + + tracer.end(keyValue("updated", "yes")); + + return Sqlite::UpdateChange::Update; + }; + + auto remove = [&](const Storage::Synchronization::EnumerationDeclarationView &view) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"remove enumeration declaration"_t, + projectStorageCategory(), + keyValue("enumeration declaration view", view)}; + + deleteEnumerationDeclarationStatement.write(view.id); + }; + + Sqlite::insertUpdateDelete(range, enumerationDeclarations, compareKey, insert, update, remove); +} + +void ProjectStorage::extractExportedTypes(TypeId typeId, + const Storage::Synchronization::Type &type, + Storage::Synchronization::ExportedTypes &exportedTypes) +{ + for (const auto &exportedType : type.exportedTypes) + exportedTypes.emplace_back(exportedType.name, exportedType.version, typeId, exportedType.moduleId); +} + +TypeId ProjectStorage::declareType(Storage::Synchronization::Type &type) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"declare type"_t, + projectStorageCategory(), + keyValue("source id", type.sourceId), + keyValue("type name", type.typeName)}; + + if (type.typeName.isEmpty()) { + type.typeId = selectTypeIdBySourceIdStatement.value<TypeId>(type.sourceId); + + tracer.end(keyValue("type id", type.typeId)); + + return type.typeId; + } + + type.typeId = insertTypeStatement.value<TypeId>(type.sourceId, type.typeName); + + if (!type.typeId) + type.typeId = selectTypeIdBySourceIdAndNameStatement.value<TypeId>(type.sourceId, + type.typeName); + + tracer.end(keyValue("type id", type.typeId)); + + return type.typeId; +} + +void ProjectStorage::syncDeclarations(Storage::Synchronization::Type &type, + AliasPropertyDeclarations &insertedAliasPropertyDeclarations, + AliasPropertyDeclarations &updatedAliasPropertyDeclarations, + PropertyDeclarationIds &propertyDeclarationIds) +{ + NanotraceHR::Tracer tracer{"synchronize declaration per type"_t, projectStorageCategory()}; + + if (type.changeLevel == Storage::Synchronization::ChangeLevel::Minimal) + return; + + synchronizePropertyDeclarations(type.typeId, + type.propertyDeclarations, + type.sourceId, + insertedAliasPropertyDeclarations, + updatedAliasPropertyDeclarations, + propertyDeclarationIds); + synchronizeFunctionDeclarations(type.typeId, type.functionDeclarations); + synchronizeSignalDeclarations(type.typeId, type.signalDeclarations); + synchronizeEnumerationDeclarations(type.typeId, type.enumerationDeclarations); +} + +void ProjectStorage::syncDeclarations(Storage::Synchronization::Types &types, + AliasPropertyDeclarations &insertedAliasPropertyDeclarations, + AliasPropertyDeclarations &updatedAliasPropertyDeclarations, + PropertyDeclarations &relinkablePropertyDeclarations) +{ + NanotraceHR::Tracer tracer{"synchronize declaration"_t, projectStorageCategory()}; + + PropertyDeclarationIds propertyDeclarationIds; + propertyDeclarationIds.reserve(types.size() * 10); + + for (auto &&type : types) + syncDeclarations(type, + insertedAliasPropertyDeclarations, + updatedAliasPropertyDeclarations, + propertyDeclarationIds); + + removeRelinkableEntries(relinkablePropertyDeclarations, + propertyDeclarationIds, + PropertyCompare<PropertyDeclaration>{}); +} + +void ProjectStorage::syncDefaultProperties(Storage::Synchronization::Types &types) +{ + NanotraceHR::Tracer tracer{"synchronize default properties"_t, projectStorageCategory()}; + + auto range = selectTypesWithDefaultPropertyStatement.range<TypeWithDefaultPropertyView>(); + + auto compareKey = [](const TypeWithDefaultPropertyView &view, + const Storage::Synchronization::Type &value) { + return view.typeId - value.typeId; + }; + + auto insert = [&](const Storage::Synchronization::Type &) { + + }; + + auto update = [&](const TypeWithDefaultPropertyView &view, + const Storage::Synchronization::Type &value) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"synchronize default properties by update"_t, + projectStorageCategory(), + keyValue("type id", value.typeId), + keyValue("value", value), + keyValue("view", view)}; + + PropertyDeclarationId valueDefaultPropertyId; + if (value.defaultPropertyName.size()) + valueDefaultPropertyId = fetchPropertyDeclarationByTypeIdAndNameUngarded(value.typeId, + value.defaultPropertyName) + .propertyDeclarationId; + + if (compareInvalidAreTrue(valueDefaultPropertyId, view.defaultPropertyId)) + return Sqlite::UpdateChange::No; + + updateDefaultPropertyIdStatement.write(value.typeId, valueDefaultPropertyId); + + tracer.end(keyValue("updated", "yes"), + keyValue("default property id", valueDefaultPropertyId)); + + return Sqlite::UpdateChange::Update; + }; + + auto remove = [&](const TypeWithDefaultPropertyView &) {}; + + Sqlite::insertUpdateDelete(range, types, compareKey, insert, update, remove); +} + +void ProjectStorage::resetDefaultPropertiesIfChanged(Storage::Synchronization::Types &types) +{ + NanotraceHR::Tracer tracer{"reset changed default properties"_t, projectStorageCategory()}; + + auto range = selectTypesWithDefaultPropertyStatement.range<TypeWithDefaultPropertyView>(); + + auto compareKey = [](const TypeWithDefaultPropertyView &view, + const Storage::Synchronization::Type &value) { + return view.typeId - value.typeId; + }; + + auto insert = [&](const Storage::Synchronization::Type &) { + + }; + + auto update = [&](const TypeWithDefaultPropertyView &view, + const Storage::Synchronization::Type &value) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"reset changed default properties by update"_t, + projectStorageCategory(), + keyValue("type id", value.typeId), + keyValue("value", value), + keyValue("view", view)}; + + PropertyDeclarationId valueDefaultPropertyId; + if (value.defaultPropertyName.size()) { + auto optionalValueDefaultPropertyId = fetchOptionalPropertyDeclarationByTypeIdAndNameUngarded( + value.typeId, value.defaultPropertyName); + if (optionalValueDefaultPropertyId) + valueDefaultPropertyId = optionalValueDefaultPropertyId->propertyDeclarationId; + } + + if (compareInvalidAreTrue(valueDefaultPropertyId, view.defaultPropertyId)) + return Sqlite::UpdateChange::No; + + updateDefaultPropertyIdStatement.write(value.typeId, Sqlite::NullValue{}); + + tracer.end(keyValue("updated", "yes")); + + return Sqlite::UpdateChange::Update; + }; + + auto remove = [&](const TypeWithDefaultPropertyView &) {}; + + Sqlite::insertUpdateDelete(range, types, compareKey, insert, update, remove); +} + +void ProjectStorage::checkForPrototypeChainCycle(TypeId typeId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"check for prototype chain cycle"_t, + projectStorageCategory(), + keyValue("type id", typeId)}; + + auto callback = [=](TypeId currentTypeId) { + if (typeId == currentTypeId) + throw PrototypeChainCycle{}; + }; + + selectPrototypeAndExtensionIdsStatement.readCallback(callback, typeId); +} + +void ProjectStorage::checkForAliasChainCycle(PropertyDeclarationId propertyDeclarationId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"check for alias chain cycle"_t, + projectStorageCategory(), + keyValue("property declaration id", propertyDeclarationId)}; + auto callback = [=](PropertyDeclarationId currentPropertyDeclarationId) { + if (propertyDeclarationId == currentPropertyDeclarationId) + throw AliasChainCycle{}; + }; + + selectPropertyDeclarationIdsForAliasChainStatement.readCallback(callback, propertyDeclarationId); +} + +std::pair<TypeId, ImportedTypeNameId> ProjectStorage::fetchImportedTypeNameIdAndTypeId( + const Storage::Synchronization::ImportedTypeName &typeName, SourceId sourceId) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch imported type name id and type id"_t, + projectStorageCategory(), + keyValue("imported type name", typeName), + keyValue("source id", sourceId)}; + + TypeId typeId; + ImportedTypeNameId typeNameId; + if (!std::visit([](auto &&typeName_) -> bool { return typeName_.name.isEmpty(); }, typeName)) { + typeNameId = fetchImportedTypeNameId(typeName, sourceId); + + typeId = fetchTypeId(typeNameId); + + tracer.end(keyValue("type id", typeId), keyValue("type name id", typeNameId)); + + if (!typeId) + throw TypeNameDoesNotExists{fetchImportedTypeName(typeNameId), sourceId}; + } + + return {typeId, typeNameId}; +} + +void ProjectStorage::syncPrototypeAndExtension(Storage::Synchronization::Type &type, TypeIds &typeIds) +{ + if (type.changeLevel == Storage::Synchronization::ChangeLevel::Minimal) + return; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"synchronize prototype and extension"_t, + projectStorageCategory(), + keyValue("prototype", type.prototype), + keyValue("extension", type.extension), + keyValue("type id", type.typeId), + keyValue("source id", type.sourceId)}; + + auto [prototypeId, prototypeTypeNameId] = fetchImportedTypeNameIdAndTypeId(type.prototype, + type.sourceId); + auto [extensionId, extensionTypeNameId] = fetchImportedTypeNameIdAndTypeId(type.extension, + type.sourceId); + + updatePrototypeAndExtensionStatement.write(type.typeId, + prototypeId, + prototypeTypeNameId, + extensionId, + extensionTypeNameId); + + if (prototypeId || extensionId) + checkForPrototypeChainCycle(type.typeId); + + typeIds.push_back(type.typeId); + + tracer.end(keyValue("prototype id", prototypeId), + keyValue("prototype type name id", prototypeTypeNameId), + keyValue("extension id", extensionId), + keyValue("extension type name id", extensionTypeNameId)); +} + +void ProjectStorage::syncPrototypesAndExtensions(Storage::Synchronization::Types &types, + Prototypes &relinkablePrototypes, + Prototypes &relinkableExtensions) +{ + NanotraceHR::Tracer tracer{"synchronize prototypes and extensions"_t, projectStorageCategory()}; + + TypeIds typeIds; + typeIds.reserve(types.size()); + + for (auto &type : types) + syncPrototypeAndExtension(type, typeIds); + + removeRelinkableEntries(relinkablePrototypes, typeIds, TypeCompare<Prototype>{}); + removeRelinkableEntries(relinkableExtensions, typeIds, TypeCompare<Prototype>{}); +} + +ImportId ProjectStorage::fetchImportId(SourceId sourceId, const Storage::Import &import) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch imported type name id"_t, + projectStorageCategory(), + keyValue("import", import), + keyValue("source id", sourceId)}; + + ImportId importId; + if (import.version) { + importId = selectImportIdBySourceIdAndModuleIdAndVersionStatement.value<ImportId>( + sourceId, import.moduleId, import.version.major.value, import.version.minor.value); + } else if (import.version.major) { + importId = selectImportIdBySourceIdAndModuleIdAndMajorVersionStatement + .value<ImportId>(sourceId, import.moduleId, import.version.major.value); + } else { + importId = selectImportIdBySourceIdAndModuleIdStatement.value<ImportId>(sourceId, + import.moduleId); + } + + tracer.end(keyValue("import id", importId)); + + return importId; +} + +ImportedTypeNameId ProjectStorage::fetchImportedTypeNameId( + const Storage::Synchronization::ImportedTypeName &name, SourceId sourceId) +{ + struct Inspect + { + auto operator()(const Storage::Synchronization::ImportedType &importedType) + { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch imported type name id"_t, + projectStorageCategory(), + keyValue("imported type name", importedType.name), + keyValue("source id", sourceId), + keyValue("type name kind", "exported"sv)}; + + return storage.fetchImportedTypeNameId(Storage::Synchronization::TypeNameKind::Exported, + sourceId, + importedType.name); + } + + auto operator()(const Storage::Synchronization::QualifiedImportedType &importedType) + { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch imported type name id"_t, + projectStorageCategory(), + keyValue("imported type name", importedType.name), + keyValue("import", importedType.import), + keyValue("type name kind", "qualified exported"sv)}; + + ImportId importId = storage.fetchImportId(sourceId, importedType.import); + + auto importedTypeNameId = storage.fetchImportedTypeNameId( + Storage::Synchronization::TypeNameKind::QualifiedExported, importId, importedType.name); + + tracer.end(keyValue("import id", importId), keyValue("source id", sourceId)); + + return importedTypeNameId; + } + + ProjectStorage &storage; + SourceId sourceId; + }; + + return std::visit(Inspect{*this, sourceId}, name); +} + +TypeId ProjectStorage::fetchTypeId(ImportedTypeNameId typeNameId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch type id with type name kind"_t, + projectStorageCategory(), + keyValue("type name id", typeNameId)}; + + auto kind = selectKindFromImportedTypeNamesStatement.value<Storage::Synchronization::TypeNameKind>( + typeNameId); + + auto typeId = fetchTypeId(typeNameId, kind); + + tracer.end(keyValue("type id", typeId), keyValue("type name kind", kind)); + + return typeId; +} + +Utils::SmallString ProjectStorage::fetchImportedTypeName(ImportedTypeNameId typeNameId) const +{ + return selectNameFromImportedTypeNamesStatement.value<Utils::SmallString>(typeNameId); +} + +TypeId ProjectStorage::fetchTypeId(ImportedTypeNameId typeNameId, + Storage::Synchronization::TypeNameKind kind) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch type id"_t, + projectStorageCategory(), + keyValue("type name id", typeNameId), + keyValue("type name kind", kind)}; + + TypeId typeId; + if (kind == Storage::Synchronization::TypeNameKind::Exported) { + typeId = selectTypeIdForImportedTypeNameNamesStatement.value<TypeId>(typeNameId); + } else { + typeId = selectTypeIdForQualifiedImportedTypeNameNamesStatement.value<TypeId>(typeNameId); + } + + tracer.end(keyValue("type id", typeId)); + + return typeId; +} + +std::optional<ProjectStorage::FetchPropertyDeclarationResult> +ProjectStorage::fetchOptionalPropertyDeclarationByTypeIdAndNameUngarded(TypeId typeId, + Utils::SmallStringView name) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch optional property declaration by type id and name ungarded"_t, + projectStorageCategory(), + keyValue("type id", typeId), + keyValue("property name", name)}; + + auto propertyDeclarationId = fetchPropertyDeclarationId(typeId, name); + auto propertyDeclaration = selectPropertyDeclarationResultByPropertyDeclarationIdStatement + .optionalValue<FetchPropertyDeclarationResult>( + propertyDeclarationId); + + tracer.end(keyValue("property declaration", propertyDeclaration)); + + return propertyDeclaration; +} + +ProjectStorage::FetchPropertyDeclarationResult ProjectStorage::fetchPropertyDeclarationByTypeIdAndNameUngarded( + TypeId typeId, Utils::SmallStringView name) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch property declaration by type id and name ungarded"_t, + projectStorageCategory(), + keyValue("type id", typeId), + keyValue("property name", name)}; + + auto propertyDeclaration = fetchOptionalPropertyDeclarationByTypeIdAndNameUngarded(typeId, name); + tracer.end(keyValue("property declaration", propertyDeclaration)); + + if (propertyDeclaration) + return *propertyDeclaration; + + throw PropertyNameDoesNotExists{}; +} + +PropertyDeclarationId ProjectStorage::fetchPropertyDeclarationIdByTypeIdAndNameUngarded( + TypeId typeId, Utils::SmallStringView name) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch property declaration id by type id and name ungarded"_t, + projectStorageCategory(), + keyValue("type id", typeId), + keyValue("property name", name)}; + + auto propertyDeclarationId = fetchPropertyDeclarationId(typeId, name); + + tracer.end(keyValue("property declaration id", propertyDeclarationId)); + + if (propertyDeclarationId) + return propertyDeclarationId; + + throw PropertyNameDoesNotExists{}; +} + +SourceContextId ProjectStorage::readSourceContextId(Utils::SmallStringView sourceContextPath) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"read source context id"_t, + projectStorageCategory(), + keyValue("source context path", sourceContextPath)}; + + auto sourceContextId = selectSourceContextIdFromSourceContextsBySourceContextPathStatement + .value<SourceContextId>(sourceContextPath); + + tracer.end(keyValue("source context id", sourceContextId)); + + return sourceContextId; +} + +SourceContextId ProjectStorage::writeSourceContextId(Utils::SmallStringView sourceContextPath) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"write source context id"_t, + projectStorageCategory(), + keyValue("source context path", sourceContextPath)}; + + insertIntoSourceContextsStatement.write(sourceContextPath); + + auto sourceContextId = SourceContextId::create(static_cast<int>(database.lastInsertedRowId())); + + tracer.end(keyValue("source context id", sourceContextId)); + + return sourceContextId; +} + +SourceId ProjectStorage::writeSourceId(SourceContextId sourceContextId, + Utils::SmallStringView sourceName) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"write source id"_t, + projectStorageCategory(), + keyValue("source context id", sourceContextId), + keyValue("source name", sourceName)}; + + insertIntoSourcesStatement.write(sourceContextId, sourceName); + + auto sourceId = SourceId::create(static_cast<int>(database.lastInsertedRowId())); + + tracer.end(keyValue("source id", sourceId)); + + return sourceId; +} + +SourceId ProjectStorage::readSourceId(SourceContextId sourceContextId, + 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 = selectSourceIdFromSourcesBySourceContextIdAndSourceNameStatement + .value<SourceId>(sourceContextId, sourceName); + + tracer.end(keyValue("source id", sourceId)); + + return sourceId; +} + +Storage::Synchronization::ExportedTypes ProjectStorage::fetchExportedTypes(TypeId typeId) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch exported type"_t, + projectStorageCategory(), + keyValue("type id", typeId)}; + + auto exportedTypes = selectExportedTypesByTypeIdStatement + .values<Storage::Synchronization::ExportedType, 12>(typeId); + + tracer.end(keyValue("exported types", exportedTypes)); + + return exportedTypes; +} + +Storage::Synchronization::PropertyDeclarations ProjectStorage::fetchPropertyDeclarations(TypeId typeId) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch property declarations"_t, + projectStorageCategory(), + keyValue("type id", typeId)}; + + auto propertyDeclarations = selectPropertyDeclarationsByTypeIdStatement + .values<Storage::Synchronization::PropertyDeclaration, 24>(typeId); + + tracer.end(keyValue("property declarations", propertyDeclarations)); + + return propertyDeclarations; +} + +Storage::Synchronization::FunctionDeclarations ProjectStorage::fetchFunctionDeclarations(TypeId typeId) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch signal declarations"_t, + projectStorageCategory(), + keyValue("type id", typeId)}; + + Storage::Synchronization::FunctionDeclarations functionDeclarations; + + auto callback = [&](Utils::SmallStringView name, + Utils::SmallStringView returnType, + FunctionDeclarationId functionDeclarationId) { + auto &functionDeclaration = functionDeclarations.emplace_back(name, returnType); + functionDeclaration.parameters = selectFunctionParameterDeclarationsStatement + .values<Storage::Synchronization::ParameterDeclaration, 8>( + functionDeclarationId); + }; + + selectFunctionDeclarationsForTypeIdWithoutSignatureStatement.readCallback(callback, typeId); + + tracer.end(keyValue("function declarations", functionDeclarations)); + + return functionDeclarations; +} + +Storage::Synchronization::SignalDeclarations ProjectStorage::fetchSignalDeclarations(TypeId typeId) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch signal declarations"_t, + projectStorageCategory(), + keyValue("type id", typeId)}; + + Storage::Synchronization::SignalDeclarations signalDeclarations; + + auto callback = [&](Utils::SmallStringView name, SignalDeclarationId signalDeclarationId) { + auto &signalDeclaration = signalDeclarations.emplace_back(name); + signalDeclaration.parameters = selectSignalParameterDeclarationsStatement + .values<Storage::Synchronization::ParameterDeclaration, 8>( + signalDeclarationId); + }; + + selectSignalDeclarationsForTypeIdWithoutSignatureStatement.readCallback(callback, typeId); + + tracer.end(keyValue("signal declarations", signalDeclarations)); + + return signalDeclarations; +} + +Storage::Synchronization::EnumerationDeclarations ProjectStorage::fetchEnumerationDeclarations(TypeId typeId) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch enumeration declarations"_t, + projectStorageCategory(), + keyValue("type id", typeId)}; + + Storage::Synchronization::EnumerationDeclarations enumerationDeclarations; + + auto callback = [&](Utils::SmallStringView name, + EnumerationDeclarationId enumerationDeclarationId) { + enumerationDeclarations.emplace_back( + name, + selectEnumeratorDeclarationStatement + .values<Storage::Synchronization::EnumeratorDeclaration, 8>(enumerationDeclarationId)); + }; + + selectEnumerationDeclarationsForTypeIdWithoutEnumeratorDeclarationsStatement.readCallback(callback, + typeId); + + tracer.end(keyValue("enumeration declarations", enumerationDeclarations)); + + return enumerationDeclarations; +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h index 70d5e92b25..d7687a8c6f 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h @@ -33,10 +33,10 @@ using namespace NanotraceHR::Literals; using ProjectStorageTracing::projectStorageCategory; -template<typename Database> class ProjectStorage final : public ProjectStorageInterface { - friend Storage::Info::CommonTypeCache<Database>; + using Database = Sqlite::Database; + friend Storage::Info::CommonTypeCache<ProjectStorageType>; public: template<int ResultCount, int BindParameterCount = 0> @@ -46,655 +46,79 @@ public: template<int BindParameterCount> using WriteStatement = typename Database::template WriteStatement<BindParameterCount>; - ProjectStorage(Database &database, bool isInitialized) - : database{database} - , exclusiveTransaction{database} - , initializer{database, isInitialized} - { - NanotraceHR::Tracer tracer{"initialize"_t, projectStorageCategory()}; - - exclusiveTransaction.commit(); + ProjectStorage(Database &database, bool isInitialized); + ~ProjectStorage(); - database.walCheckpointFull(); + void synchronize(Storage::Synchronization::SynchronizationPackage package) override; - moduleCache.populate(); - } + void synchronizeDocumentImports(Storage::Imports imports, SourceId sourceId) override; - void synchronize(Storage::Synchronization::SynchronizationPackage package) override - { - NanotraceHR::Tracer tracer{"synchronize"_t, projectStorageCategory()}; - - TypeIds deletedTypeIds; - Sqlite::withImmediateTransaction(database, [&] { - AliasPropertyDeclarations insertedAliasPropertyDeclarations; - AliasPropertyDeclarations updatedAliasPropertyDeclarations; - - AliasPropertyDeclarations relinkableAliasPropertyDeclarations; - PropertyDeclarations relinkablePropertyDeclarations; - Prototypes relinkablePrototypes; - Prototypes relinkableExtensions; - - TypeIds updatedTypeIds; - updatedTypeIds.reserve(package.types.size()); - - TypeIds typeIdsToBeDeleted; - - std::sort(package.updatedSourceIds.begin(), package.updatedSourceIds.end()); - - synchronizeFileStatuses(package.fileStatuses, package.updatedFileStatusSourceIds); - synchronizeImports(package.imports, - package.updatedSourceIds, - package.moduleDependencies, - package.updatedModuleDependencySourceIds, - package.moduleExportedImports, - package.updatedModuleIds); - synchronizeTypes(package.types, - updatedTypeIds, - insertedAliasPropertyDeclarations, - updatedAliasPropertyDeclarations, - relinkableAliasPropertyDeclarations, - relinkablePropertyDeclarations, - relinkablePrototypes, - relinkableExtensions, - package.updatedSourceIds); - synchronizeTypeAnnotations(package.typeAnnotations, - package.updatedTypeAnnotationSourceIds); - synchronizePropertyEditorQmlPaths(package.propertyEditorQmlPaths, - package.updatedPropertyEditorQmlPathSourceIds); - - deleteNotUpdatedTypes(updatedTypeIds, - package.updatedSourceIds, - typeIdsToBeDeleted, - relinkableAliasPropertyDeclarations, - relinkablePropertyDeclarations, - relinkablePrototypes, - relinkableExtensions, - deletedTypeIds); - - relink(relinkableAliasPropertyDeclarations, - relinkablePropertyDeclarations, - relinkablePrototypes, - relinkableExtensions, - deletedTypeIds); - - linkAliases(insertedAliasPropertyDeclarations, updatedAliasPropertyDeclarations); - - synchronizeProjectDatas(package.projectDatas, package.updatedProjectSourceIds); - - commonTypeCache_.resetTypeIds(); - }); - - callRefreshMetaInfoCallback(deletedTypeIds); - } - - void synchronizeDocumentImports(Storage::Imports imports, SourceId sourceId) override - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"synchronize document imports"_t, - projectStorageCategory(), - keyValue("imports", imports), - keyValue("source id", sourceId)}; + void addObserver(ProjectStorageObserver *observer) override; - Sqlite::withImmediateTransaction(database, [&] { - synchronizeDocumentImports(imports, - {sourceId}, - Storage::Synchronization::ImportKind::Import); - }); - } + void removeObserver(ProjectStorageObserver *observer) override; - void addObserver(ProjectStorageObserver *observer) override - { - NanotraceHR::Tracer tracer{"add observer"_t, projectStorageCategory()}; - observers.push_back(observer); - } + ModuleId moduleId(Utils::SmallStringView moduleName) const override; - void removeObserver(ProjectStorageObserver *observer) override - { - NanotraceHR::Tracer tracer{"remove observer"_t, projectStorageCategory()}; - observers.removeOne(observer); - } - - ModuleId moduleId(Utils::SmallStringView moduleName) const override - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get module id"_t, - projectStorageCategory(), - keyValue("module name", moduleName)}; - - auto moduleId = moduleCache.id(moduleName); - - tracer.end(keyValue("module id", moduleId)); - - return moduleId; - } - - Utils::SmallString moduleName(ModuleId moduleId) const override - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get module name"_t, - projectStorageCategory(), - keyValue("module id", moduleId)}; - - if (!moduleId) - throw ModuleDoesNotExists{}; - - auto moduleName = moduleCache.value(moduleId); - - tracer.end(keyValue("module name", moduleName)); - - return moduleName; - } + Utils::SmallString moduleName(ModuleId moduleId) const override; TypeId typeId(ModuleId moduleId, Utils::SmallStringView exportedTypeName, - Storage::Version version) const override - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get type id by exported name"_t, - projectStorageCategory(), - keyValue("module id", moduleId), - keyValue("exported type name", exportedTypeName), - keyValue("version", version)}; - - TypeId typeId; - - if (version.minor) { - typeId = selectTypeIdByModuleIdAndExportedNameAndVersionStatement - .template valueWithTransaction<TypeId>(moduleId, - exportedTypeName, - version.major.value, - version.minor.value); - - } else if (version.major) { - typeId = selectTypeIdByModuleIdAndExportedNameAndMajorVersionStatement - .template valueWithTransaction<TypeId>(moduleId, - exportedTypeName, - version.major.value); - - } else { - typeId = selectTypeIdByModuleIdAndExportedNameStatement - .template valueWithTransaction<TypeId>(moduleId, exportedTypeName); - } - - tracer.end(keyValue("type id", typeId)); - - return typeId; - } - - TypeId typeId(ImportedTypeNameId typeNameId) const override - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get type id by imported type name"_t, - projectStorageCategory(), - keyValue("imported type name id", typeNameId)}; - - auto typeId = Sqlite::withDeferredTransaction(database, - [&] { return fetchTypeId(typeNameId); }); - - tracer.end(keyValue("type id", typeId)); - - return typeId; - } - - QVarLengthArray<TypeId, 256> typeIds(ModuleId moduleId) const override - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get type ids by module id"_t, - projectStorageCategory(), - keyValue("module id", moduleId)}; - - auto typeIds = selectTypeIdsByModuleIdStatement - .template valuesWithTransaction<QVarLengthArray<TypeId, 256>>(moduleId); - - tracer.end(keyValue("type ids", typeIds)); - - return typeIds; - } - - Storage::Info::ExportedTypeNames exportedTypeNames(TypeId typeId) const override - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get exported type names by type id"_t, - projectStorageCategory(), - keyValue("type id", typeId)}; - - auto exportedTypenames = selectExportedTypesByTypeIdStatement - .template valuesWithTransaction<Storage::Info::ExportedTypeName, 4>( - typeId); - - tracer.end(keyValue("exported type names", exportedTypenames)); + Storage::Version version) const override; - return exportedTypenames; - } - - Storage::Info::ExportedTypeNames exportedTypeNames(TypeId typeId, SourceId sourceId) const override - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get exported type names by source id"_t, - projectStorageCategory(), - keyValue("type id", typeId), - keyValue("source id", sourceId)}; - - auto exportedTypenames = selectExportedTypesByTypeIdAndSourceIdStatement - .template valuesWithTransaction<Storage::Info::ExportedTypeName, - 4>(typeId, sourceId); - - tracer.end(keyValue("exported type names", exportedTypenames)); - - return exportedTypenames; - } - - ImportId importId(const Storage::Import &import) const override - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get import id by import"_t, - projectStorageCategory(), - keyValue("import", import)}; - - auto importId = Sqlite::withDeferredTransaction(database, [&] { - return fetchImportId(import.sourceId, import); - }); - - tracer.end(keyValue("import id", importId)); - - return importId; - } - - ImportedTypeNameId importedTypeNameId(ImportId importId, Utils::SmallStringView typeName) override - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get imported type name id by import id"_t, - projectStorageCategory(), - keyValue("import id", importId), - keyValue("imported type name", typeName)}; - - auto importedTypeNameId = Sqlite::withDeferredTransaction(database, [&] { - return fetchImportedTypeNameId(Storage::Synchronization::TypeNameKind::QualifiedExported, - importId, - typeName); - }); - - tracer.end(keyValue("imported type name id", importedTypeNameId)); - - return importedTypeNameId; - } - - ImportedTypeNameId importedTypeNameId(SourceId sourceId, Utils::SmallStringView typeName) override - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get imported type name id by source id"_t, - projectStorageCategory(), - keyValue("source id", sourceId), - keyValue("imported type name", typeName)}; - - auto importedTypeNameId = Sqlite::withDeferredTransaction(database, [&] { - return fetchImportedTypeNameId(Storage::Synchronization::TypeNameKind::Exported, - sourceId, - typeName); - }); - - tracer.end(keyValue("imported type name id", importedTypeNameId)); - - return importedTypeNameId; - } - - QVarLengthArray<PropertyDeclarationId, 128> propertyDeclarationIds(TypeId typeId) const override - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get property declaration ids"_t, - projectStorageCategory(), - keyValue("type id", typeId)}; + TypeId typeId(ImportedTypeNameId typeNameId) const override; - auto propertyDeclarationIds = Sqlite::withDeferredTransaction(database, [&] { - return fetchPropertyDeclarationIds(typeId); - }); + QVarLengthArray<TypeId, 256> typeIds(ModuleId moduleId) const override; - std::sort(propertyDeclarationIds.begin(), propertyDeclarationIds.end()); + Storage::Info::ExportedTypeNames exportedTypeNames(TypeId typeId) const override; - tracer.end(keyValue("property declaration ids", propertyDeclarationIds)); + Storage::Info::ExportedTypeNames exportedTypeNames(TypeId typeId, SourceId sourceId) const override; - return propertyDeclarationIds; - } + ImportId importId(const Storage::Import &import) const override; - QVarLengthArray<PropertyDeclarationId, 128> localPropertyDeclarationIds(TypeId typeId) const override - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get local property declaration ids"_t, - projectStorageCategory(), - keyValue("type id", typeId)}; + ImportedTypeNameId importedTypeNameId(ImportId importId, Utils::SmallStringView typeName) override; - auto propertyDeclarationIds = selectLocalPropertyDeclarationIdsForTypeStatement - .template valuesWithTransaction< - QVarLengthArray<PropertyDeclarationId, 128>>(typeId); + ImportedTypeNameId importedTypeNameId(SourceId sourceId, Utils::SmallStringView typeName) override; - tracer.end(keyValue("property declaration ids", propertyDeclarationIds)); + QVarLengthArray<PropertyDeclarationId, 128> propertyDeclarationIds(TypeId typeId) const override; - return propertyDeclarationIds; - } + QVarLengthArray<PropertyDeclarationId, 128> localPropertyDeclarationIds(TypeId typeId) const override; PropertyDeclarationId propertyDeclarationId(TypeId typeId, - Utils::SmallStringView propertyName) const override - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get property declaration id"_t, - projectStorageCategory(), - keyValue("type id", typeId), - keyValue("property name", propertyName)}; - - auto propertyDeclarationId = Sqlite::withDeferredTransaction(database, [&] { - return fetchPropertyDeclarationId(typeId, propertyName); - }); - - tracer.end(keyValue("property declaration id", propertyDeclarationId)); - - return propertyDeclarationId; - } + Utils::SmallStringView propertyName) const override; PropertyDeclarationId localPropertyDeclarationId(TypeId typeId, - Utils::SmallStringView propertyName) const - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get local property declaration id"_t, - projectStorageCategory(), - keyValue("type id", typeId), - keyValue("property name", propertyName)}; - - auto propertyDeclarationId = selectLocalPropertyDeclarationIdForTypeAndPropertyNameStatement - .template valueWithTransaction<PropertyDeclarationId>( - typeId, propertyName); - - tracer.end(keyValue("property declaration id", propertyDeclarationId)); - - return propertyDeclarationId; - } - - PropertyDeclarationId defaultPropertyDeclarationId(TypeId typeId) const override - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get default property declaration id"_t, - projectStorageCategory(), - keyValue("type id", typeId)}; + Utils::SmallStringView propertyName) const; - auto propertyDeclarationId = Sqlite::withDeferredTransaction(database, [&] { - return fetchDefaultPropertyDeclarationId(typeId); - }); - - tracer.end(keyValue("property declaration id", propertyDeclarationId)); - - return propertyDeclarationId; - } + PropertyDeclarationId defaultPropertyDeclarationId(TypeId typeId) const override; std::optional<Storage::Info::PropertyDeclaration> propertyDeclaration( - PropertyDeclarationId propertyDeclarationId) const override - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get property declaration"_t, - projectStorageCategory(), - keyValue("property declaration id", propertyDeclarationId)}; - - auto propertyDeclaration = selectPropertyDeclarationForPropertyDeclarationIdStatement - .template optionalValueWithTransaction<Storage::Info::PropertyDeclaration>( - propertyDeclarationId); - - tracer.end(keyValue("property declaration", propertyDeclaration)); - - return propertyDeclaration; - } - - std::optional<Storage::Info::Type> type(TypeId typeId) const override - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get type"_t, projectStorageCategory(), keyValue("type id", typeId)}; - - auto type = selectInfoTypeByTypeIdStatement - .template optionalValueWithTransaction<Storage::Info::Type>(typeId); - - tracer.end(keyValue("type", type)); - - return type; - } - - Utils::PathString typeIconPath(TypeId typeId) const override - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get type icon path"_t, - projectStorageCategory(), - keyValue("type id", typeId)}; - - auto typeIconPath = selectTypeIconPathStatement.template valueWithTransaction<Utils::PathString>( - typeId); - - tracer.end(keyValue("type icon path", typeIconPath)); - - return typeIconPath; - } - - Storage::Info::TypeHints typeHints(TypeId typeId) const override - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get type hints"_t, - projectStorageCategory(), - keyValue("type id", typeId)}; - - auto typeHints = selectTypeHintsStatement - .template valuesWithTransaction<Storage::Info::TypeHints, 4>(typeId); - - tracer.end(keyValue("type hints", typeHints)); - - return typeHints; - } - - SmallSourceIds<4> typeAnnotationSourceIds(SourceId directoryId) const override - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get type annotaion source ids"_t, - projectStorageCategory(), - keyValue("source id", directoryId)}; - - auto sourceIds = selectTypeAnnotationSourceIdsStatement - .template valuesWithTransaction<SmallSourceIds<4>>(directoryId); - - tracer.end(keyValue("source ids", sourceIds)); - - return sourceIds; - } - - SmallSourceIds<64> typeAnnotationDirectorySourceIds() const override - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get type annotaion source ids"_t, projectStorageCategory()}; - - auto sourceIds = selectTypeAnnotationDirectorySourceIdsStatement - .template valuesWithTransaction<SmallSourceIds<64>>(); - - tracer.end(keyValue("source ids", sourceIds)); - - return sourceIds; - } - - Storage::Info::ItemLibraryEntries itemLibraryEntries(TypeId typeId) const override - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get item library entries by type id"_t, - projectStorageCategory(), - keyValue("type id", typeId)}; - - using Storage::Info::ItemLibraryProperties; - Storage::Info::ItemLibraryEntries entries; - - auto callback = [&](TypeId typeId_, - Utils::SmallStringView name, - Utils::SmallStringView iconPath, - Utils::SmallStringView category, - Utils::SmallStringView import, - Utils::SmallStringView toolTip, - Utils::SmallStringView properties, - Utils::SmallStringView extraFilePaths, - Utils::SmallStringView templatePath) { - auto &last = entries.emplace_back( - typeId_, name, iconPath, category, import, toolTip, templatePath); - if (properties.size()) - selectItemLibraryPropertiesStatement.readTo(last.properties, properties); - if (extraFilePaths.size()) - selectItemLibraryExtraFilePathsStatement.readTo(last.extraFilePaths, extraFilePaths); - }; - - selectItemLibraryEntriesByTypeIdStatement.readCallbackWithTransaction(callback, typeId); - - tracer.end(keyValue("item library entries", entries)); - - return entries; - } - - Storage::Info::ItemLibraryEntries itemLibraryEntries(ImportId importId) const - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get item library entries by import id"_t, - projectStorageCategory(), - keyValue("import id", importId)}; - - using Storage::Info::ItemLibraryProperties; - Storage::Info::ItemLibraryEntries entries; - - auto callback = [&](TypeId typeId_, - Utils::SmallStringView name, - Utils::SmallStringView iconPath, - Utils::SmallStringView category, - Utils::SmallStringView import, - Utils::SmallStringView toolTip, - Utils::SmallStringView properties, - Utils::SmallStringView extraFilePaths, - Utils::SmallStringView templatePath) { - auto &last = entries.emplace_back( - typeId_, name, iconPath, category, import, toolTip, templatePath); - if (properties.size()) - selectItemLibraryPropertiesStatement.readTo(last.properties, properties); - if (extraFilePaths.size()) - selectItemLibraryExtraFilePathsStatement.readTo(last.extraFilePaths, extraFilePaths); - }; - - selectItemLibraryEntriesByTypeIdStatement.readCallbackWithTransaction(callback, importId); - - tracer.end(keyValue("item library entries", entries)); - - return entries; - } - - Storage::Info::ItemLibraryEntries itemLibraryEntries(SourceId sourceId) const override - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get item library entries by source id"_t, - projectStorageCategory(), - keyValue("source id", sourceId)}; - - using Storage::Info::ItemLibraryProperties; - Storage::Info::ItemLibraryEntries entries; - - auto callback = [&](TypeId typeId, - Utils::SmallStringView name, - Utils::SmallStringView iconPath, - Utils::SmallStringView category, - Utils::SmallStringView import, - Utils::SmallStringView toolTip, - Utils::SmallStringView properties, - Utils::SmallStringView extraFilePaths, - Utils::SmallStringView templatePath) { - auto &last = entries.emplace_back( - typeId, name, iconPath, category, import, toolTip, templatePath); - if (properties.size()) - selectItemLibraryPropertiesStatement.readTo(last.properties, properties); - if (extraFilePaths.size()) - selectItemLibraryExtraFilePathsStatement.readTo(last.extraFilePaths, extraFilePaths); - }; - - selectItemLibraryEntriesBySourceIdStatement.readCallbackWithTransaction(callback, sourceId); - - tracer.end(keyValue("item library entries", entries)); - - return entries; - } - - Storage::Info::ItemLibraryEntries allItemLibraryEntries() const override - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get all item library entries"_t, projectStorageCategory()}; - - using Storage::Info::ItemLibraryProperties; - Storage::Info::ItemLibraryEntries entries; - - auto callback = [&](TypeId typeId, - Utils::SmallStringView name, - Utils::SmallStringView iconPath, - Utils::SmallStringView category, - Utils::SmallStringView import, - Utils::SmallStringView toolTip, - Utils::SmallStringView properties, - Utils::SmallStringView extraFilePaths, - Utils::SmallStringView templatePath) { - auto &last = entries.emplace_back( - typeId, name, iconPath, category, import, toolTip, templatePath); - if (properties.size()) - selectItemLibraryPropertiesStatement.readTo(last.properties, properties); - if (extraFilePaths.size()) - selectItemLibraryExtraFilePathsStatement.readTo(last.extraFilePaths, extraFilePaths); - }; - - selectItemLibraryEntriesStatement.readCallbackWithTransaction(callback); - - tracer.end(keyValue("item library entries", entries)); - - return entries; - } + PropertyDeclarationId propertyDeclarationId) const override; - std::vector<Utils::SmallString> signalDeclarationNames(TypeId typeId) const override - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get signal names"_t, - projectStorageCategory(), - keyValue("type id", typeId)}; + std::optional<Storage::Info::Type> type(TypeId typeId) const override; - auto signalDeclarationNames = selectSignalDeclarationNamesForTypeStatement - .template valuesWithTransaction<Utils::SmallString, 32>( - typeId); + Utils::PathString typeIconPath(TypeId typeId) const override; - tracer.end(keyValue("signal names", signalDeclarationNames)); + Storage::Info::TypeHints typeHints(TypeId typeId) const override; - return signalDeclarationNames; - } + SmallSourceIds<4> typeAnnotationSourceIds(SourceId directoryId) const override; - std::vector<Utils::SmallString> functionDeclarationNames(TypeId typeId) const override - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get function names"_t, - projectStorageCategory(), - keyValue("type id", typeId)}; + SmallSourceIds<64> typeAnnotationDirectorySourceIds() const override; - auto functionDeclarationNames = selectFuncionDeclarationNamesForTypeStatement - .template valuesWithTransaction<Utils::SmallString, 32>( - typeId); + Storage::Info::ItemLibraryEntries itemLibraryEntries(TypeId typeId) const override; - tracer.end(keyValue("function names", functionDeclarationNames)); + Storage::Info::ItemLibraryEntries itemLibraryEntries(ImportId importId) const; - return functionDeclarationNames; - } + Storage::Info::ItemLibraryEntries itemLibraryEntries(SourceId sourceId) const override; - std::optional<Utils::SmallString> propertyName(PropertyDeclarationId propertyDeclarationId) const override - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get property name"_t, - projectStorageCategory(), - keyValue("property declaration id", propertyDeclarationId)}; + Storage::Info::ItemLibraryEntries allItemLibraryEntries() const override; - auto propertyName = selectPropertyNameStatement - .template optionalValueWithTransaction<Utils::SmallString>( - propertyDeclarationId); + std::vector<Utils::SmallString> signalDeclarationNames(TypeId typeId) const override; - tracer.end(keyValue("property name", propertyName)); + std::vector<Utils::SmallString> functionDeclarationNames(TypeId typeId) const override; - return propertyName; - } + std::optional<Utils::SmallString> propertyName(PropertyDeclarationId propertyDeclarationId) const override; - const Storage::Info::CommonTypeCache<ProjectStorageInterface> &commonTypeCache() const override + const Storage::Info::CommonTypeCache<ProjectStorageType> &commonTypeCache() const override { return commonTypeCache_; } @@ -708,7 +132,7 @@ public: keyValue("module name", std::string_view{moduleName}), keyValue("type name", std::string_view{typeName})}; - auto typeId = commonTypeCache_.template typeId<moduleName, typeName>(); + auto typeId = commonTypeCache_.typeId<moduleName, typeName>(); tracer.end(keyValue("type id", typeId)); @@ -722,7 +146,7 @@ public: NanotraceHR::Tracer tracer{"get builtin type id from common type cache"_t, projectStorageCategory()}; - auto typeId = commonTypeCache_.template builtinTypeId<BuiltinType>(); + auto typeId = commonTypeCache_.builtinTypeId<BuiltinType>(); tracer.end(keyValue("type id", typeId)); @@ -736,55 +160,18 @@ public: NanotraceHR::Tracer tracer{"get builtin type id from common type cache"_t, projectStorageCategory()}; - auto typeId = commonTypeCache_.template builtinTypeId<builtinType>(); + auto typeId = commonTypeCache_.builtinTypeId<builtinType>(); tracer.end(keyValue("type id", typeId)); return typeId; } - SmallTypeIds<16> prototypeIds(TypeId type) const override - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get prototypes"_t, - projectStorageCategory(), - keyValue("type id", type)}; - - auto prototypeIds = selectPrototypeAndExtensionIdsStatement - .template valuesWithTransaction<SmallTypeIds<16>>(type); + SmallTypeIds<16> prototypeIds(TypeId type) const override; - tracer.end(keyValue("type ids", prototypeIds)); + SmallTypeIds<16> prototypeAndSelfIds(TypeId typeId) const override; - return prototypeIds; - } - - SmallTypeIds<16> prototypeAndSelfIds(TypeId typeId) const override - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get prototypes and self"_t, projectStorageCategory()}; - - SmallTypeIds<16> prototypeAndSelfIds; - prototypeAndSelfIds.push_back(typeId); - - selectPrototypeAndExtensionIdsStatement.readToWithTransaction(prototypeAndSelfIds, typeId); - - tracer.end(keyValue("type ids", prototypeAndSelfIds)); - - return prototypeAndSelfIds; - } - - SmallTypeIds<64> heirIds(TypeId typeId) const override - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get heirs"_t, projectStorageCategory()}; - - auto heirIds = selectHeirTypeIdsStatement.template valuesWithTransaction<SmallTypeIds<64>>( - typeId); - - tracer.end(keyValue("type ids", heirIds)); - - return heirIds; - } + SmallTypeIds<64> heirIds(TypeId typeId) const override; template<typename... TypeIds> bool isBasedOn_(TypeId typeId, TypeIds... baseTypeIds) const @@ -802,8 +189,7 @@ public: return true; } - auto range = selectPrototypeAndExtensionIdsStatement.template rangeWithTransaction<TypeId>( - typeId); + auto range = selectPrototypeAndExtensionIdsStatement.rangeWithTransaction<TypeId>(typeId); auto isBasedOn = std::any_of(range.begin(), range.end(), [&](TypeId currentTypeId) { return ((currentTypeId == baseTypeIds) || ...); @@ -814,35 +200,20 @@ public: return isBasedOn; } - bool isBasedOn(TypeId) const { return false; } + bool isBasedOn(TypeId) const; - bool isBasedOn(TypeId typeId, TypeId id1) const override { return isBasedOn_(typeId, id1); } + bool isBasedOn(TypeId typeId, TypeId id1) const override; - bool isBasedOn(TypeId typeId, TypeId id1, TypeId id2) const override - { - return isBasedOn_(typeId, id1, id2); - } + bool isBasedOn(TypeId typeId, TypeId id1, TypeId id2) const override; - bool isBasedOn(TypeId typeId, TypeId id1, TypeId id2, TypeId id3) const override - { - return isBasedOn_(typeId, id1, id2, id3); - } + bool isBasedOn(TypeId typeId, TypeId id1, TypeId id2, TypeId id3) const override; - bool isBasedOn(TypeId typeId, TypeId id1, TypeId id2, TypeId id3, TypeId id4) const override - { - return isBasedOn_(typeId, id1, id2, id3, id4); - } + bool isBasedOn(TypeId typeId, TypeId id1, TypeId id2, TypeId id3, TypeId id4) const override; - bool isBasedOn(TypeId typeId, TypeId id1, TypeId id2, TypeId id3, TypeId id4, TypeId id5) const override - { - return isBasedOn_(typeId, id1, id2, id3, id4, id5); - } + bool isBasedOn(TypeId typeId, TypeId id1, TypeId id2, TypeId id3, TypeId id4, TypeId id5) const override; - bool isBasedOn( - TypeId typeId, TypeId id1, TypeId id2, TypeId id3, TypeId id4, TypeId id5, TypeId id6) const override - { - return isBasedOn_(typeId, id1, id2, id3, id4, id5, id6); - } + bool isBasedOn(TypeId typeId, TypeId id1, TypeId id2, TypeId id3, TypeId id4, TypeId id5, TypeId id6) + const override; bool isBasedOn(TypeId typeId, TypeId id1, @@ -851,361 +222,62 @@ public: TypeId id4, TypeId id5, TypeId id6, - TypeId id7) const override - { - return isBasedOn_(typeId, id1, id2, id3, id4, id5, id6, id7); - } - - TypeId fetchTypeIdByExportedName(Utils::SmallStringView name) const - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"is based on"_t, - projectStorageCategory(), - keyValue("exported type name", name)}; - - auto typeId = selectTypeIdByExportedNameStatement.template valueWithTransaction<TypeId>(name); - - tracer.end(keyValue("type id", typeId)); - - return typeId; - } - - TypeId fetchTypeIdByModuleIdsAndExportedName(ModuleIds moduleIds, Utils::SmallStringView name) const - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"fetch type id by module ids and exported name"_t, - projectStorageCategory(), - keyValue("module ids", NanotraceHR::array(moduleIds)), - keyValue("exported type name", name)}; - auto typeId = selectTypeIdByModuleIdsAndExportedNameStatement.template valueWithTransaction<TypeId>( - static_cast<void *>(moduleIds.data()), static_cast<long long>(moduleIds.size()), name); - - tracer.end(keyValue("type id", typeId)); - - return typeId; - } - - TypeId fetchTypeIdByName(SourceId sourceId, Utils::SmallStringView name) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"fetch type id by name"_t, - projectStorageCategory(), - keyValue("source id", sourceId), - keyValue("internal type name", name)}; - - auto typeId = selectTypeIdBySourceIdAndNameStatement - .template valueWithTransaction<TypeId>(sourceId, name); - - tracer.end(keyValue("type id", typeId)); - - return typeId; - } - - Storage::Synchronization::Type fetchTypeByTypeId(TypeId typeId) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"fetch type by type id"_t, - projectStorageCategory(), - keyValue("type id", typeId)}; - - auto type = Sqlite::withDeferredTransaction(database, [&] { - auto type = selectTypeByTypeIdStatement.template value<Storage::Synchronization::Type>( - typeId); - - type.exportedTypes = fetchExportedTypes(typeId); - type.propertyDeclarations = fetchPropertyDeclarations(type.typeId); - type.functionDeclarations = fetchFunctionDeclarations(type.typeId); - type.signalDeclarations = fetchSignalDeclarations(type.typeId); - type.enumerationDeclarations = fetchEnumerationDeclarations(type.typeId); - - return type; - }); - - tracer.end(keyValue("type", type)); - - return type; - } - - Storage::Synchronization::Types fetchTypes() - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"fetch types"_t, projectStorageCategory()}; - - auto types = Sqlite::withDeferredTransaction(database, [&] { - auto types = selectTypesStatement.template values<Storage::Synchronization::Type, 64>(); - - for (Storage::Synchronization::Type &type : types) { - type.exportedTypes = fetchExportedTypes(type.typeId); - type.propertyDeclarations = fetchPropertyDeclarations(type.typeId); - type.functionDeclarations = fetchFunctionDeclarations(type.typeId); - type.signalDeclarations = fetchSignalDeclarations(type.typeId); - type.enumerationDeclarations = fetchEnumerationDeclarations(type.typeId); - } - - return types; - }); - - tracer.end(keyValue("type", types)); - - return types; - } - - SourceContextId fetchSourceContextIdUnguarded(Utils::SmallStringView sourceContextPath) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"fetch source context id unguarded"_t, projectStorageCategory()}; - - auto sourceContextId = readSourceContextId(sourceContextPath); - - return sourceContextId ? sourceContextId : writeSourceContextId(sourceContextPath); - } - - SourceContextId fetchSourceContextId(Utils::SmallStringView sourceContextPath) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"fetch source context id"_t, - projectStorageCategory(), - keyValue("source context path", sourceContextPath)}; - - SourceContextId sourceContextId; - try { - sourceContextId = Sqlite::withDeferredTransaction(database, [&] { - return fetchSourceContextIdUnguarded(sourceContextPath); - }); - } catch (const Sqlite::ConstraintPreventsModification &) { - sourceContextId = fetchSourceContextId(sourceContextPath); - } - - tracer.end(keyValue("source context id", sourceContextId)); - - return sourceContextId; - } - - Utils::PathString fetchSourceContextPath(SourceContextId sourceContextId) const - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"fetch source context path"_t, - projectStorageCategory(), - keyValue("source context id", sourceContextId)}; - - auto path = Sqlite::withDeferredTransaction(database, [&] { - auto optionalSourceContextPath = selectSourceContextPathFromSourceContextsBySourceContextIdStatement - .template optionalValue<Utils::PathString>( - sourceContextId); + TypeId id7) const override; - if (!optionalSourceContextPath) - throw SourceContextIdDoesNotExists(); - - return std::move(*optionalSourceContextPath); - }); - - tracer.end(keyValue("source context path", path)); - - return path; - } - - auto fetchAllSourceContexts() const - { - NanotraceHR::Tracer tracer{"fetch all source contexts"_t, projectStorageCategory()}; - - return selectAllSourceContextsStatement - .template valuesWithTransaction<Cache::SourceContext, 128>(); - } + TypeId fetchTypeIdByExportedName(Utils::SmallStringView name) const; - SourceId fetchSourceId(SourceContextId sourceContextId, 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); - }); - - tracer.end(keyValue("source id", sourceId)); - - return sourceId; - } - - auto fetchSourceNameAndSourceContextId(SourceId sourceId) const - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"fetch source name and source context id"_t, - projectStorageCategory(), - keyValue("source id", sourceId)}; - - auto value = selectSourceNameAndSourceContextIdFromSourcesBySourceIdStatement - .template valueWithTransaction<Cache::SourceNameAndSourceContextId>(sourceId); - - if (!value.sourceContextId) - throw SourceIdDoesNotExists(); - - tracer.end(keyValue("source name", value.sourceName), - keyValue("source context id", value.sourceContextId)); - - return value; - } + TypeId fetchTypeIdByModuleIdsAndExportedName(ModuleIds moduleIds, + Utils::SmallStringView name) const; - void clearSources() - { - Sqlite::withImmediateTransaction(database, [&] { - deleteAllSourceContextsStatement.execute(); - deleteAllSourcesStatement.execute(); - }); - } + TypeId fetchTypeIdByName(SourceId sourceId, Utils::SmallStringView name); - SourceContextId fetchSourceContextId(SourceId sourceId) const - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"fetch source context id"_t, - projectStorageCategory(), - keyValue("source id", sourceId)}; + Storage::Synchronization::Type fetchTypeByTypeId(TypeId typeId); - auto sourceContextId = selectSourceContextIdFromSourcesBySourceIdStatement - .template valueWithTransaction<SourceContextId>(sourceId); + Storage::Synchronization::Types fetchTypes(); - if (!sourceContextId) - throw SourceIdDoesNotExists(); + SourceContextId fetchSourceContextIdUnguarded(Utils::SmallStringView sourceContextPath); - tracer.end(keyValue("source context id", sourceContextId)); + SourceContextId fetchSourceContextId(Utils::SmallStringView sourceContextPath); - return sourceContextId; - } + Utils::PathString fetchSourceContextPath(SourceContextId sourceContextId) const; - auto fetchAllSources() const - { - NanotraceHR::Tracer tracer{"fetch all sources"_t, projectStorageCategory()}; + Cache::SourceContexts fetchAllSourceContexts() const; - return selectAllSourcesStatement.template valuesWithTransaction<Cache::Source, 1024>(); - } + SourceId fetchSourceId(SourceContextId sourceContextId, Utils::SmallStringView sourceName); - SourceId fetchSourceIdUnguarded(SourceContextId sourceContextId, Utils::SmallStringView sourceName) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"fetch source id unguarded"_t, - projectStorageCategory(), - keyValue("source context id", sourceContextId), - keyValue("source name", sourceName)}; + Cache::SourceNameAndSourceContextId fetchSourceNameAndSourceContextId(SourceId sourceId) const; - auto sourceId = readSourceId(sourceContextId, sourceName); + void clearSources(); - if (!sourceId) - sourceId = writeSourceId(sourceContextId, sourceName); + SourceContextId fetchSourceContextId(SourceId sourceId) const; - tracer.end(keyValue("source id", sourceId)); + Cache::Sources fetchAllSources() const; - return sourceId; - } + SourceId fetchSourceIdUnguarded(SourceContextId sourceContextId, + Utils::SmallStringView sourceName); auto fetchAllFileStatuses() const { NanotraceHR::Tracer tracer{"fetch all file statuses"_t, projectStorageCategory()}; - return selectAllFileStatusesStatement.template rangeWithTransaction<FileStatus>(); - } - - FileStatus fetchFileStatus(SourceId sourceId) const override - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"fetch file status"_t, - projectStorageCategory(), - keyValue("source id", sourceId)}; - - auto fileStatus = selectFileStatusesForSourceIdStatement - .template valueWithTransaction<FileStatus>(sourceId); - - tracer.end(keyValue("file status", fileStatus)); - - return fileStatus; - } - - std::optional<Storage::Synchronization::ProjectData> fetchProjectData(SourceId sourceId) const override - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"fetch project data"_t, - projectStorageCategory(), - keyValue("source id", sourceId)}; - - auto projectData = selectProjectDataForSourceIdStatement.template optionalValueWithTransaction< - Storage::Synchronization::ProjectData>(sourceId); - - tracer.end(keyValue("project data", projectData)); - - return projectData; - } - - Storage::Synchronization::ProjectDatas fetchProjectDatas(SourceId projectSourceId) const override - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"fetch project datas by source id"_t, - projectStorageCategory(), - keyValue("source id", projectSourceId)}; - - auto projectDatas = selectProjectDatasForSourceIdStatement - .template valuesWithTransaction<Storage::Synchronization::ProjectData, 1024>( - projectSourceId); - - tracer.end(keyValue("project datas", projectDatas)); - - return projectDatas; - } - - Storage::Synchronization::ProjectDatas fetchProjectDatas(const SourceIds &projectSourceIds) const - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"fetch project datas by source ids"_t, - projectStorageCategory(), - keyValue("source ids", projectSourceIds)}; - - auto projectDatas = selectProjectDatasForSourceIdsStatement - .template valuesWithTransaction<Storage::Synchronization::ProjectData, 64>( - toIntegers(projectSourceIds)); - - tracer.end(keyValue("project datas", projectDatas)); - - return projectDatas; + return selectAllFileStatusesStatement.rangeWithTransaction<FileStatus>(); } - void setPropertyEditorPathId(TypeId typeId, SourceId pathId) - { - Sqlite::ImmediateSessionTransaction transaction{database}; + FileStatus fetchFileStatus(SourceId sourceId) const override; - upsertPropertyEditorPathIdStatement.write(typeId, pathId); + std::optional<Storage::Synchronization::ProjectData> fetchProjectData(SourceId sourceId) const override; - transaction.commit(); - } + Storage::Synchronization::ProjectDatas fetchProjectDatas(SourceId projectSourceId) const override; - SourceId propertyEditorPathId(TypeId typeId) const override - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"property editor path id"_t, - projectStorageCategory(), - keyValue("type id", typeId)}; + Storage::Synchronization::ProjectDatas fetchProjectDatas(const SourceIds &projectSourceIds) const; - auto sourceId = selectPropertyEditorPathIdStatement.template valueWithTransaction<SourceId>( - typeId); + void setPropertyEditorPathId(TypeId typeId, SourceId pathId); - tracer.end(keyValue("source id", sourceId)); + SourceId propertyEditorPathId(TypeId typeId) const override; - return sourceId; - } + Storage::Imports fetchDocumentImports() const; - Storage::Imports fetchDocumentImports() const - { - NanotraceHR::Tracer tracer{"fetch document imports"_t, projectStorageCategory()}; - - return selectAllDocumentImportForSourceIdStatement - .template valuesWithTransaction<Storage::Imports>(); - } - - void resetForTestsOnly() - { - database.clearAllTablesForTestsOnly(); - commonTypeCache_.clearForTestsOnly(); - moduleCache.clearForTestOnly(); - } + void resetForTestsOnly(); private: class ModuleStorageAdapter @@ -1233,12 +305,11 @@ private: } }; + using Modules = std::vector<Module>; + friend ModuleStorageAdapter; - static bool moduleNameLess(Utils::SmallStringView first, Utils::SmallStringView second) noexcept - { - return first < second; - } + static bool moduleNameLess(Utils::SmallStringView first, Utils::SmallStringView second) noexcept; using ModuleCache = StorageCache<Utils::PathString, Utils::SmallStringView, @@ -1248,57 +319,13 @@ private: moduleNameLess, Module>; - ModuleId fetchModuleId(Utils::SmallStringView moduleName) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"fetch module id"_t, - projectStorageCategory(), - keyValue("module name", moduleName)}; - - auto moduleId = Sqlite::withDeferredTransaction(database, [&] { - return fetchModuleIdUnguarded(moduleName); - }); - - tracer.end(keyValue("module id", moduleId)); - - return moduleId; - } - - auto fetchModuleName(ModuleId id) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"fetch module name"_t, - projectStorageCategory(), - keyValue("module id", id)}; - - auto moduleName = Sqlite::withDeferredTransaction(database, [&] { - return fetchModuleNameUnguarded(id); - }); - - tracer.end(keyValue("module name", moduleName)); - - return moduleName; - } - - auto fetchAllModules() const - { - NanotraceHR::Tracer tracer{"fetch all modules"_t, projectStorageCategory()}; + ModuleId fetchModuleId(Utils::SmallStringView moduleName); - return selectAllModulesStatement.template valuesWithTransaction<Module, 128>(); - } + Utils::PathString fetchModuleName(ModuleId id); - void callRefreshMetaInfoCallback(const TypeIds &deletedTypeIds) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"call refresh meta info callback"_t, - projectStorageCategory(), - keyValue("type ids", deletedTypeIds)}; + Modules fetchAllModules() const; - if (deletedTypeIds.size()) { - for (ProjectStorageObserver *observer : observers) - observer->removedTypeIds(deletedTypeIds); - } - } + void callRefreshMetaInfoCallback(const TypeIds &deletedTypeIds); class AliasPropertyDeclaration { @@ -1457,48 +484,14 @@ private: } }; - SourceIds filterSourceIdsWithoutType(const SourceIds &updatedSourceIds, SourceIds &sourceIdsOfTypes) - { - std::sort(sourceIdsOfTypes.begin(), sourceIdsOfTypes.end()); + SourceIds filterSourceIdsWithoutType(const SourceIds &updatedSourceIds, + SourceIds &sourceIdsOfTypes); - SourceIds sourceIdsWithoutTypeSourceIds; - sourceIdsWithoutTypeSourceIds.reserve(updatedSourceIds.size()); - std::set_difference(updatedSourceIds.begin(), - updatedSourceIds.end(), - sourceIdsOfTypes.begin(), - sourceIdsOfTypes.end(), - std::back_inserter(sourceIdsWithoutTypeSourceIds)); + TypeIds fetchTypeIds(const SourceIds &sourceIds); - return sourceIdsWithoutTypeSourceIds; - } + void unique(SourceIds &sourceIds); - TypeIds fetchTypeIds(const SourceIds &sourceIds) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"fetch type ids"_t, - projectStorageCategory(), - keyValue("source ids", sourceIds)}; - - return selectTypeIdsForSourceIdsStatement.template values<TypeId, 128>(toIntegers(sourceIds)); - } - - void unique(SourceIds &sourceIds) - { - std::sort(sourceIds.begin(), sourceIds.end()); - auto newEnd = std::unique(sourceIds.begin(), sourceIds.end()); - sourceIds.erase(newEnd, sourceIds.end()); - } - - void synchronizeTypeTraits(TypeId typeId, Storage::TypeTraits traits) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"synchronize type traits"_t, - projectStorageCategory(), - keyValue("type id", typeId), - keyValue("type traits", traits)}; - - updateTypeAnnotationTraitStatement.write(typeId, traits.annotation); - } + void synchronizeTypeTraits(TypeId typeId, Storage::TypeTraits traits); class TypeAnnotationView { @@ -1533,28 +526,7 @@ private: Utils::PathString hintsJson; }; - void updateTypeIdInTypeAnnotations(Storage::Synchronization::TypeAnnotations &typeAnnotations) - { - NanotraceHR::Tracer tracer{"update type id in type annotations"_t, projectStorageCategory()}; - - for (auto &annotation : typeAnnotations) { - annotation.typeId = fetchTypeIdByModuleIdAndExportedName(annotation.moduleId, - annotation.typeName); - } - - for (auto &annotation : typeAnnotations) { - if (!annotation.typeId) - qWarning() << moduleName(annotation.moduleId).toQString() - << annotation.typeName.toQString(); - } - - typeAnnotations.erase(std::remove_if(typeAnnotations.begin(), - typeAnnotations.end(), - [](const auto &annotation) { - return !annotation.typeId; - }), - typeAnnotations.end()); - } + void updateTypeIdInTypeAnnotations(Storage::Synchronization::TypeAnnotations &typeAnnotations); template<typename Value> static Sqlite::ValueView createEmptyAsNull(const Value &value) @@ -1566,84 +538,9 @@ private: } void synchronizeTypeAnnotations(Storage::Synchronization::TypeAnnotations &typeAnnotations, - const SourceIds &updatedTypeAnnotationSourceIds) - { - NanotraceHR::Tracer tracer{"synchronize type annotations"_t, projectStorageCategory()}; - - using Storage::Synchronization::TypeAnnotation; - - updateTypeIdInTypeAnnotations(typeAnnotations); - - auto compareKey = [](auto &&first, auto &&second) { return first.typeId - second.typeId; }; - - std::sort(typeAnnotations.begin(), typeAnnotations.end(), [&](auto &&first, auto &&second) { - return first.typeId < second.typeId; - }); - - auto range = selectTypeAnnotationsForSourceIdsStatement.template range<TypeAnnotationView>( - toIntegers(updatedTypeAnnotationSourceIds)); - - auto insert = [&](const TypeAnnotation &annotation) { - if (!annotation.sourceId) - throw TypeAnnotationHasInvalidSourceId{}; - - synchronizeTypeTraits(annotation.typeId, annotation.traits); - - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"insert type annotations"_t, - projectStorageCategory(), - keyValue("type annotation", annotation)}; - - insertTypeAnnotationStatement.write(annotation.typeId, - annotation.sourceId, - annotation.directorySourceId, - annotation.iconPath, - createEmptyAsNull(annotation.itemLibraryJson), - createEmptyAsNull(annotation.hintsJson)); - }; - - auto update = [&](const TypeAnnotationView &annotationFromDatabase, - const TypeAnnotation &annotation) { - synchronizeTypeTraits(annotation.typeId, annotation.traits); - - if (annotationFromDatabase.iconPath != annotation.iconPath - || annotationFromDatabase.itemLibraryJson != annotation.itemLibraryJson - || annotationFromDatabase.hintsJson != annotation.hintsJson) { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"update type annotations"_t, - projectStorageCategory(), - keyValue("type annotation from database", - annotationFromDatabase), - keyValue("type annotation", annotation)}; - - updateTypeAnnotationStatement.write(annotation.typeId, - annotation.iconPath, - createEmptyAsNull(annotation.itemLibraryJson), - createEmptyAsNull(annotation.hintsJson)); - return Sqlite::UpdateChange::Update; - } - - return Sqlite::UpdateChange::No; - }; - - auto remove = [&](const TypeAnnotationView &annotationFromDatabase) { - synchronizeTypeTraits(annotationFromDatabase.typeId, Storage::TypeTraits{}); - - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"remove type annotations"_t, - projectStorageCategory(), - keyValue("type annotation", annotationFromDatabase)}; + const SourceIds &updatedTypeAnnotationSourceIds); - deleteTypeAnnotationStatement.write(annotationFromDatabase.typeId); - }; - - Sqlite::insertUpdateDelete(range, typeAnnotations, compareKey, insert, update, remove); - } - - void synchronizeTypeTrait(const Storage::Synchronization::Type &type) - { - updateTypeTraitStatement.write(type.typeId, type.traits.type); - } + void synchronizeTypeTrait(const Storage::Synchronization::Type &type); void synchronizeTypes(Storage::Synchronization::Types &types, TypeIds &updatedTypeIds, @@ -1653,486 +550,49 @@ private: PropertyDeclarations &relinkablePropertyDeclarations, Prototypes &relinkablePrototypes, Prototypes &relinkableExtensions, - const SourceIds &updatedSourceIds) - { - NanotraceHR::Tracer tracer{"synchronize types"_t, projectStorageCategory()}; - - Storage::Synchronization::ExportedTypes exportedTypes; - exportedTypes.reserve(types.size() * 3); - SourceIds sourceIdsOfTypes; - sourceIdsOfTypes.reserve(updatedSourceIds.size()); - SourceIds notUpdatedExportedSourceIds; - notUpdatedExportedSourceIds.reserve(updatedSourceIds.size()); - SourceIds exportedSourceIds; - exportedSourceIds.reserve(types.size()); - - for (auto &type : types) { - if (!type.sourceId) - throw TypeHasInvalidSourceId{}; - - TypeId typeId = declareType(type); - synchronizeTypeTrait(type); - sourceIdsOfTypes.push_back(type.sourceId); - updatedTypeIds.push_back(typeId); - if (type.changeLevel != Storage::Synchronization::ChangeLevel::ExcludeExportedTypes) { - exportedSourceIds.push_back(type.sourceId); - extractExportedTypes(typeId, type, exportedTypes); - } - } - - std::sort(types.begin(), types.end(), [](const auto &first, const auto &second) { - return first.typeId < second.typeId; - }); - - unique(exportedSourceIds); - - SourceIds sourceIdsWithoutType = filterSourceIdsWithoutType(updatedSourceIds, - sourceIdsOfTypes); - exportedSourceIds.insert(exportedSourceIds.end(), - sourceIdsWithoutType.begin(), - sourceIdsWithoutType.end()); - TypeIds exportedTypeIds = fetchTypeIds(exportedSourceIds); - synchronizeExportedTypes(exportedTypeIds, - exportedTypes, - relinkableAliasPropertyDeclarations, - relinkablePropertyDeclarations, - relinkablePrototypes, - relinkableExtensions); - - syncPrototypesAndExtensions(types, relinkablePrototypes, relinkableExtensions); - resetDefaultPropertiesIfChanged(types); - resetRemovedAliasPropertyDeclarationsToNull(types, relinkableAliasPropertyDeclarations); - syncDeclarations(types, - insertedAliasPropertyDeclarations, - updatedAliasPropertyDeclarations, - relinkablePropertyDeclarations); - syncDefaultProperties(types); - } + const SourceIds &updatedSourceIds); void synchronizeProjectDatas(Storage::Synchronization::ProjectDatas &projectDatas, - const SourceIds &updatedProjectSourceIds) - { - NanotraceHR::Tracer tracer{"synchronize project datas"_t, projectStorageCategory()}; - - auto compareKey = [](auto &&first, auto &&second) { - auto projectSourceIdDifference = first.projectSourceId - second.projectSourceId; - if (projectSourceIdDifference != 0) - return projectSourceIdDifference; - - return first.sourceId - second.sourceId; - }; - - std::sort(projectDatas.begin(), projectDatas.end(), [&](auto &&first, auto &&second) { - return std::tie(first.projectSourceId, first.sourceId) - < std::tie(second.projectSourceId, second.sourceId); - }); + const SourceIds &updatedProjectSourceIds); - auto range = selectProjectDatasForSourceIdsStatement - .template range<Storage::Synchronization::ProjectData>( - toIntegers(updatedProjectSourceIds)); - - auto insert = [&](const Storage::Synchronization::ProjectData &projectData) { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"insert project data"_t, - projectStorageCategory(), - keyValue("project data", projectData)}; - - if (!projectData.projectSourceId) - throw ProjectDataHasInvalidProjectSourceId{}; - if (!projectData.sourceId) - throw ProjectDataHasInvalidSourceId{}; - - insertProjectDataStatement.write(projectData.projectSourceId, - projectData.sourceId, - projectData.moduleId, - projectData.fileType); - }; - - auto update = [&](const Storage::Synchronization::ProjectData &projectDataFromDatabase, - const Storage::Synchronization::ProjectData &projectData) { - if (projectDataFromDatabase.fileType != projectData.fileType - || !compareInvalidAreTrue(projectDataFromDatabase.moduleId, projectData.moduleId)) { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"update project data"_t, - projectStorageCategory(), - keyValue("project data", projectData), - keyValue("project data from database", - projectDataFromDatabase)}; - - updateProjectDataStatement.write(projectData.projectSourceId, - projectData.sourceId, - projectData.moduleId, - projectData.fileType); - return Sqlite::UpdateChange::Update; - } - - return Sqlite::UpdateChange::No; - }; - - auto remove = [&](const Storage::Synchronization::ProjectData &projectData) { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"remove project data"_t, - projectStorageCategory(), - keyValue("project data", projectData)}; - - deleteProjectDataStatement.write(projectData.projectSourceId, projectData.sourceId); - }; - - Sqlite::insertUpdateDelete(range, projectDatas, compareKey, insert, update, remove); - } - - void synchronizeFileStatuses(FileStatuses &fileStatuses, const SourceIds &updatedSourceIds) - { - NanotraceHR::Tracer tracer{"synchronize file statuses"_t, projectStorageCategory()}; - - auto compareKey = [](auto &&first, auto &&second) { - return first.sourceId - second.sourceId; - }; - - std::sort(fileStatuses.begin(), fileStatuses.end(), [&](auto &&first, auto &&second) { - return first.sourceId < second.sourceId; - }); - - auto range = selectFileStatusesForSourceIdsStatement.template range<FileStatus>( - toIntegers(updatedSourceIds)); - - auto insert = [&](const FileStatus &fileStatus) { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"insert file status"_t, - projectStorageCategory(), - keyValue("file status", fileStatus)}; - - if (!fileStatus.sourceId) - throw FileStatusHasInvalidSourceId{}; - insertFileStatusStatement.write(fileStatus.sourceId, - fileStatus.size, - fileStatus.lastModified); - }; - - auto update = [&](const FileStatus &fileStatusFromDatabase, const FileStatus &fileStatus) { - if (fileStatusFromDatabase.lastModified != fileStatus.lastModified - || fileStatusFromDatabase.size != fileStatus.size) { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"update file status"_t, - projectStorageCategory(), - keyValue("file status", fileStatus), - keyValue("file status from database", - fileStatusFromDatabase)}; - - updateFileStatusStatement.write(fileStatus.sourceId, - fileStatus.size, - fileStatus.lastModified); - return Sqlite::UpdateChange::Update; - } - - return Sqlite::UpdateChange::No; - }; - - auto remove = [&](const FileStatus &fileStatus) { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"remove file status"_t, - projectStorageCategory(), - keyValue("file status", fileStatus)}; - - deleteFileStatusStatement.write(fileStatus.sourceId); - }; - - Sqlite::insertUpdateDelete(range, fileStatuses, compareKey, insert, update, remove); - } + void synchronizeFileStatuses(FileStatuses &fileStatuses, const SourceIds &updatedSourceIds); void synchronizeImports(Storage::Imports &imports, const SourceIds &updatedSourceIds, Storage::Imports &moduleDependencies, const SourceIds &updatedModuleDependencySourceIds, Storage::Synchronization::ModuleExportedImports &moduleExportedImports, - const ModuleIds &updatedModuleIds) - { - NanotraceHR::Tracer tracer{"synchronize imports"_t, projectStorageCategory()}; - - synchromizeModuleExportedImports(moduleExportedImports, updatedModuleIds); - NanotraceHR::Tracer importTracer{"synchronize qml document imports"_t, - projectStorageCategory()}; - synchronizeDocumentImports(imports, - updatedSourceIds, - Storage::Synchronization::ImportKind::Import); - importTracer.end(); - NanotraceHR::Tracer moduleDependenciesTracer{"synchronize module depdencies"_t, - projectStorageCategory()}; - synchronizeDocumentImports(moduleDependencies, - updatedModuleDependencySourceIds, - Storage::Synchronization::ImportKind::ModuleDependency); - moduleDependenciesTracer.end(); - } + const ModuleIds &updatedModuleIds); void synchromizeModuleExportedImports( Storage::Synchronization::ModuleExportedImports &moduleExportedImports, - const ModuleIds &updatedModuleIds) - { - NanotraceHR::Tracer tracer{"synchronize module exported imports"_t, projectStorageCategory()}; - std::sort(moduleExportedImports.begin(), - moduleExportedImports.end(), - [](auto &&first, auto &&second) { - return std::tie(first.moduleId, first.exportedModuleId) - < std::tie(second.moduleId, second.exportedModuleId); - }); - - auto range = selectModuleExportedImportsForSourceIdStatement - .template range<Storage::Synchronization::ModuleExportedImportView>( - toIntegers(updatedModuleIds)); - - auto compareKey = [](const Storage::Synchronization::ModuleExportedImportView &view, - const Storage::Synchronization::ModuleExportedImport &import) -> long long { - auto moduleIdDifference = view.moduleId - import.moduleId; - if (moduleIdDifference != 0) - return moduleIdDifference; - - return view.exportedModuleId - import.exportedModuleId; - }; - - auto insert = [&](const Storage::Synchronization::ModuleExportedImport &import) { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"insert module exported import"_t, - projectStorageCategory(), - keyValue("module exported import", import), - keyValue("module id", import.moduleId)}; - tracer.tick("exported module"_t, keyValue("module id", import.exportedModuleId)); - - if (import.version.minor) { - insertModuleExportedImportWithVersionStatement.write(import.moduleId, - import.exportedModuleId, - import.isAutoVersion, - import.version.major.value, - import.version.minor.value); - } else if (import.version.major) { - insertModuleExportedImportWithMajorVersionStatement.write(import.moduleId, - import.exportedModuleId, - import.isAutoVersion, - import.version.major.value); - } else { - insertModuleExportedImportWithoutVersionStatement.write(import.moduleId, - import.exportedModuleId, - import.isAutoVersion); - } - }; - - auto update = [](const Storage::Synchronization::ModuleExportedImportView &, - const Storage::Synchronization::ModuleExportedImport &) { - return Sqlite::UpdateChange::No; - }; - - auto remove = [&](const Storage::Synchronization::ModuleExportedImportView &view) { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"remove module exported import"_t, - projectStorageCategory(), - keyValue("module exported import view", view), - keyValue("module id", view.moduleId)}; - tracer.tick("exported module"_t, keyValue("module id", view.exportedModuleId)); - - deleteModuleExportedImportStatement.write(view.moduleExportedImportId); - }; - - Sqlite::insertUpdateDelete(range, moduleExportedImports, compareKey, insert, update, remove); - } - - ModuleId fetchModuleIdUnguarded(Utils::SmallStringView name) const override - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"fetch module id ungarded"_t, - projectStorageCategory(), - keyValue("module name", name)}; - - auto moduleId = selectModuleIdByNameStatement.template value<ModuleId>(name); - - if (!moduleId) - moduleId = insertModuleNameStatement.template value<ModuleId>(name); - - tracer.end(keyValue("module id", moduleId)); - - return moduleId; - } + const ModuleIds &updatedModuleIds); - auto fetchModuleNameUnguarded(ModuleId id) const - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"fetch module name ungarded"_t, - projectStorageCategory(), - keyValue("module id", id)}; - - auto moduleName = selectModuleNameStatement.template value<Utils::PathString>(id); - - if (moduleName.empty()) - throw ModuleDoesNotExists{}; + ModuleId fetchModuleIdUnguarded(Utils::SmallStringView name) const override; - tracer.end(keyValue("module name", moduleName)); - - return moduleName; - } + Utils::PathString fetchModuleNameUnguarded(ModuleId id) const; void handleAliasPropertyDeclarationsWithPropertyType( - TypeId typeId, AliasPropertyDeclarations &relinkableAliasPropertyDeclarations) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"handle alias property declarations with property type"_t, - projectStorageCategory(), - keyValue("type id", typeId), - keyValue("relinkable alias property declarations", - relinkableAliasPropertyDeclarations)}; - - auto callback = [&](TypeId typeId_, - PropertyDeclarationId propertyDeclarationId, - ImportedTypeNameId propertyImportedTypeNameId, - PropertyDeclarationId aliasPropertyDeclarationId, - PropertyDeclarationId aliasPropertyDeclarationTailId) { - auto aliasPropertyName = selectPropertyNameStatement.template value<Utils::SmallString>( - aliasPropertyDeclarationId); - Utils::SmallString aliasPropertyNameTail; - if (aliasPropertyDeclarationTailId) - aliasPropertyNameTail = selectPropertyNameStatement.template value<Utils::SmallString>( - aliasPropertyDeclarationTailId); - - relinkableAliasPropertyDeclarations - .emplace_back(TypeId{typeId_}, - PropertyDeclarationId{propertyDeclarationId}, - ImportedTypeNameId{propertyImportedTypeNameId}, - std::move(aliasPropertyName), - std::move(aliasPropertyNameTail)); - - updateAliasPropertyDeclarationToNullStatement.write(propertyDeclarationId); - }; - - selectAliasPropertiesDeclarationForPropertiesWithTypeIdStatement.readCallback(callback, - typeId); - } + TypeId typeId, AliasPropertyDeclarations &relinkableAliasPropertyDeclarations); void handlePropertyDeclarationWithPropertyType(TypeId typeId, - PropertyDeclarations &relinkablePropertyDeclarations) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"handle property declarations with property type"_t, - projectStorageCategory(), - keyValue("type id", typeId), - keyValue("relinkable property declarations", - relinkablePropertyDeclarations)}; + PropertyDeclarations &relinkablePropertyDeclarations); - updatesPropertyDeclarationPropertyTypeToNullStatement.readTo(relinkablePropertyDeclarations, - typeId); - } + void handlePrototypes(TypeId prototypeId, Prototypes &relinkablePrototypes); - void handlePrototypes(TypeId prototypeId, Prototypes &relinkablePrototypes) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"handle prototypes"_t, - projectStorageCategory(), - keyValue("type id", prototypeId), - keyValue("relinkable prototypes", relinkablePrototypes)}; - - auto callback = [&](TypeId typeId, ImportedTypeNameId prototypeNameId) { - relinkablePrototypes.emplace_back(typeId, prototypeNameId); - }; - - updatePrototypeIdToNullStatement.readCallback(callback, prototypeId); - } - - void handleExtensions(TypeId extensionId, Prototypes &relinkableExtensions) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"handle extension"_t, - projectStorageCategory(), - keyValue("type id", extensionId), - keyValue("relinkable extensions", relinkableExtensions)}; - - auto callback = [&](TypeId typeId, ImportedTypeNameId extensionNameId) { - relinkableExtensions.emplace_back(typeId, extensionNameId); - }; - - updateExtensionIdToNullStatement.readCallback(callback, extensionId); - } + void handleExtensions(TypeId extensionId, Prototypes &relinkableExtensions); void deleteType(TypeId typeId, AliasPropertyDeclarations &relinkableAliasPropertyDeclarations, PropertyDeclarations &relinkablePropertyDeclarations, Prototypes &relinkablePrototypes, - Prototypes &relinkableExtensions) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"delete type"_t, - projectStorageCategory(), - keyValue("type id", typeId)}; - - handlePropertyDeclarationWithPropertyType(typeId, relinkablePropertyDeclarations); - handleAliasPropertyDeclarationsWithPropertyType(typeId, relinkableAliasPropertyDeclarations); - handlePrototypes(typeId, relinkablePrototypes); - handleExtensions(typeId, relinkableExtensions); - deleteTypeNamesByTypeIdStatement.write(typeId); - deleteEnumerationDeclarationByTypeIdStatement.write(typeId); - deletePropertyDeclarationByTypeIdStatement.write(typeId); - deleteFunctionDeclarationByTypeIdStatement.write(typeId); - deleteSignalDeclarationByTypeIdStatement.write(typeId); - deleteTypeStatement.write(typeId); - } + Prototypes &relinkableExtensions); void relinkAliasPropertyDeclarations(AliasPropertyDeclarations &aliasPropertyDeclarations, - const TypeIds &deletedTypeIds) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"relink alias properties"_t, - projectStorageCategory(), - keyValue("alias property declarations", aliasPropertyDeclarations), - keyValue("deleted type ids", deletedTypeIds)}; - - std::sort(aliasPropertyDeclarations.begin(), aliasPropertyDeclarations.end()); - - Utils::set_greedy_difference( - aliasPropertyDeclarations.cbegin(), - aliasPropertyDeclarations.cend(), - deletedTypeIds.begin(), - deletedTypeIds.end(), - [&](const AliasPropertyDeclaration &alias) { - auto typeId = fetchTypeId(alias.aliasImportedTypeNameId); - - if (!typeId) - throw TypeNameDoesNotExists{fetchImportedTypeName(alias.aliasImportedTypeNameId)}; - - auto [propertyTypeId, aliasId, propertyTraits] = fetchPropertyDeclarationByTypeIdAndNameUngarded( - typeId, alias.aliasPropertyName); - - updatePropertyDeclarationWithAliasAndTypeStatement.write(alias.propertyDeclarationId, - propertyTypeId, - propertyTraits, - alias.aliasImportedTypeNameId, - aliasId); - }, - TypeCompare<AliasPropertyDeclaration>{}); - } + const TypeIds &deletedTypeIds); void relinkPropertyDeclarations(PropertyDeclarations &relinkablePropertyDeclaration, - const TypeIds &deletedTypeIds) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"relink property declarations"_t, - projectStorageCategory(), - keyValue("relinkable property declarations", - relinkablePropertyDeclaration), - keyValue("deleted type ids", deletedTypeIds)}; - - std::sort(relinkablePropertyDeclaration.begin(), relinkablePropertyDeclaration.end()); - - Utils::set_greedy_difference( - relinkablePropertyDeclaration.cbegin(), - relinkablePropertyDeclaration.cend(), - deletedTypeIds.begin(), - deletedTypeIds.end(), - [&](const PropertyDeclaration &property) { - TypeId propertyTypeId = fetchTypeId(property.importedTypeNameId); - - if (!propertyTypeId) - throw TypeNameDoesNotExists{fetchImportedTypeName(property.importedTypeNameId)}; - - updatePropertyDeclarationTypeStatement.write(property.propertyDeclarationId, - propertyTypeId); - }, - TypeCompare<PropertyDeclaration>{}); - } + const TypeIds &deletedTypeIds); template<typename Callable> void relinkPrototypes(Prototypes &relinkablePrototypes, @@ -2171,435 +631,66 @@ private: PropertyDeclarations &relinkablePropertyDeclarations, Prototypes &relinkablePrototypes, Prototypes &relinkableExtensions, - TypeIds &deletedTypeIds) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"delete not updated types"_t, - projectStorageCategory(), - keyValue("updated type ids", updatedTypeIds), - keyValue("updated source ids", updatedSourceIds), - keyValue("type ids to be deleted", typeIdsToBeDeleted)}; - - auto callback = [&](TypeId typeId) { - deletedTypeIds.push_back(typeId); - deleteType(typeId, - relinkableAliasPropertyDeclarations, - relinkablePropertyDeclarations, - relinkablePrototypes, - relinkableExtensions); - }; - - selectNotUpdatedTypesInSourcesStatement.readCallback(callback, - toIntegers(updatedSourceIds), - toIntegers(updatedTypeIds)); - for (TypeId typeIdToBeDeleted : typeIdsToBeDeleted) - callback(typeIdToBeDeleted); - } + TypeIds &deletedTypeIds); void relink(AliasPropertyDeclarations &relinkableAliasPropertyDeclarations, PropertyDeclarations &relinkablePropertyDeclarations, Prototypes &relinkablePrototypes, Prototypes &relinkableExtensions, - TypeIds &deletedTypeIds) - { - NanotraceHR::Tracer tracer{"relink"_t, projectStorageCategory()}; - - std::sort(deletedTypeIds.begin(), deletedTypeIds.end()); - - relinkPrototypes(relinkablePrototypes, deletedTypeIds, [&](TypeId typeId, TypeId prototypeId) { - updateTypePrototypeStatement.write(typeId, prototypeId); - }); - relinkPrototypes(relinkableExtensions, deletedTypeIds, [&](TypeId typeId, TypeId prototypeId) { - updateTypeExtensionStatement.write(typeId, prototypeId); - }); - relinkPropertyDeclarations(relinkablePropertyDeclarations, deletedTypeIds); - relinkAliasPropertyDeclarations(relinkableAliasPropertyDeclarations, deletedTypeIds); - } + TypeIds &deletedTypeIds); PropertyDeclarationId fetchAliasId(TypeId aliasTypeId, Utils::SmallStringView aliasPropertyName, - Utils::SmallStringView aliasPropertyNameTail) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"fetch alias id"_t, - projectStorageCategory(), - keyValue("alias type id", aliasTypeId), - keyValue("alias property name", aliasPropertyName), - keyValue("alias property name tail", aliasPropertyNameTail)}; - - if (aliasPropertyNameTail.empty()) - return fetchPropertyDeclarationIdByTypeIdAndNameUngarded(aliasTypeId, aliasPropertyName); - - auto stemAlias = fetchPropertyDeclarationByTypeIdAndNameUngarded(aliasTypeId, - aliasPropertyName); - - return fetchPropertyDeclarationIdByTypeIdAndNameUngarded(stemAlias.propertyTypeId, - aliasPropertyNameTail); - } - - void linkAliasPropertyDeclarationAliasIds(const AliasPropertyDeclarations &aliasDeclarations) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"link alias property declarations alias ids"_t, - projectStorageCategory(), - keyValue("alias property declarations", aliasDeclarations)}; + Utils::SmallStringView aliasPropertyNameTail); - for (const auto &aliasDeclaration : aliasDeclarations) { - auto aliasTypeId = fetchTypeId(aliasDeclaration.aliasImportedTypeNameId); + void linkAliasPropertyDeclarationAliasIds(const AliasPropertyDeclarations &aliasDeclarations); - if (!aliasTypeId) { - throw TypeNameDoesNotExists{ - fetchImportedTypeName(aliasDeclaration.aliasImportedTypeNameId)}; - } + void updateAliasPropertyDeclarationValues(const AliasPropertyDeclarations &aliasDeclarations); - auto aliasId = fetchAliasId(aliasTypeId, - aliasDeclaration.aliasPropertyName, - aliasDeclaration.aliasPropertyNameTail); - - updatePropertyDeclarationAliasIdAndTypeNameIdStatement - .write(aliasDeclaration.propertyDeclarationId, - aliasId, - aliasDeclaration.aliasImportedTypeNameId); - } - } - - void updateAliasPropertyDeclarationValues(const AliasPropertyDeclarations &aliasDeclarations) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"update alias property declarations"_t, - projectStorageCategory(), - keyValue("alias property declarations", aliasDeclarations)}; - - for (const auto &aliasDeclaration : aliasDeclarations) { - updatetPropertiesDeclarationValuesOfAliasStatement.write( - aliasDeclaration.propertyDeclarationId); - updatePropertyAliasDeclarationRecursivelyStatement.write( - aliasDeclaration.propertyDeclarationId); - } - } - - void checkAliasPropertyDeclarationCycles(const AliasPropertyDeclarations &aliasDeclarations) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"check alias property declarations cycles"_t, - projectStorageCategory(), - keyValue("alias property declarations", aliasDeclarations)}; - for (const auto &aliasDeclaration : aliasDeclarations) - checkForAliasChainCycle(aliasDeclaration.propertyDeclarationId); - } + void checkAliasPropertyDeclarationCycles(const AliasPropertyDeclarations &aliasDeclarations); void linkAliases(const AliasPropertyDeclarations &insertedAliasPropertyDeclarations, - const AliasPropertyDeclarations &updatedAliasPropertyDeclarations) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"link aliases"_t, projectStorageCategory()}; - - linkAliasPropertyDeclarationAliasIds(insertedAliasPropertyDeclarations); - linkAliasPropertyDeclarationAliasIds(updatedAliasPropertyDeclarations); - - checkAliasPropertyDeclarationCycles(insertedAliasPropertyDeclarations); - checkAliasPropertyDeclarationCycles(updatedAliasPropertyDeclarations); - - updateAliasPropertyDeclarationValues(insertedAliasPropertyDeclarations); - updateAliasPropertyDeclarationValues(updatedAliasPropertyDeclarations); - } + const AliasPropertyDeclarations &updatedAliasPropertyDeclarations); void synchronizeExportedTypes(const TypeIds &updatedTypeIds, Storage::Synchronization::ExportedTypes &exportedTypes, AliasPropertyDeclarations &relinkableAliasPropertyDeclarations, PropertyDeclarations &relinkablePropertyDeclarations, Prototypes &relinkablePrototypes, - Prototypes &relinkableExtensions) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"synchronize exported types"_t, projectStorageCategory()}; - - std::sort(exportedTypes.begin(), exportedTypes.end(), [](auto &&first, auto &&second) { - if (first.moduleId < second.moduleId) - return true; - else if (first.moduleId > second.moduleId) - return false; - - auto nameCompare = Sqlite::compare(first.name, second.name); - - if (nameCompare < 0) - return true; - else if (nameCompare > 0) - return false; - - return first.version < second.version; - }); - - auto range = selectExportedTypesForSourceIdsStatement - .template range<Storage::Synchronization::ExportedTypeView>( - toIntegers(updatedTypeIds)); - - auto compareKey = [](const Storage::Synchronization::ExportedTypeView &view, - const Storage::Synchronization::ExportedType &type) -> long long { - auto moduleIdDifference = view.moduleId - type.moduleId; - if (moduleIdDifference != 0) - return moduleIdDifference; - - auto nameDifference = Sqlite::compare(view.name, type.name); - if (nameDifference != 0) - return nameDifference; - - auto versionDifference = view.version.major.value - type.version.major.value; - if (versionDifference != 0) - return versionDifference; - - return view.version.minor.value - type.version.minor.value; - }; - - auto insert = [&](const Storage::Synchronization::ExportedType &type) { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"insert exported type"_t, - projectStorageCategory(), - keyValue("exported type", type), - keyValue("type id", type.typeId), - keyValue("module id", type.moduleId)}; - if (!type.moduleId) - throw QmlDesigner::ModuleDoesNotExists{}; - - try { - if (type.version) { - insertExportedTypeNamesWithVersionStatement.write(type.moduleId, - type.name, - type.version.major.value, - type.version.minor.value, - type.typeId); - - } else if (type.version.major) { - insertExportedTypeNamesWithMajorVersionStatement.write(type.moduleId, - type.name, - type.version.major.value, - type.typeId); - } else { - insertExportedTypeNamesWithoutVersionStatement.write(type.moduleId, - type.name, - type.typeId); - } - } catch (const Sqlite::ConstraintPreventsModification &) { - throw QmlDesigner::ExportedTypeCannotBeInserted{type.name}; - } - }; - - auto update = [&](const Storage::Synchronization::ExportedTypeView &view, - const Storage::Synchronization::ExportedType &type) { - if (view.typeId != type.typeId) { - NanotraceHR::Tracer tracer{"update exported type"_t, - projectStorageCategory(), - keyValue("exported type", type), - keyValue("exported type view", view), - keyValue("type id", type.typeId), - keyValue("module id", type.typeId)}; - - handlePropertyDeclarationWithPropertyType(view.typeId, relinkablePropertyDeclarations); - handleAliasPropertyDeclarationsWithPropertyType(view.typeId, - relinkableAliasPropertyDeclarations); - handlePrototypes(view.typeId, relinkablePrototypes); - handleExtensions(view.typeId, relinkableExtensions); - updateExportedTypeNameTypeIdStatement.write(view.exportedTypeNameId, type.typeId); - return Sqlite::UpdateChange::Update; - } - return Sqlite::UpdateChange::No; - }; - - auto remove = [&](const Storage::Synchronization::ExportedTypeView &view) { - NanotraceHR::Tracer tracer{"remove exported type"_t, - projectStorageCategory(), - keyValue("exported type", view), - keyValue("type id", view.typeId), - keyValue("module id", view.moduleId)}; - - handlePropertyDeclarationWithPropertyType(view.typeId, relinkablePropertyDeclarations); - handleAliasPropertyDeclarationsWithPropertyType(view.typeId, - relinkableAliasPropertyDeclarations); - handlePrototypes(view.typeId, relinkablePrototypes); - handleExtensions(view.typeId, relinkableExtensions); - deleteExportedTypeNameStatement.write(view.exportedTypeNameId); - }; - - Sqlite::insertUpdateDelete(range, exportedTypes, compareKey, insert, update, remove); - } + Prototypes &relinkableExtensions); void synchronizePropertyDeclarationsInsertAlias( AliasPropertyDeclarations &insertedAliasPropertyDeclarations, const Storage::Synchronization::PropertyDeclaration &value, SourceId sourceId, - TypeId typeId) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"insert property declaration to alias"_t, - projectStorageCategory(), - keyValue("property declaration", value)}; - - auto callback = [&](PropertyDeclarationId propertyDeclarationId) { - insertedAliasPropertyDeclarations.emplace_back(typeId, - propertyDeclarationId, - fetchImportedTypeNameId(value.typeName, - sourceId), - value.aliasPropertyName, - value.aliasPropertyNameTail); - return Sqlite::CallbackControl::Abort; - }; - - insertAliasPropertyDeclarationStatement.readCallback(callback, typeId, value.name); - } + TypeId typeId); - auto fetchPropertyDeclarationIds(TypeId baseTypeId) const - { - QVarLengthArray<PropertyDeclarationId, 128> propertyDeclarationIds; - - selectLocalPropertyDeclarationIdsForTypeStatement.readTo(propertyDeclarationIds, baseTypeId); - - auto range = selectPrototypeAndExtensionIdsStatement.template range<TypeId>(baseTypeId); - - for (TypeId prototype : range) { - selectLocalPropertyDeclarationIdsForTypeStatement.readTo(propertyDeclarationIds, - prototype); - } - - return propertyDeclarationIds; - } + QVarLengthArray<PropertyDeclarationId, 128> fetchPropertyDeclarationIds(TypeId baseTypeId) const; PropertyDeclarationId fetchNextPropertyDeclarationId(TypeId baseTypeId, - Utils::SmallStringView propertyName) const - { - auto range = selectPrototypeAndExtensionIdsStatement.template range<TypeId>(baseTypeId); - - for (TypeId prototype : range) { - auto propertyDeclarationId = selectPropertyDeclarationIdByTypeIdAndNameStatement - .template value<PropertyDeclarationId>(prototype, - propertyName); - - if (propertyDeclarationId) - return propertyDeclarationId; - } - - return PropertyDeclarationId{}; - } + Utils::SmallStringView propertyName) const; PropertyDeclarationId fetchPropertyDeclarationId(TypeId typeId, - Utils::SmallStringView propertyName) const - { - auto propertyDeclarationId = selectPropertyDeclarationIdByTypeIdAndNameStatement - .template value<PropertyDeclarationId>(typeId, propertyName); - - if (propertyDeclarationId) - return propertyDeclarationId; - - return fetchNextPropertyDeclarationId(typeId, propertyName); - } - - PropertyDeclarationId fetchNextDefaultPropertyDeclarationId(TypeId baseTypeId) const - { - auto range = selectPrototypeAndExtensionIdsStatement.template range<TypeId>(baseTypeId); - - for (TypeId prototype : range) { - auto propertyDeclarationId = selectDefaultPropertyDeclarationIdStatement - .template value<PropertyDeclarationId>(prototype); + Utils::SmallStringView propertyName) const; - if (propertyDeclarationId) - return propertyDeclarationId; - } - - return PropertyDeclarationId{}; - } + PropertyDeclarationId fetchNextDefaultPropertyDeclarationId(TypeId baseTypeId) const; - PropertyDeclarationId fetchDefaultPropertyDeclarationId(TypeId typeId) const - { - auto propertyDeclarationId = selectDefaultPropertyDeclarationIdStatement - .template value<PropertyDeclarationId>(typeId); - - if (propertyDeclarationId) - return propertyDeclarationId; - - return fetchNextDefaultPropertyDeclarationId(typeId); - } + PropertyDeclarationId fetchDefaultPropertyDeclarationId(TypeId typeId) const; void synchronizePropertyDeclarationsInsertProperty( - const Storage::Synchronization::PropertyDeclaration &value, SourceId sourceId, TypeId typeId) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"insert property declaration"_t, - projectStorageCategory(), - keyValue("property declaration", value)}; - - auto propertyImportedTypeNameId = fetchImportedTypeNameId(value.typeName, sourceId); - auto propertyTypeId = fetchTypeId(propertyImportedTypeNameId); - - if (!propertyTypeId) - throw TypeNameDoesNotExists{fetchImportedTypeName(propertyImportedTypeNameId), sourceId}; - - auto propertyDeclarationId = insertPropertyDeclarationStatement.template value<PropertyDeclarationId>( - typeId, value.name, propertyTypeId, value.traits, propertyImportedTypeNameId); - - auto nextPropertyDeclarationId = fetchNextPropertyDeclarationId(typeId, value.name); - if (nextPropertyDeclarationId) { - updateAliasIdPropertyDeclarationStatement.write(nextPropertyDeclarationId, - propertyDeclarationId); - updatePropertyAliasDeclarationRecursivelyWithTypeAndTraitsStatement - .write(propertyDeclarationId, propertyTypeId, value.traits); - } - } + const Storage::Synchronization::PropertyDeclaration &value, SourceId sourceId, TypeId typeId); void synchronizePropertyDeclarationsUpdateAlias( AliasPropertyDeclarations &updatedAliasPropertyDeclarations, const Storage::Synchronization::PropertyDeclarationView &view, const Storage::Synchronization::PropertyDeclaration &value, - SourceId sourceId) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"update property declaration to alias"_t, - projectStorageCategory(), - keyValue("property declaration", value), - keyValue("property declaration view", view)}; - - updatedAliasPropertyDeclarations.emplace_back(view.typeId, - view.id, - fetchImportedTypeNameId(value.typeName, sourceId), - value.aliasPropertyName, - value.aliasPropertyNameTail, - view.aliasId); - } + SourceId sourceId); - auto synchronizePropertyDeclarationsUpdateProperty( + Sqlite::UpdateChange synchronizePropertyDeclarationsUpdateProperty( const Storage::Synchronization::PropertyDeclarationView &view, const Storage::Synchronization::PropertyDeclaration &value, SourceId sourceId, - PropertyDeclarationIds &propertyDeclarationIds) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"update property declaration"_t, - projectStorageCategory(), - keyValue("property declaration", value), - keyValue("property declaration view", view)}; - - auto propertyImportedTypeNameId = fetchImportedTypeNameId(value.typeName, sourceId); - - auto propertyTypeId = fetchTypeId(propertyImportedTypeNameId); - - if (!propertyTypeId) - throw TypeNameDoesNotExists{fetchImportedTypeName(propertyImportedTypeNameId), sourceId}; - - if (view.traits == value.traits && propertyTypeId == view.typeId - && propertyImportedTypeNameId == view.typeNameId) - return Sqlite::UpdateChange::No; - - updatePropertyDeclarationStatement.write(view.id, - propertyTypeId, - value.traits, - propertyImportedTypeNameId); - updatePropertyAliasDeclarationRecursivelyWithTypeAndTraitsStatement.write(view.id, - propertyTypeId, - value.traits); - propertyDeclarationIds.push_back(view.id); - - tracer.end(keyValue("updated", "yes")); - - return Sqlite::UpdateChange::Update; - } + PropertyDeclarationIds &propertyDeclarationIds); void synchronizePropertyDeclarations( TypeId typeId, @@ -2607,73 +698,7 @@ private: SourceId sourceId, AliasPropertyDeclarations &insertedAliasPropertyDeclarations, AliasPropertyDeclarations &updatedAliasPropertyDeclarations, - PropertyDeclarationIds &propertyDeclarationIds) - { - NanotraceHR::Tracer tracer{"synchronize property declaration"_t, projectStorageCategory()}; - - std::sort(propertyDeclarations.begin(), - propertyDeclarations.end(), - [](auto &&first, auto &&second) { - return Sqlite::compare(first.name, second.name) < 0; - }); - - auto range = selectPropertyDeclarationsForTypeIdStatement - .template range<Storage::Synchronization::PropertyDeclarationView>(typeId); - - auto compareKey = [](const Storage::Synchronization::PropertyDeclarationView &view, - const Storage::Synchronization::PropertyDeclaration &value) { - return Sqlite::compare(view.name, value.name); - }; - - auto insert = [&](const Storage::Synchronization::PropertyDeclaration &value) { - if (value.kind == Storage::Synchronization::PropertyKind::Alias) { - synchronizePropertyDeclarationsInsertAlias(insertedAliasPropertyDeclarations, - value, - sourceId, - typeId); - } else { - synchronizePropertyDeclarationsInsertProperty(value, sourceId, typeId); - } - }; - - auto update = [&](const Storage::Synchronization::PropertyDeclarationView &view, - const Storage::Synchronization::PropertyDeclaration &value) { - if (value.kind == Storage::Synchronization::PropertyKind::Alias) { - synchronizePropertyDeclarationsUpdateAlias(updatedAliasPropertyDeclarations, - view, - value, - sourceId); - propertyDeclarationIds.push_back(view.id); - } else { - return synchronizePropertyDeclarationsUpdateProperty(view, - value, - sourceId, - propertyDeclarationIds); - } - - return Sqlite::UpdateChange::No; - }; - - auto remove = [&](const Storage::Synchronization::PropertyDeclarationView &view) { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"remove property declaration"_t, - projectStorageCategory(), - keyValue("property declaratio viewn", view)}; - - auto nextPropertyDeclarationId = fetchNextPropertyDeclarationId(typeId, view.name); - - if (nextPropertyDeclarationId) { - updateAliasPropertyDeclarationByAliasPropertyDeclarationIdStatement - .write(nextPropertyDeclarationId, view.id); - } - - updateDefaultPropertyIdToNullStatement.write(view.id); - deletePropertyDeclarationStatement.write(view.id); - propertyDeclarationIds.push_back(view.id); - }; - - Sqlite::insertUpdateDelete(range, propertyDeclarations, compareKey, insert, update, remove); - } + PropertyDeclarationIds &propertyDeclarationIds); class AliasPropertyDeclarationView { @@ -2706,237 +731,27 @@ private: }; void resetRemovedAliasPropertyDeclarationsToNull(Storage::Synchronization::Type &type, - PropertyDeclarationIds &propertyDeclarationIds) - { - NanotraceHR::Tracer tracer{"reset removed alias property declaration to null"_t, - projectStorageCategory()}; - - if (type.changeLevel == Storage::Synchronization::ChangeLevel::Minimal) - return; - - Storage::Synchronization::PropertyDeclarations &aliasDeclarations = type.propertyDeclarations; - - std::sort(aliasDeclarations.begin(), aliasDeclarations.end(), [](auto &&first, auto &&second) { - return Sqlite::compare(first.name, second.name) < 0; - }); - - auto range = selectPropertyDeclarationsWithAliasForTypeIdStatement - .template range<AliasPropertyDeclarationView>(type.typeId); - - auto compareKey = [](const AliasPropertyDeclarationView &view, - const Storage::Synchronization::PropertyDeclaration &value) { - return Sqlite::compare(view.name, value.name); - }; - - auto insert = [&](const Storage::Synchronization::PropertyDeclaration &) {}; - - auto update = [&](const AliasPropertyDeclarationView &, - const Storage::Synchronization::PropertyDeclaration &) { - return Sqlite::UpdateChange::No; - }; - - auto remove = [&](const AliasPropertyDeclarationView &view) { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"reset removed alias property declaration to null"_t, - projectStorageCategory(), - keyValue("alias property declaration view", view)}; - - updatePropertyDeclarationAliasIdToNullStatement.write(view.id); - propertyDeclarationIds.push_back(view.id); - }; - - Sqlite::insertUpdateDelete(range, aliasDeclarations, compareKey, insert, update, remove); - } + PropertyDeclarationIds &propertyDeclarationIds); void resetRemovedAliasPropertyDeclarationsToNull( Storage::Synchronization::Types &types, - AliasPropertyDeclarations &relinkableAliasPropertyDeclarations) - { - NanotraceHR::Tracer tracer{"reset removed alias properties to null"_t, - projectStorageCategory()}; - - PropertyDeclarationIds propertyDeclarationIds; - propertyDeclarationIds.reserve(types.size()); - - for (auto &&type : types) - resetRemovedAliasPropertyDeclarationsToNull(type, propertyDeclarationIds); - - removeRelinkableEntries(relinkableAliasPropertyDeclarations, - propertyDeclarationIds, - PropertyCompare<AliasPropertyDeclaration>{}); - } + AliasPropertyDeclarations &relinkableAliasPropertyDeclarations); ImportId insertDocumentImport(const Storage::Import &import, Storage::Synchronization::ImportKind importKind, ModuleId sourceModuleId, - ImportId parentImportId) - { - if (import.version.minor) { - return insertDocumentImportWithVersionStatement - .template value<ImportId>(import.sourceId, - import.moduleId, - sourceModuleId, - importKind, - import.version.major.value, - import.version.minor.value, - parentImportId); - } else if (import.version.major) { - return insertDocumentImportWithMajorVersionStatement - .template value<ImportId>(import.sourceId, - import.moduleId, - sourceModuleId, - importKind, - import.version.major.value, - parentImportId); - } else { - return insertDocumentImportWithoutVersionStatement.template value<ImportId>( - import.sourceId, import.moduleId, sourceModuleId, importKind, parentImportId); - } - } + ImportId parentImportId); void synchronizeDocumentImports(Storage::Imports &imports, const SourceIds &updatedSourceIds, - Storage::Synchronization::ImportKind importKind) - { - std::sort(imports.begin(), imports.end(), [](auto &&first, auto &&second) { - return std::tie(first.sourceId, first.moduleId, first.version) - < std::tie(second.sourceId, second.moduleId, second.version); - }); - - auto range = selectDocumentImportForSourceIdStatement - .template range<Storage::Synchronization::ImportView>(toIntegers( - updatedSourceIds), - importKind); - - auto compareKey = [](const Storage::Synchronization::ImportView &view, - const Storage::Import &import) -> long long { - auto sourceIdDifference = view.sourceId - import.sourceId; - if (sourceIdDifference != 0) - return sourceIdDifference; - - auto moduleIdDifference = view.moduleId - import.moduleId; - if (moduleIdDifference != 0) - return moduleIdDifference; - - auto versionDifference = view.version.major.value - import.version.major.value; - if (versionDifference != 0) - return versionDifference; + Storage::Synchronization::ImportKind importKind); - return view.version.minor.value - import.version.minor.value; - }; - - auto insert = [&](const Storage::Import &import) { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"insert import"_t, - projectStorageCategory(), - keyValue("import", import), - keyValue("import kind", importKind), - keyValue("source id", import.sourceId), - keyValue("module id", import.moduleId)}; - - auto importId = insertDocumentImport(import, importKind, import.moduleId, ImportId{}); - auto callback = [&](ModuleId exportedModuleId, int majorVersion, int minorVersion) { - Storage::Import additionImport{exportedModuleId, - Storage::Version{majorVersion, minorVersion}, - import.sourceId}; - - auto exportedImportKind = importKind == Storage::Synchronization::ImportKind::Import - ? Storage::Synchronization::ImportKind::ModuleExportedImport - : Storage::Synchronization::ImportKind::ModuleExportedModuleDependency; - - NanotraceHR::Tracer tracer{"insert indirect import"_t, - projectStorageCategory(), - keyValue("import", import), - keyValue("import kind", exportedImportKind), - keyValue("source id", import.sourceId), - keyValue("module id", import.moduleId)}; - - auto indirectImportId = insertDocumentImport(additionImport, - exportedImportKind, - import.moduleId, - importId); - - tracer.end(keyValue("import id", indirectImportId)); - }; - - selectModuleExportedImportsForModuleIdStatement.readCallback(callback, - import.moduleId, - import.version.major.value, - import.version.minor.value); - tracer.end(keyValue("import id", importId)); - }; - - auto update = [](const Storage::Synchronization::ImportView &, const Storage::Import &) { - return Sqlite::UpdateChange::No; - }; - - auto remove = [&](const Storage::Synchronization::ImportView &view) { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"remove import"_t, - projectStorageCategory(), - keyValue("import", view), - keyValue("import id", view.importId), - keyValue("source id", view.sourceId), - keyValue("module id", view.moduleId)}; - - deleteDocumentImportStatement.write(view.importId); - deleteDocumentImportsWithParentImportIdStatement.write(view.sourceId, view.importId); - }; - - Sqlite::insertUpdateDelete(range, imports, compareKey, insert, update, remove); - } - - static Utils::PathString createJson(const Storage::Synchronization::ParameterDeclarations ¶meters) - { - NanotraceHR::Tracer tracer{"create json from parameter declarations"_t, - projectStorageCategory()}; - - Utils::PathString json; - json.append("["); - - Utils::SmallStringView comma{""}; - - for (const auto ¶meter : parameters) { - json.append(comma); - comma = ","; - json.append(R"({"n":")"); - json.append(parameter.name); - json.append(R"(","tn":")"); - json.append(parameter.typeName); - if (parameter.traits == Storage::PropertyDeclarationTraits::None) { - json.append("\"}"); - } else { - json.append(R"(","tr":)"); - json.append(Utils::SmallString::number(to_underlying(parameter.traits))); - json.append("}"); - } - } - - json.append("]"); - - return json; - } + static Utils::PathString createJson(const Storage::Synchronization::ParameterDeclarations ¶meters); TypeId fetchTypeIdByModuleIdAndExportedName(ModuleId moduleId, - Utils::SmallStringView name) const override - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"fetch type id by module id and exported name"_t, - projectStorageCategory(), - keyValue("module id", moduleId), - keyValue("exported name", name)}; + Utils::SmallStringView name) const override; - return selectTypeIdByModuleIdAndExportedNameStatement.template value<TypeId>(moduleId, name); - } - - void addTypeIdToPropertyEditorQmlPaths(Storage::Synchronization::PropertyEditorQmlPaths &paths) - { - NanotraceHR::Tracer tracer{"add type id to property editor qml paths"_t, - projectStorageCategory()}; - - for (auto &path : paths) - path.typeId = fetchTypeIdByModuleIdAndExportedName(path.moduleId, path.typeName); - } + void addTypeIdToPropertyEditorQmlPaths(Storage::Synchronization::PropertyEditorQmlPaths &paths); class PropertyEditorQmlPathView { @@ -2967,358 +782,33 @@ private: }; void synchronizePropertyEditorPaths(Storage::Synchronization::PropertyEditorQmlPaths &paths, - SourceIds updatedPropertyEditorQmlPathsSourceIds) - { - using Storage::Synchronization::PropertyEditorQmlPath; - std::sort(paths.begin(), paths.end(), [](auto &&first, auto &&second) { - return first.typeId < second.typeId; - }); - - auto range = selectPropertyEditorPathsForForSourceIdsStatement - .template range<PropertyEditorQmlPathView>( - toIntegers(updatedPropertyEditorQmlPathsSourceIds)); - - auto compareKey = [](const PropertyEditorQmlPathView &view, - const PropertyEditorQmlPath &value) -> long long { - return view.typeId - value.typeId; - }; - - auto insert = [&](const PropertyEditorQmlPath &path) { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"insert property editor paths"_t, - projectStorageCategory(), - keyValue("property editor qml path", path)}; - - if (path.typeId) - insertPropertyEditorPathStatement.write(path.typeId, path.pathId, path.directoryId); - }; - - auto update = [&](const PropertyEditorQmlPathView &view, const PropertyEditorQmlPath &value) { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"update property editor paths"_t, - projectStorageCategory(), - keyValue("property editor qml path", value), - keyValue("property editor qml path view", view)}; - - if (value.pathId != view.pathId || value.directoryId != view.directoryId) { - updatePropertyEditorPathsStatement.write(value.typeId, value.pathId, value.directoryId); - - tracer.end(keyValue("updated", "yes")); - - return Sqlite::UpdateChange::Update; - } - return Sqlite::UpdateChange::No; - }; - - auto remove = [&](const PropertyEditorQmlPathView &view) { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"remove property editor paths"_t, - projectStorageCategory(), - keyValue("property editor qml path view", view)}; - - deletePropertyEditorPathStatement.write(view.typeId); - }; - - Sqlite::insertUpdateDelete(range, paths, compareKey, insert, update, remove); - } + SourceIds updatedPropertyEditorQmlPathsSourceIds); void synchronizePropertyEditorQmlPaths(Storage::Synchronization::PropertyEditorQmlPaths &paths, - SourceIds updatedPropertyEditorQmlPathsSourceIds) - { - NanotraceHR::Tracer tracer{"synchronize property editor qml paths"_t, - projectStorageCategory()}; - - addTypeIdToPropertyEditorQmlPaths(paths); - synchronizePropertyEditorPaths(paths, updatedPropertyEditorQmlPathsSourceIds); - } + SourceIds updatedPropertyEditorQmlPathsSourceIds); void synchronizeFunctionDeclarations( - TypeId typeId, Storage::Synchronization::FunctionDeclarations &functionsDeclarations) - { - NanotraceHR::Tracer tracer{"synchronize function declaration"_t, projectStorageCategory()}; - - std::sort(functionsDeclarations.begin(), - functionsDeclarations.end(), - [](auto &&first, auto &&second) { - auto compare = Sqlite::compare(first.name, second.name); - - if (compare == 0) { - Utils::PathString firstSignature{createJson(first.parameters)}; - Utils::PathString secondSignature{createJson(second.parameters)}; - - return Sqlite::compare(firstSignature, secondSignature) < 0; - } - - return compare < 0; - }); - - auto range = selectFunctionDeclarationsForTypeIdStatement - .template range<Storage::Synchronization::FunctionDeclarationView>(typeId); - - auto compareKey = [](const Storage::Synchronization::FunctionDeclarationView &view, - const Storage::Synchronization::FunctionDeclaration &value) { - auto nameKey = Sqlite::compare(view.name, value.name); - if (nameKey != 0) - return nameKey; - - Utils::PathString valueSignature{createJson(value.parameters)}; - - return Sqlite::compare(view.signature, valueSignature); - }; - - auto insert = [&](const Storage::Synchronization::FunctionDeclaration &value) { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"insert function declaration"_t, - projectStorageCategory(), - keyValue("function declaration", value)}; - - Utils::PathString signature{createJson(value.parameters)}; - - insertFunctionDeclarationStatement.write(typeId, value.name, value.returnTypeName, signature); - }; - - auto update = [&](const Storage::Synchronization::FunctionDeclarationView &view, - const Storage::Synchronization::FunctionDeclaration &value) { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"update function declaration"_t, - projectStorageCategory(), - keyValue("function declaration", value), - keyValue("function declaration view", view)}; - - Utils::PathString signature{createJson(value.parameters)}; - - if (value.returnTypeName == view.returnTypeName) - return Sqlite::UpdateChange::No; - - updateFunctionDeclarationStatement.write(view.id, value.returnTypeName); - - tracer.end(keyValue("updated", "yes")); - - return Sqlite::UpdateChange::Update; - }; - - auto remove = [&](const Storage::Synchronization::FunctionDeclarationView &view) { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"remove function declaration"_t, - projectStorageCategory(), - keyValue("function declaration view", view)}; - - deleteFunctionDeclarationStatement.write(view.id); - }; - - Sqlite::insertUpdateDelete(range, functionsDeclarations, compareKey, insert, update, remove); - } + TypeId typeId, Storage::Synchronization::FunctionDeclarations &functionsDeclarations); void synchronizeSignalDeclarations(TypeId typeId, - Storage::Synchronization::SignalDeclarations &signalDeclarations) - { - NanotraceHR::Tracer tracer{"synchronize signal declaration"_t, projectStorageCategory()}; - - std::sort(signalDeclarations.begin(), signalDeclarations.end(), [](auto &&first, auto &&second) { - auto compare = Sqlite::compare(first.name, second.name); - - if (compare == 0) { - Utils::PathString firstSignature{createJson(first.parameters)}; - Utils::PathString secondSignature{createJson(second.parameters)}; - - return Sqlite::compare(firstSignature, secondSignature) < 0; - } - - return compare < 0; - }); - - auto range = selectSignalDeclarationsForTypeIdStatement - .template range<Storage::Synchronization::SignalDeclarationView>(typeId); - - auto compareKey = [](const Storage::Synchronization::SignalDeclarationView &view, - const Storage::Synchronization::SignalDeclaration &value) { - auto nameKey = Sqlite::compare(view.name, value.name); - if (nameKey != 0) - return nameKey; - - Utils::PathString valueSignature{createJson(value.parameters)}; - - return Sqlite::compare(view.signature, valueSignature); - }; - - auto insert = [&](const Storage::Synchronization::SignalDeclaration &value) { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"insert signal declaration"_t, - projectStorageCategory(), - keyValue("signal declaration", value)}; - - Utils::PathString signature{createJson(value.parameters)}; - - insertSignalDeclarationStatement.write(typeId, value.name, signature); - }; - - auto update = [&]([[maybe_unused]] const Storage::Synchronization::SignalDeclarationView &view, - [[maybe_unused]] const Storage::Synchronization::SignalDeclaration &value) { - return Sqlite::UpdateChange::No; - }; - - auto remove = [&](const Storage::Synchronization::SignalDeclarationView &view) { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"remove signal declaration"_t, - projectStorageCategory(), - keyValue("signal declaration view", view)}; - - deleteSignalDeclarationStatement.write(view.id); - }; - - Sqlite::insertUpdateDelete(range, signalDeclarations, compareKey, insert, update, remove); - } + Storage::Synchronization::SignalDeclarations &signalDeclarations); static Utils::PathString createJson( - const Storage::Synchronization::EnumeratorDeclarations &enumeratorDeclarations) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"create json from enumerator declarations"_t, - projectStorageCategory()}; - - Utils::PathString json; - json.append("{"); - - Utils::SmallStringView comma{"\""}; - - for (const auto &enumerator : enumeratorDeclarations) { - json.append(comma); - comma = ",\""; - json.append(enumerator.name); - if (enumerator.hasValue) { - json.append("\":\""); - json.append(Utils::SmallString::number(enumerator.value)); - json.append("\""); - } else { - json.append("\":null"); - } - } - - json.append("}"); - - return json; - } + const Storage::Synchronization::EnumeratorDeclarations &enumeratorDeclarations); void synchronizeEnumerationDeclarations( - TypeId typeId, Storage::Synchronization::EnumerationDeclarations &enumerationDeclarations) - { - NanotraceHR::Tracer tracer{"synchronize enumeration declaration"_t, projectStorageCategory()}; - - std::sort(enumerationDeclarations.begin(), - enumerationDeclarations.end(), - [](auto &&first, auto &&second) { - return Sqlite::compare(first.name, second.name) < 0; - }); - - auto range = selectEnumerationDeclarationsForTypeIdStatement - .template range<Storage::Synchronization::EnumerationDeclarationView>(typeId); - - auto compareKey = [](const Storage::Synchronization::EnumerationDeclarationView &view, - const Storage::Synchronization::EnumerationDeclaration &value) { - return Sqlite::compare(view.name, value.name); - }; - - auto insert = [&](const Storage::Synchronization::EnumerationDeclaration &value) { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"insert enumeration declaration"_t, - projectStorageCategory(), - keyValue("enumeration declaration", value)}; - - Utils::PathString signature{createJson(value.enumeratorDeclarations)}; - - insertEnumerationDeclarationStatement.write(typeId, value.name, signature); - }; - - auto update = [&](const Storage::Synchronization::EnumerationDeclarationView &view, - const Storage::Synchronization::EnumerationDeclaration &value) { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"update enumeration declaration"_t, - projectStorageCategory(), - keyValue("enumeration declaration", value), - keyValue("enumeration declaration view", view)}; - - Utils::PathString enumeratorDeclarations{createJson(value.enumeratorDeclarations)}; - - if (enumeratorDeclarations == view.enumeratorDeclarations) - return Sqlite::UpdateChange::No; - - updateEnumerationDeclarationStatement.write(view.id, enumeratorDeclarations); - - tracer.end(keyValue("updated", "yes")); - - return Sqlite::UpdateChange::Update; - }; - - auto remove = [&](const Storage::Synchronization::EnumerationDeclarationView &view) { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"remove enumeration declaration"_t, - projectStorageCategory(), - keyValue("enumeration declaration view", view)}; - - deleteEnumerationDeclarationStatement.write(view.id); - }; - - Sqlite::insertUpdateDelete(range, enumerationDeclarations, compareKey, insert, update, remove); - } + TypeId typeId, Storage::Synchronization::EnumerationDeclarations &enumerationDeclarations); void extractExportedTypes(TypeId typeId, const Storage::Synchronization::Type &type, - Storage::Synchronization::ExportedTypes &exportedTypes) - { - for (const auto &exportedType : type.exportedTypes) - exportedTypes.emplace_back(exportedType.name, - exportedType.version, - typeId, - exportedType.moduleId); - } - - TypeId declareType(Storage::Synchronization::Type &type) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"declare type"_t, - projectStorageCategory(), - keyValue("source id", type.sourceId), - keyValue("type name", type.typeName)}; - - if (type.typeName.isEmpty()) { - type.typeId = selectTypeIdBySourceIdStatement.template value<TypeId>(type.sourceId); + Storage::Synchronization::ExportedTypes &exportedTypes); - tracer.end(keyValue("type id", type.typeId)); - - return type.typeId; - } - - type.typeId = insertTypeStatement.template value<TypeId>(type.sourceId, type.typeName); - - if (!type.typeId) - type.typeId = selectTypeIdBySourceIdAndNameStatement.template value<TypeId>(type.sourceId, - type.typeName); - - tracer.end(keyValue("type id", type.typeId)); - - return type.typeId; - } + TypeId declareType(Storage::Synchronization::Type &type); void syncDeclarations(Storage::Synchronization::Type &type, AliasPropertyDeclarations &insertedAliasPropertyDeclarations, AliasPropertyDeclarations &updatedAliasPropertyDeclarations, - PropertyDeclarationIds &propertyDeclarationIds) - { - NanotraceHR::Tracer tracer{"synchronize declaration per type"_t, projectStorageCategory()}; - - if (type.changeLevel == Storage::Synchronization::ChangeLevel::Minimal) - return; - - synchronizePropertyDeclarations(type.typeId, - type.propertyDeclarations, - type.sourceId, - insertedAliasPropertyDeclarations, - updatedAliasPropertyDeclarations, - propertyDeclarationIds); - synchronizeFunctionDeclarations(type.typeId, type.functionDeclarations); - synchronizeSignalDeclarations(type.typeId, type.signalDeclarations); - synchronizeEnumerationDeclarations(type.typeId, type.enumerationDeclarations); - } + PropertyDeclarationIds &propertyDeclarationIds); template<typename Relinkable, typename Ids, typename Compare> void removeRelinkableEntries(std::vector<Relinkable> &relinkables, Ids &ids, Compare compare) @@ -3345,23 +835,7 @@ private: void syncDeclarations(Storage::Synchronization::Types &types, AliasPropertyDeclarations &insertedAliasPropertyDeclarations, AliasPropertyDeclarations &updatedAliasPropertyDeclarations, - PropertyDeclarations &relinkablePropertyDeclarations) - { - NanotraceHR::Tracer tracer{"synchronize declaration"_t, projectStorageCategory()}; - - PropertyDeclarationIds propertyDeclarationIds; - propertyDeclarationIds.reserve(types.size() * 10); - - for (auto &&type : types) - syncDeclarations(type, - insertedAliasPropertyDeclarations, - updatedAliasPropertyDeclarations, - propertyDeclarationIds); - - removeRelinkableEntries(relinkablePropertyDeclarations, - propertyDeclarationIds, - PropertyCompare<PropertyDeclaration>{}); - } + PropertyDeclarations &relinkablePropertyDeclarations); class TypeWithDefaultPropertyView { @@ -3386,279 +860,27 @@ private: PropertyDeclarationId defaultPropertyId; }; - void syncDefaultProperties(Storage::Synchronization::Types &types) - { - NanotraceHR::Tracer tracer{"synchronize default properties"_t, projectStorageCategory()}; - - auto range = selectTypesWithDefaultPropertyStatement.template range<TypeWithDefaultPropertyView>(); - - auto compareKey = [](const TypeWithDefaultPropertyView &view, - const Storage::Synchronization::Type &value) { - return view.typeId - value.typeId; - }; + void syncDefaultProperties(Storage::Synchronization::Types &types); - auto insert = [&](const Storage::Synchronization::Type &) { + void resetDefaultPropertiesIfChanged(Storage::Synchronization::Types &types); - }; + void checkForPrototypeChainCycle(TypeId typeId) const; - auto update = [&](const TypeWithDefaultPropertyView &view, - const Storage::Synchronization::Type &value) { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"synchronize default properties by update"_t, - projectStorageCategory(), - keyValue("type id", value.typeId), - keyValue("value", value), - keyValue("view", view)}; - - PropertyDeclarationId valueDefaultPropertyId; - if (value.defaultPropertyName.size()) - valueDefaultPropertyId = fetchPropertyDeclarationByTypeIdAndNameUngarded( - value.typeId, value.defaultPropertyName) - .propertyDeclarationId; - - if (compareInvalidAreTrue(valueDefaultPropertyId, view.defaultPropertyId)) - return Sqlite::UpdateChange::No; - - updateDefaultPropertyIdStatement.write(value.typeId, valueDefaultPropertyId); - - tracer.end(keyValue("updated", "yes"), - keyValue("default property id", valueDefaultPropertyId)); - - return Sqlite::UpdateChange::Update; - }; - - auto remove = [&](const TypeWithDefaultPropertyView &) {}; - - Sqlite::insertUpdateDelete(range, types, compareKey, insert, update, remove); - } - - void resetDefaultPropertiesIfChanged(Storage::Synchronization::Types &types) - { - NanotraceHR::Tracer tracer{"reset changed default properties"_t, projectStorageCategory()}; - - auto range = selectTypesWithDefaultPropertyStatement.template range<TypeWithDefaultPropertyView>(); - - auto compareKey = [](const TypeWithDefaultPropertyView &view, - const Storage::Synchronization::Type &value) { - return view.typeId - value.typeId; - }; - - auto insert = [&](const Storage::Synchronization::Type &) { - - }; - - auto update = [&](const TypeWithDefaultPropertyView &view, - const Storage::Synchronization::Type &value) { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"reset changed default properties by update"_t, - projectStorageCategory(), - keyValue("type id", value.typeId), - keyValue("value", value), - keyValue("view", view)}; - - PropertyDeclarationId valueDefaultPropertyId; - if (value.defaultPropertyName.size()) { - auto optionalValueDefaultPropertyId = fetchOptionalPropertyDeclarationByTypeIdAndNameUngarded( - value.typeId, value.defaultPropertyName); - if (optionalValueDefaultPropertyId) - valueDefaultPropertyId = optionalValueDefaultPropertyId->propertyDeclarationId; - } - - if (compareInvalidAreTrue(valueDefaultPropertyId, view.defaultPropertyId)) - return Sqlite::UpdateChange::No; - - updateDefaultPropertyIdStatement.write(value.typeId, Sqlite::NullValue{}); - - tracer.end(keyValue("updated", "yes")); - - return Sqlite::UpdateChange::Update; - }; - - auto remove = [&](const TypeWithDefaultPropertyView &) {}; - - Sqlite::insertUpdateDelete(range, types, compareKey, insert, update, remove); - } - - void checkForPrototypeChainCycle(TypeId typeId) const - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"check for prototype chain cycle"_t, - projectStorageCategory(), - keyValue("type id", typeId)}; - - auto callback = [=](TypeId currentTypeId) { - if (typeId == currentTypeId) - throw PrototypeChainCycle{}; - }; - - selectPrototypeAndExtensionIdsStatement.readCallback(callback, typeId); - } - - void checkForAliasChainCycle(PropertyDeclarationId propertyDeclarationId) const - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"check for alias chain cycle"_t, - projectStorageCategory(), - keyValue("property declaration id", propertyDeclarationId)}; - auto callback = [=](PropertyDeclarationId currentPropertyDeclarationId) { - if (propertyDeclarationId == currentPropertyDeclarationId) - throw AliasChainCycle{}; - }; - - selectPropertyDeclarationIdsForAliasChainStatement.readCallback(callback, - propertyDeclarationId); - } + void checkForAliasChainCycle(PropertyDeclarationId propertyDeclarationId) const; std::pair<TypeId, ImportedTypeNameId> fetchImportedTypeNameIdAndTypeId( - const Storage::Synchronization::ImportedTypeName &typeName, SourceId sourceId) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"fetch imported type name id and type id"_t, - projectStorageCategory(), - keyValue("imported type name", typeName), - keyValue("source id", sourceId)}; - - TypeId typeId; - ImportedTypeNameId typeNameId; - if (!std::visit([](auto &&typeName_) -> bool { return typeName_.name.isEmpty(); }, typeName)) { - typeNameId = fetchImportedTypeNameId(typeName, sourceId); - - typeId = fetchTypeId(typeNameId); + const Storage::Synchronization::ImportedTypeName &typeName, SourceId sourceId); - tracer.end(keyValue("type id", typeId), keyValue("type name id", typeNameId)); - - if (!typeId) - throw TypeNameDoesNotExists{fetchImportedTypeName(typeNameId), sourceId}; - } - - return {typeId, typeNameId}; - } - - void syncPrototypeAndExtension(Storage::Synchronization::Type &type, TypeIds &typeIds) - { - if (type.changeLevel == Storage::Synchronization::ChangeLevel::Minimal) - return; - - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"synchronize prototype and extension"_t, - projectStorageCategory(), - keyValue("prototype", type.prototype), - keyValue("extension", type.extension), - keyValue("type id", type.typeId), - keyValue("source id", type.sourceId)}; - - auto [prototypeId, prototypeTypeNameId] = fetchImportedTypeNameIdAndTypeId(type.prototype, - type.sourceId); - auto [extensionId, extensionTypeNameId] = fetchImportedTypeNameIdAndTypeId(type.extension, - type.sourceId); - - updatePrototypeAndExtensionStatement.write(type.typeId, - prototypeId, - prototypeTypeNameId, - extensionId, - extensionTypeNameId); - - if (prototypeId || extensionId) - checkForPrototypeChainCycle(type.typeId); - - typeIds.push_back(type.typeId); - - tracer.end(keyValue("prototype id", prototypeId), - keyValue("prototype type name id", prototypeTypeNameId), - keyValue("extension id", extensionId), - keyValue("extension type name id", extensionTypeNameId)); - } + void syncPrototypeAndExtension(Storage::Synchronization::Type &type, TypeIds &typeIds); void syncPrototypesAndExtensions(Storage::Synchronization::Types &types, Prototypes &relinkablePrototypes, - Prototypes &relinkableExtensions) - { - NanotraceHR::Tracer tracer{"synchronize prototypes and extensions"_t, - projectStorageCategory()}; + Prototypes &relinkableExtensions); - TypeIds typeIds; - typeIds.reserve(types.size()); - - for (auto &type : types) - syncPrototypeAndExtension(type, typeIds); - - removeRelinkableEntries(relinkablePrototypes, typeIds, TypeCompare<Prototype>{}); - removeRelinkableEntries(relinkableExtensions, typeIds, TypeCompare<Prototype>{}); - } - - ImportId fetchImportId(SourceId sourceId, const Storage::Import &import) const - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"fetch imported type name id"_t, - projectStorageCategory(), - keyValue("import", import), - keyValue("source id", sourceId)}; - - ImportId importId; - if (import.version) { - importId = selectImportIdBySourceIdAndModuleIdAndVersionStatement.template value<ImportId>( - sourceId, import.moduleId, import.version.major.value, import.version.minor.value); - } else if (import.version.major) { - importId = selectImportIdBySourceIdAndModuleIdAndMajorVersionStatement - .template value<ImportId>(sourceId, - import.moduleId, - import.version.major.value); - } else { - importId = selectImportIdBySourceIdAndModuleIdStatement - .template value<ImportId>(sourceId, import.moduleId); - } - - tracer.end(keyValue("import id", importId)); - - return importId; - } + ImportId fetchImportId(SourceId sourceId, const Storage::Import &import) const; ImportedTypeNameId fetchImportedTypeNameId(const Storage::Synchronization::ImportedTypeName &name, - SourceId sourceId) - { - struct Inspect - { - auto operator()(const Storage::Synchronization::ImportedType &importedType) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"fetch imported type name id"_t, - projectStorageCategory(), - keyValue("imported type name", importedType.name), - keyValue("source id", sourceId), - keyValue("type name kind", "exported"sv)}; - - return storage.fetchImportedTypeNameId(Storage::Synchronization::TypeNameKind::Exported, - sourceId, - importedType.name); - } - - auto operator()(const Storage::Synchronization::QualifiedImportedType &importedType) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"fetch imported type name id"_t, - projectStorageCategory(), - keyValue("imported type name", importedType.name), - keyValue("import", importedType.import), - keyValue("type name kind", "qualified exported"sv)}; - - ImportId importId = storage.fetchImportId(sourceId, importedType.import); - - auto importedTypeNameId = storage.fetchImportedTypeNameId( - Storage::Synchronization::TypeNameKind::QualifiedExported, - importId, - importedType.name); - - tracer.end(keyValue("import id", importId), keyValue("source id", sourceId)); - - return importedTypeNameId; - } - - ProjectStorage &storage; - SourceId sourceId; - }; - - return std::visit(Inspect{*this, sourceId}, name); - } + SourceId sourceId); template<typename Id> ImportedTypeNameId fetchImportedTypeNameId(Storage::Synchronization::TypeNameKind kind, @@ -3671,60 +893,26 @@ private: keyValue("imported type name", typeName), keyValue("kind", kind)}; - auto importedTypeNameId = selectImportedTypeNameIdStatement - .template value<ImportedTypeNameId>(kind, id, typeName); + auto importedTypeNameId = selectImportedTypeNameIdStatement.value<ImportedTypeNameId>(kind, + id, + typeName); if (!importedTypeNameId) - importedTypeNameId = insertImportedTypeNameIdStatement - .template value<ImportedTypeNameId>(kind, id, typeName); + importedTypeNameId = insertImportedTypeNameIdStatement.value<ImportedTypeNameId>(kind, + id, + typeName); tracer.end(keyValue("imported type name id", importedTypeNameId)); return importedTypeNameId; } - TypeId fetchTypeId(ImportedTypeNameId typeNameId) const - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"fetch type id with type name kind"_t, - projectStorageCategory(), - keyValue("type name id", typeNameId)}; - - auto kind = selectKindFromImportedTypeNamesStatement - .template value<Storage::Synchronization::TypeNameKind>(typeNameId); - - auto typeId = fetchTypeId(typeNameId, kind); - - tracer.end(keyValue("type id", typeId), keyValue("type name kind", kind)); - - return typeId; - } - - Utils::SmallString fetchImportedTypeName(ImportedTypeNameId typeNameId) const - { - return selectNameFromImportedTypeNamesStatement.template value<Utils::SmallString>(typeNameId); - } + TypeId fetchTypeId(ImportedTypeNameId typeNameId) const; - TypeId fetchTypeId(ImportedTypeNameId typeNameId, Storage::Synchronization::TypeNameKind kind) const - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"fetch type id"_t, - projectStorageCategory(), - keyValue("type name id", typeNameId), - keyValue("type name kind", kind)}; + Utils::SmallString fetchImportedTypeName(ImportedTypeNameId typeNameId) const; - TypeId typeId; - if (kind == Storage::Synchronization::TypeNameKind::Exported) { - typeId = selectTypeIdForImportedTypeNameNamesStatement.template value<TypeId>(typeNameId); - } else { - typeId = selectTypeIdForQualifiedImportedTypeNameNamesStatement.template value<TypeId>( - typeNameId); - } - - tracer.end(keyValue("type id", typeId)); - - return typeId; - } + TypeId fetchTypeId(ImportedTypeNameId typeNameId, + Storage::Synchronization::TypeNameKind kind) const; class FetchPropertyDeclarationResult { @@ -3755,641 +943,41 @@ private: Storage::PropertyDeclarationTraits propertyTraits; }; - auto fetchOptionalPropertyDeclarationByTypeIdAndNameUngarded(TypeId typeId, - Utils::SmallStringView name) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"fetch optional property declaration by type id and name ungarded"_t, - projectStorageCategory(), - keyValue("type id", typeId), - keyValue("property name", name)}; - - auto propertyDeclarationId = fetchPropertyDeclarationId(typeId, name); - auto propertyDeclaration = selectPropertyDeclarationResultByPropertyDeclarationIdStatement - .template optionalValue<FetchPropertyDeclarationResult>( - propertyDeclarationId); - - tracer.end(keyValue("property declaration", propertyDeclaration)); - - return propertyDeclaration; - } + std::optional<FetchPropertyDeclarationResult> fetchOptionalPropertyDeclarationByTypeIdAndNameUngarded( + TypeId typeId, Utils::SmallStringView name); FetchPropertyDeclarationResult fetchPropertyDeclarationByTypeIdAndNameUngarded( - TypeId typeId, Utils::SmallStringView name) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"fetch property declaration by type id and name ungarded"_t, - projectStorageCategory(), - keyValue("type id", typeId), - keyValue("property name", name)}; - - auto propertyDeclaration = fetchOptionalPropertyDeclarationByTypeIdAndNameUngarded(typeId, - name); - tracer.end(keyValue("property declaration", propertyDeclaration)); - - if (propertyDeclaration) - return *propertyDeclaration; - - throw PropertyNameDoesNotExists{}; - } + TypeId typeId, Utils::SmallStringView name); PropertyDeclarationId fetchPropertyDeclarationIdByTypeIdAndNameUngarded(TypeId typeId, - Utils::SmallStringView name) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"fetch property declaration id by type id and name ungarded"_t, - projectStorageCategory(), - keyValue("type id", typeId), - keyValue("property name", name)}; - - auto propertyDeclarationId = fetchPropertyDeclarationId(typeId, name); - - tracer.end(keyValue("property declaration id", propertyDeclarationId)); - - if (propertyDeclarationId) - return propertyDeclarationId; - - throw PropertyNameDoesNotExists{}; - } - - SourceContextId readSourceContextId(Utils::SmallStringView sourceContextPath) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"read source context id"_t, - projectStorageCategory(), - keyValue("source context path", sourceContextPath)}; - - auto sourceContextId = selectSourceContextIdFromSourceContextsBySourceContextPathStatement - .template value<SourceContextId>(sourceContextPath); - - tracer.end(keyValue("source context id", sourceContextId)); - - return sourceContextId; - } - - SourceContextId writeSourceContextId(Utils::SmallStringView sourceContextPath) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"write source context id"_t, - projectStorageCategory(), - keyValue("source context path", sourceContextPath)}; - - insertIntoSourceContextsStatement.write(sourceContextPath); - - auto sourceContextId = SourceContextId::create(database.lastInsertedRowId()); - - tracer.end(keyValue("source context id", sourceContextId)); - - return sourceContextId; - } - - SourceId writeSourceId(SourceContextId sourceContextId, Utils::SmallStringView sourceName) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"write source id"_t, - projectStorageCategory(), - keyValue("source context id", sourceContextId), - keyValue("source name", sourceName)}; - - insertIntoSourcesStatement.write(sourceContextId, sourceName); - - auto sourceId = SourceId::create(database.lastInsertedRowId()); - - tracer.end(keyValue("source id", sourceId)); - - return sourceId; - } - - SourceId readSourceId(SourceContextId sourceContextId, 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 = selectSourceIdFromSourcesBySourceContextIdAndSourceNameStatement - .template value<SourceId>(sourceContextId, sourceName); - - tracer.end(keyValue("source id", sourceId)); - - return sourceId; - } - - auto fetchExportedTypes(TypeId typeId) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"fetch exported type"_t, - projectStorageCategory(), - keyValue("type id", typeId)}; - - auto typeIds = selectExportedTypesByTypeIdStatement - .template values<Storage::Synchronization::ExportedType, 12>(typeId); - - tracer.end(keyValue("type ids", typeIds)); - - return typeIds; - } - - auto fetchPropertyDeclarations(TypeId typeId) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"fetch property declarations"_t, - projectStorageCategory(), - keyValue("type id", typeId)}; - - auto propertyDeclarations = selectPropertyDeclarationsByTypeIdStatement - .template values<Storage::Synchronization::PropertyDeclaration, 24>( - typeId); - - tracer.end(keyValue("property declarations", propertyDeclarations)); - - return propertyDeclarations; - } - - auto fetchFunctionDeclarations(TypeId typeId) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"fetch signal declarations"_t, - projectStorageCategory(), - keyValue("type id", typeId)}; - - Storage::Synchronization::FunctionDeclarations functionDeclarations; - - auto callback = [&](Utils::SmallStringView name, - Utils::SmallStringView returnType, - FunctionDeclarationId functionDeclarationId) { - auto &functionDeclaration = functionDeclarations.emplace_back(name, returnType); - functionDeclaration.parameters = selectFunctionParameterDeclarationsStatement - .template values<Storage::Synchronization::ParameterDeclaration, - 8>(functionDeclarationId); - }; - - selectFunctionDeclarationsForTypeIdWithoutSignatureStatement.readCallback(callback, typeId); + Utils::SmallStringView name); - tracer.end(keyValue("function declarations", functionDeclarations)); + SourceContextId readSourceContextId(Utils::SmallStringView sourceContextPath); - return functionDeclarations; - } - - auto fetchSignalDeclarations(TypeId typeId) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"fetch signal declarations"_t, - projectStorageCategory(), - keyValue("type id", typeId)}; - - Storage::Synchronization::SignalDeclarations signalDeclarations; - - auto callback = [&](Utils::SmallStringView name, SignalDeclarationId signalDeclarationId) { - auto &signalDeclaration = signalDeclarations.emplace_back(name); - signalDeclaration.parameters = selectSignalParameterDeclarationsStatement - .template values<Storage::Synchronization::ParameterDeclaration, - 8>(signalDeclarationId); - }; - - selectSignalDeclarationsForTypeIdWithoutSignatureStatement.readCallback(callback, typeId); - - tracer.end(keyValue("signal declarations", signalDeclarations)); - - return signalDeclarations; - } - - auto fetchEnumerationDeclarations(TypeId typeId) - { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"fetch enumeration declarations"_t, - projectStorageCategory(), - keyValue("type id", typeId)}; - - Storage::Synchronization::EnumerationDeclarations enumerationDeclarations; - - auto callback = [&](Utils::SmallStringView name, - EnumerationDeclarationId enumerationDeclarationId) { - enumerationDeclarations.emplace_back( - name, - selectEnumeratorDeclarationStatement - .template values<Storage::Synchronization::EnumeratorDeclaration, 8>( - enumerationDeclarationId)); - }; - - selectEnumerationDeclarationsForTypeIdWithoutEnumeratorDeclarationsStatement - .readCallback(callback, typeId); - - tracer.end(keyValue("enumeration declarations", enumerationDeclarations)); - - return enumerationDeclarations; - } - - class Initializer - { - public: - Initializer(Database &database, bool isInitialized) - { - if (!isInitialized) { - auto moduleIdColumn = createModulesTable(database); - createSourceContextsTable(database); - createSourcesTable(database); - createTypesAndePropertyDeclarationsTables(database, moduleIdColumn); - createExportedTypeNamesTable(database, moduleIdColumn); - createImportedTypeNamesTable(database); - createEnumerationsTable(database); - createFunctionsTable(database); - createSignalsTable(database); - createModuleExportedImportsTable(database, moduleIdColumn); - createDocumentImportsTable(database, moduleIdColumn); - createFileStatusesTable(database); - createProjectDatasTable(database); - createPropertyEditorPathsTable(database); - createTypeAnnotionsTable(database); - } - database.setIsInitialized(true); - } - - void createSourceContextsTable(Database &database) - { - Sqlite::Table table; - table.setUseIfNotExists(true); - table.setName("sourceContexts"); - table.addColumn("sourceContextId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}}); - const Sqlite::Column &sourceContextPathColumn = table.addColumn("sourceContextPath"); - - table.addUniqueIndex({sourceContextPathColumn}); - - table.initialize(database); - } - - void createSourcesTable(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}}); - const auto &sourceNameColumn = table.addColumn("sourceName", - Sqlite::StrictColumnType::Text); - table.addUniqueIndex({sourceContextIdColumn, sourceNameColumn}); - - table.initialize(database); - } - - void createTypesAndePropertyDeclarationsTables( - Database &database, [[maybe_unused]] const Sqlite::StrictColumn &foreignModuleIdColumn) - { - Sqlite::StrictTable typesTable; - typesTable.setUseIfNotExists(true); - typesTable.setName("types"); - typesTable.addColumn("typeId", Sqlite::StrictColumnType::Integer, {Sqlite::PrimaryKey{}}); - auto &sourceIdColumn = typesTable.addColumn("sourceId", Sqlite::StrictColumnType::Integer); - auto &typesNameColumn = typesTable.addColumn("name", Sqlite::StrictColumnType::Text); - typesTable.addColumn("traits", Sqlite::StrictColumnType::Integer); - auto &prototypeIdColumn = typesTable.addForeignKeyColumn("prototypeId", - typesTable, - Sqlite::ForeignKeyAction::NoAction, - Sqlite::ForeignKeyAction::Restrict); - typesTable.addColumn("prototypeNameId", Sqlite::StrictColumnType::Integer); - auto &extensionIdColumn = typesTable.addForeignKeyColumn("extensionId", - typesTable, - Sqlite::ForeignKeyAction::NoAction, - Sqlite::ForeignKeyAction::Restrict); - typesTable.addColumn("extensionNameId", Sqlite::StrictColumnType::Integer); - auto &defaultPropertyIdColumn = typesTable.addColumn("defaultPropertyId", - Sqlite::StrictColumnType::Integer); - typesTable.addColumn("annotationTraits", Sqlite::StrictColumnType::Integer); - typesTable.addUniqueIndex({sourceIdColumn, typesNameColumn}); - typesTable.addIndex({defaultPropertyIdColumn}); - typesTable.addIndex({prototypeIdColumn}); - typesTable.addIndex({extensionIdColumn}); - - typesTable.initialize(database); - - { - Sqlite::StrictTable propertyDeclarationTable; - propertyDeclarationTable.setUseIfNotExists(true); - propertyDeclarationTable.setName("propertyDeclarations"); - propertyDeclarationTable.addColumn("propertyDeclarationId", - Sqlite::StrictColumnType::Integer, - {Sqlite::PrimaryKey{}}); - auto &typeIdColumn = propertyDeclarationTable.addColumn("typeId"); - auto &nameColumn = propertyDeclarationTable.addColumn("name"); - auto &propertyTypeIdColumn = propertyDeclarationTable.addForeignKeyColumn( - "propertyTypeId", - typesTable, - Sqlite::ForeignKeyAction::NoAction, - Sqlite::ForeignKeyAction::Restrict); - propertyDeclarationTable.addColumn("propertyTraits", - Sqlite::StrictColumnType::Integer); - propertyDeclarationTable.addColumn("propertyImportedTypeNameId", - Sqlite::StrictColumnType::Integer); - auto &aliasPropertyDeclarationIdColumn = propertyDeclarationTable.addForeignKeyColumn( - "aliasPropertyDeclarationId", - propertyDeclarationTable, - Sqlite::ForeignKeyAction::NoAction, - Sqlite::ForeignKeyAction::Restrict); - auto &aliasPropertyDeclarationTailIdColumn = propertyDeclarationTable.addForeignKeyColumn( - "aliasPropertyDeclarationTailId", - propertyDeclarationTable, - Sqlite::ForeignKeyAction::NoAction, - Sqlite::ForeignKeyAction::Restrict); - - propertyDeclarationTable.addUniqueIndex({typeIdColumn, nameColumn}); - propertyDeclarationTable.addIndex({propertyTypeIdColumn}); - propertyDeclarationTable.addIndex({aliasPropertyDeclarationIdColumn}, - "aliasPropertyDeclarationId IS NOT NULL"); - propertyDeclarationTable.addIndex({aliasPropertyDeclarationTailIdColumn}, - "aliasPropertyDeclarationTailId IS NOT NULL"); - - propertyDeclarationTable.initialize(database); - } - } - - void createExportedTypeNamesTable(Database &database, - const Sqlite::StrictColumn &foreignModuleIdColumn) - { - Sqlite::StrictTable table; - table.setUseIfNotExists(true); - table.setName("exportedTypeNames"); - table.addColumn("exportedTypeNameId", - Sqlite::StrictColumnType::Integer, - {Sqlite::PrimaryKey{}}); - auto &moduleIdColumn = table.addForeignKeyColumn("moduleId", - foreignModuleIdColumn, - Sqlite::ForeignKeyAction::NoAction, - Sqlite::ForeignKeyAction::NoAction); - auto &nameColumn = table.addColumn("name", Sqlite::StrictColumnType::Text); - auto &typeIdColumn = table.addColumn("typeId", Sqlite::StrictColumnType::Integer); - auto &majorVersionColumn = table.addColumn("majorVersion", - Sqlite::StrictColumnType::Integer); - auto &minorVersionColumn = table.addColumn("minorVersion", - Sqlite::StrictColumnType::Integer); - - table.addUniqueIndex({moduleIdColumn, nameColumn}, - "majorVersion IS NULL AND minorVersion IS NULL"); - table.addUniqueIndex({moduleIdColumn, nameColumn, majorVersionColumn}, - "majorVersion IS NOT NULL AND minorVersion IS NULL"); - table.addUniqueIndex({moduleIdColumn, nameColumn, majorVersionColumn, minorVersionColumn}, - "majorVersion IS NOT NULL AND minorVersion IS NOT NULL"); - - table.addIndex({typeIdColumn}); - table.addIndex({moduleIdColumn, nameColumn}); - - table.initialize(database); - } + SourceContextId writeSourceContextId(Utils::SmallStringView sourceContextPath); - void createImportedTypeNamesTable(Database &database) - { - Sqlite::StrictTable table; - table.setUseIfNotExists(true); - table.setName("importedTypeNames"); - table.addColumn("importedTypeNameId", - Sqlite::StrictColumnType::Integer, - {Sqlite::PrimaryKey{}}); - auto &importOrSourceIdColumn = table.addColumn("importOrSourceId"); - auto &nameColumn = table.addColumn("name", Sqlite::StrictColumnType::Text); - auto &kindColumn = table.addColumn("kind", Sqlite::StrictColumnType::Integer); - - table.addUniqueIndex({kindColumn, importOrSourceIdColumn, nameColumn}); - table.addIndex({nameColumn}); - - table.initialize(database); - } - - void createEnumerationsTable(Database &database) - { - Sqlite::StrictTable table; - table.setUseIfNotExists(true); - table.setName("enumerationDeclarations"); - table.addColumn("enumerationDeclarationId", - Sqlite::StrictColumnType::Integer, - {Sqlite::PrimaryKey{}}); - auto &typeIdColumn = table.addColumn("typeId", Sqlite::StrictColumnType::Integer); - auto &nameColumn = table.addColumn("name", Sqlite::StrictColumnType::Text); - table.addColumn("enumeratorDeclarations", Sqlite::StrictColumnType::Text); - - table.addUniqueIndex({typeIdColumn, nameColumn}); - - table.initialize(database); - } + SourceId writeSourceId(SourceContextId sourceContextId, Utils::SmallStringView sourceName); - void createFunctionsTable(Database &database) - { - Sqlite::StrictTable table; - table.setUseIfNotExists(true); - table.setName("functionDeclarations"); - table.addColumn("functionDeclarationId", - Sqlite::StrictColumnType::Integer, - {Sqlite::PrimaryKey{}}); - auto &typeIdColumn = table.addColumn("typeId", Sqlite::StrictColumnType::Integer); - auto &nameColumn = table.addColumn("name", Sqlite::StrictColumnType::Text); - auto &signatureColumn = table.addColumn("signature", Sqlite::StrictColumnType::Text); - table.addColumn("returnTypeName"); - - table.addUniqueIndex({typeIdColumn, nameColumn, signatureColumn}); - - table.initialize(database); - } + SourceId readSourceId(SourceContextId sourceContextId, Utils::SmallStringView sourceName); - void createSignalsTable(Database &database) - { - Sqlite::StrictTable table; - table.setUseIfNotExists(true); - table.setName("signalDeclarations"); - table.addColumn("signalDeclarationId", - Sqlite::StrictColumnType::Integer, - {Sqlite::PrimaryKey{}}); - auto &typeIdColumn = table.addColumn("typeId", Sqlite::StrictColumnType::Integer); - auto &nameColumn = table.addColumn("name", Sqlite::StrictColumnType::Text); - auto &signatureColumn = table.addColumn("signature", Sqlite::StrictColumnType::Text); - - table.addUniqueIndex({typeIdColumn, nameColumn, signatureColumn}); - - table.initialize(database); - } + Storage::Synchronization::ExportedTypes fetchExportedTypes(TypeId typeId); - Sqlite::StrictColumn createModulesTable(Database &database) - { - Sqlite::StrictTable table; - table.setUseIfNotExists(true); - table.setName("modules"); - auto &modelIdColumn = table.addColumn("moduleId", - Sqlite::StrictColumnType::Integer, - {Sqlite::PrimaryKey{}}); - auto &nameColumn = table.addColumn("name", Sqlite::StrictColumnType::Text); + Storage::Synchronization::PropertyDeclarations fetchPropertyDeclarations(TypeId typeId); - table.addUniqueIndex({nameColumn}); + Storage::Synchronization::FunctionDeclarations fetchFunctionDeclarations(TypeId typeId); - table.initialize(database); + Storage::Synchronization::SignalDeclarations fetchSignalDeclarations(TypeId typeId); - return std::move(modelIdColumn); - } + Storage::Synchronization::EnumerationDeclarations fetchEnumerationDeclarations(TypeId typeId); - void createModuleExportedImportsTable(Database &database, - const Sqlite::StrictColumn &foreignModuleIdColumn) - { - Sqlite::StrictTable table; - table.setUseIfNotExists(true); - table.setName("moduleExportedImports"); - table.addColumn("moduleExportedImportId", - Sqlite::StrictColumnType::Integer, - {Sqlite::PrimaryKey{}}); - auto &moduleIdColumn = table.addForeignKeyColumn("moduleId", - foreignModuleIdColumn, - Sqlite::ForeignKeyAction::NoAction, - Sqlite::ForeignKeyAction::Cascade, - Sqlite::Enforment::Immediate); - auto &sourceIdColumn = table.addColumn("exportedModuleId", - Sqlite::StrictColumnType::Integer); - table.addColumn("isAutoVersion", Sqlite::StrictColumnType::Integer); - table.addColumn("majorVersion", Sqlite::StrictColumnType::Integer); - table.addColumn("minorVersion", Sqlite::StrictColumnType::Integer); - - table.addUniqueIndex({sourceIdColumn, moduleIdColumn}); - - table.initialize(database); - } - - void createDocumentImportsTable(Database &database, - const Sqlite::StrictColumn &foreignModuleIdColumn) - { - Sqlite::StrictTable table; - table.setUseIfNotExists(true); - table.setName("documentImports"); - table.addColumn("importId", Sqlite::StrictColumnType::Integer, {Sqlite::PrimaryKey{}}); - auto &sourceIdColumn = table.addColumn("sourceId", Sqlite::StrictColumnType::Integer); - auto &moduleIdColumn = table.addForeignKeyColumn("moduleId", - foreignModuleIdColumn, - Sqlite::ForeignKeyAction::NoAction, - Sqlite::ForeignKeyAction::Cascade, - Sqlite::Enforment::Immediate); - auto &sourceModuleIdColumn = table.addForeignKeyColumn("sourceModuleId", - foreignModuleIdColumn, - Sqlite::ForeignKeyAction::NoAction, - Sqlite::ForeignKeyAction::Cascade, - Sqlite::Enforment::Immediate); - auto &kindColumn = table.addColumn("kind", Sqlite::StrictColumnType::Integer); - auto &majorVersionColumn = table.addColumn("majorVersion", - Sqlite::StrictColumnType::Integer); - auto &minorVersionColumn = table.addColumn("minorVersion", - Sqlite::StrictColumnType::Integer); - auto &parentImportIdColumn = table.addColumn("parentImportId", - Sqlite::StrictColumnType::Integer); - - table.addUniqueIndex({sourceIdColumn, - moduleIdColumn, - kindColumn, - sourceModuleIdColumn, - parentImportIdColumn}, - "majorVersion IS NULL AND minorVersion IS NULL"); - table.addUniqueIndex({sourceIdColumn, - moduleIdColumn, - kindColumn, - sourceModuleIdColumn, - majorVersionColumn, - parentImportIdColumn}, - "majorVersion IS NOT NULL AND minorVersion IS NULL"); - table.addUniqueIndex({sourceIdColumn, - moduleIdColumn, - kindColumn, - sourceModuleIdColumn, - majorVersionColumn, - minorVersionColumn, - parentImportIdColumn}, - "majorVersion IS NOT NULL AND minorVersion IS NOT NULL"); - - table.addIndex({sourceIdColumn, kindColumn}); - - table.initialize(database); - } - - void createFileStatusesTable(Database &database) - { - 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("size", Sqlite::StrictColumnType::Integer); - table.addColumn("lastModified", Sqlite::StrictColumnType::Integer); - - table.initialize(database); - } - - void createProjectDatasTable(Database &database) - { - Sqlite::StrictTable table; - table.setUseIfNotExists(true); - table.setUseWithoutRowId(true); - table.setName("projectDatas"); - auto &projectSourceIdColumn = table.addColumn("projectSourceId", - Sqlite::StrictColumnType::Integer); - auto &sourceIdColumn = table.addColumn("sourceId", Sqlite::StrictColumnType::Integer); - table.addColumn("moduleId", Sqlite::StrictColumnType::Integer); - table.addColumn("fileType", Sqlite::StrictColumnType::Integer); - - table.addPrimaryKeyContraint({projectSourceIdColumn, sourceIdColumn}); - table.addUniqueIndex({sourceIdColumn}); - - table.initialize(database); - } - - void createPropertyEditorPathsTable(Database &database) - { - Sqlite::StrictTable table; - table.setUseIfNotExists(true); - table.setUseWithoutRowId(true); - table.setName("propertyEditorPaths"); - table.addColumn("typeId", Sqlite::StrictColumnType::Integer, {Sqlite::PrimaryKey{}}); - table.addColumn("pathSourceId", Sqlite::StrictColumnType::Integer); - auto &directoryIdColumn = table.addColumn("directoryId", - Sqlite::StrictColumnType::Integer); - - table.addIndex({directoryIdColumn}); - - table.initialize(database); - } - - void createTypeAnnotionsTable(Database &database) - { - Sqlite::StrictTable table; - table.setUseIfNotExists(true); - table.setUseWithoutRowId(true); - table.setName("typeAnnotations"); - auto &typeIdColumn = table.addColumn("typeId", - Sqlite::StrictColumnType::Integer, - {Sqlite::PrimaryKey{}}); - auto &sourceIdColumn = table.addColumn("sourceId", Sqlite::StrictColumnType::Integer); - auto &directorySourceIdColumn = table.addColumn("directorySourceId", - Sqlite::StrictColumnType::Integer); - - table.addColumn("iconPath", Sqlite::StrictColumnType::Text); - table.addColumn("itemLibrary", Sqlite::StrictColumnType::Text); - table.addColumn("hints", Sqlite::StrictColumnType::Text); - - table.addUniqueIndex({sourceIdColumn, typeIdColumn}); - table.addIndex({directorySourceIdColumn}); - - table.initialize(database); - } - }; + class Initializer; public: Database &database; Sqlite::ExclusiveNonThrowingDestructorTransaction<Database> exclusiveTransaction; - Initializer initializer; + std::unique_ptr<Initializer> initializer; mutable ModuleCache moduleCache{ModuleStorageAdapter{*this}}; - Storage::Info::CommonTypeCache<ProjectStorageInterface> commonTypeCache_{*this}; + Storage::Info::CommonTypeCache<ProjectStorageType> commonTypeCache_{*this}; QVarLengthArray<ProjectStorageObserver *, 24> observers; ReadWriteStatement<1, 2> insertTypeStatement{ "INSERT OR IGNORE INTO types(sourceId, name) VALUES(?1, ?2) RETURNING typeId", database}; @@ -4564,8 +1152,10 @@ public: "INSERT INTO functionDeclarations(typeId, name, returnTypeName, signature) VALUES(?1, ?2, " "?3, ?4)", database}; - WriteStatement<2> updateFunctionDeclarationStatement{ - "UPDATE functionDeclarations SET returnTypeName=?2 WHERE functionDeclarationId=?1", database}; + WriteStatement<3> updateFunctionDeclarationStatement{"UPDATE functionDeclarations " + "SET returnTypeName=?2, signature=?3 " + "WHERE functionDeclarationId=?1", + database}; WriteStatement<1> deleteFunctionDeclarationStatement{ "DELETE FROM functionDeclarations WHERE functionDeclarationId=?", database}; mutable ReadStatement<3, 1> selectSignalDeclarationsForTypeIdStatement{ @@ -5078,6 +1668,5 @@ public: database}; }; -extern template class ProjectStorage<Sqlite::Database>; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragefwd.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragefwd.h index b33c609509..cbb7d4265a 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragefwd.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragefwd.h @@ -11,7 +11,6 @@ namespace QmlDesigner { class ProjectStorageInterface; class SourcePathCacheInterface; -template<typename Database> class ProjectStorage; template<typename Type> diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h index 20d988f7aa..971e635517 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h @@ -84,7 +84,7 @@ public: virtual std::optional<Storage::Synchronization::ProjectData> fetchProjectData(SourceId sourceId) const = 0; virtual SourceId propertyEditorPathId(TypeId typeId) const = 0; - virtual const Storage::Info::CommonTypeCache<ProjectStorageInterface> &commonTypeCache() const = 0; + virtual const Storage::Info::CommonTypeCache<ProjectStorageType> &commonTypeCache() const = 0; template<const char *moduleName, const char *typeName> TypeId commonTypeId() const diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h index e21531deea..640969fe99 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h @@ -32,7 +32,6 @@ class ProjectStorageInterface; template<typename ProjectStorage, typename Mutex> class SourcePathCache; class FileStatusCache; -template<typename Database> class ProjectStorage; class QmlDocumentParserInterface; class QmlTypesParserInterface; @@ -40,7 +39,7 @@ class QmlTypesParserInterface; class ProjectStorageUpdater final : public ProjectStoragePathWatcherNotifierInterface { public: - using PathCache = SourcePathCache<ProjectStorage<Sqlite::Database>, NonLockingMutex>; + using PathCache = SourcePathCache<ProjectStorage, NonLockingMutex>; ProjectStorageUpdater(FileSystemInterface &fileSystem, ProjectStorageType &projectStorage, diff --git a/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.h b/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.h index b8ab4ec4b1..1b494a2f69 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.h @@ -15,7 +15,7 @@ class SourcePathCache; class QmlDocumentParser final : public QmlDocumentParserInterface { public: - using ProjectStorage = QmlDesigner::ProjectStorage<Sqlite::Database>; + using ProjectStorage = QmlDesigner::ProjectStorage; using PathCache = QmlDesigner::SourcePathCache<ProjectStorage, NonLockingMutex>; #ifdef QDS_BUILD_QMLPARSER diff --git a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.h b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.h index 7c41925f30..4a6427501b 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.h @@ -4,6 +4,7 @@ #pragma once #include "nonlockingmutex.h" +#include "projectstoragefwd.h" #include "qmltypesparserinterface.h" namespace Sqlite { @@ -12,17 +13,13 @@ class Database; namespace QmlDesigner { -template<typename Database> -class ProjectStorage; - template<typename ProjectStorage, typename Mutex> class SourcePathCache; class QmlTypesParser final : public QmlTypesParserInterface { public: - using ProjectStorage = QmlDesigner::ProjectStorage<Sqlite::Database>; - + using ProjectStorage = QmlDesigner::ProjectStorage; #ifdef QDS_BUILD_QMLPARSER QmlTypesParser(ProjectStorage &storage) : m_storage{storage} diff --git a/src/plugins/qmldesigner/designercore/projectstorage/sourcepathcachetypes.h b/src/plugins/qmldesigner/designercore/projectstorage/sourcepathcachetypes.h index 5feaf30d00..1ef8ba7f21 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/sourcepathcachetypes.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/sourcepathcachetypes.h @@ -125,4 +125,6 @@ public: SourceContextId sourceContextId; }; +using SourceNameAndSourceContextIds = std::vector<SourceNameAndSourceContextId>; + } // namespace QmlDesigner::Cache |