Heim  >  Artikel  >  Backend-Entwicklung  >  Aufbau einer PostgreSQL-Bibliothek in D

Aufbau einer PostgreSQL-Bibliothek in D

Patricia Arquette
Patricia ArquetteOriginal
2024-10-24 06:16:30866Durchsuche

Building a PostgreSQL Library in D

Ich war schon immer neugierig auf neue Programmiersprachen und deren Frameworks. Die ganze Zeit über erstreckte sich meine Erfahrung und Neugier nur auf die Front-End-Entwicklung (habe ich aber auch einige Backend-Entwicklungen gemacht?). Ich habe mich der Herausforderung gestellt, meine Fähigkeiten zu erweitern, und bin auf die Programmiersprache D gestoßen. D ist in einfachen Worten die erweiterte Version von C und CPP.

Was ist D? Auf der Website heißt es: „**D ist eine Allzweck-Programmiersprache mit statischer Typisierung, Zugriff auf Systemebene und C-ähnlicher Syntax. Mit der D-Programmiersprache können Sie schnell schreiben, schnell lesen und schnell ausführen.

Ich habe PostgreSQL als Datenbank für meine Arbeiten verwendet und habe es deshalb auch für diese Bibliothek ausgewählt. PostgreSQL ist eines der wichtigsten Open-Source-SQL-Datenbanksysteme, das Unternehmen derzeit verwenden, und seine Funktionen werden immer weiter erweitert.

Warum eine benutzerdefinierte ORM-Bibliothek erstellen?

Als ich mich mit der D-Sprache beschäftigt habe, konnte ich kein Paket finden, das meine Erwartungen erfüllt. Entweder wurde die Wartung der Pakete eingestellt oder sie können für direkte Abfragen verwendet werden. Aus einem JavaScript-Hintergrund heraus habe ich Sequalize ORM verwendet. Das bringt mich auf eine Idee. Wie wäre es mit einer ähnlichen in D.

Also habe ich etwas recherchiert und herausgefunden, dass Postgres eine Bibliothek für C bereitstellt. Dann dachte ich, wie wäre es, wenn ich die C-Bindungen in D verwenden und sie für die Entwicklung des ORM verwenden würde. Ich habe den Quellcode von https://github.com/adamdruppe/arsd/blob/master/postgres.d zum Binden der C-Bibliothek an D gefunden.

Erste Schritte

Anforderungen:

  • PostgreSQL muss in Ihrem System installiert sein. ( Ich habe für PostgreSQL 16 entwickelt)
  • IDE (Zed/VSCode/Vim)
  • DMD – D-Sprach-Compiler

Um ein neues Projekt zu erstellen, verwenden Sie den folgenden Befehl in Ihrem Terminal:

  1. Öffnen Sie Ihr Terminal oder Ihre Eingabeaufforderung.
  2. Navigieren Sie zu dem Verzeichnis, in dem Sie Ihr Projekt erstellen möchten.
  3. Führen Sie den Befehl aus:
dub init <project_name>

Dieser Befehl erstellt ein neues Projektverzeichnis mit dem angegebenen Namen und richtet die Grundstruktur für ein D-Projekt ein.

  1. Sie werden aufgefordert, die folgenden Informationen einzugeben:
    • Format – .sdl oder .json (ich habe JSON ausgewählt)
    • Beschreibung des Projekts (optional)
    • Name des Autors
    • Lizenz (z. B. MIT, BSD usw.)
    • Copyright-Zeichenfolge
    • Abhängigkeit hinzufügen (optional)
  2. Nach der Bereitstellung der Informationen erstellt dub ein neues Verzeichnis mit Ihrem Projektnamen und generiert die folgenden Dateien:
    • dub.json: Konfigurationsdatei für Ihr Projekt
    • source/app.d: Hauptquelldatei
    • .gitignore: Git-Ignorierdatei
  3. Navigieren Sie in Ihr neues Projektverzeichnis: cd
  4. Sie können jetzt mit der Entwicklung Ihres D-Projekts beginnen!

Nach Abschluss dieser Schritte haben Sie eine grundlegende D-Projektstruktur eingerichtet und sind bereit für die Entwicklung.

Unter Windows muss der folgende Abschnitt zur dub.json hinzugefügt werden.

dub init <project_name>

oder

Ich habe alle notwendigen DLL-Dateien in den lib-Ordner (manuell erstellt) kopiert und dann den folgenden Code hinzugefügt:

"libs": [ "pq" ],
    "lflags-windows-x86_64": [ "-LIBPATH:C:/Program Files/PostgreSQL/16/lib/" ],
    "copyFiles-windows-x86_64": [
        "C:/Program Files/PostgreSQL/16/lib/libpq.dll",
        "C:/Program Files/PostgreSQL/16/bin/libintl-9.dll",
        "C:/Program Files/PostgreSQL/16/bin/libssl-3-x64.dll",
        "C:/Program Files/PostgreSQL/16/bin/libcrypto-3-x64.dll",
        "C:/Program Files/PostgreSQL/16/bin/libwinpthread-1.dll",
        "C:/Program Files/PostgreSQL/16/bin/libiconv-2.dll"
    ],

Unter Linux oder macOS müssen Sie sicherstellen, dass die PostgreSQL-Entwicklungsbibliotheken installiert und ordnungsgemäß verknüpft sind. Normalerweise können Sie dies tun, indem Sie die entsprechenden Pakete über den Paketmanager Ihres Systems installieren. Auf Ubuntu- oder Debian-basierten Systemen könnten Sie beispielsweise Folgendes verwenden:

"copyFiles-windows": [
        "libs/*.dll"
    ],
    "lflags-windows": [
        "/LIBPATH:$PACKAGE_DIR/libs"
    ],
    "libs": [
        "pq"
    ]

Sobald Sie die erforderlichen Bibliotheken installiert und ordnungsgemäß verknüpft haben, können Sie mit der Einrichtung Ihres D-Projekts für die Arbeit mit PostgreSQL fortfahren.

C-Bindungen implementieren:

Hier sind die C-Bindungen für D.

sudo apt-get install libpq-dev

Jetzt können wir diese Funktionen problemlos in D verwenden.
Dies ist der Code für einige grundlegende Ausnahmebehandlungen:

module postgres.implementation.implementationc;

extern (C)
{
    struct PGconn
    {
    }

    struct PGresult
    {
    }

    void PQfinish(PGconn*);

    PGconn* PQconnectdb(const char*);

    int PQstatus(PGconn*); // FIXME check return value

    const(char*) PQerrorMessage(PGconn*);

    char* PQresultVerboseErrorMessage(const PGresult* res,
        PGVerbosity verbosity,
        PGContextVisibility show_context);
    PGresult* PQexec(PGconn*, const char*);
    void PQclear(PGresult*);

    PGresult* PQprepare(PGconn*, const char* stmtName, const char* query,
        ulong nParams, const void* paramTypes);

    PGresult* PQexecPrepared(PGconn*, const char* stmtName,
        int nParams, const char** paramValues,
        const int* paramLengths, const int* paramFormats, int resultFormat);

    int PQresultStatus(PGresult*); // FIXME check return value

    int PQnfields(PGresult*); // number of fields in a result
    const(char*) PQfname(PGresult*, int); // name of field

    int PQntuples(PGresult*); // number of rows in result
    const(char*) PQgetvalue(PGresult*, int row, int column);

    size_t PQescapeString(char* to, const char* from, size_t length);

    enum int CONNECTION_OK = 0;
    enum int PGRES_COMMAND_OK = 1;
    enum int PGRES_TUPLES_OK = 2;
    enum int PGRES_FATAL_ERROR = 7;
    enum PGContextVisibility
    {
        PQSHOW_CONTEXT_NEVER,
        PQSHOW_CONTEXT_ERRORS,
        PQSHOW_CONTEXT_ALWAYS
    }

    enum PGVerbosity
    {
        PQERRORS_TERSE,
        PQERRORS_DEFAULT,
        PQERRORS_VERBOSE,
        PQERRORS_SQLSTATE
    }

    int PQgetlength(const PGresult* res,
        int row_number,
        int column_number);
    int PQgetisnull(const PGresult* res,
        int row_number,
        int column_number);

    int PQfformat(const PGresult* res, int column_number);

    alias Oid = int;
    enum BYTEAOID = 17;
    Oid PQftype(const PGresult* res, int column_number);

    char* PQescapeByteaConn(PGconn* conn,
        const ubyte* from,
        size_t from_length,
        size_t* to_length);
    char* PQunescapeBytea(const char* from, size_t* to_length);
    void PQfreemem(void* ptr);

    char* PQcmdTuples(PGresult* res);

}

  • PGSqlException: Eine benutzerdefinierte Ausnahmeklasse, die von der Standard-D-Ausnahmeklasse erbt. Es ist für die Behandlung von PostgreSQL-spezifischen Fehlern konzipiert.
  • Felder:
    • Code: Speichert den Fehlercode
    • sqlState: Speichert den SQL-Status
    • Nachricht: Speichert die Fehlermeldung
  • Konstruktor: Nimmt eine PGconn* (PostgreSQL-Verbindung) und ein optionales PGresult* (Ergebnis einer Abfrage) an. PQresultVerboseErrorMessage und PQerrorMessage zum Extrahieren detaillierter Fehlerinformationen.
  • DuplicateKeyException: Eine einfache Ausnahmeklasse zur Behandlung doppelter Schlüsselfehler. Es nimmt nur einen Nachrichtenparameter entgegen und übergibt ihn an die Basis-Exception-Klasse.

Ich werde weitere Ausnahmen und andere Situationen hinzufügen, während ich an diesem Projekt arbeite

Erstellen Sie nun eine Datei „implementation/core/core.d“ zum Schreiben des Verbindungscodes.

module postgres.implementation.exception;

public:
import std.conv;

private import postgres.implementation.implementationc;

class PGSqlException : Exception
{
    string code;
    string sqlState;
    string message;
    this(PGconn* conn, PGresult* res = null)
    {
        if (res != null)
        {
            char* c = PQresultVerboseErrorMessage(res, PGVerbosity.PQERRORS_VERBOSE, PGContextVisibility
                    .PQSHOW_CONTEXT_ALWAYS);
            char* s = PQresultVerboseErrorMessage(res, PGVerbosity.PQERRORS_SQLSTATE, PGContextVisibility
                    .PQSHOW_CONTEXT_ALWAYS);
           string ss = to!string(c);
           import std.string:split;
           this.code = to!string(ss.split(':')[1]);

            this.sqlState = to!string(s);
        }
        const char* m = PQerrorMessage(conn);

        this.message = to!string(m);
        super(this.message);
    }
}

class DuplicateKeyException : Exception
{
    this(string message)
    {
        super(message);
    }
}

Wichtige Punkte des obigen Codes:

  • Postgres-Klasse: Stellt eine PostgreSQL-Datenbankverbindung dar.
    • Verwaltet die Verbindungserstellung, Abfrage und Ausführung vorbereiteter Anweisungen.
    • Verwendet die zuvor definierten C-Bindungen für die Interaktion mit der PostgreSQL-Bibliothek.
  • QueryResult-Klasse: Kapselt das Ergebnis einer Datenbankabfrage.
    • Speichert Abfrageergebnisse in einem strukturierten Format.
    • Verarbeitet verschiedene Datentypen und Formate, die von PostgreSQL zurückgegeben werden.
  • Fehlerbehandlung: Implementiert eine benutzerdefinierte Ausnahmebehandlung für PostgreSQL-Fehler.
  • Verbindungsverwaltung: Beinhaltet automatische Wiederverbindungsversuche bei Verbindungsverlust.
  • Vorbereitete Anweisungen: Unterstützt die Ausführung vorbereiteter SQL-Anweisungen mit Parameterbindung.
  • Speicherverwaltung: Gibt Ressourcen mithilfe von Destruktoren ordnungsgemäß frei (~this()).
  • UTF-8-Unterstützung:Setzt die Verbindungskodierung standardmäßig auf UTF-8.

Diese Implementierung bietet eine High-Level-Schnittstelle für D-Anwendungen zur Interaktion mit PostgreSQL-Datenbanken und abstrahiert viele der Low-Level-Details der C-API.

Möglicherweise erhalten Sie jetzt eine IDE-Warnung/Fehlermeldung „Verbindungsmodul nicht gefunden

Lassen Sie uns ein Verbindungsmodul erstellen:

Erstellen Sie die Datei _internal/connection.d und fügen Sie diesen Code hinzu:

dub init <project_name>

Konstanten und andere Optionen für SQL hinzufügen:

_internal/consts.d

"libs": [ "pq" ],
    "lflags-windows-x86_64": [ "-LIBPATH:C:/Program Files/PostgreSQL/16/lib/" ],
    "copyFiles-windows-x86_64": [
        "C:/Program Files/PostgreSQL/16/lib/libpq.dll",
        "C:/Program Files/PostgreSQL/16/bin/libintl-9.dll",
        "C:/Program Files/PostgreSQL/16/bin/libssl-3-x64.dll",
        "C:/Program Files/PostgreSQL/16/bin/libcrypto-3-x64.dll",
        "C:/Program Files/PostgreSQL/16/bin/libwinpthread-1.dll",
        "C:/Program Files/PostgreSQL/16/bin/libiconv-2.dll"
    ],

Modellvorlage erstellen

D unterstützt Template-Metaprogrammierung, eine Funktion, die es Ihnen ermöglicht, sehr generischen Code zu schreiben. Das bedeutet, dass D über Vorlagen verfügt, die denen in C ähneln, jedoch leistungsfähiger und flexibler sind.
Das ABC der Vorlagen in D | Der D-Blog

Hauptmerkmale der D-Vorlagen:

  1. Typprüfung zur Kompilierungszeit: Vorlagen werden zur Kompilierzeit überprüft, um die Typsicherheit zu gewährleisten.
  2. Codegenerierung: Sie können Vorlagen verwenden, um speziellen Code für verschiedene Typen oder Werte zu generieren.
  3. Variadische Vorlagen: D unterstützt Vorlagen, die eine beliebige Anzahl von Argumenten annehmen können, einschließlich Typen und Werten.
  4. Statische Ifs und Mixins: Damit können Sie Code während der Kompilierung basierend auf Bedingungen generieren und bearbeiten oder sogar stringbasierten Code (mit Mixin) einfügen.

Jetzt erstellen wir eine Vorlagenklasse.

model.d

Verwenden Sie jetzt den Code von https://github.com/rodevasia/sequelized/blob/main/source/postgres/model.d und fügen Sie ihn in Ihre Datei ein

Sehen wir uns den Code über den bereitgestellten GitHub-Link an:

"copyFiles-windows": [
        "libs/*.dll"
    ],
    "lflags-windows": [
        "/LIBPATH:$PACKAGE_DIR/libs"
    ],
    "libs": [
        "pq"
    ]

Dieser Code definiert ein Vorlagenklassenmodell in D. Hier ist eine Aufschlüsselung seiner Schlüsselkomponenten:

  1. Moduldeklaration: Der Code ist Teil des postgres.model-Moduls.
  2. Importe: Verschiedene Standard-D-Bibliotheken und benutzerdefinierte Module werden zur Verwendung in der Klasse importiert.
  3. Template-Klasse: Die Model-Klasse ist als Vorlage mit dem Typparameter T definiert. Dadurch kann die Klasse mit verschiedenen Typen arbeiten.
  4. Klassenmethoden: Die Klasse enthält mehrere Methoden für Datenbankoperationen wie save(), update(), delete() und find().
  5. Reflexion zur Kompilierungszeit: Der Code verwendet die Kompilierzeitfunktionen von D, um die Felder des Typs T zu überprüfen und entsprechende SQL-Abfragen zu generieren.
  6. SQL-Abfragegenerierung: Methoden wie getInsertQuery() und getUpdateQuery() erstellen dynamisch SQL-Abfragen basierend auf der Struktur vom Typ T.
  7. Datenbankinteraktion: Die Klasse verwendet ein Connection-Objekt, um mit einer PostgreSQL-Datenbank zu interagieren.

Wir haben den gesamten Code für die Arbeit geschrieben. Machen wir daraus eine Bibliothek. füge dies zu deiner dub.json hinzu

dub init <project_name>

Nutzung der Bibliothek:

Lassen Sie uns ein neues Projekt erstellen:

"libs": [ "pq" ],
    "lflags-windows-x86_64": [ "-LIBPATH:C:/Program Files/PostgreSQL/16/lib/" ],
    "copyFiles-windows-x86_64": [
        "C:/Program Files/PostgreSQL/16/lib/libpq.dll",
        "C:/Program Files/PostgreSQL/16/bin/libintl-9.dll",
        "C:/Program Files/PostgreSQL/16/bin/libssl-3-x64.dll",
        "C:/Program Files/PostgreSQL/16/bin/libcrypto-3-x64.dll",
        "C:/Program Files/PostgreSQL/16/bin/libwinpthread-1.dll",
        "C:/Program Files/PostgreSQL/16/bin/libiconv-2.dll"
    ],

Fügen Sie die Bibliothek als Abhängigkeit in dub.json hinzu

"copyFiles-windows": [
        "libs/*.dll"
    ],
    "lflags-windows": [
        "/LIBPATH:$PACKAGE_DIR/libs"
    ],
    "libs": [
        "pq"
    ]

app.d

sudo apt-get install libpq-dev

Lassen Sie uns den Code aufschlüsseln und seine Hauptkomponenten erklären:

Importe

Der Code importiert notwendige Module aus der Standardbibliothek und der Sequalized-Bibliothek:

  • std.stdio: Für grundlegende Ein-/Ausgabeoperationen
  • postgres._internal.connection: Verarbeitet Datenbankverbindungsdetails
  • postgres.implementation.core: Kernfunktionalität für PostgreSQL-Operationen
  • postgres.model: Stellt das Modell-Mixin zum Definieren von Datenbankmodellen bereit
  • postgres._internal.consts: Enthält konstante Werte, die in der Bibliothek verwendet werden

Hauptfunktion

Die Hauptfunktion demonstriert die Verwendung der Sequalized-Bibliothek:

  • Es erstellt ein DatabaseConnectionOption-Objekt mit Verbindungsdetails
  • Initialisiert ein Postgres-Objekt mit diesen Optionen
  • Erstellt eine Instanz der Beispielklasse
  • Ruft sync() auf, um die entsprechende Tabelle in der Datenbank zu erstellen
  • Legt einen Wert für das Textfeld fest und fügt einen Datensatz in die Datenbank ein

Beispielklasse

Diese Klasse definiert ein Modell für die Datenbanktabelle:

  • Es verwendet das Modell-Mixin, um die ORM-Funktionalität zu erben
  • Definiert zwei Felder: id und textField
  • Verwendet Attribute wie @Type, @PmKey und @unique, um Feldeigenschaften anzugeben

Ich habe nicht den gesamten Prozess aufgeführt, das müssen Sie selbst herausfinden :)

Wenn Sie gerne zu meinem Projekt beitragen möchten, finden Sie hier den Link zum Repo:
https://github.com/rodevasia/sequelized

Das obige ist der detaillierte Inhalt vonAufbau einer PostgreSQL-Bibliothek in D. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn