Freigabe wxSQLite3 Version 5.0.1

wxSQLite3, eine Schnittstelle zu SQLite-Datenbanken für wxWidgets-basierte Anwendungen, ist inzwischen seit über 20 Jahren verfügbar. In dieser Zeit hat sich insbesondere die Programmiersprache C++ ganz erheblich weiterentwickelt, so dass es höchste Eisenbahn wurde, die Schnittstelle zu modernisieren und an einige der neuen Möglichkeiten in C++ anzupassen.
Bereits im Sommer 2019 habe ich erste Ideen für die Modernisierung zusammengetragen, aber wie das Leben so spielt, hat es nun doch ein wenig länger gedauert, bis die erste überarbeitete Version jetzt im August freigegeben werden konnte.
Da die neue Version 5.x nicht source-code-kompatibel zur Vorversion 4.x ist, werde ich die 4.x-Linie noch für eine gewisse Zeit mit Updates versorgen. Wie lange das der Fall sein wird, ist noch nicht endgültig entschieden. Das “End-Of-Life”-Datum für Version 4.x wird rechtzeitig bekannt gegeben. Wann es soweit ist, wird auch vom konkreten Bedarf abhängen. Entwickler, die — aus welchen Gründen auch immer — Version 4.x weiterverwenden wollen oder müssen, sollten sich daher auf GitHub zu Wort melden. Rückmeldungen zur neuen Version sind natürlich ebenfalls willkommen.
wxSQLite3
Änderungen seit der letzten Freigabe:
-
Aktualisierung auf SQLite3 Multiple Ciphers Version 2.4.0
-
Template-Methoden
GetandBinderweitert, so dass generell integrale Typen (wieint8_t,uint16,enumusw.) verwendet werden können -
Template-Methoden
Binderweitert, so dass auch direkte Typen und nicht nurstd::optionalverwendet werden können -
class-Attribut zuenum-Aufzählungen ergänzt, wo es bislang noch gefehlt hatte -
Minimal-Beispiel angepasst
Modernes C++-Interface
wxSQLite3 bietet eine Reihe von Komfortfunktionen, die die Arbeit mit SQLite-Ergebnismengen und vorbereiteten SQL-Anweisungen in modernem C++-Code intuitiver gestalten. Diese Funktionen ergänzen die herkömmliche cursorbasierte Schnittstelle und die bestehenden typspezifischen Methoden.
Typbewusster Zugriff auf Werte aus Ergebnismengen
Zusätzlich zu den bestehenden typspezifischen Methoden zum Abrufen von Werten aus einer Ergebnismenge bietet wxSQLite3 eine vorlagenbasierte Get<T>()-Methode. Die Methode gibt einen std::optional<T> zurück und macht so die Unterscheidung zwischen einem SQL-NULL-Wert und einem Wert des angeforderten C++-Typs explizit.
Zum Beispiel:
const std::optional<int> id = resultSet.Get<int>(0);
const std::optional<wxString> name = resultSet.Get<wxString>(1);
if (id)
{
// The column contains a non-NULL integer value.
}Ist der entsprechende SQLite-Wert NULL, ist das zurückgegebene std::optional leer. Andernfalls enthält es den Wert, der in den angeforderten C++-Typ konvertiert wurde.
Die vorlagengestützte Schnittstelle wird auf Basis der bestehenden typspezifischen Methoden für Ergebnismengen implementiert. Sie bietet daher eine komfortable und typorientierte Schnittstelle, ohne einen separaten Mechanismus zur Wertkonvertierung einzuführen.
Typbewusste Bindung von Anweisungsparametern
Parameter von vorbereiteten SQL-Anweisungen können ebenfalls mithilfe der vorlagengestützten Schnittstelle Bind<T>() gebunden werden. Die Methode akzeptiert einen std::optional<T>, wodurch ein SQL-NULL-Wert auf natürliche Weise durch einen leeren std::optional dargestellt werden kann.
Zum Beispiel:
std::optional<int> id = ...;
std::optional<wxString> name = ...;
stmt.Bind(1, id);
stmt.Bind(2, name);Ein belegtes std::optional bindet den darin enthaltenen Wert, während ein leeres std::optional einen SQL-NULL-Wert bindet.
Wie bei Get<T>() nutzen die vorlagenbasierten Bindungsmethoden intern die vorhandenen typspezifischen Bindungsmethoden.
Dadurch eignet sich std::optional hervorragend für den Umgang mit nullfähigen Datenbankwerten, ohne dass SQL-NULL im Anwendungscode als Sonderfall behandelt werden muss.
Binden und Abrufen von Wertetupeln
Für Fälle, in denen mehrere Werte an eine vorbereitete Anweisung gebunden oder aus einem Ergebnissatz abgerufen werden müssen, stellt wxSQLite3 außerdem die Funktionen BindTuple() und GetTuple() zur Verfügung.
Die erste Variante verwendet fortlaufende Parameter- oder Spaltenindizes. Die Werte werden daher den Indizes zugeordnet, beginnend mit dem angegebenen ersten Index.
Zum Beispiel:
const auto values = resultSet.GetTuple<int, wxString, double>(0);ruft drei Werte aus aufeinanderfolgenden Spalten ab.
Ebenso können Werte an aufeinanderfolgende Parameter gebunden werden:
stmt.BindTuple(1, id, name, amount);Die tupelbasierten Methoden verwenden dieselbe typbezogene Konvertierung und dieselbe std::optional-Behandlung wie die einzelnen Methoden Get<T>() und Bind(). Folglich können nullfähige Datenbankwerte direkt im resultierenden oder übergebenen Tupel dargestellt werden.
Eine zweite Variante von GetTuple() und BindTuple() akzeptiert ein Array von Indizes. Dadurch können die Werte beliebigen, nicht aufeinanderfolgenden Spalten oder Parametern zugeordnet werden.
Zum Beispiel:
constexpr std::array<int, 3> columns{0, 3, 7};
const auto values =
resultSet.GetTuple<int, wxString, double>(columns);Dies ist nützlich, wenn die gesuchten Werte über eine Ergebnismenge verteilt sind und ihre Positionen keine fortlaufende Folge bilden.
Die entsprechende Bindungsoperation kann ein Index-Array auf dieselbe Weise verwenden:
constexpr std::array<int, 3> parameters{1, 4, 6};
stmt.BindTuple(parameters, id, name, amount);Die tupelbasierte Schnittstelle ist besonders nützlich, wenn mehrere Datenbankwerte direkt mit Elementen oder Werten einer C++-Datenstruktur korrespondieren und als Gruppe behandelt werden sollen.
Range-based result-set processing
Traditionell wird ein wxSQLite3ResultSet über seine cursororientierte Schnittstelle verarbeitet:
while (resultSet.NextRow())
{
const auto id = resultSet.Get<int>(0);
const auto name = resultSet.Get<wxString>(1);
// Process row
}Bei Anwendungen, die moderne C++-Funktionen nutzen, kann ein Ergebnissatz auch mit einer bereichsbasierten for-Schleife verarbeitet werden:
for (const auto& row : resultSet)
{
const auto id = row.Get<int>(0);
const auto name = row.Get<wxString>(1);
// Process row
}Dies bietet eine übersichtliche und vertraute Möglichkeit, alle Zeilen einer Ergebnismenge zu durchlaufen.
Die Iterator-Schnittstelle kann auch direkt verwendet werden, wenn mehr Kontrolle über den Durchlauf erforderlich ist:
for (auto it = resultSet.begin(); it != resultSet.end(); ++it)
{
const auto& row = *it;
// Process row
}Die iterator- und bereichsbasierten Schnittstellen sind Alternativen zur herkömmlichen NextRow()-Schleife. Sie ändern nichts am zugrunde liegenden Verarbeitungsmodell für SQLite-Ergebnismengen, sondern bieten eine zusätzliche Schnittstelle, die sich in die Standard-Iterationsmechanismen von C++ einfügt.
Kombination der Funktionen
Die einzelnen Template-Methoden, Tupeloperationen und die bereichsbasierte Verarbeitung von Ergebnismengen lassen sich kombinieren, um prägnanten und typorientierten Datenbankcode zu schreiben.
Zum Beispiel:
for (const auto& row : resultSet)
{
const auto values =
row.GetTuple<int, wxString, double>({0, 2, 5});
// Process values
}Das von GetTuple() zurückgegebene Tupel enthält std::optional-Werte, sodass sich SQL-NULL-Werte weiterhin von tatsächlichen C++-Werten unterscheiden lassen.
Diese Ergänzungen sollen die etablierte wxSQLite3-API ergänzen und nicht ersetzen. Bestehende Anwendungen können die herkömmlichen cursorbasierten und typspezifischen Methoden weiterhin ohne Änderungen verwenden.
Migration von 4.x zu 5.x
Auch wenn es erforderlich ist, den Quellcode anzupassen, um ihn unter Version 5.x lauffähig zu machen, so sind die meisten erforderlichen Änderungen sehr einfacher Natur. Auf der Dokumentationsseite für Version 5.x ist eine relativ ausführliche Migrationsanleitung verfügbar.