| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // SPDX-FileCopyrightText: 2023 Carl Zeiss Microscopy GmbH | ||
| 2 | // | ||
| 3 | // SPDX-License-Identifier: MIT | ||
| 4 | |||
| 5 | #include "documentReadBase.h" | ||
| 6 | #include <algorithm> | ||
| 7 | #include <vector> | ||
| 8 | #include <string> | ||
| 9 | #include <gsl/assert> | ||
| 10 | #include <gsl/narrow> | ||
| 11 | |||
| 12 | using namespace std; | ||
| 13 | using namespace imgdoc2; | ||
| 14 | |||
| 15 | 14 | /*static*/void DocumentReadBase::GetEntityDimensionsInternal(const unordered_set<imgdoc2::Dimension>& tile_dimensions, imgdoc2::Dimension* dimensions, std::uint32_t& count) | |
| 16 | { | ||
| 17 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 6 times.
|
14 | if (dimensions != nullptr) |
| 18 | { | ||
| 19 |
2/4✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 7 taken 8 times.
✗ Branch 8 not taken.
|
8 | copy_n(tile_dimensions.cbegin(), min(count, gsl::narrow<uint32_t>(tile_dimensions.size())), dimensions); |
| 20 | } | ||
| 21 | |||
| 22 | 14 | count = gsl::narrow<uint32_t>(tile_dimensions.size()); | |
| 23 | 14 | } | |
| 24 | |||
| 25 | 12 | std::map<imgdoc2::Dimension, imgdoc2::Int32Interval> DocumentReadBase::GetMinMaxForTileDimensionInternal( | |
| 26 | const std::vector<imgdoc2::Dimension>& dimensions_to_query_for, | ||
| 27 | const std::function<bool(imgdoc2::Dimension)>& func_is_dimension_valid, | ||
| 28 | const std::function<void(std::ostringstream&, imgdoc2::Dimension)>& func_add_dimension_table_name, | ||
| 29 | const std::string& table_name) const | ||
| 30 | { | ||
| 31 |
2/2✓ Branch 5 taken 16 times.
✓ Branch 6 taken 10 times.
|
26 | for (const auto dimension : dimensions_to_query_for) |
| 32 | { | ||
| 33 |
1/2✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
|
16 | const bool is_valid = func_is_dimension_valid(dimension); |
| 34 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
|
16 | if (!is_valid) |
| 35 | { | ||
| 36 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | ostringstream string_stream; |
| 37 |
3/6✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
|
2 | string_stream << "The dimension '" << dimension << "' is not valid."; |
| 38 |
2/4✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
|
2 | throw invalid_argument_exception(string_stream.str().c_str()); |
| 39 | 2 | } | |
| 40 | } | ||
| 41 | |||
| 42 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 8 times.
|
10 | if (dimensions_to_query_for.empty()) |
| 43 | { | ||
| 44 | 2 | return {}; | |
| 45 | } | ||
| 46 | |||
| 47 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | const auto query_statement = this->CreateQueryMinMaxStatement(dimensions_to_query_for, func_add_dimension_table_name, table_name); |
| 48 | |||
| 49 | 8 | map<imgdoc2::Dimension, imgdoc2::Int32Interval> result; | |
| 50 | |||
| 51 | // we expect exactly "2 * dimensions_to_query_for.size()" results | ||
| 52 |
1/2✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
|
8 | const bool is_done = this->GetDocument()->GetDatabase_connection()->StepStatement(query_statement.get()); |
| 53 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | if (!is_done) |
| 54 | { | ||
| 55 | ✗ | throw internal_error_exception("database-query gave no result, this is unexpected."); | |
| 56 | } | ||
| 57 | |||
| 58 |
3/4✓ Branch 2 taken 22 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 14 times.
✓ Branch 5 taken 8 times.
|
22 | for (int i = 0; i < gsl::narrow<int>(dimensions_to_query_for.size()); ++i) |
| 59 | { | ||
| 60 | 14 | Int32Interval coordinate_bounds; | |
| 61 |
1/2✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
14 | auto min = query_statement->GetResultInt32OrNull(i * 2); |
| 62 |
1/2✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
14 | auto max = query_statement->GetResultInt32OrNull(i * 2 + 1); |
| 63 |
5/6✓ Branch 1 taken 12 times.
✓ Branch 2 taken 2 times.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 12 times.
✓ Branch 7 taken 2 times.
|
14 | if (min.has_value() && max.has_value()) |
| 64 | { | ||
| 65 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
12 | coordinate_bounds.minimum_value = min.value(); |
| 66 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
12 | coordinate_bounds.maximum_value = max.value(); |
| 67 | } | ||
| 68 | |||
| 69 |
1/2✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
14 | result[dimensions_to_query_for[i]] = coordinate_bounds; |
| 70 | } | ||
| 71 | |||
| 72 | 8 | return result; | |
| 73 | 8 | } | |
| 74 | |||
| 75 | 8 | std::shared_ptr<IDbStatement> DocumentReadBase::CreateQueryMinMaxStatement( | |
| 76 | const std::vector<imgdoc2::Dimension>& dimensions, | ||
| 77 | const std::function<void(std::ostringstream&, imgdoc2::Dimension)>& func_add_dimension_table_name, | ||
| 78 | const std::string& table_name) const | ||
| 79 | { | ||
| 80 | // preconditions: | ||
| 81 | // - the dimensions specified must be valid | ||
| 82 | // - the collection must not be empty | ||
| 83 | |||
| 84 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | ostringstream string_stream; |
| 85 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | string_stream << "SELECT "; |
| 86 | 8 | bool first_iteration = true; | |
| 87 |
2/2✓ Branch 4 taken 14 times.
✓ Branch 5 taken 8 times.
|
22 | for (const auto dimension : dimensions) |
| 88 | { | ||
| 89 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 8 times.
|
14 | if (!first_iteration) |
| 90 | { | ||
| 91 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | string_stream << ','; |
| 92 | } | ||
| 93 | |||
| 94 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
14 | string_stream << "MIN(["; |
| 95 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
14 | func_add_dimension_table_name(string_stream, dimension); |
| 96 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
14 | string_stream << "]),"; |
| 97 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
14 | string_stream << "MAX(["; |
| 98 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
14 | func_add_dimension_table_name(string_stream, dimension); |
| 99 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
14 | string_stream << "])"; |
| 100 | 14 | first_iteration = false; | |
| 101 | } | ||
| 102 | |||
| 103 |
4/8✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 8 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 8 times.
✗ Branch 11 not taken.
|
8 | string_stream << " FROM " << "[" << table_name << "];"; |
| 104 | |||
| 105 |
2/4✓ Branch 5 taken 8 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 8 times.
✗ Branch 9 not taken.
|
8 | auto statement = this->GetDocument()->GetDatabase_connection()->PrepareStatement(string_stream.str()); |
| 106 | 16 | return statement; | |
| 107 | 8 | } | |
| 108 | |||
| 109 | 22 | std::shared_ptr<IDbStatement> DocumentReadBase::CreateQueryMinMaxForXyz(const std::string& table_name, const std::vector<QueryMinMaxForXyzInfo>& query_info) const | |
| 110 | { | ||
| 111 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 22 times.
|
22 | Expects(!query_info.empty()); |
| 112 | |||
| 113 |
1/2✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
|
22 | ostringstream string_stream; |
| 114 |
1/2✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
|
22 | string_stream << "SELECT "; |
| 115 | 22 | bool first_iteration = true; | |
| 116 |
2/2✓ Branch 4 taken 32 times.
✓ Branch 5 taken 22 times.
|
54 | for (const auto& info : query_info) |
| 117 | { | ||
| 118 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 22 times.
|
32 | if (!first_iteration) |
| 119 | { | ||
| 120 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | string_stream << ','; |
| 121 | } | ||
| 122 | |||
| 123 |
1/2✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
|
32 | string_stream << "MIN(["; |
| 124 |
1/2✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
|
32 | string_stream << info.column_name_coordinate; |
| 125 |
1/2✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
|
32 | string_stream << "]),"; |
| 126 |
1/2✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
|
32 | string_stream << "MAX(["; |
| 127 |
3/6✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 32 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 32 times.
✗ Branch 8 not taken.
|
32 | string_stream << info.column_name_coordinate << "]+[" << info.column_name_coordinate_extent; |
| 128 |
1/2✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
|
32 | string_stream << "])"; |
| 129 | |||
| 130 | 32 | first_iteration = false; | |
| 131 | } | ||
| 132 | |||
| 133 |
3/6✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 22 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 22 times.
✗ Branch 8 not taken.
|
22 | string_stream << " FROM [" << table_name << "];"; |
| 134 | |||
| 135 |
2/4✓ Branch 5 taken 22 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 22 times.
✗ Branch 9 not taken.
|
22 | auto statement = this->GetDocument()->GetDatabase_connection()->PrepareStatement(string_stream.str()); |
| 136 | |||
| 137 | 44 | return statement; | |
| 138 | 22 | } | |
| 139 | |||
| 140 | 52 | /*static*/int DocumentReadBase::SetCoordinateBoundsValueIfNonNull(imgdoc2::DoubleInterval* interval, IDbStatement* statement, int result_index) | |
| 141 | { | ||
| 142 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 20 times.
|
52 | if (interval != nullptr) |
| 143 | { | ||
| 144 |
1/2✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
|
32 | const auto min = statement->GetResultDoubleOrNull(result_index++); |
| 145 |
1/2✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
|
32 | const auto max = statement->GetResultDoubleOrNull(result_index++); |
| 146 |
5/6✓ Branch 1 taken 28 times.
✓ Branch 2 taken 4 times.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 28 times.
✓ Branch 7 taken 4 times.
|
32 | if (min.has_value() && max.has_value()) |
| 147 | { | ||
| 148 |
1/2✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
|
28 | interval->minimum_value = min.value(); |
| 149 |
1/2✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
|
28 | interval->maximum_value = max.value(); |
| 150 | } | ||
| 151 | else | ||
| 152 | { | ||
| 153 | 4 | *interval = DoubleInterval{}; | |
| 154 | } | ||
| 155 | } | ||
| 156 | |||
| 157 | 52 | return result_index; | |
| 158 | } | ||
| 159 | |||
| 160 | 32 | std::uint64_t DocumentReadBase::GetTotalTileCount(const std::string& table_name) | |
| 161 | { | ||
| 162 |
1/2✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
|
32 | ostringstream string_stream; |
| 163 |
3/6✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 32 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 32 times.
✗ Branch 8 not taken.
|
32 | string_stream << "SELECT COUNT(*) FROM [" << table_name << "];"; |
| 164 |
2/4✓ Branch 5 taken 32 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 32 times.
✗ Branch 9 not taken.
|
32 | const auto statement = this->GetDocument()->GetDatabase_connection()->PrepareStatement(string_stream.str()); |
| 165 | |||
| 166 |
1/2✓ Branch 6 taken 32 times.
✗ Branch 7 not taken.
|
32 | const bool is_done = this->GetDocument()->GetDatabase_connection()->StepStatement(statement.get()); |
| 167 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
|
32 | if (!is_done) |
| 168 | { | ||
| 169 | ✗ | throw internal_error_exception("database-query gave no result, this is unexpected."); | |
| 170 | } | ||
| 171 | |||
| 172 |
1/2✓ Branch 2 taken 32 times.
✗ Branch 3 not taken.
|
32 | const auto result = statement->GetResultInt64(0); |
| 173 | 32 | return result; | |
| 174 | 32 | } | |
| 175 | |||
| 176 | 14 | std::map<int, std::uint64_t> DocumentReadBase::GetTileCountPerLayer(const std::string& table_name, const std::string& pyramid_level_column_name) | |
| 177 | { | ||
| 178 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
14 | ostringstream string_stream; |
| 179 |
7/14✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 14 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 14 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 14 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 14 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 14 times.
✗ Branch 20 not taken.
|
14 | string_stream << "SELECT [" << pyramid_level_column_name << "], COUNT(*) FROM [" << table_name << "] GROUP BY [" << pyramid_level_column_name << "];"; |
| 180 |
2/4✓ Branch 5 taken 14 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 14 times.
✗ Branch 9 not taken.
|
14 | const auto statement = this->GetDocument()->GetDatabase_connection()->PrepareStatement(string_stream.str()); |
| 181 | |||
| 182 | 14 | map<int, uint64_t> result; | |
| 183 |
3/4✓ Branch 6 taken 50 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 36 times.
✓ Branch 9 taken 14 times.
|
50 | while (this->GetDocument()->GetDatabase_connection()->StepStatement(statement.get())) |
| 184 | { | ||
| 185 |
1/2✓ Branch 2 taken 36 times.
✗ Branch 3 not taken.
|
36 | const auto layer = statement->GetResultInt32(0); |
| 186 |
1/2✓ Branch 2 taken 36 times.
✗ Branch 3 not taken.
|
36 | const auto count = statement->GetResultInt64(1); |
| 187 |
1/2✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
|
36 | result[layer] = count; |
| 188 | } | ||
| 189 | |||
| 190 | 28 | return result; | |
| 191 | 14 | } | |
| 192 |