Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
TableConnection.h
Go to the documentation of this file.
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Database_SQL_ORM_TableConnection_h_
5#define _Stroika_Foundation_Database_SQL_ORM_TableConnection_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include "Stroika/Foundation/Common/GUID.h"
10#include "Stroika/Foundation/Common/Property.h"
11#include "Stroika/Foundation/DataExchange/ObjectVariantMapper.h"
16
17/**
18 * \file
19 *
20 * \note Code-Status: <a href="Code-Status.md#Alpha">Alpha</a>
21 *
22 */
23
24namespace Stroika::Foundation::Database::SQL::ORM {
25
26 using namespace Containers;
27 using namespace DataExchange;
28
29 /**
30 */
31 template <typename T, typename ID_TYPE = Common::GUID>
32 struct TableConnectionTraits {
33 using IDType = ID_TYPE;
34 static VariantValue ID2VariantValue (const IDType& id)
35 {
36 if constexpr (is_convertible_v<IDType, Memory::BLOB> or same_as<IDType, Common::GUID>) {
37 return VariantValue{static_cast<Memory::BLOB> (id)};
38 }
39 else if constexpr (same_as<IDType, IO::Network::URI>) {
40 return VariantValue{id.template As<Characters::String> ()};
41 }
42 else if constexpr (is_convertible_v<IDType, Characters::String>) {
43 return VariantValue{static_cast<Characters::String> (id)};
44 }
45 else {
46 //static_assert (false, "specify your own ID2VariantValue function for this type");
48 return VariantValue{};
49 }
50 }
51 };
52
53 /**
54 * \brief TableConnection<T> wraps a database Connection::Ptr with information to map c++ objects to/from SQL database objects, and provides a series of common, building block queries (CRUD)
55 *
56 * Generally, these functions use the (constructor provided) tableSchema to know the layout/shape of the SQL data
57 * and the (constructor provided) ObjectVariantMapper to map arguments and results between c++ T objects and
58 * VariantValue objects.
59 *
60 * Together, this means you can simple Read, Write, Update, etc C++ objects directly from a SQL database,
61 * with all intervening mapping of data handled inside the TableConnection (via the Schema::Table and
62 * ObjectVariantMapper objects provided in the TableConnection::CTOR).
63 *
64 * \note we choose to create/cache the statements in the constructor and re-use them. We COULD
65 * lazy create (which would work better if you use only a small subset of the methods). But then
66 * we would incurr a cost checking each time (locking), so unclear if lazy creation is worth it.
67 *
68 * \note \em Thread-Safety <a href="Thread-Safety.md#C++-Standard-Thread-Safety-For-Envelope-But-Ambiguous-Thread-Safety-For-Letter">C++-Standard-Thread-Safety-For-Envelope-But-Ambiguous-Thread-Safety-For-Letter/a>
69 * But though each connection can only be accessed from a single thread at a time, the underlying database may be
70 * threadsafe (even if accessed across processes).
71 */
72 template <typename T, typename TRAITS = TableConnectionTraits<T>>
74 public:
75 /**
76 * Optionally passed to TableConnection for the purpose of logging
77 */
78 enum Operation {
79 eStartingRead,
80 eCompletedRead,
81 eStartingWrite,
82 eCompletedWrite,
83 eNotifyError
84 };
85
86 public:
87 /**
88 * Optionally passed to TableConnection for the purpose of logging;
89 * note exception_ptr is only provided for eNotifyError, and is typically current_exception () but can be nullptr
90 */
91 using OpertionCallbackPtr = function<void (Operation op, const TableConnection* tableConn, const Statement* s, const exception_ptr& e)>;
92
93 public:
94 TableConnection () = delete;
95 TableConnection (const Connection::Ptr& conn, const Schema::Table& tableSchema, const ObjectVariantMapper& objectVariantMapper,
96 const OpertionCallbackPtr& operationCallback = nullptr);
98
99 public:
100 /**
101 */
103
104 public:
105 /**
106 */
108
109 public:
110 /**
111 */
113
114 public:
115 /**
116 */
118
119 public:
120 static const OpertionCallbackPtr kDefaultTracingOpertionCallback;
121
122 public:
123 /**
124 * Lookup the given object by ID. This does a select * from table where id=id, and maps the various
125 * SQL parameters that come back to a C++ object.
126 */
127 nonvirtual optional<T> Get (const VariantValue& id);
128 nonvirtual optional<T> Get (const typename TRAITS::IDType& id);
129
130 public:
131 /**
132 * Get ALL the c++ objects in this table. This does a select * from table, and maps the various
133 * SQL parameters that come back to C++ objects.
134 *
135 * If optional onItemException is provided, each conversion to an object that results
136 * in an exception is passed to onItemException. It can rethrow, or eat the exception as desired.
137 * The function returns optional<T> - so the caller can either return the would-be object
138 * or skip it if the function returns nullopt;
139 */
140 nonvirtual Sequence<T> GetAll ();
141 nonvirtual Sequence<T> GetAll (const function<optional<T> (const Statement::Row& r, const exception_ptr& e)>& onItemException);
142
143 public:
144 /**
145 * Convert the argument object to database form, and write it as a new row to the database. The ID is
146 * generally not provided as part of T (though it can be), as you generally supply a default creation rule for
147 * IDs in the Schema::Table.
148 */
149 nonvirtual void AddNew (const T& v);
150
151 public:
152 /**
153 * Equivilent to checking GetByID () to see if present, and either calling AddNew or Update().
154 */
155 nonvirtual void AddOrUpdate (const T& v);
156
157 public:
158 /**
159 * Use the ID field from the argument object to update all the OTHER fields of that object in the database.
160 * The ID field is known because of the Table::Schema, and must be valid (else this will fail).
161 */
162 nonvirtual void Update (const T& v);
163
164 public:
165 /**
166 */
167 nonvirtual void Delete (const VariantValue& id);
168 nonvirtual void Delete (const typename TRAITS::IDType& id);
169 nonvirtual void Delete (const T& v);
170
171 private:
172 Connection::Ptr fConnection_;
173 shared_ptr<const EngineProperties> fEngineProperties_;
174 Schema::Table fTableSchema_;
175 ObjectVariantMapper fObjectVariantMapper_;
176 OpertionCallbackPtr fTableOpertionCallback_;
177 Statement fGetByID_Statement_;
178 Statement fGetAll_Statement_;
179 Statement fAddNew_Statement_;
180 Statement fUpdate_Statement_;
181 Statement fDeleteByID_Statement_;
182 [[no_unique_address]] Debug::AssertExternallySynchronizedMutex fThisAssertExternallySynchronized_;
183
184 private:
185 template <typename FUN>
186 nonvirtual void DoExecute_ (FUN&& f, Statement& s, bool write);
187 nonvirtual void DoExecute_ (Statement& s, bool write);
188 };
189
190}
191
192/*
193 ********************************************************************************
194 ***************************** Implementation Details ***************************
195 ********************************************************************************
196 */
197#include "TableConnection.inl"
198
199#endif /*_Stroika_Foundation_Database_SQL_ORM_TableConnection_h_*/
#define AssertNotReached()
Definition Assertions.h:355
A generalization of a vector: a container whose elements are keyed by the natural numbers.
Definition Sequence.h:187
ObjectVariantMapper can be used to map C++ types to and from variant-union types, which can be transp...
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...
function< void(Operation op, const TableConnection *tableConn, const Statement *s, const exception_ptr &e)> OpertionCallbackPtr
nonvirtual optional< T > Get(const VariantValue &id)
NOT a real mutex - just a debugging infrastructure support tool so in debug builds can be assured thr...