File indexing completed on 2024-05-19 05:42:12

0001 // ct_lvtmdb_soci_reader.h                                      -*-C++-*-
0002 
0003 /*
0004 // Copyright 2023 Codethink Ltd <codethink@codethink.co.uk>
0005 // SPDX-License-Identifier: Apache-2.0
0006 //
0007 // Licensed under the Apache License, Version 2.0 (the "License");
0008 // you may not use this file except in compliance with the License.
0009 // You may obtain a copy of the License at
0010 //
0011 //     http://www.apache.org/licenses/LICENSE-2.0
0012 //
0013 // Unless required by applicable law or agreed to in writing, software
0014 // distributed under the License is distributed on an "AS IS" BASIS,
0015 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0016 // See the License for the specific language governing permissions and
0017 // limitations under the License.
0018 */
0019 
0020 #include <ct_lvtmdb_soci_helper.h>
0021 #include <ct_lvtmdb_soci_reader.h>
0022 #include <ct_lvtshr_graphenums.h>
0023 
0024 #include <filesystem>
0025 #include <optional>
0026 
0027 #include <soci/soci-backend.h>
0028 #include <soci/soci.h>
0029 #include <soci/sqlite3/soci-sqlite3.h>
0030 
0031 #include <ct_lvtmdb_componentobject.h>
0032 #include <ct_lvtmdb_errorobject.h>
0033 #include <ct_lvtmdb_fieldobject.h>
0034 #include <ct_lvtmdb_fileobject.h>
0035 #include <ct_lvtmdb_functionobject.h>
0036 #include <ct_lvtmdb_methodobject.h>
0037 #include <ct_lvtmdb_namespaceobject.h>
0038 #include <ct_lvtmdb_packageobject.h>
0039 #include <ct_lvtmdb_repositoryobject.h>
0040 #include <ct_lvtmdb_typeobject.h>
0041 #include <ct_lvtmdb_variableobject.h>
0042 
0043 using namespace Codethink::lvtmdb;
0044 
0045 namespace {
0046 
0047 struct Maps {
0048     std::map<std::string, RepositoryObject *> repositoryMap;
0049     std::map<std::string, PackageObject *> packageMap;
0050     std::map<int, ComponentObject *> componentMap;
0051     std::map<int, FileObject *> filesMap;
0052     std::map<std::string, NamespaceObject *> namespaceMap;
0053     std::map<int, VariableObject *> variableMap;
0054     std::map<int, FunctionObject *> functionMap;
0055     std::map<int, TypeObject *> userDefinedTypeMap;
0056     std::map<int, FieldObject *> fieldMap;
0057     std::map<int, MethodObject *> methodMap;
0058 };
0059 
0060 void loadRepositories(ObjectStore& store, soci::session& db, Maps& map)
0061 {
0062     soci::rowset<soci::row> rowset = (db.prepare << "select name, disk_path from source_repository");
0063     for (const auto& row : rowset) {
0064         const auto name = row.get<std::string>(0);
0065         const auto path = row.get<std::string>(1);
0066         auto *repo = store.getOrAddRepository(name, path);
0067         map.repositoryMap[name] = repo;
0068     }
0069 }
0070 
0071 struct PackageQueryParams {
0072     int id = 0;
0073 
0074     soci::indicator parent_ind = soci::indicator::i_null;
0075     std::string parent_qualified_name;
0076 
0077     soci::indicator repository_ind = soci::indicator::i_null;
0078     std::string repository_name;
0079 
0080     std::string name;
0081     std::string qualified_name;
0082     std::string path;
0083 };
0084 
0085 // This loads the packages in order so we don't need to worry about having
0086 // not loaded the parent yet.
0087 void loadPackages(ObjectStore& store, soci::session& db, Maps& maps, std::optional<int> parent_id)
0088 {
0089     // soci prepared statements didn't work for null vs value, neither with std::optional.'
0090     std::string query =
0091         R"(select
0092   sp.id,
0093   pp.qualified_name as parent_name,
0094   sp.name,
0095   sp.qualified_name,
0096   sp.disk_path,
0097   re.name
0098 from
0099   source_package sp
0100 left join
0101     source_package pp on sp.parent_id = pp.id
0102 left join
0103     source_repository re on sp.source_repository_id = re.id
0104 where sp.parent_id is )"
0105         + (parent_id.has_value() ? std::to_string(parent_id.value()) : "NULL");
0106 
0107     PackageQueryParams params;
0108     soci::statement st = (db.prepare << query,
0109                           soci::into(params.id),
0110                           soci::into(params.parent_qualified_name, params.parent_ind),
0111                           soci::into(params.name),
0112                           soci::into(params.qualified_name),
0113                           soci::into(params.path),
0114                           soci::into(params.repository_name, params.repository_ind));
0115 
0116     st.execute();
0117     std::vector<int> current_parents;
0118     while (st.fetch()) {
0119         PackageObject *parent = nullptr;
0120         if (params.parent_ind == soci::indicator::i_ok) {
0121             parent = maps.packageMap[params.parent_qualified_name];
0122         }
0123 
0124         RepositoryObject *repository = nullptr;
0125         if (params.repository_ind == soci::indicator::i_ok) {
0126             repository = maps.repositoryMap[params.repository_name];
0127         }
0128 
0129         PackageObject *pkg = store.getOrAddPackage(params.qualified_name, params.name, params.path, parent, repository);
0130         current_parents.push_back(params.id);
0131         maps.packageMap[params.qualified_name] = pkg;
0132 
0133         if (parent) {
0134             auto lock = parent->rwLock();
0135             (void) lock;
0136             parent->addChild(pkg);
0137         }
0138     }
0139 
0140     for (const auto current_parent : current_parents) {
0141         loadPackages(store, db, maps, current_parent);
0142     }
0143 }
0144 
0145 struct ComponentQueryParams {
0146     int id = 0;
0147     std::string packageQualifiedName;
0148     std::string qualifiedName;
0149     std::string name;
0150 };
0151 
0152 void loadComponents(ObjectStore& store, soci::session& db, Maps& maps)
0153 {
0154     // soci prepared statements didn't work for null vs value, neither with std::optional.'
0155     std::string query = R"(select
0156     sc.id,
0157     sc.qualified_name,
0158     sc.name,
0159     sp.qualified_name as package_name
0160 from
0161     source_component sc
0162 left join
0163     source_package sp on sc.package_id = sp.id)";
0164 
0165     ComponentQueryParams params;
0166     soci::statement st = (db.prepare << query,
0167                           soci::into(params.id),
0168                           soci::into(params.qualifiedName),
0169                           soci::into(params.name),
0170                           soci::into(params.packageQualifiedName));
0171 
0172     st.execute();
0173     while (st.fetch()) {
0174         PackageObject *package = maps.packageMap[params.packageQualifiedName];
0175         auto *comp = store.getOrAddComponent(params.qualifiedName, params.name, package);
0176         maps.componentMap[params.id] = comp;
0177 
0178         auto lock = package->rwLock();
0179         (void) lock;
0180         package->addComponent(comp);
0181     }
0182 }
0183 
0184 struct FileQueryParams {
0185     int id = 0;
0186     std::string package_qualified_name;
0187     int component_id = 0;
0188     std::string name;
0189     std::string qualifiedName;
0190     int is_header = false; // bool.
0191     std::string hash;
0192 };
0193 
0194 void loadFiles(ObjectStore& store, soci::session& db, Maps& maps)
0195 {
0196     std::string query = R"(select
0197     sf.id,
0198     sp.qualified_name as package_name,
0199     sf.component_id,
0200     sf.name,
0201     sf.qualified_name,
0202     sf.is_header,
0203     sf.hash
0204 from
0205     source_file sf
0206 left join
0207     source_package sp on sf.package_id = sp.id)";
0208 
0209     FileQueryParams params;
0210     soci::statement st = (db.prepare << query,
0211                           soci::into(params.id),
0212                           soci::into(params.package_qualified_name),
0213                           soci::into(params.component_id),
0214                           soci::into(params.name),
0215                           soci::into(params.qualifiedName),
0216                           soci::into(params.is_header),
0217                           soci::into(params.hash));
0218 
0219     st.execute();
0220     while (st.fetch()) {
0221         PackageObject *package = maps.packageMap[params.package_qualified_name];
0222         ComponentObject *comp = maps.componentMap[params.component_id];
0223         auto *fileObj =
0224             store.getOrAddFile(params.qualifiedName, params.name, params.is_header, params.hash, package, comp);
0225 
0226         auto lock = comp->rwLock();
0227         (void) lock;
0228         comp->addFile(fileObj);
0229         maps.filesMap[params.id] = fileObj;
0230     }
0231 }
0232 
0233 /* this is a 1-1 mapping of the Sql schema. it clearly shows that we should
0234  * change this table to have the file_id instead of the file_name.
0235  */
0236 struct ErrorQueryParams {
0237     int id = 0;
0238     int error_kind = 0;
0239     std::string fully_qualified_name;
0240     std::string error_message;
0241     std::string file_name;
0242 };
0243 
0244 void loadErrors(ObjectStore& store, soci::session& db, Maps& maps)
0245 {
0246     std::string query = "select id, error_kind, fully_qualified_name, error_message, file_name from error_messages";
0247     ErrorQueryParams params;
0248     soci::statement st = (db.prepare << query,
0249                           soci::into(params.id),
0250                           soci::into(params.error_kind),
0251                           soci::into(params.fully_qualified_name),
0252                           soci::into(params.error_message),
0253                           soci::into(params.file_name));
0254 
0255     st.execute();
0256     while (st.fetch()) {
0257         // I see no need to store the errors on a map, just load it directly.
0258         auto kind = static_cast<MdbUtil::ErrorKind>(params.error_kind);
0259         store.getOrAddError(kind, params.fully_qualified_name, params.error_message, params.file_name);
0260     }
0261 }
0262 
0263 struct NamespaceQueryParams {
0264     int id = 0;
0265     soci::indicator parent_qualified_name_ind = soci::indicator::i_null;
0266     std::string parent_qualified_name;
0267     std::string name;
0268     std::string qualified_name;
0269 };
0270 
0271 void loadNamespaces(ObjectStore& store, soci::session& db, Maps& maps, std::optional<int> parent_id)
0272 {
0273     std::string query =
0274         R"(select
0275         ns.id,
0276         ns.name,
0277         ns.qualified_name,
0278         pns.qualified_name
0279     from namespace_declaration ns
0280     left join namespace_declaration pns on ns.parent_id = pns.id
0281     where ns.parent_id is )"
0282         + (parent_id.has_value() ? std::to_string(parent_id.value()) : "NULL");
0283 
0284     NamespaceQueryParams params;
0285     soci::statement st = (db.prepare << query,
0286                           soci::into(params.id),
0287                           soci::into(params.name),
0288                           soci::into(params.qualified_name),
0289                           soci::into(params.parent_qualified_name, params.parent_qualified_name_ind));
0290 
0291     st.execute();
0292     std::vector<int> current_parents;
0293     while (st.fetch()) {
0294         NamespaceObject *parent = nullptr;
0295         if (params.parent_qualified_name_ind == soci::indicator::i_ok) {
0296             parent = maps.namespaceMap[params.parent_qualified_name];
0297         }
0298 
0299         auto *ns = store.getOrAddNamespace(params.qualified_name, params.name, parent);
0300         current_parents.push_back(params.id);
0301         maps.namespaceMap[params.qualified_name] = ns;
0302     }
0303 
0304     for (const auto current_parent : current_parents) {
0305         loadNamespaces(store, db, maps, current_parent);
0306     }
0307 }
0308 
0309 struct VariableQueryParams {
0310     int id = 0;
0311     soci::indicator ns_qual_name_ind = soci::indicator::i_null;
0312     std::string ns_qual_name;
0313     std::string name;
0314     std::string qualified_name;
0315     std::string signature;
0316     int is_global = 0; // bool.
0317 };
0318 
0319 void loadVariables(ObjectStore& store, soci::session& db, Maps& maps)
0320 {
0321     std::string query =
0322         R"(select
0323         va.id,
0324         va.name,
0325         va.qualified_name,
0326         va.signature,
0327         va.is_global,
0328         ns.qualified_name
0329     from
0330         variable_declaration va
0331     left join
0332         namespace_declaration ns on ns.id = va.namespace_id
0333     )";
0334 
0335     VariableQueryParams params;
0336     soci::statement st = (db.prepare << query,
0337                           soci::into(params.id),
0338                           soci::into(params.name),
0339                           soci::into(params.qualified_name),
0340                           soci::into(params.signature),
0341                           soci::into(params.is_global),
0342                           soci::into(params.ns_qual_name, params.ns_qual_name_ind));
0343 
0344     st.execute();
0345 
0346     while (st.fetch()) {
0347         NamespaceObject *ns = nullptr;
0348         if (params.ns_qual_name_ind != soci::indicator::i_null) {
0349             ns = maps.namespaceMap[params.ns_qual_name];
0350         }
0351 
0352         auto *variableObj =
0353             store.getOrAddVariable(params.qualified_name, params.name, params.signature, params.is_global, ns);
0354         maps.variableMap[params.id] = variableObj;
0355     }
0356 }
0357 
0358 struct FunctionQueryParams {
0359     int id = 0;
0360     soci::indicator ns_qual_name_ind = soci::indicator::i_null;
0361     std::string ns_qual_name;
0362     std::string name;
0363     std::string qualified_name;
0364     std::string signature;
0365     std::string rtype;
0366     std::string template_params;
0367 };
0368 
0369 void loadFunctions(ObjectStore& store, soci::session& db, Maps& maps)
0370 {
0371     std::string query =
0372         R"(select
0373             fn.id,
0374             fn.name,
0375             fn.qualified_name,
0376             fn.signature,
0377             fn.return_type,
0378             fn.template_parameters,
0379             ns.qualified_name
0380         from
0381             function_declaration fn
0382         left join
0383             namespace_declaration ns on ns.id = fn.namespace_id
0384 )";
0385 
0386     FunctionQueryParams params;
0387     soci::statement st = (db.prepare << query,
0388                           soci::into(params.id),
0389                           soci::into(params.name),
0390                           soci::into(params.qualified_name),
0391                           soci::into(params.signature),
0392                           soci::into(params.rtype),
0393                           soci::into(params.template_params),
0394                           soci::into(params.ns_qual_name, params.ns_qual_name_ind));
0395 
0396     st.execute();
0397 
0398     while (st.fetch()) {
0399         NamespaceObject *ns = nullptr;
0400         if (params.ns_qual_name_ind != soci::indicator::i_null) {
0401             ns = maps.namespaceMap[params.ns_qual_name];
0402         }
0403 
0404         auto *functionObj = store.getOrAddFunction(params.qualified_name,
0405                                                    params.name,
0406                                                    params.signature,
0407                                                    params.rtype,
0408                                                    params.template_params,
0409                                                    ns);
0410         maps.functionMap[params.id] = functionObj;
0411     }
0412 }
0413 
0414 struct UserDefinedTypeQueryParams {
0415     int id = 0;
0416     soci::indicator parent_ns_qual_name_ind = soci::indicator::i_null;
0417     std::string parent_ns_qual_name;
0418 
0419     soci::indicator class_namespace_ind = soci::indicator::i_null;
0420     int class_namespace_id = 0;
0421 
0422     soci::indicator parent_package_ind = soci::indicator::i_null;
0423     std::string package_qualified_name;
0424     std::string name;
0425     std::string qualified_name;
0426     int kind = 0;
0427     int access = 0;
0428 };
0429 
0430 void loadUserDefinedTypes(ObjectStore& store, soci::session& db, Maps& maps, std::optional<int> parent_id)
0431 {
0432     // soci prepared statements didn't work for null vs value, neither with std::optional.'
0433     std::string query =
0434         R"(select
0435     cd.id,
0436     cd.class_namespace_id,
0437     sp.qualified_name as package_name,
0438     cd.name,
0439     cd.qualified_name,
0440     cd.kind,
0441     cd.access,
0442     ns.qualified_name
0443 from
0444     class_declaration cd
0445 left join
0446     source_package sp on sp.id = cd.parent_package_id
0447 left join
0448     namespace_declaration ns on ns.id = cd.parent_namespace_id
0449 where class_namespace_id is )"
0450         + (parent_id.has_value() ? std::to_string(parent_id.value()) : "NULL");
0451 
0452     UserDefinedTypeQueryParams params;
0453     soci::statement st = (db.prepare << query,
0454                           soci::into(params.id),
0455                           soci::into(params.class_namespace_id, params.class_namespace_ind),
0456                           soci::into(params.package_qualified_name, params.parent_package_ind),
0457                           soci::into(params.name),
0458                           soci::into(params.qualified_name),
0459                           soci::into(params.kind),
0460                           soci::into(params.access),
0461                           soci::into(params.parent_ns_qual_name, params.parent_ns_qual_name_ind));
0462 
0463     st.execute();
0464     std::vector<int> current_parents;
0465     while (st.fetch()) {
0466         NamespaceObject *parent_ns = nullptr;
0467         if (params.parent_ns_qual_name_ind == soci::indicator::i_ok) {
0468             parent_ns = maps.namespaceMap[params.parent_ns_qual_name];
0469         }
0470 
0471         TypeObject *parent_class = nullptr;
0472         if (params.class_namespace_ind == soci::indicator::i_ok) {
0473             parent_class = maps.userDefinedTypeMap[params.class_namespace_id];
0474         }
0475 
0476         PackageObject *parent_pkg = nullptr;
0477         if (params.parent_package_ind == soci::indicator::i_ok) {
0478             parent_pkg = maps.packageMap[params.package_qualified_name];
0479         }
0480 
0481         auto kind = static_cast<Codethink::lvtshr::UDTKind>(params.kind);
0482         // TODO: Move CDBUtil::AccessSpecifier to lvtmdb.
0483         auto accessSpecifier = static_cast<Codethink::lvtshr::AccessSpecifier>(params.access);
0484 
0485         auto *udt = store.getOrAddType(params.qualified_name,
0486                                        params.name,
0487                                        kind,
0488                                        accessSpecifier,
0489                                        parent_ns,
0490                                        parent_pkg,
0491                                        parent_class);
0492         maps.userDefinedTypeMap[params.id] = udt;
0493         current_parents.push_back(params.id);
0494 
0495         if (parent_pkg) {
0496             auto lock = parent_pkg->rwLock();
0497             (void) lock;
0498             parent_pkg->addType(udt);
0499         }
0500         if (parent_ns) {
0501             auto lock = parent_ns->rwLock();
0502             (void) lock;
0503             parent_ns->addType(udt);
0504         }
0505         if (parent_class) {
0506             auto lock = parent_class->rwLock();
0507             (void) lock;
0508             parent_class->addChild(udt);
0509         }
0510     }
0511 
0512     for (const int id : current_parents) {
0513         loadUserDefinedTypes(store, db, maps, id);
0514     }
0515 }
0516 
0517 struct FieldQueryParams {
0518     int id = 0;
0519     int class_id = 0;
0520     std::string name;
0521     std::string qualified_name;
0522     std::string signature;
0523     int access = 0;
0524     int is_static = false; // bool.
0525 };
0526 
0527 void loadFields(ObjectStore& store, soci::session& db, Maps& maps)
0528 {
0529     std::string query =
0530         "select id, class_id, name, qualified_name, signature, access, is_static from "
0531         "field_declaration";
0532 
0533     FieldQueryParams params;
0534     soci::statement st = (db.prepare << query,
0535                           soci::into(params.id),
0536                           soci::into(params.class_id),
0537                           soci::into(params.name),
0538                           soci::into(params.qualified_name),
0539                           soci::into(params.signature),
0540                           soci::into(params.access),
0541                           soci::into(params.is_static));
0542 
0543     st.execute();
0544 
0545     while (st.fetch()) {
0546         TypeObject *parent = maps.userDefinedTypeMap[params.class_id];
0547         auto accessSpecifier = static_cast<Codethink::lvtshr::AccessSpecifier>(params.access);
0548         auto *field = store.getOrAddField(params.qualified_name,
0549                                           params.name,
0550                                           params.signature,
0551                                           accessSpecifier,
0552                                           params.is_static,
0553                                           parent);
0554         maps.fieldMap[params.id] = field;
0555     }
0556 }
0557 
0558 struct MethodQueryParams {
0559     int id = 0;
0560     soci::indicator class_ind = soci::indicator::i_null;
0561     int class_id = 0;
0562     std::string name;
0563     std::string qualified_name;
0564     std::string signature;
0565     std::string rtype;
0566     std::string template_parameters;
0567     int access = 0;
0568     int is_virtual = false;
0569     int is_pure = false;
0570     int is_static = false;
0571     soci::indicator const_ind = soci::indicator::i_null;
0572     int is_const = false;
0573 };
0574 
0575 void loadMethods(ObjectStore& store, soci::session& db, Maps& maps)
0576 {
0577     std::string query =
0578         "select id, class_id, name, qualified_name, signature, return_type "
0579         " template_parameters, access, is_virtual, is_pure, is_static, is_const from "
0580         "method_declaration";
0581 
0582     MethodQueryParams params;
0583     soci::statement st = (db.prepare << query,
0584                           soci::into(params.id),
0585                           soci::into(params.class_id),
0586                           soci::into(params.name),
0587                           soci::into(params.qualified_name),
0588                           soci::into(params.signature),
0589                           soci::into(params.rtype),
0590                           soci::into(params.template_parameters),
0591                           soci::into(params.access),
0592                           soci::into(params.is_virtual),
0593                           soci::into(params.is_pure),
0594                           soci::into(params.is_static),
0595 
0596                           // This looks like it's a bug on soci. `is_const`
0597                           // is defined as "NOT NULL" but soci is fetching
0598                           // a null value.
0599                           soci::into(params.is_const, params.const_ind));
0600 
0601     st.execute();
0602 
0603     while (st.fetch()) {
0604         TypeObject *parent = maps.userDefinedTypeMap[params.class_id];
0605         auto accessSpecifier = static_cast<Codethink::lvtshr::AccessSpecifier>(params.access);
0606 
0607         // This looks like it's a bug on soci. `is_const`
0608         // is defined as "NOT NULL" but soci is fetching
0609         // a null value.
0610         if (params.const_ind == soci::indicator::i_null) {
0611             params.is_const = false;
0612         }
0613 
0614         auto *method = store.getOrAddMethod(params.qualified_name,
0615                                             params.name,
0616                                             params.signature,
0617                                             params.rtype,
0618                                             params.template_parameters,
0619                                             accessSpecifier,
0620                                             params.is_virtual,
0621                                             params.is_pure,
0622                                             params.is_static,
0623                                             params.is_const,
0624                                             parent);
0625         maps.methodMap[params.id] = method;
0626     }
0627 }
0628 
0629 void loadPackageRelations(ObjectStore& store, soci::session& db, Maps& maps)
0630 {
0631     const std::string query = R"(
0632 select
0633     target.qualified_name
0634 from
0635     dependencies dep
0636 left join
0637     source_package target on target_id = target.id
0638 where dep.source_id = (
0639     select id
0640     from source_package
0641     where qualified_name = :s
0642 ) )";
0643 
0644     // Those are all the *database* connections but I guess there's more.
0645     for (const auto& [qualified_name, _] : maps.packageMap) {
0646         (void) _;
0647 
0648         PackageObject *source = maps.packageMap[qualified_name];
0649         std::string target_qual_name;
0650         soci::statement st = (db.prepare << query, soci::into(target_qual_name), soci::use(qualified_name));
0651         st.execute();
0652         while (st.fetch()) {
0653             PackageObject *target = maps.packageMap[target_qual_name];
0654             PackageObject::addDependency(target, source);
0655         }
0656     }
0657 }
0658 
0659 void loadComponentRelations(ObjectStore& store, soci::session& db, const Maps& maps)
0660 {
0661     for (const auto& [id, source] : maps.componentMap) {
0662         int target_id = 0;
0663         soci::statement st = (db.prepare << "select target_id from component_relation where source_id = :s",
0664                               soci::into(target_id),
0665                               soci::use(id));
0666         st.execute();
0667         while (st.fetch()) {
0668             ComponentObject *target = maps.componentMap.at(target_id);
0669             ComponentObject::addDependency(source, target);
0670         }
0671     }
0672 }
0673 
0674 void loadFileRelations(ObjectStore& store, soci::session& db, const Maps& maps)
0675 {
0676     const std::string query_1 = R"(select target_id from includes where source_id = :s)";
0677     const std::string query_2 =
0678         R"(select
0679             ns.qualified_name
0680         from namespace_source_file nsf
0681         left join
0682             namespace_declaration ns on ns.id = nsf.namespace_id
0683         where nsf.source_file_id = :s)";
0684 
0685     for (const auto& [source_id, source] : maps.filesMap) {
0686         int target_id = 0;
0687         soci::statement st = (db.prepare << query_1, soci::into(target_id), soci::use(source_id));
0688         st.execute();
0689         while (st.fetch()) {
0690             FileObject *target = maps.filesMap.at(target_id);
0691             FileObject::addIncludeRelation(source, target);
0692         }
0693 
0694         std::string ns_qual_name;
0695         soci::statement st2 = (db.prepare << query_2, soci::into(ns_qual_name), soci::use(source_id));
0696         st2.execute();
0697         while (st2.fetch()) {
0698             NamespaceObject *target = maps.namespaceMap.at(ns_qual_name);
0699             {
0700                 auto lock = source->rwLock();
0701                 source->addNamespace(target);
0702             }
0703             {
0704                 auto lock = target->rwLock();
0705                 target->addFile(source);
0706             }
0707         }
0708     }
0709 }
0710 
0711 void loadUserDefinedTypeRelations(ObjectStore& store, soci::session& db, const Maps& maps)
0712 {
0713     for (const auto& [source_id, source] : maps.userDefinedTypeMap) {
0714         // uses_in_the_interface.
0715         int target_id = 0;
0716         soci::statement st = (db.prepare << "select target_id from uses_in_the_interface where source_id = :s",
0717                               soci::into(target_id),
0718                               soci::use(source_id));
0719         st.execute();
0720         while (st.fetch()) {
0721             TypeObject *target = maps.userDefinedTypeMap.at(target_id);
0722             TypeObject::addUsesInTheInterface(source, target);
0723         }
0724 
0725         // uses_in_the_implementation
0726         target_id = 0;
0727         st = (db.prepare << "select target_id from uses_in_the_implementation where source_id = :s",
0728               soci::into(target_id),
0729               soci::use(source_id));
0730         st.execute();
0731         while (st.fetch()) {
0732             TypeObject *target = maps.userDefinedTypeMap.at(target_id);
0733             TypeObject::addUsesInTheImplementation(source, target);
0734         }
0735 
0736         // class_hierarchy
0737         target_id = 0;
0738         st = (db.prepare << "select target_id from class_hierarchy where source_id = :s",
0739               soci::into(target_id),
0740               soci::use(source_id));
0741         st.execute();
0742         while (st.fetch()) {
0743             TypeObject *target = maps.userDefinedTypeMap.at(target_id);
0744             TypeObject::addIsARelationship(source, target);
0745         }
0746 
0747         // components
0748         target_id = 0;
0749         st = (db.prepare << "select component_id from udt_component where udt_id = :s",
0750               soci::into(target_id),
0751               soci::use(source_id));
0752         st.execute();
0753         while (st.fetch()) {
0754             ComponentObject *target = maps.componentMap.at(target_id);
0755             {
0756                 auto lock = target->rwLock();
0757                 (void) lock;
0758                 target->addType(source);
0759             }
0760             {
0761                 auto lock = source->rwLock();
0762                 (void) lock;
0763                 source->addComponent(target);
0764             }
0765         }
0766 
0767         // source files.
0768         target_id = 0;
0769         st = (db.prepare << "select source_file_id from class_source_file where class_id = :s",
0770               soci::into(target_id),
0771               soci::use(source_id));
0772         st.execute();
0773         while (st.fetch()) {
0774             FileObject *target = maps.filesMap.at(target_id);
0775             {
0776                 auto lock = target->rwLock();
0777                 (void) lock;
0778                 target->addType(source);
0779             }
0780             {
0781                 auto lock = source->rwLock();
0782                 (void) lock;
0783                 source->addFile(target);
0784             }
0785         }
0786     }
0787 }
0788 
0789 void loadFieldRelations(ObjectStore& store, soci::session& db, const Maps& maps)
0790 {
0791     for (const auto& [source_id, source] : maps.fieldMap) {
0792         int target_id = 0;
0793         soci::statement st = (db.prepare << "select type_class_id from field_type where field_id = :s",
0794                               soci::into(target_id),
0795                               soci::use(source_id));
0796         st.execute();
0797         while (st.fetch()) {
0798             TypeObject *target = maps.userDefinedTypeMap.at(target_id);
0799             {
0800                 auto lock = target->rwLock();
0801                 (void) lock;
0802                 target->addField(source);
0803             }
0804             {
0805                 auto lock = source->rwLock();
0806                 (void) lock;
0807                 source->addType(target);
0808             }
0809         }
0810     }
0811 }
0812 
0813 void loadMethodRelations(ObjectStore& store, soci::session& db, const Maps& maps)
0814 {
0815     for (const auto& [source_id, source] : maps.methodMap) {
0816         int target_id = 0;
0817         soci::statement st = (db.prepare << "select type_class_id from method_argument_class where method_id = :s",
0818                               soci::into(target_id),
0819                               soci::use(source_id));
0820         st.execute();
0821         while (st.fetch()) {
0822             TypeObject *target = maps.userDefinedTypeMap.at(target_id);
0823             auto lock = target->rwLock();
0824             (void) lock;
0825             target->addMethod(source);
0826         }
0827     }
0828 }
0829 
0830 } // end namespace
0831 
0832 cpp::result<void, ObjectStore::ReadFromDatabaseError> SociReader::readInto(ObjectStore& store, const std::string& path)
0833 {
0834     auto lock = store.rwLock();
0835     (void) lock;
0836 
0837     if (path != ":memory:") {
0838         if (!std::filesystem::exists(path)) {
0839             return cpp::fail(ObjectStore::ReadFromDatabaseError{"File doesn't exist on disk"});
0840         }
0841     }
0842 
0843     soci::session db;
0844     db.open(*soci::factory_sqlite3(), path);
0845 
0846     // Currently there's no version check on lvtmdb.'
0847     //  const int version_key = static_cast<int>(SociHelper::Key::Version);
0848     const int db_state_key = static_cast<int>(SociHelper::Key::DatabaseState);
0849 
0850     int query_res;
0851     db << "select value from db_option where key = :k", soci::into(query_res), soci::use(db_state_key);
0852 
0853     // Load the Repositories
0854     Maps maps;
0855 
0856     loadRepositories(store, db, maps);
0857     loadPackages(store, db, maps, std::nullopt);
0858     loadComponents(store, db, maps);
0859     loadFiles(store, db, maps);
0860     loadErrors(store, db, maps);
0861     loadNamespaces(store, db, maps, std::nullopt);
0862     loadVariables(store, db, maps);
0863     loadFunctions(store, db, maps);
0864     loadUserDefinedTypes(store, db, maps, std::nullopt);
0865     loadFields(store, db, maps);
0866     loadMethods(store, db, maps);
0867 
0868     // Here we have all the entities, we now need to add the connections between them.
0869     loadPackageRelations(store, db, maps);
0870     loadComponentRelations(store, db, maps);
0871     loadFileRelations(store, db, maps);
0872     loadUserDefinedTypeRelations(store, db, maps);
0873     loadFieldRelations(store, db, maps);
0874     loadMethodRelations(store, db, maps);
0875     return {};
0876 }