SQLon test coverage


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 97.8% 45 / 0 / 46
Functions: 100.0% 6 / 0 / 6
Branches: 100.0% 45 / 0 / 45

src/prepared_query.cpp
Line Branch Exec Source
1 /******************************************************************************
2 **
3 ** Copyright (C) 2026 Ivan Pinezhaninov <ivan.pinezhaninov@gmail.com>
4 **
5 ** This file is part of the SQLon - which can be found at
6 ** https://github.com/IvanPinezhaninov/sqlon/.
7 **
8 ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
9 ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
10 ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
11 ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
12 ** DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
13 ** OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
14 ** THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 **
16 ******************************************************************************/
17
18 #include <sqlon/prepared_query.h>
19
20 #include <unordered_set>
21 #include <utility>
22
23 namespace sqlon {
24
25 7 prepared_query::prepared_query(std::string sql, std::vector<prepared_parameter> parameters)
26 7 : m_sql(std::move(sql))
27 7 , m_parameters(std::move(parameters))
28 {
29
1/1
✓ Branch 2 taken 7 times.
7 m_bindings.reserve(m_parameters.size());
30
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 7 times.
13 for (std::size_t index = 0; index < m_parameters.size(); ++index)
31
1/1
✓ Branch 1 taken 6 times.
6 m_bindings.push_back({index, std::nullopt});
32
1/1
✓ Branch 1 taken 7 times.
7 validate_layout();
33 7 }
34
35 26 prepared_query::prepared_query(std::string sql, std::vector<prepared_parameter> parameters,
36 26 std::vector<prepared_binding> bindings)
37 26 : m_sql(std::move(sql))
38 26 , m_parameters(std::move(parameters))
39 26 , m_bindings(std::move(bindings))
40 {
41
1/1
✓ Branch 1 taken 20 times.
26 validate_layout();
42 44 }
43
44 12 const std::string& prepared_query::sql() const noexcept
45 {
46 12 return m_sql;
47 }
48
49 17 const std::vector<prepared_parameter>& prepared_query::parameters() const noexcept
50 {
51 17 return m_parameters;
52 }
53
54 22 bound_parameters prepared_query::materialize(const std::vector<std::optional<rendered_parameter>>& values) const
55 {
56
2/2
✓ Branch 5 taken 28 times.
✓ Branch 6 taken 21 times.
49 for (const std::optional<rendered_parameter>& value : values)
57
3/3
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 27 times.
✓ Branch 5 taken 1 time.
28 if (!value) throw invalid_query{"not all prepared parameters were bound"};
58
59 21 bound_parameters result;
60
1/1
✓ Branch 2 taken 21 times.
21 result.reserve(m_bindings.size());
61
2/2
✓ Branch 5 taken 29 times.
✓ Branch 6 taken 21 times.
50 for (const prepared_binding& binding : m_bindings) {
62
1/1
✓ Branch 3 taken 29 times.
29 rendered_parameter parameter = *values[binding.parameter_index];
63
1/1
✓ Branch 1 taken 29 times.
29 parameter.placeholder = binding.placeholder;
64
1/1
✓ Branch 2 taken 29 times.
29 result.push_back(std::move(parameter));
65 29 }
66 21 return result;
67 ✗ }
68
69 33 void prepared_query::validate_layout()
70 {
71
3/3
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 32 times.
✓ Branch 5 taken 1 time.
33 if (m_sql.empty()) throw invalid_query{"prepared SQL cannot be empty"};
72
73
1/1
✓ Branch 2 taken 32 times.
32 std::vector<bool> referenced(m_parameters.size());
74
2/2
✓ Branch 4 taken 42 times.
✓ Branch 5 taken 31 times.
73 for (const prepared_binding& binding : m_bindings) {
75
3/3
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 41 times.
✓ Branch 5 taken 1 time.
42 if (binding.parameter_index >= m_parameters.size()) throw invalid_query{"prepared binding layout is out of range"};
76
1/1
✓ Branch 1 taken 41 times.
41 referenced[binding.parameter_index] = true;
77 }
78
79
2/2
✓ Branch 6 taken 40 times.
✓ Branch 7 taken 30 times.
70 for (const bool is_referenced : referenced)
80
3/3
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 39 times.
✓ Branch 4 taken 1 time.
40 if (!is_referenced) throw invalid_query{"prepared parameter is missing from the binding layout"};
81
82 30 std::unordered_set<std::string> names;
83
2/2
✓ Branch 1 taken 38 times.
✓ Branch 2 taken 27 times.
65 for (std::size_t index = 0; index < m_parameters.size(); ++index) {
84
3/3
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 37 times.
✓ Branch 6 taken 1 time.
38 if (m_parameters[index].name.empty()) throw invalid_query{"a prepared parameter name cannot be empty"};
85
4/4
✓ Branch 2 taken 37 times.
✓ Branch 4 taken 1 time.
✓ Branch 5 taken 36 times.
✓ Branch 8 taken 1 time.
37 if (!names.insert(m_parameters[index].name).second) throw invalid_query{"prepared parameter names must be unique"};
86
1/1
✓ Branch 2 taken 36 times.
36 const bool inserted = m_parameter_indices.emplace(m_parameters[index].identity, index).second;
87
3/3
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 35 times.
✓ Branch 4 taken 1 time.
36 if (!inserted) throw invalid_query{"prepared parameter identities must be unique"};
88 }
89 35 }
90
91 } // namespace sqlon
92