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

0001 // ct_lvtldr_sociutils.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 #ifndef DIAGRAM_SERVER_CT_LVTLDR_SOCIUTILS_H
0021 #define DIAGRAM_SERVER_CT_LVTLDR_SOCIUTILS_H
0022 
0023 #include <ct_lvtldr_componentnodefields.h>
0024 #include <ct_lvtldr_databasehandler.h>
0025 #include <ct_lvtshr_uniqueid.h>
0026 
0027 #include <soci/soci.h>
0028 #include <soci/sqlite3/soci-sqlite3.h>
0029 
0030 #include <QString>
0031 
0032 #include <iostream>
0033 #include <variant>
0034 
0035 namespace {
0036 template<typename T>
0037 std::string optionalToDb(std::optional<T> data)
0038 {
0039     if (!data) {
0040         return "NULL";
0041     }
0042     return std::to_string(*data);
0043 }
0044 } // namespace
0045 
0046 namespace Codethink::lvtldr {
0047 
0048 class SociDatabaseHandler : public DatabaseHandler {
0049     using RecordNumberType = Codethink::lvtshr::UniqueId::RecordNumberType;
0050 
0051   public:
0052     explicit SociDatabaseHandler(std::string const& path)
0053     {
0054         d_db.open(*soci::factory_sqlite3(), path);
0055     }
0056 
0057     void close() override
0058     {
0059         d_db.close();
0060     }
0061 
0062     std::vector<lvtshr::UniqueId> getTopLevelEntityIds() override
0063     {
0064         auto out = std::vector<lvtshr::UniqueId>{};
0065         {
0066             soci::rowset<RecordNumberType> rs = (d_db.prepare << "select id from source_repository where name != ''");
0067             for (auto&& i : rs) {
0068                 out.emplace_back(lvtshr::UniqueId{lvtshr::DiagramType::RepositoryType, i});
0069             }
0070         }
0071         {
0072             soci::rowset<RecordNumberType> rs =
0073                 (d_db.prepare
0074                  << "select id from source_package where parent_id is NULL and source_repository_id is NULL");
0075             for (auto&& i : rs) {
0076                 out.emplace_back(lvtshr::UniqueId{lvtshr::DiagramType::PackageType, i});
0077             }
0078         }
0079         return out;
0080     }
0081 
0082     RepositoryNodeFields getRepositoryFieldsByQualifiedName(std::string const& qualifiedName) override
0083     {
0084         return getRepositoryFields("qualified_name", qualifiedName);
0085     }
0086 
0087     RepositoryNodeFields getRepositoryFieldsById(RecordNumberType id) override
0088     {
0089         return getRepositoryFields("id", id);
0090     }
0091 
0092     void updateFields(RepositoryNodeFields const& dao) override
0093     {
0094     }
0095 
0096     TypeNodeFields getUdtFieldsByQualifiedName(std::string const& qualifiedName) override
0097     {
0098         return getUdtFields("qualified_name", qualifiedName);
0099     }
0100 
0101     TypeNodeFields getUdtFieldsById(RecordNumberType id) override
0102     {
0103         return getUdtFields("id", id);
0104     }
0105 
0106     void addFields(TypeNodeFields& dao) override
0107     {
0108         soci::transaction tr(d_db);
0109         d_db << "insert into class_declaration (version, qualified_name, name, kind, access, class_namespace_id, "
0110                 "parent_package_id) "
0111                 "values "
0112              << "(" << dao.version << ", "
0113              << "'" << dao.qualifiedName << "', "
0114              << "'" << dao.name << "', "
0115              << "" << static_cast<int>(dao.kind) << ", "
0116              << "" << dao.access << ", "
0117              << "" << optionalToDb(dao.classNamespaceId) << ", "
0118              << "" << optionalToDb(dao.parentPackageId) << ""
0119              << ")";
0120 
0121         d_db.get_last_insert_id("class_declaration", dao.id);
0122 
0123         for (auto&& id : dao.componentIds) {
0124             d_db << "insert into udt_component (component_id, udt_id) values "
0125                  << "(" << id << ", " << dao.id << ")";
0126         }
0127         tr.commit();
0128     }
0129 
0130     void updateFields(TypeNodeFields const& dao) override
0131     {
0132         soci::transaction tr(d_db);
0133         d_db << "update class_declaration set "
0134              << "version = " << dao.version << ", "
0135              << "name = '" << dao.name << "', "
0136              << "qualified_name = '" << dao.qualifiedName << "', "
0137              << "kind = " << static_cast<int>(dao.kind) << ", "
0138              << "access = " << dao.access << ", "
0139              << "class_namespace_id = " << optionalToDb(dao.classNamespaceId) << " "
0140              << "where id = :k",
0141             soci::use(dao.id);
0142         tr.commit();
0143     }
0144 
0145     void removeUdtFieldsById(RecordNumberType id) override
0146     {
0147         soci::transaction tr(d_db);
0148         d_db << "delete from class_declaration where id = " << id;
0149         tr.commit();
0150     }
0151 
0152     ComponentNodeFields getComponentFieldsByQualifiedName(std::string const& qualifiedName) override
0153     {
0154         return getComponentFields("qualified_name", qualifiedName);
0155     }
0156 
0157     ComponentNodeFields getComponentFieldsById(RecordNumberType id) override
0158     {
0159         return getComponentFields("id", id);
0160     }
0161 
0162     void addFields(ComponentNodeFields& dao) override
0163     {
0164         soci::transaction tr(d_db);
0165         d_db << "insert into source_component (version, qualified_name, name, package_id) "
0166                 "values "
0167              << "(" << dao.version << ", "
0168              << "'" << dao.qualifiedName << "', "
0169              << "'" << dao.name << "', "
0170              << "" << optionalToDb(dao.packageId) << ""
0171              << ")";
0172         d_db.get_last_insert_id("source_component", dao.id);
0173         tr.commit();
0174     }
0175 
0176     void updateFields(ComponentNodeFields const& dao) override
0177     {
0178         soci::transaction tr(d_db);
0179         d_db << "update source_component set "
0180              << "version = " << dao.version << ", "
0181              << "qualified_name = '" << dao.qualifiedName << "', "
0182              << "name = '" << dao.name << "', "
0183              << "package_id = " << optionalToDb(dao.packageId) << " "
0184              << "where id = :k",
0185             soci::use(dao.id);
0186         tr.commit();
0187     }
0188 
0189     void removeComponentFieldsById(RecordNumberType id) override
0190     {
0191         soci::transaction tr(d_db);
0192         d_db << "delete from source_component where id = " << id;
0193         tr.commit();
0194     }
0195 
0196     PackageNodeFields getPackageFieldsByQualifiedName(std::string const& qualifiedName) override
0197     {
0198         return getPackageFields("qualified_name", qualifiedName);
0199     }
0200 
0201     PackageNodeFields getPackageFieldsById(RecordNumberType id) override
0202     {
0203         return getPackageFields("id", id);
0204     }
0205 
0206     void updateFields(FreeFunctionNodeFields const& dao) override
0207     {
0208         // Intentionally not implemented
0209     }
0210 
0211     FreeFunctionNodeFields getFreeFunctionFieldsByQualifiedName(std::string const& qualifiedName) override
0212     {
0213         return getFreeFunctionFields("qualified_name", qualifiedName);
0214     }
0215 
0216     FreeFunctionNodeFields getFreeFunctionFieldsById(RecordNumberType id) override
0217     {
0218         return getFreeFunctionFields("id", id);
0219     }
0220 
0221     void addFields(PackageNodeFields& dao) override
0222     {
0223         soci::transaction tr(d_db);
0224         d_db
0225             << "insert into source_package (version, qualified_name, name, disk_path, parent_id, source_repository_id) "
0226                "values "
0227             << "(" << dao.version << ", "
0228             << "'" << dao.qualifiedName << "', "
0229             << "'" << dao.name << "', "
0230             << "'" << dao.diskPath << "', "
0231             << "" << optionalToDb(dao.parentId) << ", "
0232             << "" << optionalToDb(dao.sourceRepositoryId) << " "
0233             << ")";
0234         d_db.get_last_insert_id("source_package", dao.id);
0235         tr.commit();
0236     }
0237 
0238     void updateFields(PackageNodeFields const& dao) override
0239     {
0240         soci::transaction tr(d_db);
0241         d_db << "update source_package set "
0242              << "version = " << dao.version << ", "
0243              << "parent_id = " << optionalToDb(dao.parentId) << ", "
0244              << "source_repository_id = " << optionalToDb(dao.sourceRepositoryId) << ", "
0245              << "name = '" << dao.name << "', "
0246              << "qualified_name = '" << dao.qualifiedName << "', "
0247              << "disk_path = '" << dao.diskPath << "' "
0248              << "where id = :k",
0249             soci::use(dao.id);
0250         tr.commit();
0251     }
0252 
0253     void removePackageFieldsById(RecordNumberType id) override
0254     {
0255         soci::transaction tr(d_db);
0256         d_db << "delete from source_package where id = " << id;
0257         d_db << "delete from cad_notes where entity_id = " << id
0258              << " and entity_type = " << static_cast<int>(lvtshr::DiagramType::PackageType);
0259         tr.commit();
0260     }
0261 
0262     void addConcreteDependency(RecordNumberType idFrom, RecordNumberType idTo) override
0263     {
0264         soci::transaction tr(d_db);
0265         d_db << "insert into dependencies (source_id, target_id) values (" << idFrom << ", " << idTo << ")";
0266         tr.commit();
0267     }
0268 
0269     void removeConcreteDependency(RecordNumberType idFrom, RecordNumberType idTo) override
0270     {
0271         soci::transaction tr(d_db);
0272         d_db << "delete from dependencies where source_id = " << idFrom << " and target_id = " << idTo;
0273         tr.commit();
0274     }
0275 
0276     void addComponentDependency(RecordNumberType idFrom, RecordNumberType idTo) override
0277     {
0278         soci::transaction tr(d_db);
0279         d_db << "insert into component_relation (source_id, target_id) values (" << idFrom << ", " << idTo << ")";
0280         tr.commit();
0281     }
0282 
0283     void removeComponentDependency(RecordNumberType idFrom, RecordNumberType idTo) override
0284     {
0285         soci::transaction tr(d_db);
0286         d_db << "delete from component_relation where source_id = " << idFrom << " and target_id = " << idTo;
0287         tr.commit();
0288     }
0289 
0290     void addClassHierarchy(RecordNumberType idFrom, RecordNumberType idTo) override
0291     {
0292         soci::transaction tr(d_db);
0293         d_db << "insert into class_hierarchy (source_id, target_id) values (" << idFrom << ", " << idTo << ")";
0294         tr.commit();
0295     }
0296 
0297     void removeClassHierarchy(RecordNumberType idFrom, RecordNumberType idTo) override
0298     {
0299         soci::transaction tr(d_db);
0300         d_db << "delete from class_hierarchy where source_id = " << idFrom << " and target_id = " << idTo;
0301         tr.commit();
0302     }
0303 
0304     void addImplementationRelationship(RecordNumberType idFrom, RecordNumberType idTo) override
0305     {
0306         soci::transaction tr(d_db);
0307         d_db << "insert into uses_in_the_implementation (source_id, target_id) values (" << idFrom << ", " << idTo
0308              << ")";
0309         tr.commit();
0310     }
0311 
0312     void removeImplementationRelationship(RecordNumberType idFrom, RecordNumberType idTo) override
0313     {
0314         soci::transaction tr(d_db);
0315         d_db << "delete from uses_in_the_implementation where source_id = " << idFrom << " and target_id = " << idTo;
0316         tr.commit();
0317     }
0318 
0319     void addInterfaceRelationship(RecordNumberType idFrom, RecordNumberType idTo) override
0320     {
0321         soci::transaction tr(d_db);
0322         d_db << "insert into uses_in_the_interface (source_id, target_id) values (" << idFrom << ", " << idTo << ")";
0323         tr.commit();
0324     }
0325 
0326     void removeInterfaceRelationship(RecordNumberType idFrom, RecordNumberType idTo) override
0327     {
0328         soci::transaction tr(d_db);
0329         d_db << "delete from uses_in_the_interface where source_id = " << idFrom << " and target_id = " << idTo;
0330         tr.commit();
0331     }
0332 
0333     std::string getNotesFromId(lvtshr::UniqueId uid) override
0334     {
0335         try {
0336             std::string notes;
0337             soci::transaction tr(d_db);
0338             d_db << "select notes from cad_notes where entity_id = " << uid.recordNumber()
0339                  << " and entity_type = " << static_cast<int>(uid.diagramType()),
0340                 soci::into(notes);
0341             tr.commit();
0342             return notes;
0343         } catch (...) {
0344             return "";
0345         }
0346     }
0347 
0348     bool hasNotes(lvtshr::UniqueId uid) override
0349     {
0350         try {
0351             int n;
0352             soci::transaction tr(d_db);
0353             d_db << "select count(*) from cad_notes where entity_id = " << uid.recordNumber()
0354                  << " and entity_type = " << static_cast<int>(uid.diagramType()),
0355                 soci::into(n);
0356             tr.commit();
0357             return n > 0;
0358         } catch (...) {
0359             return false;
0360         }
0361     }
0362 
0363     void addNotes(lvtshr::UniqueId uid, std::string const& notes) override
0364     {
0365         std::string our_notes = QString::fromStdString(notes).replace("'", "''").toStdString();
0366         soci::transaction tr(d_db);
0367         d_db << "insert into cad_notes (version, entity_id, entity_type, notes) values (" << 0 << ", "
0368              << uid.recordNumber() << ", " << static_cast<int>(uid.diagramType()) << ", "
0369              << "'" << our_notes << "')";
0370         tr.commit();
0371     }
0372 
0373     void setNotes(lvtshr::UniqueId uid, std::string const& notes) override
0374     {
0375         std::string our_notes = QString::fromStdString(notes).replace("'", "''").toStdString();
0376         soci::transaction tr(d_db);
0377         d_db << "update cad_notes set notes = '" << our_notes << "' where "
0378              << "entity_id = " << uid.recordNumber() << " and "
0379              << "entity_type = " << static_cast<int>(uid.diagramType());
0380         tr.commit();
0381     }
0382 
0383     soci::session& getSession()
0384     {
0385         return d_db;
0386     }
0387 
0388   private:
0389     template<typename T>
0390     RepositoryNodeFields getRepositoryFields(std::string const& uniqueKeyColumnName, T const& keyValue)
0391     {
0392         decltype(getRepositoryFields(uniqueKeyColumnName, keyValue)) dao;
0393         d_db << "select * from source_repository where " + uniqueKeyColumnName + " = :k", soci::into(dao.id),
0394             soci::into(dao.version), soci::into(dao.name), soci::into(dao.qualifiedName), soci::into(dao.diskPath),
0395             soci::use(keyValue);
0396 
0397         {
0398             soci::rowset<RecordNumberType> rs =
0399                 (d_db.prepare << "select id from source_package where source_repository_id = :k and parent_id is NULL",
0400                  soci::use(dao.id));
0401             for (auto&& i : rs) {
0402                 dao.childPackagesIds.emplace_back(i);
0403             }
0404         }
0405 
0406         return dao;
0407     }
0408 
0409     template<typename T>
0410     TypeNodeFields getUdtFields(std::string const& uniqueKeyColumnName, T const& keyValue)
0411     {
0412         decltype(getUdtFields(uniqueKeyColumnName, keyValue)) dao;
0413         soci::indicator parentNamespaceIdIndicator = soci::indicator::i_null;
0414         typename std::remove_reference<decltype(dao.parentNamespaceId.value())>::type maybeParentNamespaceId = 0;
0415         soci::indicator classNamespaceIdIndicator = soci::indicator::i_null;
0416         typename std::remove_reference<decltype(dao.classNamespaceId.value())>::type maybeClassNamespaceId = 0;
0417         soci::indicator parentPackageIdIndicator = soci::indicator::i_null;
0418         typename std::remove_reference<decltype(dao.parentPackageId.value())>::type maybeParentPackageId = 0;
0419 
0420         int kindAsInt = -1;
0421 
0422         d_db << "select * from class_declaration where " + uniqueKeyColumnName + " = :k", soci::into(dao.id),
0423             soci::into(dao.version), soci::into(maybeParentNamespaceId, parentNamespaceIdIndicator),
0424             soci::into(maybeClassNamespaceId, classNamespaceIdIndicator),
0425             soci::into(maybeParentPackageId, parentPackageIdIndicator), soci::into(dao.name),
0426             soci::into(dao.qualifiedName), soci::into(kindAsInt), soci::into(dao.access), soci::use(keyValue);
0427 
0428         dao.kind = static_cast<lvtshr::UDTKind>(kindAsInt);
0429 
0430         if (parentNamespaceIdIndicator == soci::indicator::i_ok) {
0431             dao.parentNamespaceId = maybeParentNamespaceId;
0432         } else {
0433             dao.parentNamespaceId = std::nullopt;
0434         }
0435 
0436         if (classNamespaceIdIndicator == soci::indicator::i_ok) {
0437             dao.classNamespaceId = maybeClassNamespaceId;
0438         } else {
0439             dao.classNamespaceId = std::nullopt;
0440         }
0441 
0442         if (parentPackageIdIndicator == soci::indicator::i_ok) {
0443             dao.parentPackageId = maybeParentPackageId;
0444         } else {
0445             dao.parentPackageId = std::nullopt;
0446         }
0447 
0448         {
0449             soci::rowset<RecordNumberType> rs =
0450                 (d_db.prepare << "select component_id from udt_component where udt_id = :k", soci::use(dao.id));
0451             for (auto&& i : rs) {
0452                 dao.componentIds.emplace_back(i);
0453             }
0454         }
0455         {
0456             soci::rowset<RecordNumberType> rs =
0457                 (d_db.prepare << "select id from class_declaration where class_namespace_id = :k", soci::use(dao.id));
0458             for (auto&& i : rs) {
0459                 dao.nestedTypeIds.emplace_back(i);
0460             }
0461         }
0462         {
0463             soci::rowset<RecordNumberType> rs =
0464                 (d_db.prepare << "select source_id from class_hierarchy where target_id = :k", soci::use(dao.id));
0465             for (auto&& i : rs) {
0466                 dao.isAIds.emplace_back(i);
0467             }
0468         }
0469         {
0470             soci::rowset<RecordNumberType> rs =
0471                 (d_db.prepare << "select target_id from uses_in_the_interface where source_id = :k", soci::use(dao.id));
0472             for (auto&& i : rs) {
0473                 dao.usesInInterfaceIds.emplace_back(i);
0474             }
0475         }
0476         {
0477             soci::rowset<RecordNumberType> rs =
0478                 (d_db.prepare << "select target_id from uses_in_the_implementation where source_id = :k",
0479                  soci::use(dao.id));
0480             for (auto&& i : rs) {
0481                 dao.usesInImplementationIds.emplace_back(i);
0482             }
0483         }
0484 
0485         {
0486             soci::rowset<RecordNumberType> rs =
0487                 (d_db.prepare << "select target_id from class_hierarchy where source_id = :k", soci::use(dao.id));
0488             for (auto&& i : rs) {
0489                 dao.isBaseOfIds.emplace_back(i);
0490             }
0491         }
0492         {
0493             soci::rowset<RecordNumberType> rs =
0494                 (d_db.prepare << "select source_id from uses_in_the_interface where target_id = :k", soci::use(dao.id));
0495             for (auto&& i : rs) {
0496                 dao.usedByInterfaceIds.emplace_back(i);
0497             }
0498         }
0499         {
0500             soci::rowset<RecordNumberType> rs =
0501                 (d_db.prepare << "select source_id from uses_in_the_implementation where target_id = :k",
0502                  soci::use(dao.id));
0503             for (auto&& i : rs) {
0504                 dao.usedByImplementationIds.emplace_back(i);
0505             }
0506         }
0507 
0508         {
0509             soci::rowset<RecordNumberType> rs =
0510                 (d_db.prepare << "select id from field_declaration where class_id = :k", soci::use(dao.id));
0511             for (auto&& i : rs) {
0512                 dao.fieldIds.emplace_back(i);
0513             }
0514         }
0515 
0516         {
0517             soci::rowset<std::string> rs =
0518                 (d_db.prepare << "select name from field_declaration where class_id = :k", soci::use(dao.id));
0519             for (auto&& i : rs) {
0520                 dao.fieldNames.emplace_back(i);
0521             }
0522         }
0523 
0524         return dao;
0525     }
0526 
0527     template<typename T>
0528     ComponentNodeFields getComponentFields(std::string const& uniqueKeyColumnName, T const& keyValue)
0529     {
0530         decltype(getComponentFields(uniqueKeyColumnName, keyValue)) dao;
0531         soci::indicator parentIdIndicator = soci::indicator::i_null;
0532         typename std::remove_reference<decltype(dao.packageId.value())>::type maybeParentId = 0;
0533         d_db << "select * from source_component where " + uniqueKeyColumnName + " = :k", soci::into(dao.id),
0534             soci::into(dao.version), soci::into(dao.qualifiedName), soci::into(dao.name),
0535             soci::into(maybeParentId, parentIdIndicator), soci::use(keyValue);
0536 
0537         if (parentIdIndicator == soci::indicator::i_ok) {
0538             dao.packageId = maybeParentId;
0539         } else {
0540             dao.packageId = std::nullopt;
0541         }
0542 
0543         {
0544             soci::rowset<RecordNumberType> rs =
0545                 (d_db.prepare << "select target_id from component_relation where source_id = :k", soci::use(dao.id));
0546             for (auto&& i : rs) {
0547                 dao.providerIds.emplace_back(i);
0548             }
0549         }
0550         {
0551             soci::rowset<RecordNumberType> rs =
0552                 (d_db.prepare << "select source_id from component_relation where target_id = :k", soci::use(dao.id));
0553             for (auto&& i : rs) {
0554                 dao.clientIds.emplace_back(i);
0555             }
0556         }
0557         {
0558             soci::rowset<RecordNumberType> rs =
0559                 (d_db.prepare << "select udt_id from udt_component where component_id = :k", soci::use(dao.id));
0560             for (auto&& i : rs) {
0561                 dao.childUdtIds.emplace_back(i);
0562             }
0563         }
0564         try {
0565             soci::rowset<RecordNumberType> files_rs =
0566                 (d_db.prepare << "select id from source_file where component_id = :k", soci::use(dao.id));
0567             for (auto const& source_id : files_rs) {
0568                 soci::rowset<RecordNumberType> rs =
0569                     (d_db.prepare << "select function_id from global_function_source_file where source_file_id = :k",
0570                      soci::use(source_id));
0571                 for (auto const& i : rs) {
0572                     dao.childGlobalFunctionIds.emplace_back(i);
0573                 }
0574             }
0575         } catch (soci::sqlite3_soci_error const&) {
0576             /* Ignore missing data on old databases */
0577         }
0578 
0579         return dao;
0580     }
0581 
0582     template<typename T>
0583     PackageNodeFields getPackageFields(std::string const& uniqueKeyColumnName, T const& keyValue)
0584     {
0585         decltype(getPackageFields(uniqueKeyColumnName, keyValue)) dao;
0586         soci::indicator parentIdIndicator = soci::indicator::i_null;
0587         typename std::remove_reference<decltype(dao.parentId.value())>::type maybeParentId = 0;
0588         soci::indicator sourceRepositoryIdIndicator = soci::indicator::i_null;
0589         typename std::remove_reference<decltype(dao.sourceRepositoryId.value())>::type maybeSourceRepositoryId = 0;
0590         d_db << "select * from source_package where " + uniqueKeyColumnName + " = :k", soci::into(dao.id),
0591             soci::into(dao.version), soci::into(maybeParentId, parentIdIndicator),
0592             soci::into(maybeSourceRepositoryId, sourceRepositoryIdIndicator), soci::into(dao.name),
0593             soci::into(dao.qualifiedName), soci::use(keyValue);
0594 
0595         if (parentIdIndicator == soci::indicator::i_ok) {
0596             dao.parentId = maybeParentId;
0597         } else {
0598             dao.parentId = std::nullopt;
0599         }
0600 
0601         if (sourceRepositoryIdIndicator == soci::indicator::i_ok) {
0602             dao.sourceRepositoryId = maybeSourceRepositoryId;
0603         } else {
0604             dao.sourceRepositoryId = std::nullopt;
0605         }
0606 
0607         {
0608             soci::rowset<RecordNumberType> rs =
0609                 (d_db.prepare << "select id from source_package where parent_id = :k", soci::use(dao.id));
0610             for (auto&& i : rs) {
0611                 dao.childPackagesIds.emplace_back(i);
0612             }
0613         }
0614         {
0615             soci::rowset<RecordNumberType> rs =
0616                 (d_db.prepare << "select id from source_component where package_id = :k", soci::use(dao.id));
0617             for (auto&& i : rs) {
0618                 dao.childComponentsIds.emplace_back(i);
0619             }
0620         }
0621         {
0622             soci::rowset<RecordNumberType> rs =
0623                 (d_db.prepare << "select target_id from dependencies where source_id = :k", soci::use(dao.id));
0624             for (auto&& i : rs) {
0625                 dao.providerIds.emplace_back(i);
0626             }
0627         }
0628         {
0629             soci::rowset<RecordNumberType> rs =
0630                 (d_db.prepare << "select source_id from dependencies where target_id = :k", soci::use(dao.id));
0631             for (auto&& i : rs) {
0632                 dao.clientIds.emplace_back(i);
0633             }
0634         }
0635 
0636         return dao;
0637     }
0638 
0639     template<typename T>
0640     FreeFunctionNodeFields getFreeFunctionFields(std::string const& uniqueKeyColumnName, T const& keyValue)
0641     {
0642         decltype(getFreeFunctionFields(uniqueKeyColumnName, keyValue)) dao;
0643         d_db << "select id, version, name, qualified_name from function_declaration where " + uniqueKeyColumnName
0644                 + " = :k limit 1",
0645             soci::into(dao.id), soci::into(dao.version), soci::into(dao.name), soci::into(dao.qualifiedName),
0646             soci::use(keyValue);
0647 
0648         {
0649             auto source_id = -1;
0650             d_db << "select source_file_id from global_function_source_file where function_id = :k limit 1",
0651                 soci::into(source_id), soci::use(dao.id);
0652 
0653             auto component_id = -1;
0654             d_db << "select component_id from source_file where id = :k limit 1", soci::into(component_id),
0655                 soci::use(source_id);
0656             dao.componentId = component_id;
0657         }
0658 
0659         {
0660             soci::rowset<RecordNumberType> rs =
0661                 (d_db.prepare << "select callee_id from function_calls where caller_id = :k", soci::use(dao.id));
0662             for (auto&& i : rs) {
0663                 dao.calleeIds.emplace_back(i);
0664             }
0665         }
0666 
0667         {
0668             soci::rowset<RecordNumberType> rs =
0669                 (d_db.prepare << "select caller_id from function_calls where callee_id = :k", soci::use(dao.id));
0670             for (auto&& i : rs) {
0671                 dao.callerIds.emplace_back(i);
0672             }
0673         }
0674 
0675         return dao;
0676     }
0677 
0678     soci::session d_db;
0679 };
0680 
0681 } // namespace Codethink::lvtldr
0682 
0683 #endif // DIAGRAM_SERVER_CT_LVTLDR_SOCIUTILS_H