1 /****************************************************************************
2 **
3 ** Copyright (C) 2021 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25 
26 #pragma once
27 
28 #include "projectstorageexceptions.h"
29 #include "projectstorageids.h"
30 #include "projectstoragetypes.h"
31 #include "sourcepathcachetypes.h"
32 
33 #include <sqlitealgorithms.h>
34 #include <sqlitetable.h>
35 #include <sqlitetransaction.h>
36 
37 #include <utils/algorithm.h>
38 #include <utils/optional.h>
39 
40 #include <tuple>
41 
42 namespace QmlDesigner {
43 
44 template<typename Database>
45 class ProjectStorage
46 {
47 public:
48     template<int ResultCount>
49     using ReadStatement = typename Database::template ReadStatement<ResultCount>;
50     template<int ResultCount>
51     using ReadWriteStatement = typename Database::template ReadWriteStatement<ResultCount>;
52     using WriteStatement = typename Database::WriteStatement;
53 
ProjectStorage(Database & database,bool isInitialized)54     ProjectStorage(Database &database, bool isInitialized)
55         : database{database}
56         , initializer{database, isInitialized}
57     {}
58 
synchronizeTypes(Storage::Types types,SourceIds sourceIds)59     void synchronizeTypes(Storage::Types types, SourceIds sourceIds)
60     {
61         Sqlite::ImmediateTransaction transaction{database};
62 
63         TypeIds updatedTypeIds;
64         updatedTypeIds.reserve(types.size());
65 
66         for (auto &&type : types) {
67             if (!type.sourceId)
68                 throw TypeHasInvalidSourceId{};
69 
70             updatedTypeIds.push_back(declareType(type));
71         }
72 
73         for (auto &&type : types)
74             synchronizeAliasPropertyDeclarationsRemoval(type);
75 
76         for (auto &&type : types)
77             syncType(type);
78 
79         for (auto &&type : types)
80             synchronizeAliasPropertyDeclarations(type);
81 
82         deleteNotUpdatedTypes(updatedTypeIds, sourceIds);
83 
84         transaction.commit();
85     }
86 
synchronizeImports(Storage::Imports imports)87     void synchronizeImports(Storage::Imports imports)
88     {
89         Sqlite::ImmediateTransaction transaction{database};
90 
91         synchronizeImportsAndUpdatesImportIds(imports);
92         synchronizeImportDependencies(createSortedImportDependecies(imports));
93 
94         transaction.commit();
95     }
96 
fetchImportIds(const Storage::Imports & imports)97     ImportIds fetchImportIds(const Storage::Imports &imports)
98     {
99         ImportIds importIds;
100 
101         Sqlite::DeferredTransaction transaction{database};
102 
103         for (auto &&import : imports)
104             importIds.push_back(fetchImportId(import));
105 
106         transaction.commit();
107 
108         return importIds;
109     }
110 
fetchImportDependencyIds(ImportIds importIds)111     ImportIds fetchImportDependencyIds(ImportIds importIds) const
112     {
113         return fetchImportDependencyIdsStatement.template valuesWithTransaction<ImportId>(
114             16, static_cast<void *>(importIds.data()), static_cast<long long>(importIds.size()));
115     }
116 
fetchPropertyDeclarationByTypeIdAndName(TypeId typeId,Utils::SmallStringView name)117     PropertyDeclarationId fetchPropertyDeclarationByTypeIdAndName(TypeId typeId,
118                                                                   Utils::SmallStringView name)
119     {
120         return selectPropertyDeclarationIdByTypeIdAndNameStatement
121             .template valueWithTransaction<PropertyDeclarationId>(&typeId, name);
122     }
123 
fetchTypeIdByExportedName(Utils::SmallStringView name)124     TypeId fetchTypeIdByExportedName(Utils::SmallStringView name) const
125     {
126         return selectTypeIdByExportedNameStatement.template valueWithTransaction<TypeId>(name);
127     }
128 
fetchTypeIdByImportIdsAndExportedName(ImportIds importIds,Utils::SmallStringView name)129     TypeId fetchTypeIdByImportIdsAndExportedName(ImportIds importIds, Utils::SmallStringView name) const
130     {
131         return selectTypeIdByImportIdsAndExportedNameStatement.template valueWithTransaction<TypeId>(
132             static_cast<void *>(importIds.data()), static_cast<long long>(importIds.size()), name);
133     }
134 
fetchTypeIdByName(ImportId importId,Utils::SmallStringView name)135     TypeId fetchTypeIdByName(ImportId importId, Utils::SmallStringView name)
136     {
137         return selectTypeIdByImportIdAndNameStatement.template valueWithTransaction<TypeId>(&importId,
138                                                                                             name);
139     }
140 
fetchTypeByTypeId(TypeId typeId)141     Storage::Type fetchTypeByTypeId(TypeId typeId)
142     {
143         Sqlite::DeferredTransaction transaction{database};
144 
145         auto type = selectTypeByTypeIdStatement.template value<Storage::Type>(&typeId);
146 
147         type.exportedTypes = fetchExportedTypes(typeId);
148 
149         transaction.commit();
150 
151         return type;
152     }
153 
fetchTypes()154     Storage::Types fetchTypes()
155     {
156         Sqlite::DeferredTransaction transaction{database};
157 
158         auto types = selectTypesStatement.template values<Storage::Type>(64);
159 
160         for (Storage::Type &type : types) {
161             type.exportedTypes = fetchExportedTypes(type.typeId);
162             type.propertyDeclarations = fetchPropertyDeclarations(type.typeId);
163             type.functionDeclarations = fetchFunctionDeclarations(type.typeId);
164             type.signalDeclarations = fetchSignalDeclarations(type.typeId);
165             type.enumerationDeclarations = fetchEnumerationDeclarations(type.typeId);
166         }
167 
168         transaction.commit();
169 
170         return types;
171     }
172 
fetchIsProtype(TypeId type,TypeId prototype)173     bool fetchIsProtype(TypeId type, TypeId prototype)
174     {
175         return bool(
176             selectPrototypeIdStatement.template valueWithTransaction<TypeId>(&type, &prototype));
177     }
178 
fetchPrototypes(TypeId type)179     auto fetchPrototypes(TypeId type)
180     {
181         return selectPrototypeIdsStatement.template rangeWithTransaction<TypeId>(&type);
182     }
183 
fetchSourceContextIdUnguarded(Utils::SmallStringView sourceContextPath)184     SourceContextId fetchSourceContextIdUnguarded(Utils::SmallStringView sourceContextPath)
185     {
186         auto sourceContextId = readSourceContextId(sourceContextPath);
187 
188         return sourceContextId ? sourceContextId : writeSourceContextId(sourceContextPath);
189     }
190 
fetchSourceContextId(Utils::SmallStringView sourceContextPath)191     SourceContextId fetchSourceContextId(Utils::SmallStringView sourceContextPath)
192     {
193         try {
194             Sqlite::DeferredTransaction transaction{database};
195 
196             auto sourceContextId = fetchSourceContextIdUnguarded(sourceContextPath);
197 
198             transaction.commit();
199 
200             return sourceContextId;
201         } catch (const Sqlite::ConstraintPreventsModification &) {
202             return fetchSourceContextId(sourceContextPath);
203         }
204     }
205 
fetchSourceContextPath(SourceContextId sourceContextId)206     Utils::PathString fetchSourceContextPath(SourceContextId sourceContextId) const
207     {
208         Sqlite::DeferredTransaction transaction{database};
209 
210         auto optionalSourceContextPath = selectSourceContextPathFromSourceContextsBySourceContextIdStatement
211                                              .template optionalValue<Utils::PathString>(
212                                                  &sourceContextId);
213 
214         if (!optionalSourceContextPath)
215             throw SourceContextIdDoesNotExists();
216 
217         transaction.commit();
218 
219         return std::move(*optionalSourceContextPath);
220     }
221 
fetchAllSourceContexts()222     auto fetchAllSourceContexts() const
223     {
224         return selectAllSourceContextsStatement.template valuesWithTransaction<Cache::SourceContext>(
225             128);
226     }
227 
fetchSourceId(SourceContextId sourceContextId,Utils::SmallStringView sourceName)228     SourceId fetchSourceId(SourceContextId sourceContextId, Utils::SmallStringView sourceName)
229     {
230         Sqlite::DeferredTransaction transaction{database};
231 
232         auto sourceId = fetchSourceIdUnguarded(sourceContextId, sourceName);
233 
234         transaction.commit();
235 
236         return sourceId;
237     }
238 
fetchSourceNameAndSourceContextId(SourceId sourceId)239     auto fetchSourceNameAndSourceContextId(SourceId sourceId) const
240     {
241         auto value = selectSourceNameAndSourceContextIdFromSourcesBySourceIdStatement
242                          .template valueWithTransaction<Cache::SourceNameAndSourceContextId>(&sourceId);
243 
244         if (!value.sourceContextId)
245             throw SourceIdDoesNotExists();
246 
247         return value;
248     }
249 
fetchSourceContextId(SourceId sourceId)250     SourceContextId fetchSourceContextId(SourceId sourceId) const
251     {
252         auto sourceContextId = selectSourceContextIdFromSourcesBySourceIdStatement
253                                    .template valueWithTransaction<SourceContextId>(sourceId.id);
254 
255         if (!sourceContextId)
256             throw SourceIdDoesNotExists();
257 
258         return sourceContextId;
259     }
260 
fetchAllSources()261     auto fetchAllSources() const
262     {
263         return selectAllSourcesStatement.template valuesWithTransaction<Cache::Source>(1024);
264     }
265 
fetchSourceIdUnguarded(SourceContextId sourceContextId,Utils::SmallStringView sourceName)266     SourceId fetchSourceIdUnguarded(SourceContextId sourceContextId, Utils::SmallStringView sourceName)
267     {
268         auto sourceId = readSourceId(sourceContextId, sourceName);
269 
270         if (sourceId)
271             return sourceId;
272 
273         return writeSourceId(sourceContextId, sourceName);
274     }
275 
fetchAllImports()276     auto fetchAllImports() const
277     {
278         Storage::Imports imports;
279         imports.reserve(128);
280 
281         auto callback = [&](Utils::SmallStringView name, int version, int sourceId, long long importId) {
282             auto &lastImport = imports.emplace_back(name,
283                                                     Storage::VersionNumber{version},
284                                                     SourceId{sourceId});
285 
286             lastImport.importDependencies = selectImportsForThatDependentOnThisImportIdStatement
287                                                 .template values<Storage::BasicImport>(6, importId);
288 
289             return Sqlite::CallbackControl::Continue;
290         };
291 
292         selectAllImportsStatement.readCallbackWithTransaction(callback);
293 
294         return imports;
295     }
296 
297 private:
298     struct ImportDependency
299     {
ImportDependencyImportDependency300         ImportDependency(ImportId id, ImportId dependencyId)
301             : id{id}
302             , dependencyId{dependencyId}
303         {}
304 
ImportDependencyImportDependency305         ImportDependency(long long id, long long dependencyId)
306             : id{id}
307             , dependencyId{dependencyId}
308         {}
309 
310         ImportId id;
311         ImportId dependencyId;
312 
313         friend bool operator<(ImportDependency first, ImportDependency second)
314         {
315             return std::tie(first.id, first.dependencyId) < std::tie(second.id, second.dependencyId);
316         }
317 
318         friend bool operator==(ImportDependency first, ImportDependency second)
319         {
320             return first.id == second.id && first.dependencyId == second.dependencyId;
321         }
322     };
323 
synchronizeImportsAndUpdatesImportIds(Storage::Imports & imports)324     void synchronizeImportsAndUpdatesImportIds(Storage::Imports &imports)
325     {
326         auto compareKey = [](auto &&first, auto &&second) {
327             auto nameCompare = Sqlite::compare(first.name, second.name);
328 
329             if (nameCompare != 0)
330                 return nameCompare;
331 
332             return first.version.version - second.version.version;
333         };
334 
335         std::sort(imports.begin(), imports.end(), [&](auto &&first, auto &&second) {
336             return compareKey(first, second) < 0;
337         });
338 
339         auto range = selectAllImportsStatement.template range<Storage::ImportView>();
340 
341         auto insert = [&](Storage::Import &import) {
342             import.importId = insertImportStatement.template value<ImportId>(import.name,
343                                                                              import.version.version,
344                                                                              &import.sourceId);
345         };
346 
347         auto update = [&](const Storage::ImportView &importView, Storage::Import &import) {
348             if (importView.sourceId.id != import.sourceId.id)
349                 updateImportStatement.write(&importView.importId, &import.sourceId);
350             import.importId = importView.importId;
351         };
352 
353         auto remove = [&](const Storage::ImportView &importView) {
354             deleteImportStatement.write(&importView.importId);
355             deleteTypesForImportId(importView.importId);
356         };
357 
358         Sqlite::insertUpdateDelete(range, imports, compareKey, insert, update, remove);
359     }
360 
createSortedImportDependecies(const Storage::Imports & imports)361     std::vector<ImportDependency> createSortedImportDependecies(const Storage::Imports &imports) const
362     {
363         std::vector<ImportDependency> importDependecies;
364         importDependecies.reserve(imports.size() * 5);
365 
366         for (const Storage::Import &import : imports) {
367             for (const Storage::BasicImport &importDependency : import.importDependencies) {
368                 auto importIdForDependency = fetchImportId(importDependency);
369 
370                 if (!importIdForDependency)
371                     throw ImportDoesNotExists{};
372 
373                 importDependecies.emplace_back(import.importId, importIdForDependency);
374             }
375         }
376 
377         std::sort(importDependecies.begin(), importDependecies.end());
378         importDependecies.erase(std::unique(importDependecies.begin(), importDependecies.end()),
379                                 importDependecies.end());
380 
381         return importDependecies;
382     }
383 
synchronizeImportDependencies(const std::vector<ImportDependency> & importDependecies)384     void synchronizeImportDependencies(const std::vector<ImportDependency> &importDependecies)
385     {
386         auto compareKey = [](ImportDependency first, ImportDependency second) {
387             auto idCompare = first.id.id - second.id.id;
388 
389             if (idCompare != 0)
390                 return idCompare;
391 
392             return first.dependencyId.id - second.dependencyId.id;
393         };
394 
395         auto range = selectAllImportDependenciesStatement.template range<ImportDependency>();
396 
397         auto insert = [&](ImportDependency dependency) {
398             insertImportDependencyStatement.write(&dependency.id, &dependency.dependencyId);
399         };
400 
401         auto update = [](ImportDependency, ImportDependency) {};
402 
403         auto remove = [&](ImportDependency dependency) {
404             deleteImportDependencyStatement.write(&dependency.id, &dependency.dependencyId);
405         };
406 
407         Sqlite::insertUpdateDelete(range, importDependecies, compareKey, insert, update, remove);
408     }
409 
fetchImportId(const Storage::BasicImport & import)410     ImportId fetchImportId(const Storage::BasicImport &import) const
411     {
412         if (import.version) {
413             return selectImportIdByNameAndVersionStatement
414                 .template value<ImportId>(import.name, import.version.version);
415         }
416 
417         return selectImportIdByNameStatement.template value<ImportId>(import.name);
418     }
419 
deleteType(TypeId typeId)420     void deleteType(TypeId typeId)
421     {
422         deleteExportTypesByTypeIdStatement.write(&typeId);
423         deleteEnumerationDeclarationByTypeIdStatement.write(&typeId);
424         deletePropertyDeclarationByTypeIdStatement.write(&typeId);
425         deleteFunctionDeclarationByTypeIdStatement.write(&typeId);
426         deleteSignalDeclarationByTypeIdStatement.write(&typeId);
427         deleteTypeStatement.write(&typeId);
428     }
429 
deleteNotUpdatedTypes(const TypeIds & updatedTypeIds,const SourceIds & sourceIds)430     void deleteNotUpdatedTypes(const TypeIds &updatedTypeIds, const SourceIds &sourceIds)
431     {
432         auto updatedTypeIdValues = Utils::transform<std::vector>(updatedTypeIds, [](TypeId typeId) {
433             return &typeId;
434         });
435 
436         auto sourceIdValues = Utils::transform<std::vector>(sourceIds, [](SourceId sourceId) {
437             return &sourceId;
438         });
439 
440         auto callback = [&](long long typeId) {
441             deleteType(TypeId{typeId});
442             return Sqlite::CallbackControl::Continue;
443         };
444 
445         selectNotUpdatedTypesInSourcesStatement.readCallback(callback,
446                                                              Utils::span(sourceIdValues),
447                                                              Utils::span(updatedTypeIdValues));
448     }
449 
deleteTypesForImportId(ImportId importId)450     void deleteTypesForImportId(ImportId importId)
451     {
452         auto callback = [&](long long typeId) {
453             deleteType(TypeId{typeId});
454             return Sqlite::CallbackControl::Continue;
455         };
456 
457         selectTypeIdsForImportIdStatement.readCallback(callback, &importId);
458     }
459 
upsertExportedType(ImportId importId,Utils::SmallStringView name,TypeId typeId)460     void upsertExportedType(ImportId importId, Utils::SmallStringView name, TypeId typeId)
461     {
462         upsertExportedTypesStatement.write(&importId, name, &typeId);
463     }
464 
synchronizePropertyDeclarations(TypeId typeId,Storage::PropertyDeclarations & propertyDeclarations,ImportIds & importIds)465     void synchronizePropertyDeclarations(TypeId typeId,
466                                          Storage::PropertyDeclarations &propertyDeclarations,
467                                          ImportIds &importIds)
468     {
469         std::sort(propertyDeclarations.begin(),
470                   propertyDeclarations.end(),
471                   [](auto &&first, auto &&second) {
472                       return Sqlite::compare(first.name, second.name) < 0;
473                   });
474 
475         auto range = selectPropertyDeclarationsForTypeIdStatement
476                          .template range<Storage::PropertyDeclarationView>(&typeId);
477 
478         auto compareKey = [](const Storage::PropertyDeclarationView &view,
479                              const Storage::PropertyDeclaration &value) {
480             return Sqlite::compare(view.name, value.name);
481         };
482 
483         auto insert = [&](const Storage::PropertyDeclaration &value) {
484             auto propertyTypeId = fetchTypeIdByNameUngarded(value.typeName, importIds);
485 
486             insertPropertyDeclarationStatement.write(&typeId,
487                                                      value.name,
488                                                      &propertyTypeId,
489                                                      static_cast<int>(value.traits));
490         };
491 
492         auto update = [&](const Storage::PropertyDeclarationView &view,
493                           const Storage::PropertyDeclaration &value) {
494             auto propertyTypeId = fetchTypeIdByNameUngarded(value.typeName, importIds);
495 
496             if (view.traits == value.traits && propertyTypeId == view.typeId)
497                 return;
498 
499             updatePropertyDeclarationStatement.write(&view.id,
500                                                      &propertyTypeId,
501                                                      static_cast<int>(value.traits));
502         };
503 
504         auto remove = [&](const Storage::PropertyDeclarationView &view) {
505             deletePropertyDeclarationStatement.write(&view.id);
506         };
507 
508         Sqlite::insertUpdateDelete(range, propertyDeclarations, compareKey, insert, update, remove);
509     }
510 
synchronizeAliasPropertyDeclarationsRemoval(Storage::Type & type)511     void synchronizeAliasPropertyDeclarationsRemoval(Storage::Type &type)
512     {
513         auto &aliasDeclarations = type.aliasDeclarations;
514         TypeId typeId = type.typeId;
515 
516         std::sort(aliasDeclarations.begin(), aliasDeclarations.end(), [](auto &&first, auto &&second) {
517             return Sqlite::compare(first.name, second.name) < 0;
518         });
519 
520         auto range = selectPropertyDeclarationsWithAliasForTypeIdStatement
521                          .template range<Storage::AliasPropertyDeclarationView>(&typeId);
522 
523         auto compareKey = [](const Storage::AliasPropertyDeclarationView &view,
524                              const Storage::AliasPropertyDeclaration &value) {
525             return Sqlite::compare(view.name, value.name);
526         };
527 
528         auto insert = [&](const Storage::AliasPropertyDeclaration &) {};
529 
530         auto update = [&](const Storage::AliasPropertyDeclarationView &,
531                           const Storage::AliasPropertyDeclaration &) {};
532 
533         auto remove = [&](const Storage::AliasPropertyDeclarationView &view) {
534             deletePropertyDeclarationStatement.write(&view.id);
535         };
536 
537         Sqlite::insertUpdateDelete(range, aliasDeclarations, compareKey, insert, update, remove);
538     }
539 
synchronizeAliasPropertyDeclarations(Storage::Type & type)540     void synchronizeAliasPropertyDeclarations(Storage::Type &type)
541     {
542         auto &aliasDeclarations = type.aliasDeclarations;
543         TypeId typeId = type.typeId;
544         ImportIds &importIds = type.importIds;
545 
546         std::sort(aliasDeclarations.begin(), aliasDeclarations.end(), [](auto &&first, auto &&second) {
547             return Sqlite::compare(first.name, second.name) < 0;
548         });
549 
550         auto range = selectPropertyDeclarationsWithAliasForTypeIdStatement
551                          .template range<Storage::AliasPropertyDeclarationView>(&typeId);
552 
553         auto compareKey = [](const Storage::AliasPropertyDeclarationView &view,
554                              const Storage::AliasPropertyDeclaration &value) {
555             return Sqlite::compare(view.name, value.name);
556         };
557 
558         auto insert = [&](const Storage::AliasPropertyDeclaration &value) {
559             auto [aliasTypeId, aliasId, propertyTraits] = fetchPropertyDeclarationByTypeNameAndName(
560                 value.aliasTypeName, value.aliasPropertyName, importIds);
561 
562             insertPropertyDeclarationWithAliasStatement.write(&typeId,
563                                                               value.name,
564                                                               &aliasTypeId,
565                                                               propertyTraits,
566                                                               &aliasId);
567         };
568 
569         auto update = [&](const Storage::AliasPropertyDeclarationView &view,
570                           const Storage::AliasPropertyDeclaration &value) {
571             auto [aliasTypeId, aliasId, propertyTraits] = fetchPropertyDeclarationByTypeNameAndName(
572                 value.aliasTypeName, value.aliasPropertyName, importIds);
573 
574             if (view.aliasId == aliasId)
575                 return;
576 
577             updatePropertyDeclarationWithAliasStatement.write(&view.id,
578                                                               &aliasTypeId,
579                                                               propertyTraits,
580                                                               &aliasId);
581         };
582 
583         auto remove = [&](const Storage::AliasPropertyDeclarationView &) {};
584 
585         Sqlite::insertUpdateDelete(range, aliasDeclarations, compareKey, insert, update, remove);
586     }
587 
createJson(const Storage::ParameterDeclarations & parameters)588     Utils::PathString createJson(const Storage::ParameterDeclarations &parameters)
589     {
590         Utils::PathString json;
591         json.append("[");
592 
593         Utils::SmallStringView comma{""};
594 
595         for (const auto &parameter : parameters) {
596             json.append(comma);
597             comma = ",";
598             json.append("{\"n\":\"");
599             json.append(parameter.name);
600             json.append("\",\"tn\":\"");
601             json.append(parameter.typeName);
602             if (parameter.traits == Storage::PropertyDeclarationTraits::Non) {
603                 json.append("\"}");
604             } else {
605                 json.append("\",\"tr\":");
606                 json.append(Utils::SmallString::number(static_cast<int>(parameter.traits)));
607                 json.append("}");
608             }
609         }
610 
611         json.append("]");
612 
613         return json;
614     }
615 
synchronizeFunctionDeclarations(TypeId typeId,Storage::FunctionDeclarations & functionsDeclarations)616     void synchronizeFunctionDeclarations(TypeId typeId,
617                                          Storage::FunctionDeclarations &functionsDeclarations)
618     {
619         std::sort(functionsDeclarations.begin(),
620                   functionsDeclarations.end(),
621                   [](auto &&first, auto &&second) {
622                       return Sqlite::compare(first.name, second.name) < 0;
623                   });
624 
625         auto range = selectFunctionDeclarationsForTypeIdStatement
626                          .template range<Storage::FunctionDeclarationView>(&typeId);
627 
628         auto compareKey = [](const Storage::FunctionDeclarationView &view,
629                              const Storage::FunctionDeclaration &value) {
630             return Sqlite::compare(view.name, value.name);
631         };
632 
633         auto insert = [&](const Storage::FunctionDeclaration &value) {
634             Utils::PathString signature{createJson(value.parameters)};
635 
636             insertFunctionDeclarationStatement.write(&typeId, value.name, value.returnTypeName, signature);
637         };
638 
639         auto update = [&](const Storage::FunctionDeclarationView &view,
640                           const Storage::FunctionDeclaration &value) {
641             Utils::PathString signature{createJson(value.parameters)};
642 
643             if (value.returnTypeName == view.returnTypeName && signature == view.signature)
644                 return;
645 
646             updateFunctionDeclarationStatement.write(&view.id, value.returnTypeName, signature);
647         };
648 
649         auto remove = [&](const Storage::FunctionDeclarationView &view) {
650             deleteFunctionDeclarationStatement.write(&view.id);
651         };
652 
653         Sqlite::insertUpdateDelete(range, functionsDeclarations, compareKey, insert, update, remove);
654     }
655 
synchronizeSignalDeclarations(TypeId typeId,Storage::SignalDeclarations & signalDeclarations)656     void synchronizeSignalDeclarations(TypeId typeId, Storage::SignalDeclarations &signalDeclarations)
657     {
658         std::sort(signalDeclarations.begin(), signalDeclarations.end(), [](auto &&first, auto &&second) {
659             return Sqlite::compare(first.name, second.name) < 0;
660         });
661 
662         auto range = selectSignalDeclarationsForTypeIdStatement
663                          .template range<Storage::SignalDeclarationView>(&typeId);
664 
665         auto compareKey = [](const Storage::SignalDeclarationView &view,
666                              const Storage::SignalDeclaration &value) {
667             return Sqlite::compare(view.name, value.name);
668         };
669 
670         auto insert = [&](const Storage::SignalDeclaration &value) {
671             Utils::PathString signature{createJson(value.parameters)};
672 
673             insertSignalDeclarationStatement.write(&typeId, value.name, signature);
674         };
675 
676         auto update = [&](const Storage::SignalDeclarationView &view,
677                           const Storage::SignalDeclaration &value) {
678             Utils::PathString signature{createJson(value.parameters)};
679 
680             if (signature == view.signature)
681                 return;
682 
683             updateSignalDeclarationStatement.write(&view.id, signature);
684         };
685 
686         auto remove = [&](const Storage::SignalDeclarationView &view) {
687             deleteSignalDeclarationStatement.write(&view.id);
688         };
689 
690         Sqlite::insertUpdateDelete(range, signalDeclarations, compareKey, insert, update, remove);
691     }
692 
createJson(const Storage::EnumeratorDeclarations & enumeratorDeclarations)693     Utils::PathString createJson(const Storage::EnumeratorDeclarations &enumeratorDeclarations)
694     {
695         Utils::PathString json;
696         json.append("{");
697 
698         Utils::SmallStringView comma{"\""};
699 
700         for (const auto &enumerator : enumeratorDeclarations) {
701             json.append(comma);
702             comma = ",\"";
703             json.append(enumerator.name);
704             if (enumerator.hasValue) {
705                 json.append("\":\"");
706                 json.append(Utils::SmallString::number(enumerator.value));
707                 json.append("\"");
708             } else {
709                 json.append("\":null");
710             }
711         }
712 
713         json.append("}");
714 
715         return json;
716     }
717 
synchronizeEnumerationDeclarations(TypeId typeId,Storage::EnumerationDeclarations & enumerationDeclarations)718     void synchronizeEnumerationDeclarations(TypeId typeId,
719                                             Storage::EnumerationDeclarations &enumerationDeclarations)
720     {
721         std::sort(enumerationDeclarations.begin(),
722                   enumerationDeclarations.end(),
723                   [](auto &&first, auto &&second) {
724                       return Sqlite::compare(first.name, second.name) < 0;
725                   });
726 
727         auto range = selectEnumerationDeclarationsForTypeIdStatement
728                          .template range<Storage::EnumerationDeclarationView>(&typeId);
729 
730         auto compareKey = [](const Storage::EnumerationDeclarationView &view,
731                              const Storage::EnumerationDeclaration &value) {
732             return Sqlite::compare(view.name, value.name);
733         };
734 
735         auto insert = [&](const Storage::EnumerationDeclaration &value) {
736             Utils::PathString signature{createJson(value.enumeratorDeclarations)};
737 
738             insertEnumerationDeclarationStatement.write(&typeId, value.name, signature);
739         };
740 
741         auto update = [&](const Storage::EnumerationDeclarationView &view,
742                           const Storage::EnumerationDeclaration &value) {
743             Utils::PathString enumeratorDeclarations{createJson(value.enumeratorDeclarations)};
744 
745             if (enumeratorDeclarations == view.enumeratorDeclarations)
746                 return;
747 
748             updateEnumerationDeclarationStatement.write(&view.id, enumeratorDeclarations);
749         };
750 
751         auto remove = [&](const Storage::EnumerationDeclarationView &view) {
752             deleteEnumerationDeclarationStatement.write(&view.id);
753         };
754 
755         Sqlite::insertUpdateDelete(range, enumerationDeclarations, compareKey, insert, update, remove);
756     }
757 
declareType(Storage::Type & type)758     TypeId declareType(Storage::Type &type)
759     {
760         type.typeId = upsertTypeStatement.template value<TypeId>(&type.importId,
761                                                                  type.typeName,
762                                                                  static_cast<int>(type.accessSemantics),
763                                                                  &type.sourceId);
764 
765         for (const auto &exportedType : type.exportedTypes)
766             upsertExportedType(type.importId, exportedType.name, type.typeId);
767 
768         return type.typeId;
769     }
770 
syncType(Storage::Type & type)771     void syncType(Storage::Type &type)
772     {
773         auto typeId = type.typeId;
774 
775         auto prototypeId = fetchTypeIdByNameUngarded(type.prototype, type.importIds);
776 
777         updatePrototypeStatement.write(&typeId, &prototypeId);
778 
779         synchronizePropertyDeclarations(typeId, type.propertyDeclarations, type.importIds);
780         synchronizeFunctionDeclarations(typeId, type.functionDeclarations);
781         synchronizeSignalDeclarations(typeId, type.signalDeclarations);
782         synchronizeEnumerationDeclarations(typeId, type.enumerationDeclarations);
783     }
784 
fetchTypeIdByNameUngarded(const Storage::TypeName & name,ImportIds & importIds)785     TypeId fetchTypeIdByNameUngarded(const Storage::TypeName &name, ImportIds &importIds)
786     {
787         if (Utils::visit([](auto &&type) -> bool { return type.name.isEmpty(); }, name))
788             return TypeId{};
789 
790         struct Inspect
791         {
792             TypeId operator()(const Storage::NativeType &nativeType)
793             {
794                 return storage.selectTypeIdByImportIdsAndNameStatement
795                     .template value<TypeId>(static_cast<void *>(importIds.data()),
796                                             static_cast<long long>(importIds.size()),
797                                             nativeType.name);
798             }
799 
800             TypeId operator()(const Storage::ExportedType &exportedType)
801             {
802                 return storage.selectTypeIdByImportIdsAndExportedNameStatement
803                     .template value<TypeId>(static_cast<void *>(importIds.data()),
804                                             static_cast<long long>(importIds.size()),
805                                             exportedType.name);
806             }
807 
808             TypeId operator()(const Storage::ExplicitExportedType &exportedType)
809             {
810                 return storage.selectTypeIdByImportIdAndExportedNameStatement
811                     .template value<TypeId>(&exportedType.importId, exportedType.name);
812             }
813 
814             ProjectStorage &storage;
815             ImportIds &importIds;
816         };
817 
818         auto typeId = Utils::visit(Inspect{*this, importIds}, name);
819 
820         if (typeId)
821             return typeId;
822 
823         throw TypeNameDoesNotExists{};
824     }
825 
826     using PropertyDeclarationViewTuple = std::tuple<TypeId, PropertyDeclarationId, long long>;
827 
fetchPropertyDeclarationByTypeNameAndName(const Storage::TypeName & typeName,Utils::SmallStringView name,ImportIds & importIds)828     PropertyDeclarationViewTuple fetchPropertyDeclarationByTypeNameAndName(
829         const Storage::TypeName &typeName, Utils::SmallStringView name, ImportIds &importIds)
830     {
831         TypeId typeId = fetchTypeIdByNameUngarded(typeName, importIds);
832 
833         auto propertyDeclaration = selectPropertyDeclarationByTypeIdAndNameStatement
834                                        .template value<PropertyDeclarationViewTuple>(&typeId, name);
835 
836         if (auto id = std::get<PropertyDeclarationId>(propertyDeclaration); id)
837             return propertyDeclaration;
838 
839         throw PropertyNameDoesNotExists{};
840     }
841 
readSourceContextId(Utils::SmallStringView sourceContextPath)842     SourceContextId readSourceContextId(Utils::SmallStringView sourceContextPath)
843     {
844         return selectSourceContextIdFromSourceContextsBySourceContextPathStatement
845             .template value<SourceContextId>(sourceContextPath);
846     }
847 
writeSourceContextId(Utils::SmallStringView sourceContextPath)848     SourceContextId writeSourceContextId(Utils::SmallStringView sourceContextPath)
849     {
850         insertIntoSourceContextsStatement.write(sourceContextPath);
851 
852         return SourceContextId(database.lastInsertedRowId());
853     }
854 
writeSourceId(SourceContextId sourceContextId,Utils::SmallStringView sourceName)855     SourceId writeSourceId(SourceContextId sourceContextId, Utils::SmallStringView sourceName)
856     {
857         insertIntoSourcesStatement.write(&sourceContextId, sourceName);
858 
859         return SourceId(database.lastInsertedRowId());
860     }
861 
readSourceId(SourceContextId sourceContextId,Utils::SmallStringView sourceName)862     SourceId readSourceId(SourceContextId sourceContextId, Utils::SmallStringView sourceName)
863     {
864         return selectSourceIdFromSourcesBySourceContextIdAndSourceNameStatement
865             .template value<SourceId>(&sourceContextId, sourceName);
866     }
867 
fetchExportedTypes(TypeId typeId)868     auto fetchExportedTypes(TypeId typeId)
869     {
870         return selectExportedTypesByTypeIdStatement.template values<Storage::ExportedType>(12,
871                                                                                            &typeId);
872     }
873 
fetchPropertyDeclarations(TypeId typeId)874     auto fetchPropertyDeclarations(TypeId typeId)
875     {
876         return selectPropertyDeclarationsByTypeIdStatement
877             .template values<Storage::PropertyDeclaration>(24, &typeId);
878     }
879 
fetchFunctionDeclarations(TypeId typeId)880     auto fetchFunctionDeclarations(TypeId typeId)
881     {
882         Storage::FunctionDeclarations functionDeclarations;
883 
884         auto callback = [&](Utils::SmallStringView name,
885                             Utils::SmallStringView returnType,
886                             long long functionDeclarationId) {
887             auto &functionDeclaration = functionDeclarations.emplace_back(name, returnType);
888             functionDeclaration.parameters = selectFunctionParameterDeclarationsStatement
889                                                  .template values<Storage::ParameterDeclaration>(
890                                                      8, functionDeclarationId);
891 
892             return Sqlite::CallbackControl::Continue;
893         };
894 
895         selectFunctionDeclarationsForTypeIdWithoutSignatureStatement.readCallback(callback, &typeId);
896 
897         return functionDeclarations;
898     }
899 
fetchSignalDeclarations(TypeId typeId)900     auto fetchSignalDeclarations(TypeId typeId)
901     {
902         Storage::SignalDeclarations signalDeclarations;
903 
904         auto callback = [&](Utils::SmallStringView name, long long signalDeclarationId) {
905             auto &signalDeclaration = signalDeclarations.emplace_back(name);
906             signalDeclaration.parameters = selectSignalParameterDeclarationsStatement
907                                                .template values<Storage::ParameterDeclaration>(
908                                                    8, signalDeclarationId);
909 
910             return Sqlite::CallbackControl::Continue;
911         };
912 
913         selectSignalDeclarationsForTypeIdWithoutSignatureStatement.readCallback(callback, &typeId);
914 
915         return signalDeclarations;
916     }
917 
fetchEnumerationDeclarations(TypeId typeId)918     auto fetchEnumerationDeclarations(TypeId typeId)
919     {
920         Storage::EnumerationDeclarations enumerationDeclarations;
921 
922         auto callback = [&](Utils::SmallStringView name, long long enumerationDeclarationId) {
923             enumerationDeclarations.emplace_back(
924                 name,
925                 selectEnumeratorDeclarationStatement
926                     .template values<Storage::EnumeratorDeclaration>(8, enumerationDeclarationId));
927 
928             return Sqlite::CallbackControl::Continue;
929         };
930 
931         selectEnumerationDeclarationsForTypeIdWithoutEnumeratorDeclarationsStatement
932             .readCallback(callback, &typeId);
933 
934         return enumerationDeclarations;
935     }
936 
937     class Initializer
938     {
939     public:
Initializer(Database & database,bool isInitialized)940         Initializer(Database &database, bool isInitialized)
941         {
942             if (!isInitialized) {
943                 Sqlite::ExclusiveTransaction transaction{database};
944 
945                 createImportsTable(database);
946                 createImportDependeciesTable(database);
947                 createSourceContextsTable(database);
948                 createSourcesTable(database);
949                 createTypesAndePropertyDeclarationsTables(database);
950                 createExportedTypesTable(database);
951                 createEnumerationsTable(database);
952                 createFunctionsTable(database);
953                 createSignalsTable(database);
954 
955                 transaction.commit();
956 
957                 database.walCheckpointFull();
958             }
959         }
960 
createSourceContextsTable(Database & database)961         void createSourceContextsTable(Database &database)
962         {
963             Sqlite::Table table;
964             table.setUseIfNotExists(true);
965             table.setName("sourceContexts");
966             table.addColumn("sourceContextId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
967             const Sqlite::Column &sourceContextPathColumn = table.addColumn("sourceContextPath");
968 
969             table.addUniqueIndex({sourceContextPathColumn});
970 
971             table.initialize(database);
972         }
973 
createSourcesTable(Database & database)974         void createSourcesTable(Database &database)
975         {
976             Sqlite::Table table;
977             table.setUseIfNotExists(true);
978             table.setName("sources");
979             table.addColumn("sourceId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
980             const Sqlite::Column &sourceContextIdColumn = table.addColumn(
981                 "sourceContextId",
982                 Sqlite::ColumnType::Integer,
983                 {Sqlite::NotNull{},
984                  Sqlite::ForeignKey{"sourceContexts",
985                                     "sourceContextId",
986                                     Sqlite::ForeignKeyAction::NoAction,
987                                     Sqlite::ForeignKeyAction::Cascade}});
988             const Sqlite::Column &sourceNameColumn = table.addColumn("sourceName");
989             table.addUniqueIndex({sourceContextIdColumn, sourceNameColumn});
990 
991             table.initialize(database);
992         }
993 
createTypesAndePropertyDeclarationsTables(Database & database)994         void createTypesAndePropertyDeclarationsTables(Database &database)
995         {
996             Sqlite::Table typesTable;
997             typesTable.setUseIfNotExists(true);
998             typesTable.setName("types");
999             typesTable.addColumn("typeId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
1000             auto &importIdColumn = typesTable.addColumn("importId");
1001             auto &typesNameColumn = typesTable.addColumn("name");
1002             typesTable.addColumn("accessSemantics");
1003             typesTable.addColumn("sourceId");
1004             typesTable.addForeignKeyColumn("prototypeId",
1005                                            typesTable,
1006                                            Sqlite::ForeignKeyAction::NoAction,
1007                                            Sqlite::ForeignKeyAction::Restrict);
1008 
1009             typesTable.addUniqueIndex({importIdColumn, typesNameColumn});
1010 
1011             typesTable.initialize(database);
1012 
1013             {
1014                 Sqlite::Table propertyDeclarationTable;
1015                 propertyDeclarationTable.setUseIfNotExists(true);
1016                 propertyDeclarationTable.setName("propertyDeclarations");
1017                 propertyDeclarationTable.addColumn("propertyDeclarationId",
1018                                                    Sqlite::ColumnType::Integer,
1019                                                    {Sqlite::PrimaryKey{}});
1020                 auto &typeIdColumn = propertyDeclarationTable.addColumn("typeId");
1021                 auto &nameColumn = propertyDeclarationTable.addColumn("name");
1022                 propertyDeclarationTable.addForeignKeyColumn("propertyTypeId",
1023                                                              typesTable,
1024                                                              Sqlite::ForeignKeyAction::NoAction,
1025                                                              Sqlite::ForeignKeyAction::Restrict);
1026                 propertyDeclarationTable.addColumn("propertyTraits");
1027                 auto &aliasPropertyDeclarationIdColumn = propertyDeclarationTable.addForeignKeyColumn(
1028                     "aliasPropertyDeclarationId",
1029                     propertyDeclarationTable,
1030                     Sqlite::ForeignKeyAction::NoAction,
1031                     Sqlite::ForeignKeyAction::Restrict);
1032 
1033                 propertyDeclarationTable.addUniqueIndex({typeIdColumn, nameColumn});
1034                 propertyDeclarationTable.addIndex({aliasPropertyDeclarationIdColumn},
1035                                                   "aliasPropertyDeclarationId IS NOT NULL");
1036 
1037                 propertyDeclarationTable.initialize(database);
1038             }
1039         }
1040 
createExportedTypesTable(Database & database)1041         void createExportedTypesTable(Database &database)
1042         {
1043             Sqlite::Table table;
1044             table.setUseIfNotExists(true);
1045             table.setUseWithoutRowId(true);
1046             table.setName("exportedTypes");
1047             auto &importIdColumn = table.addColumn("importId");
1048             auto &nameColumn = table.addColumn("name");
1049             table.addColumn("typeId");
1050 
1051             table.addPrimaryKeyContraint({importIdColumn, nameColumn});
1052 
1053             table.initialize(database);
1054         }
1055 
createEnumerationsTable(Database & database)1056         void createEnumerationsTable(Database &database)
1057         {
1058             Sqlite::Table table;
1059             table.setUseIfNotExists(true);
1060             table.setName("enumerationDeclarations");
1061             table.addColumn("enumerationDeclarationId",
1062                             Sqlite::ColumnType::Integer,
1063                             {Sqlite::PrimaryKey{}});
1064             auto &typeIdColumn = table.addColumn("typeId");
1065             auto &nameColumn = table.addColumn("name");
1066             table.addColumn("enumeratorDeclarations");
1067 
1068             table.addUniqueIndex({typeIdColumn, nameColumn});
1069 
1070             table.initialize(database);
1071         }
1072 
createFunctionsTable(Database & database)1073         void createFunctionsTable(Database &database)
1074         {
1075             Sqlite::Table table;
1076             table.setUseIfNotExists(true);
1077             table.setName("functionDeclarations");
1078             table.addColumn("functionDeclarationId",
1079                             Sqlite::ColumnType::Integer,
1080                             {Sqlite::PrimaryKey{}});
1081             auto &typeIdColumn = table.addColumn("typeId");
1082             auto &nameColumn = table.addColumn("name");
1083             table.addColumn("signature");
1084             table.addColumn("returnTypeName");
1085 
1086             table.addUniqueIndex({typeIdColumn, nameColumn});
1087 
1088             table.initialize(database);
1089         }
1090 
createSignalsTable(Database & database)1091         void createSignalsTable(Database &database)
1092         {
1093             Sqlite::Table table;
1094             table.setUseIfNotExists(true);
1095             table.setName("signalDeclarations");
1096             table.addColumn("signalDeclarationId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
1097             auto &typeIdColumn = table.addColumn("typeId");
1098             auto &nameColumn = table.addColumn("name");
1099             table.addColumn("signature");
1100 
1101             table.addUniqueIndex({typeIdColumn, nameColumn});
1102 
1103             table.initialize(database);
1104         }
1105 
createImportsTable(Database & database)1106         void createImportsTable(Database &database)
1107         {
1108             Sqlite::Table table;
1109             table.setUseIfNotExists(true);
1110             table.setName("imports");
1111             table.addColumn("importId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
1112             auto &nameColumn = table.addColumn("name");
1113             auto &versionColumn = table.addColumn("version");
1114             table.addColumn("sourceId");
1115 
1116             table.addUniqueIndex({nameColumn, versionColumn});
1117 
1118             table.initialize(database);
1119         }
1120 
createImportDependeciesTable(Database & database)1121         void createImportDependeciesTable(Database &database)
1122         {
1123             Sqlite::Table table;
1124             table.setUseIfNotExists(true);
1125             table.setUseWithoutRowId(true);
1126             table.setName("importDependencies");
1127             auto &importIdColumn = table.addColumn("importId");
1128             auto &parentImportIdColumn = table.addColumn("parentImportId");
1129 
1130             table.addPrimaryKeyContraint({importIdColumn, parentImportIdColumn});
1131 
1132             table.initialize(database);
1133         }
1134     };
1135 
1136 public:
1137     Database &database;
1138     Initializer initializer;
1139     ReadWriteStatement<1> upsertTypeStatement{
1140         "INSERT INTO types(importId, name,  accessSemantics, sourceId) VALUES(?1, ?2, "
1141         "?3, nullif(?4, -1)) ON "
1142         "CONFLICT DO UPDATE SET prototypeId=excluded.prototypeId, "
1143         "accessSemantics=excluded.accessSemantics, sourceId=excluded.sourceId RETURNING typeId",
1144         database};
1145     WriteStatement updatePrototypeStatement{
1146         "UPDATE types SET prototypeId=nullif(?2, -1) WHERE typeId=?1", database};
1147     mutable ReadStatement<1> selectTypeIdByExportedNameStatement{
1148         "SELECT typeId FROM exportedTypes WHERE name=?1", database};
1149     mutable ReadStatement<1> selectPrototypeIdStatement{
1150         "WITH RECURSIVE "
1151         "  typeSelection(typeId) AS ("
1152         "      VALUES(?1) "
1153         "    UNION ALL "
1154         "      SELECT prototypeId FROM types JOIN typeSelection USING(typeId)) "
1155         "SELECT typeId FROM typeSelection WHERE typeId=?2 LIMIT 1",
1156         database};
1157     mutable ReadStatement<1> selectPropertyDeclarationIdByTypeIdAndNameStatement{
1158         "WITH RECURSIVE "
1159         "  typeSelection(typeId) AS ("
1160         "      VALUES(?1) "
1161         "    UNION ALL "
1162         "      SELECT prototypeId FROM types JOIN typeSelection USING(typeId)) "
1163         "SELECT propertyDeclarationId FROM propertyDeclarations JOIN typeSelection USING(typeId) "
1164         "  WHERE name=?2 LIMIT 1",
1165         database};
1166     mutable ReadStatement<3> selectPropertyDeclarationByTypeIdAndNameStatement{
1167         "WITH RECURSIVE "
1168         "  typeSelection(typeId) AS ("
1169         "      VALUES(?1) "
1170         "    UNION ALL "
1171         "      SELECT prototypeId FROM types JOIN typeSelection USING(typeId)) "
1172         "SELECT propertyTypeId, propertyDeclarationId, propertyTraits FROM propertyDeclarations "
1173         "    JOIN typeSelection USING(typeId) "
1174         "  WHERE name=?2 LIMIT 1",
1175         database};
1176     WriteStatement upsertExportedTypesStatement{"INSERT INTO exportedTypes(importId, name, typeId) "
1177                                                 "VALUES(?1, ?2, ?3) ON CONFLICT DO NOTHING",
1178                                                 database};
1179     mutable ReadStatement<1> selectPrototypeIdsStatement{
1180         "WITH RECURSIVE "
1181         "  typeSelection(typeId) AS ("
1182         "      VALUES(?1) "
1183         "    UNION ALL "
1184         "      SELECT prototypeId FROM types JOIN typeSelection USING(typeId)) "
1185         "SELECT typeId FROM typeSelection",
1186         database};
1187     mutable ReadStatement<1> selectSourceContextIdFromSourceContextsBySourceContextPathStatement{
1188         "SELECT sourceContextId FROM sourceContexts WHERE sourceContextPath = ?", database};
1189     mutable ReadStatement<1> selectSourceContextPathFromSourceContextsBySourceContextIdStatement{
1190         "SELECT sourceContextPath FROM sourceContexts WHERE sourceContextId = ?", database};
1191     mutable ReadStatement<2> selectAllSourceContextsStatement{
1192         "SELECT sourceContextPath, sourceContextId FROM sourceContexts", database};
1193     WriteStatement insertIntoSourceContextsStatement{
1194         "INSERT INTO sourceContexts(sourceContextPath) VALUES (?)", database};
1195     mutable ReadStatement<1> selectSourceIdFromSourcesBySourceContextIdAndSourceNameStatement{
1196         "SELECT sourceId FROM sources WHERE sourceContextId = ? AND sourceName = ?", database};
1197     mutable ReadStatement<2> selectSourceNameAndSourceContextIdFromSourcesBySourceIdStatement{
1198         "SELECT sourceName, sourceContextId FROM sources WHERE sourceId = ?", database};
1199     mutable ReadStatement<1> selectSourceContextIdFromSourcesBySourceIdStatement{
1200         "SELECT sourceContextId FROM sources WHERE sourceId = ?", database};
1201     WriteStatement insertIntoSourcesStatement{
1202         "INSERT INTO sources(sourceContextId, sourceName) VALUES (?,?)", database};
1203     mutable ReadStatement<3> selectAllSourcesStatement{
1204         "SELECT sourceName, sourceContextId, sourceId  FROM sources", database};
1205     mutable ReadStatement<1> selectTypeIdByImportIdsAndNameStatement{
1206         "SELECT typeId FROM types WHERE importId IN carray(?1, ?2, 'int64') AND name=?3", database};
1207     mutable ReadStatement<5> selectTypeByTypeIdStatement{
1208         "SELECT importId, name, (SELECT name FROM types WHERE typeId=outerTypes.prototypeId), "
1209         "accessSemantics, ifnull(sourceId, -1) FROM types AS outerTypes WHERE typeId=?",
1210         database};
1211     mutable ReadStatement<1> selectExportedTypesByTypeIdStatement{
1212         "SELECT name FROM exportedTypes WHERE typeId=?", database};
1213     mutable ReadStatement<6> selectTypesStatement{
1214         "SELECT importId, name, typeId, (SELECT name FROM types WHERE "
1215         "typeId=outerTypes.prototypeId), accessSemantics, ifnull(sourceId, -1) FROM types AS "
1216         "outerTypes",
1217         database};
1218     ReadStatement<1> selectNotUpdatedTypesInSourcesStatement{
1219         "SELECT typeId FROM types WHERE (sourceId IN carray(?1) AND typeId NOT IN carray(?2))",
1220         database};
1221     WriteStatement deleteExportTypesByTypeIdStatement{"DELETE FROM exportedTypes WHERE typeId=?",
1222                                                       database};
1223     WriteStatement deleteEnumerationDeclarationByTypeIdStatement{
1224         "DELETE FROM enumerationDeclarations WHERE typeId=?", database};
1225     WriteStatement deletePropertyDeclarationByTypeIdStatement{
1226         "DELETE FROM propertyDeclarations WHERE typeId=?", database};
1227     WriteStatement deleteFunctionDeclarationByTypeIdStatement{
1228         "DELETE FROM functionDeclarations WHERE typeId=?", database};
1229     WriteStatement deleteSignalDeclarationByTypeIdStatement{
1230         "DELETE FROM signalDeclarations WHERE typeId=?", database};
1231     WriteStatement deleteTypeStatement{"DELETE FROM types  WHERE typeId=?", database};
1232     mutable ReadStatement<3> selectPropertyDeclarationsByTypeIdStatement{
1233         "SELECT name, (SELECT name FROM types WHERE typeId=propertyDeclarations.propertyTypeId),"
1234         "propertyTraits FROM propertyDeclarations WHERE typeId=?",
1235         database};
1236     ReadStatement<4> selectPropertyDeclarationsForTypeIdStatement{
1237         "SELECT name, propertyTraits, propertyTypeId, propertyDeclarationId FROM "
1238         "propertyDeclarations WHERE typeId=? AND aliasPropertyDeclarationId IS NULL ORDER BY "
1239         "name",
1240         database};
1241     WriteStatement insertPropertyDeclarationStatement{
1242         "INSERT INTO propertyDeclarations(typeId, name, propertyTypeId, propertyTraits) "
1243         "VALUES(?1, ?2, ?3, ?4)",
1244         database};
1245     WriteStatement updatePropertyDeclarationStatement{
1246         "UPDATE propertyDeclarations SET propertyTypeId=?2, propertyTraits=?3 WHERE "
1247         "propertyDeclarationId=?1 OR aliasPropertyDeclarationId=?1",
1248         database};
1249     WriteStatement deletePropertyDeclarationStatement{
1250         "DELETE FROM propertyDeclarations WHERE propertyDeclarationId=?", database};
1251     ReadStatement<3> selectPropertyDeclarationsWithAliasForTypeIdStatement{
1252         "SELECT name, propertyDeclarationId, aliasPropertyDeclarationId FROM propertyDeclarations "
1253         "WHERE typeId=? AND aliasPropertyDeclarationId IS NOT NULL ORDER BY name",
1254         database};
1255     WriteStatement insertPropertyDeclarationWithAliasStatement{
1256         "INSERT INTO propertyDeclarations(typeId, name, propertyTypeId, propertyTraits, "
1257         "aliasPropertyDeclarationId) VALUES(?1, ?2, ?3, ?4, ?5) ",
1258         database};
1259     WriteStatement updatePropertyDeclarationWithAliasStatement{
1260         "UPDATE propertyDeclarations SET propertyTypeId=?2, propertyTraits=?3, "
1261         "aliasPropertyDeclarationId=?4 WHERE propertyDeclarationId=?1",
1262         database};
1263     mutable ReadStatement<4> selectFunctionDeclarationsForTypeIdStatement{
1264         "SELECT name, returnTypeName, signature, functionDeclarationId FROM "
1265         "functionDeclarations WHERE typeId=? ORDER BY name",
1266         database};
1267     mutable ReadStatement<3> selectFunctionDeclarationsForTypeIdWithoutSignatureStatement{
1268         "SELECT name, returnTypeName, functionDeclarationId FROM "
1269         "functionDeclarations WHERE typeId=? ORDER BY name",
1270         database};
1271     mutable ReadStatement<3> selectFunctionParameterDeclarationsStatement{
1272         "SELECT json_extract(json_each.value, '$.n'), json_extract(json_each.value, '$.tn'), "
1273         "json_extract(json_each.value, '$.tr') FROM functionDeclarations, "
1274         "json_each(functionDeclarations.signature) WHERE functionDeclarationId=?",
1275         database};
1276     WriteStatement insertFunctionDeclarationStatement{
1277         "INSERT INTO functionDeclarations(typeId, name, returnTypeName, signature) VALUES(?1, ?2, "
1278         "?3, ?4)",
1279         database};
1280     WriteStatement updateFunctionDeclarationStatement{
1281         "UPDATE functionDeclarations SET returnTypeName=?2, signature=?3 WHERE "
1282         "functionDeclarationId=?1",
1283         database};
1284     WriteStatement deleteFunctionDeclarationStatement{
1285         "DELETE FROM functionDeclarations WHERE functionDeclarationId=?", database};
1286     mutable ReadStatement<3> selectSignalDeclarationsForTypeIdStatement{
1287         "SELECT name, signature, signalDeclarationId FROM signalDeclarations WHERE typeId=? ORDER "
1288         "BY name",
1289         database};
1290     mutable ReadStatement<2> selectSignalDeclarationsForTypeIdWithoutSignatureStatement{
1291         "SELECT name, signalDeclarationId FROM signalDeclarations WHERE typeId=? ORDER BY name",
1292         database};
1293     mutable ReadStatement<3> selectSignalParameterDeclarationsStatement{
1294         "SELECT json_extract(json_each.value, '$.n'), json_extract(json_each.value, '$.tn'), "
1295         "json_extract(json_each.value, '$.tr') FROM signalDeclarations, "
1296         "json_each(signalDeclarations.signature) WHERE signalDeclarationId=?",
1297         database};
1298     WriteStatement insertSignalDeclarationStatement{
1299         "INSERT INTO signalDeclarations(typeId, name, signature) VALUES(?1, ?2, ?3)", database};
1300     WriteStatement updateSignalDeclarationStatement{
1301         "UPDATE signalDeclarations SET  signature=?2 WHERE signalDeclarationId=?1", database};
1302     WriteStatement deleteSignalDeclarationStatement{
1303         "DELETE FROM signalDeclarations WHERE signalDeclarationId=?", database};
1304     mutable ReadStatement<3> selectEnumerationDeclarationsForTypeIdStatement{
1305         "SELECT name, enumeratorDeclarations, enumerationDeclarationId FROM "
1306         "enumerationDeclarations WHERE typeId=? ORDER BY name",
1307         database};
1308     mutable ReadStatement<2> selectEnumerationDeclarationsForTypeIdWithoutEnumeratorDeclarationsStatement{
1309         "SELECT name, enumerationDeclarationId FROM enumerationDeclarations WHERE typeId=? ORDER "
1310         "BY name",
1311         database};
1312     mutable ReadStatement<3> selectEnumeratorDeclarationStatement{
1313         "SELECT json_each.key, json_each.value, json_each.type!='null' FROM "
1314         "enumerationDeclarations, json_each(enumerationDeclarations.enumeratorDeclarations) WHERE "
1315         "enumerationDeclarationId=?",
1316         database};
1317     WriteStatement insertEnumerationDeclarationStatement{
1318         "INSERT INTO enumerationDeclarations(typeId, name, enumeratorDeclarations) VALUES(?1, ?2, "
1319         "?3)",
1320         database};
1321     WriteStatement updateEnumerationDeclarationStatement{
1322         "UPDATE enumerationDeclarations SET  enumeratorDeclarations=?2 WHERE "
1323         "enumerationDeclarationId=?1",
1324         database};
1325     WriteStatement deleteEnumerationDeclarationStatement{
1326         "DELETE FROM enumerationDeclarations WHERE enumerationDeclarationId=?", database};
1327     mutable ReadWriteStatement<1> insertImportStatement{
1328         "INSERT INTO imports(name, version, sourceId) VALUES(?1, ?2, ?3) RETURNING importId",
1329         database};
1330     WriteStatement updateImportStatement{"UPDATE imports SET sourceId=?2 WHERE importId=?1", database};
1331     WriteStatement deleteImportStatement{"DELETE FROM imports WHERE importId=?", database};
1332     mutable ReadStatement<1> selectImportIdByNameStatement{
1333         "SELECT importId FROM imports WHERE name=? ORDER BY version DESC LIMIT 1", database};
1334     mutable ReadStatement<1> selectImportIdByNameAndVersionStatement{
1335         "SELECT importId FROM imports WHERE name=? AND version=?", database};
1336     mutable ReadStatement<4> selectAllImportsStatement{
1337         "SELECT name, version, sourceId, importId FROM imports ORDER BY name, version", database};
1338     WriteStatement insertImportDependencyStatement{
1339         "INSERT INTO importDependencies(importId, parentImportId) VALUES(?1, ?2)", database};
1340     WriteStatement deleteImportDependencyStatement{
1341         "DELETE FROM importDependencies WHERE importId=?1 AND parentImportId=?2", database};
1342     mutable ReadStatement<2> selectAllImportDependenciesStatement{
1343         "SELECT importId, parentImportId FROM importDependencies ORDER BY importId, parentImportId",
1344         database};
1345     mutable ReadStatement<2> selectImportsForThatDependentOnThisImportIdStatement{
1346         "SELECT name, version FROM importDependencies JOIN imports ON "
1347         "importDependencies.parentImportId = imports.importId WHERE importDependencies.importId=?",
1348         database};
1349     mutable ReadStatement<1> selectTypeIdsForImportIdStatement{
1350         "SELECT typeId FROM types WHERE importId=?", database};
1351     mutable ReadStatement<1> selectTypeIdByImportIdAndNameStatement{
1352         "SELECT typeId FROM types WHERE importId=?1 and name=?2", database};
1353     mutable ReadStatement<1> selectTypeIdByImportIdsAndExportedNameStatement{
1354         "SELECT typeId FROM exportedTypes WHERE importId IN carray(?1, ?2, 'int64') AND name=?3",
1355         database};
1356     mutable ReadStatement<1> selectTypeIdByImportIdAndExportedNameStatement{
1357         "SELECT typeId FROM exportedTypes WHERE importId=?1 AND name=?2", database};
1358     mutable ReadStatement<1> fetchImportDependencyIdsStatement{
1359         "WITH RECURSIVE "
1360         "  importIds(importId) AS ("
1361         "      SELECT value FROM carray(?1, ?2, 'int64') "
1362         "    UNION "
1363         "      SELECT parentImportId FROM importDependencies JOIN importIds USING(importId)) "
1364         "SELECT importId FROM importIds",
1365         database};
1366 };
1367 
1368 } // namespace QmlDesigner
1369