Atlas Game Manager
A game manager for f95 and dlsite written in c++
Loading...
Searching...
No Matches
Binder.hpp
Go to the documentation of this file.
1//
2// Created by kj16609 on 6/23/23.
3//
4
5#pragma once
6#ifndef ATLASGAMEMANAGER_BINDER_HPP
7#define ATLASGAMEMANAGER_BINDER_HPP
8
9#include <sqlite3.h>
10#include <string>
11
12#include "Database.hpp"
13#include "FunctionDecomp.hpp"
14#include "binders.hpp"
15#include "core/exceptions.hpp"
17#include "extractors.hpp"
18
19template < typename T >
20concept has_value = requires( T& t ) {
21 {
22 t.value()
23 } -> std::same_as< typename T::value_type& >;
24};
25
26template < typename T >
27concept has_value_check = requires( T& t ) {
28 {
29 t.has_value()
30 } -> std::same_as< bool >;
31};
32
33template < typename T >
34concept has_get = requires( T& t ) {
35 {
36 std::get< 0 >( t )
37 };
38};
39
40template < typename T > concept is_tuple = has_get< std::remove_reference_t< T > >;
41
42template < typename T >
44
45class Binder
46{
47 sqlite3_stmt* stmt { nullptr };
48 int param_counter { 0 };
49 int max_param_count { 0 };
50 bool ran { false };
51
52 Q_DISABLE_COPY_MOVE( Binder )
53
54 public:
55
56 Binder() = delete;
57
58 Binder( const std::string_view sql );
59
60 template < typename T >
61 // Why was this here? What reason did I put it here for?
62 //requires( !std::is_same_v< std::remove_reference_t< T >, std::string > )
64 {
66 {
67 throw DatabaseException( format_ns::format(
68 "param_counter > param_count = {} > {} for query \"{}\"",
70 sqlite3_bind_parameter_count( stmt ),
71 std::string( sqlite3_sql( stmt ) ) ) );
72 }
73
74 switch ( bindParameter< std::remove_reference_t< T > >( stmt, std::move( t ), ++param_counter ) )
75 {
76 case SQLITE_OK:
77 break;
78 default:
79 {
80 throw DatabaseException( format_ns::format(
81 "Failed to bind to \"{}\": Reason: \"{}\"",
82 sqlite3_sql( stmt ),
83 sqlite3_errmsg( &Database::ref() ) ) );
84 }
85 }
86
87 return *this;
88 }
89
90 template < typename T >
91 requires( (!is_optional< T >) && (!is_tuple< T >))
92 void operator>>( T& t )
93 {
94 std::optional< std::tuple< T > > tpl;
95
96 executeQuery( tpl );
97
98 if ( tpl.has_value() ) t = std::move( std::get< 0, T >( tpl.value() ) );
99 }
100
101 template < typename T >
102 requires( !is_optional< T > && (!is_tuple< T >))
103 void operator>>( std::optional< T >& t )
104 {
105 std::optional< std::tuple< T > > tpl;
106
107 executeQuery( tpl );
108
109 if ( tpl.has_value() )
110 t = std::move( std::get< 0, T >( tpl.value() ) );
111 else
112 t = std::nullopt;
113 }
114
115 template < typename Function >
117 void operator>>( Function&& func )
118 {
119 using FuncArgs = FunctionDecomp< Function >;
120 using Tpl = FuncArgs::ArgTuple;
121
122 std::optional< Tpl > opt_tpl { std::nullopt };
123 executeQuery( opt_tpl );
124
125 while ( opt_tpl.has_value() )
126 {
127 std::apply( func, std::move( opt_tpl.value() ) );
128 executeQuery( opt_tpl );
129 }
130 }
131
132 template < typename... Ts >
133 requires( !( is_optional< Ts > && ... ) ) && ( !( is_tuple< Ts > && ... ) )
134 void operator>>( std::tuple< Ts... >& tpl )
135 {
136 ran = true;
137
138 std::optional< std::tuple< Ts... > > opt_tpl { std::nullopt };
139 executeQuery( opt_tpl );
140
141 if ( opt_tpl.has_value() )
142 {
143 tpl = std::move( opt_tpl.value() );
144 }
145 return;
146 }
147
148 private:
149
150 template < typename... Ts >
151 requires( !( is_optional< Ts > || ... ) && !( is_tuple< Ts > || ... ) )
152 void executeQuery( std::optional< std::tuple< Ts... > >& tpl_opt )
153 {
155 throw AtlasException( format_ns::format(
156 "Not enough parameters given for query! Given {}, Expected {}. param_counter != max_param_count = {} != {} for query \"{}\"",
161 std::string( sqlite3_sql( stmt ) ) ) );
162
163 ran = true;
164
165 if ( stmt == nullptr ) throw DatabaseException( "stmt was nullptr" );
166
167 atlas::logging::debug( "Executing query {}", sqlite3_expanded_sql( stmt ) );
168
169 const auto step_ret { sqlite3_step( stmt ) };
170
171 switch ( step_ret )
172 {
173 case SQLITE_ROW:
174 [[likely]]
175 {
176 if constexpr ( sizeof...( Ts ) > 0 )
177 {
178 std::tuple< Ts... > tpl;
179 extractRow< 0, Ts... >( stmt, tpl );
180 tpl_opt = std::move( tpl );
181 return;
182 }
183 else
184 {
185 tpl_opt = std::nullopt;
186 return;
187 }
188 }
189 case SQLITE_DONE:
190 {
191 atlas::logging::debug( "Finished query {}", sqlite3_expanded_sql( stmt ) );
192 tpl_opt = std::nullopt;
193 return;
194
195 default:
196 [[fallthrough]];
197 case SQLITE_MISUSE:
198 [[fallthrough]];
199 case SQLITE_BUSY:
200 [[fallthrough]];
201 case SQLITE_ERROR:
202 {
203 throw AtlasException( format_ns::format(
204 "DB: Query error: \"{}\", Query: \"{}\"",
205 sqlite3_errmsg( &Database::ref() ),
206 sqlite3_expanded_sql( stmt ) ) );
207 }
208 }
209 }
210 }
211
212 public:
213
214 ~Binder() noexcept( false );
215};
216
217#endif //ATLASGAMEMANAGER_BINDER_HPP
int bindParameter(sqlite3_stmt *, const T, const int) noexcept=delete
Definition binders.hpp:20
Definition Binder.hpp:46
sqlite3_stmt * stmt
Definition Binder.hpp:47
bool ran
Definition Binder.hpp:50
void executeQuery(std::optional< std::tuple< Ts... > > &tpl_opt)
Definition Binder.hpp:152
~Binder() noexcept(false)
Definition Binder.cpp:24
Binder & operator<<(T t)
Definition Binder.hpp:63
int max_param_count
Definition Binder.hpp:49
Binder()=delete
int param_counter
Definition Binder.hpp:48
static sqlite3 & ref()
Returns a ref to the sqlite DB.
Definition Database.cpp:22
Definition Binder.hpp:34
Definition Binder.hpp:27
Definition Binder.hpp:20
Definition Binder.hpp:43
Definition Binder.hpp:40
void extractRow(sqlite3_stmt *stmt, std::tuple< Args... > &tpl) noexcept
Definition extractors.hpp:103
debug(format_ns::format_string< Ts... >, Ts &&...) -> debug< Ts... >
Definition FunctionDecomp.hpp:19
Definition exceptions.hpp:17
Definition exceptions.hpp:63