Maison  >  Article  >  développement back-end  >  Construire une bibliothèque PostgreSQL en D

Construire une bibliothèque PostgreSQL en D

Patricia Arquette
Patricia Arquetteoriginal
2024-10-24 06:16:30866parcourir

Building a PostgreSQL Library in D

J'ai toujours été curieux de connaître les nouveaux langages de programmation et leurs frameworks. Pendant tout ce temps, mon expérience et ma curiosité se sont concentrées uniquement sur le développement front-end (mais j'ai fait du backend ?). Je me suis mis au défi d'élargir mes compétences et j'ai découvert le langage de programmation D. D est en termes simples la version avancée de C et CPP.

Qu'est-ce que D ? le site Web indique « **D est un langage de programmation à usage général avec un typage statique, un accès au niveau système et une syntaxe de type C. Avec le Langage de programmation D, écrivez vite, lisez vite et exécutez vite.

J'ai utilisé PostgreSQL comme base de données pour mes travaux, et c'est pourquoi je l'ai également choisi pour cette bibliothèque. PostgreSQL est l'un des principaux systèmes de base de données SQL open source que les entreprises utilisent actuellement et ses fonctionnalités se développent encore plus.

Pourquoi créer une bibliothèque ORM personnalisée ?

En jouant avec le langage D, je n'ai pas trouvé un seul paquet qui me satisfasse, soit les paquets sont arrêtés en maintenance, soit ils peuvent être utilisés comme pour une requête directe. À partir d'un arrière-plan JavaScript, j'ai utilisé Sequalize ORM. Cela m'éclaire sur une idée, que diriez-vous d'une idée similaire en D.

Alors, j'ai fait quelques recherches et j'ai découvert que Postgres fournissait une bibliothèque pour C. Ensuite, j'ai pensé, que diriez-vous d'utiliser les liaisons C en D et de les utiliser pour développer l'ORM. J'ai trouvé le code source sur https://github.com/adamdruppe/arsd/blob/master/postgres.d pour lier la bibliothèque C à D.

Commencer

Exigences :

  • PostgreSQL doit être installé sur votre système. ( J'ai développé pour PostgreSQL 16)
  • IDE (Zed/VSCode/Vim)
  • Compilateur de langage DMD - d

Pour créer un nouveau projet, utilisez la commande suivante dans votre terminal :

  1. Ouvrez votre terminal ou votre invite de commande.
  2. Naviguez jusqu'au répertoire dans lequel vous souhaitez créer votre projet.
  3. Exécutez la commande :
dub init <project_name>

Cette commande créera un nouveau répertoire de projet avec le nom spécifié et mettra en place la structure de base d'un projet D.

  1. Vous serez invité à saisir les informations suivantes :
    • Format - .sdl ou .json (j'ai sélectionné json)
    • Description du projet (facultatif)
    • Nom de l'auteur
    • Licence (par exemple, MIT, BSD, etc.)
    • Chaîne de copyright
    • Ajouter une dépendance (facultatif)
  2. Après avoir fourni les informations, dub créera un nouveau répertoire avec le nom de votre projet et générera les fichiers suivants :
    • dub.json : Fichier de configuration de votre projet
    • source/app.d : Fichier source principal
    • .gitignore : Git ignore le fichier
  3. Naviguez dans le nouveau répertoire de votre projet : cd
  4. Vous pouvez maintenant commencer à développer votre projet D !

Une fois ces étapes terminées, vous disposerez d'une structure de projet D de base configurée et prête à être développée.

Sous Windows, la section ci-dessous doit être ajoutée sur dub.json.

dub init <project_name>

ou

La façon dont je l'ai fait est de copier tous les fichiers DLL nécessaires dans le dossier lib (créé manuellement), puis d'ajouter le code ci-dessous :

"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"
    ],

Sous Linux ou macOS, vous devez vous assurer que les bibliothèques de développement PostgreSQL sont installées et correctement liées. Vous pouvez généralement le faire en installant les packages appropriés via le gestionnaire de packages de votre système. Par exemple, sur les systèmes basés sur Ubuntu ou Debian, vous pouvez utiliser :

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

Une fois que vous avez installé et correctement lié les bibliothèques nécessaires, vous pouvez procéder à la configuration de votre projet D pour qu'il fonctionne avec PostgreSQL.

Implémentation des liaisons C :

Voici les liaisons C pour D.

sudo apt-get install libpq-dev

Maintenant, nous pouvons facilement utiliser ces fonctions dans D.
Voici le code pour une gestion de base des exceptions :

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 : Une classe d'exception personnalisée qui hérite de la classe D Exception standard. Il est conçu pour gérer les erreurs spécifiques à PostgreSQL.
  • Champs :
    • code : stocke le code d'erreur
    • sqlState : stocke l'état SQL
    • message : stocke le message d'erreur
  • Constructeur : Prend un PGconn* (connexion PostgreSQL) et un PGresult* optionnel (résultat d'une requête). PQresultVerboseErrorMessage et PQerrorMessage pour extraire des informations détaillées sur l'erreur.
  • DuplicateKeyException : Une classe d'exception simple pour gérer les erreurs de clé en double. Il prend uniquement un paramètre de message et le transmet à la classe Exception de base.

J'ajouterai d'autres exceptions et autres situations au fur et à mesure que je travaillerai sur ce projet

Créez maintenant un fichier Implementation/core/core.d pour écrire le code de connexion.

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);
    }
}

Points clés du code ci-dessus :

  • Classe Postgres : Représente une connexion à la base de données PostgreSQL.
    • Gère la création de connexions, les requêtes et l'exécution des instructions préparées.
    • Utilise les liaisons C définies précédemment pour interagir avec la bibliothèque PostgreSQL.
  • Classe QueryResult : Encapsule le résultat d'une requête de base de données.
    • Stocke les résultats des requêtes dans un format structuré.
    • Gère différents types et formats de données renvoyés par PostgreSQL.
  • Gestion des erreurs : Implémente une gestion personnalisée des exceptions pour les erreurs PostgreSQL.
  • Gestion des connexions : Inclut les tentatives de reconnexion automatiques en cas de perte de connexion.
  • Instructions préparées : Prend en charge l'exécution d'instructions SQL préparées avec liaison de paramètres.
  • Gestion de la mémoire : Libère correctement les ressources à l'aide de destructeurs (~this()).
  • Prise en charge UTF-8 : Définit le codage de connexion sur UTF-8 par défaut.

Cette implémentation fournit une interface de haut niveau permettant aux applications D d'interagir avec les bases de données PostgreSQL, en éliminant de nombreux détails de bas niveau de l'API C.

Vous pourriez avoir un avertissement/erreur IDE maintenant que « module de connexion introuvable »

Créons un module de connexion :

Créez le fichier _internal/connection.d ajoutez ce code :

dub init <project_name>

Ajouter des constantes et d'autres options pour SQL :

_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"
    ],

Création d'un modèle de modèle

D prend en charge la métaprogrammation de modèles, une fonctionnalité qui vous permet d'écrire du code hautement générique. Cela signifie que D a des modèles similaires à ceux de C mais plus puissants et flexibles.
L’ABC des modèles en D | Le blog D

Principales caractéristiques des modèles D :

  1. Vérification du type au moment de la compilation : Les modèles sont vérifiés au moment de la compilation, garantissant ainsi la sécurité du type.
  2. Génération de code : Vous pouvez utiliser des modèles pour générer du code spécialisé pour différents types ou valeurs.
  3. Modèles variadiques : D prend en charge les modèles qui peuvent prendre un nombre arbitraire d'arguments, y compris des types et des valeurs.
  4. Ifs et mixins statiques : Ceux-ci vous permettent de générer et de manipuler du code lors de la compilation en fonction de conditions ou même d'injecter du code basé sur des chaînes (avec mixin).

Créons maintenant une classe modèle.

modèle.d

Utilisez maintenant le code de https://github.com/rodevasia/sequelized/blob/main/source/postgres/model.d et collez-le dans votre fichier

Examinons le code du lien GitHub fourni :

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

Ce code définit une classe de modèle Model en D. Voici une répartition de ses composants clés :

  1. Déclaration du module : Le code fait partie du module postgres.model.
  2. Importations : Diverses bibliothèques D standard et modules personnalisés sont importés pour être utilisés dans la classe.
  3. Classe Template : La classe Model est définie comme un modèle avec le paramètre de type T. Cela permet à la classe de travailler avec différents types.
  4. Méthodes de classe : La classe comprend plusieurs méthodes pour les opérations de base de données telles que save(), update(), delete() et find().
  5. Réflexion au moment de la compilation : Le code utilise les fonctionnalités de compilation de D pour inspecter les champs de type T et générer des requêtes SQL appropriées.
  6. Génération de requêtes SQL : Des méthodes telles que getInsertQuery() et getUpdateQuery() créent dynamiquement des requêtes SQL basées sur la structure de type T.
  7. Interaction avec la base de données : La classe utilise un objet Connection pour interagir avec une base de données PostgreSQL.

Nous avons écrit tout le code pour travailler. Faisons-en une bibliothèque. ajoutez ceci sur votre dub.json

dub init <project_name>

Utilisation de la bibliothèque :

Créons un nouveau projet :

"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"
    ],

ajouter la bibliothèque comme dépendance dans dub.json

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

app.d

sudo apt-get install libpq-dev

Décomposons le code et expliquons ses principaux composants :

Importations

Le code importe les modules nécessaires de la bibliothèque standard et de la bibliothèque séqualisée :

  • std.stdio : pour les opérations d'entrée/sortie de base
  • postgres._internal.connection : gère les détails de connexion à la base de données
  • postgres.implementation.core : fonctionnalité de base pour les opérations PostgreSQL
  • postgres.model : fournit le mixin Model pour définir des modèles de base de données
  • postgres._internal.consts : contient les valeurs constantes utilisées dans la bibliothèque

Fonction principale

La fonction principale montre comment utiliser la bibliothèque Sequalized :

  • Il crée un objet DatabaseConnectionOption avec les détails de connexion
  • Initialise un objet Postgres avec ces options
  • Crée une instance de la classe Exemple
  • Appelle sync() pour créer la table correspondante dans la base de données
  • Définit une valeur pour textField et insère un enregistrement dans la base de données

Exemple de classe

Cette classe définit un modèle pour la table de la base de données :

  • Il utilise le mixin Model pour hériter des fonctionnalités ORM
  • Définit deux champs : id et textField
  • Utilise des attributs tels que @Type, @PmKey et @unique pour spécifier les propriétés du champ

Je n'ai pas inclus le processus complet, et c'est à vous de le découvrir :)

Si vous aimeriez contribuer à mon projet voici le lien pour le repo :
https://github.com/rodevasia/sequelized

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn