Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
TableConnection.inl
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
6
7namespace Stroika::Foundation::Database::SQL::ORM {
8
9 /*
10 ********************************************************************************
11 ******************************** TableConnection *******************************
12 ********************************************************************************
13 */
14 template <typename T, typename TRAITS>
15 TableConnection<T, TRAITS>::TableConnection (const Connection::Ptr& conn, const Schema::Table& tableSchema,
16 const ObjectVariantMapper& objectVariantMapper, const OpertionCallbackPtr& operationCallback)
17 : connection{[qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] const auto* property) {
18 const TableConnection* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &TableConnection::connection);
19 return thisObj->fConnection_;
20 }}
21 , tableSchema{[qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] const auto* property) {
22 const TableConnection* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &TableConnection::tableSchema);
23 return thisObj->fTableSchema_;
24 }}
25 , objectVariantMapper{[qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] const auto* property) {
26 const TableConnection* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &TableConnection::objectVariantMapper);
27 return thisObj->fObjectVariantMapper_;
28 }}
29 , operationCallback{[qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] const auto* property) {
30 const TableConnection* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &TableConnection::operationCallback);
31 return thisObj->fTableOpertionCallback_;
32 }}
33 , fConnection_{conn}
34 , fEngineProperties_{conn->GetEngineProperties ()}
35 , fTableSchema_{tableSchema}
36 , fObjectVariantMapper_{objectVariantMapper}
37 , fTableOpertionCallback_{operationCallback}
38 , fGetByID_Statement_{conn->mkStatement (Schema::StandardSQLStatements{tableSchema}.GetByID ())}
39 , fGetAll_Statement_{conn->mkStatement (Schema::StandardSQLStatements{tableSchema}.GetAllElements ())}
40 , fAddNew_Statement_{conn->mkStatement (Schema::StandardSQLStatements{tableSchema}.Insert ())}
41 , fUpdate_Statement_{conn->mkStatement (Schema::StandardSQLStatements{tableSchema}.UpdateByID ())}
42 , fDeleteByID_Statement_{conn->mkStatement (Schema::StandardSQLStatements{tableSchema}.DeleteByID ())}
43 {
44 Require (conn != nullptr); // too late, but good docs
45 }
46 template <typename T, typename TRAITS>
47 inline TableConnection<T, TRAITS>::TableConnection (const TableConnection& src)
48 : TableConnection{src.fConnection_, src.fTableSchema_, src.fObjectVariantMapper_, src.fTableOpertionCallback_}
49 {
50 }
51 template <typename T, typename TRAITS>
53 {
54 Debug::AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
57 fGetByID_Statement_.Reset ();
58 fGetByID_Statement_.Bind (initializer_list<KeyValuePair<String, VariantValue>>{{fTableSchema_.GetIDField ()->fName, id}});
59 optional<Statement::Row> row;
60 DoExecute_ ([&] (Statement& s) { row = s.GetNextRow (); }, fGetByID_Statement_, false);
61 [[maybe_unused]] auto&& cleanup = Execution::Finally ([&] () noexcept {
62 if (fEngineProperties_->RequireStatementResetAfterModifyingStatmentToCompleteTransaction ()) {
63 // could potentially avoid this if I added way to track if existing transaction object, but not clearly any point
64 fGetByID_Statement_.Reset ();
65 }
66 });
67 if (row) {
68 return fObjectVariantMapper_.ToObject<T> (VariantValue{fTableSchema_.MapFromDB (*row)});
69 }
70 return nullopt;
71 }
72 template <typename T, typename TRAITS>
73 optional<T> TableConnection<T, TRAITS>::Get (const typename TRAITS::IDType& id)
74 {
75 return Get (TRAITS::ID2VariantValue (id));
76 }
77 template <typename T, typename TRAITS>
79 {
80 Debug::AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
84 DoExecute_ ([&] (Statement& s) { rows = s.GetAllRows (); }, fGetAll_Statement_, false);
85 [[maybe_unused]] auto&& cleanup = Execution::Finally ([&] () noexcept {
86 if (fEngineProperties_->RequireStatementResetAfterModifyingStatmentToCompleteTransaction ()) {
87 // could potentially avoid this if I added way to track if existing transaction object, but not clearly any point
88 fGetAll_Statement_.Reset ();
89 }
90 });
91 return rows.template Map<Sequence<T>> (
92 [this] (const Statement::Row& r) { return fObjectVariantMapper_.ToObject<T> (VariantValue{fTableSchema_.MapFromDB (r)}); });
93 }
94 template <typename T, typename TRAITS>
95 Sequence<T> TableConnection<T, TRAITS>::GetAll (const function<optional<T> (const Statement::Row&, const exception_ptr&)>& onItemException)
96 {
97 Debug::AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
101 DoExecute_ ([&] (Statement& s) { rows = s.GetAllRows (); }, fGetAll_Statement_, false);
102 [[maybe_unused]] auto&& cleanup = Execution::Finally ([&] () noexcept {
103 if (fEngineProperties_->RequireStatementResetAfterModifyingStatmentToCompleteTransaction ()) {
104 // could potentially avoid this if I added way to track if existing transaction object, but not clearly any point
105 fGetAll_Statement_.Reset ();
106 }
107 });
108 // Map VariantValue objects from DB (Row) to ORM-based (object variant mapper) objects, and pass any failures
109 // through onItemException, which returns optional<T>, so if missing returned the values skipped
110 return rows.template Map<Sequence<T>> ([this, &onItemException] (const Statement::Row& r) -> optional<T> {
111 try {
112 return fObjectVariantMapper_.ToObject<T> (VariantValue{fTableSchema_.MapFromDB (r)});
113 }
114 catch (...) {
115 return onItemException (r, current_exception ());
116 }
117 });
118 }
119 template <typename T, typename TRAITS>
121 {
122 Debug::AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
124 fAddNew_Statement_.Reset ();
125 fAddNew_Statement_.Bind (fTableSchema_.MapToDB (fObjectVariantMapper_.FromObject (v).template As<Mapping<String, VariantValue>> ()));
126 DoExecute_ (fAddNew_Statement_, true);
127 [[maybe_unused]] auto&& cleanup = Execution::Finally ([&] () noexcept {
128 if (fEngineProperties_->RequireStatementResetAfterModifyingStatmentToCompleteTransaction ()) {
129 // could potentially avoid this if I added way to track if existing transaction object, but not clearly any point
130 fAddNew_Statement_.Reset ();
131 }
132 });
133 }
134 template <typename T, typename TRAITS>
136 {
137 // @todo: this can and should be done much more efficiently
139 fTableSchema_.MapToDB (fObjectVariantMapper_.FromObject (v).template As<Mapping<String, VariantValue>> ());
140 if (Get (dbV[fTableSchema_.GetIDField ()->fName])) {
141 Update (v);
142 }
143 else {
144 AddNew (v);
145 }
146 }
147 template <typename T, typename TRAITS>
149 {
150 Debug::AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
153 fUpdate_Statement_.Reset ();
154 fUpdate_Statement_.Bind (fTableSchema_.MapToDB (fObjectVariantMapper_.FromObject (v).template As<Mapping<String, VariantValue>> ()));
155 DoExecute_ (fUpdate_Statement_, true);
156 [[maybe_unused]] auto&& cleanup = Execution::Finally ([&] () noexcept {
157 if (fEngineProperties_->RequireStatementResetAfterModifyingStatmentToCompleteTransaction ()) {
158 // could potentially avoid this if I added way to track if existing transaction object, but not clearly any point
159 fUpdate_Statement_.Reset ();
160 }
161 });
162 }
163 template <typename T, typename TRAITS>
165 {
166 Debug::AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
169 fDeleteByID_Statement_.Reset ();
170 fDeleteByID_Statement_.Bind (initializer_list<KeyValuePair<String, VariantValue>>{{fTableSchema_.GetIDField ()->fName, id}});
171 DoExecute_ (fDeleteByID_Statement_, true);
172 [[maybe_unused]] auto&& cleanup = Execution::Finally ([&] () noexcept {
173 if (fEngineProperties_->RequireStatementResetAfterModifyingStatmentToCompleteTransaction ()) {
174 // could potentially avoid this if I added way to track if existing transaction object, but not clearly any point
175 fDeleteByID_Statement_.Reset ();
176 }
177 });
178 }
179 template <typename T, typename TRAITS>
180 inline void TableConnection<T, TRAITS>::Delete (const typename TRAITS::IDType& id)
181 {
182 Delete (TRAITS::ID2VariantValue (id));
183 }
184 template <typename T, typename TRAITS>
185 inline void TableConnection<T, TRAITS>::Delete (const T& v)
186 {
187 Debug::AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
188 using DataExchange::VariantValue;
189 Mapping<String, VariantValue> objFields = fObjectVariantMapper_.FromObject (v).template As<Mapping<String, VariantValue>> ();
190 VariantValue idField = *objFields.Lookup (Memory::ValueOf (fTableSchema_.GetIDField ()).GetVariantValueFieldName ());
191 Delete (idField);
192 }
193 template <typename T, typename TRAITS>
194 template <typename FUN>
195 void TableConnection<T, TRAITS>::DoExecute_ (FUN&& f, Statement& s, bool write)
196 {
197 if (fTableOpertionCallback_ == nullptr) {
198 f (s);
199 }
200 else {
201 fTableOpertionCallback_ (write ? Operation::eStartingWrite : Operation::eStartingRead, this, &s, nullptr);
202 try {
203 f (s);
204 fTableOpertionCallback_ (write ? Operation::eCompletedWrite : Operation::eCompletedRead, this, &s, nullptr);
205 }
206 catch (...) {
207 fTableOpertionCallback_ (Operation::eNotifyError, this, &s, current_exception ());
208 fTableOpertionCallback_ (write ? Operation::eCompletedWrite : Operation::eCompletedRead, this, &fUpdate_Statement_, nullptr);
209 Execution::ReThrow ();
210 }
211 }
212 }
213 template <typename T, typename TRAITS>
214 inline void TableConnection<T, TRAITS>::DoExecute_ (Statement& s, bool write)
215 {
216 DoExecute_ ([] (Statement& s) { s.Execute (); }, s, write);
217 }
218 template <typename T, typename TRAITS>
219 const typename TableConnection<T, TRAITS>::OpertionCallbackPtr TableConnection<T, TRAITS>::kDefaultTracingOpertionCallback =
220 [] (Operation op, const TableConnection* tableConn, const Statement* s) {
221 if (op == Operation::eStartingRead or op == Operation::eStartingWrite) {
222 if (s != nullptr) {
223 using namespace Characters::Literals;
224 DbgTrace ("SQL: {}"_f, s->GetSQL (Statement::WhichSQLFlag::eExpanded));
225 }
226 }
227 };
228
229}
#define DbgTrace
Definition Trace.h:309
A generalization of a vector: a container whose elements are keyed by the natural numbers.
Definition Sequence.h:187
Simple variant-value (case variant union) object, with (variant) basic types analogous to a value in ...
TableConnection<T> wraps a database Connection::Ptr with information to map c++ objects to/from SQL d...
nonvirtual optional< Row > GetNextRow()
Definition Statement.inl:58
nonvirtual Sequence< Row > GetAllRows()
call Reset (), and then GetAllRemainingRows () - which always starts current statement with current b...
Definition Statement.inl:64
unique_lock< AssertExternallySynchronizedMutex > WriteContext
Instantiate AssertExternallySynchronizedMutex::WriteContext to designate an area of code where protec...