首页 > 后端开发 > C++ > 正文

用 D 构建 PostgreSQL 库

Patricia Arquette
发布: 2024-10-24 06:16:30
原创
933 人浏览过

Building a PostgreSQL Library in D

我总是对新的编程语言及其框架感到好奇。一直以来,我的经验和好奇心都只集中在前端开发上(不过我也做过一些后端开发?)。我挑战自己以扩展我的技能,并找到了 D 编程语言。 D简单来说就是C和CPP的高级版本。

D是什么?该网站称“**D 是一种通用编程语言,具有静态类型、系统级访问和类似 C 的语法。使用D 编程语言,快速写入、快速读取和快速运行。

我使用 PostgreSQL 作为我作品的数据库,这也是我为这个库选择它的原因。 PostgreSQL 是公司现在使用的主要开源 SQL 数据库系统之一,其功能正在不断扩展。

为什么要构建自定义 ORM 库?

在搞D语言的时候找不到一个能满足我需求的包,要么是停止维护了,要么是可以直接查询。我有 JavaScript 背景,使用 Sequalize ORM。这让我想到了一个主意,D 中类似的怎么样。

所以,我做了一些研究,发现 Postgres 为 C 提供了库。然后我想,如何在 D 中使用 C 绑定并使用它来开发 ORM。 我从 https://github.com/adamdruppe/arsd/blob/master/postgres.d 找到了用于将 C 库绑定到 D 的源代码。

入门

要求:

  • 您的系统中必须安装 PostgreSQL。 ( 我为 PostgreSQL 16 开发)
  • IDE(Zed/ VSCode/Vim)
  • DMD - d 语言编译器

要创建新项目,请在终端中使用以下命令:

  1. 打开终端或命令提示符。
  2. 导航到您要创建项目的目录。
  3. 运行命令:
dub init <project_name>
登录后复制
登录后复制
登录后复制
登录后复制

此命令将创建一个具有指定名称的新项目目录,并设置 D 项目的基本结构。

  1. 系统将提示您输入以下信息:
    • 格式 - .sdl 或 .json(我选择了 json )
    • 项目描述(可选)
    • 作者姓名
    • 许可证(例如 MIT、BSD 等)
    • 版权字符串
    • 添加依赖项(可选)
  2. 提供信息后,dub 将以您的项目名称创建一个新目录并生成以下文件:
    • dub.json:项目的配置文件
    • source/app.d:主要源文件
    • .gitignore:Git 忽略文件
  3. 导航到新项目目录:cd ;
  4. 您现在可以开始开发您的 D 项目了!

完成这些步骤后,您将建立一个基本的 D 项目结构并准备好进行开发。

在 Windows 中,需要将以下部分添加到 dub.json。

dub init <project_name>
登录后复制
登录后复制
登录后复制
登录后复制

我的方法是将所有必需的 DLL 文件复制到 lib(手动创建)文件夹,然后添加以下代码:

"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"
    ],
登录后复制
登录后复制
登录后复制

在 Linux 或 macOS 中,您需要确保 PostgreSQL 开发库已安装并正确链接。通常,您可以通过系统的包管理器安装适当的包来完成此操作。例如,在基于 Ubuntu 或 Debian 的系统上,您可以使用:

"copyFiles-windows": [
        "libs/*.dll"
    ],
    "lflags-windows": [
        "/LIBPATH:$PACKAGE_DIR/libs"
    ],
    "libs": [
        "pq"
    ]
登录后复制
登录后复制
登录后复制

安装并正确链接必要的库后,您可以继续设置 D 项目以使用 PostgreSQL。

实现 C 绑定:

这是 D 的 C 绑定。

sudo apt-get install libpq-dev
登录后复制
登录后复制

现在我们可以在D中轻松使用这些函数了。
这是一些基本异常处理的代码:

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: 继承自标准 D Exception 类的自定义异常类。它旨在处理 PostgreSQL 特定的错误。
  • 字段:
    • code:存储错误代码
    • sqlState:存储 SQL 状态
    • message:存储错误消息
  • 构造函数: 采用 PGconn* (PostgreSQL 连接)和可选的 PGresult* (查询结果)。 PQresultVerboseErrorMessage 和 PQerrorMessage 用于提取详细的错误信息。
  • DuplicateKeyException: 一个用于处理重复键错误的简单异常类。它只接受一个消息参数并将其传递给 Exception 基类。

当我从事这个项目时,我将添加更多例外和其他情况

现在创建一个implementation/core/core.d 文件用于编写连接代码。

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);
    }
}
登录后复制

上述代码要点:

  • Postgres 类: 表示 PostgreSQL 数据库连接。
    • 管理连接创建、查询和准备语句执行。
    • 使用之前定义的 C 绑定与 PostgreSQL 库交互。
  • QueryResult 类: 封装数据库查询的结果。
    • 以结构化格式存储查询结果。
    • 处理 PostgreSQL 返回的不同数据类型和格式。
  • 错误处理: 实现 PostgreSQL 错误的自定义异常处理。
  • 连接管理:包括连接丢失时的自动重新连接尝试。
  • 准备好的语句:支持执行带有参数绑定的准备好的SQL语句。
  • 内存管理:使用析构函数(~this())正确释放资源。
  • UTF-8 支持: 默认将连接编码设置为 UTF-8。

此实现为 D 应用程序提供了与 PostgreSQL 数据库交互的高级接口,抽象了 C API 的许多低级细节。

现在您可能会收到 IDE 警告/错误“未找到连接模块

让我们创建连接模块:

创建 _internal/connection.d 文件添加以下代码:

dub init <project_name>
登录后复制
登录后复制
登录后复制
登录后复制

为 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"
    ],
登录后复制
登录后复制
登录后复制

创建模型模板

D 支持模板元编程,该功能允许您编写高度通用的代码。这意味着 D 的模板与 C 中的相似,但更强大、更灵活。
D 中模板的 ABC | D 博客

D 模板的主要特点:

  1. 编译时类型检查:模板在编译时进行检查,确保类型安全。
  2. 代码生成:您可以使用模板为不同类型或值生成专门的代码。
  3. 可变参数模板: D 支持可以采用任意数量参数的模板,包括类型和值。
  4. 静态 if 和 mixin: 这些允许您在编译期间根据条件生成和操作代码,甚至注入基于字符串的代码(使用 mixin)。

现在让我们创建一个模板类。

模型.d

现在使用 https://github.com/rodevasia/sequelized/blob/main/source/postgres/model.d 中的代码粘贴到您的文件

让我们检查一下所提供的 GitHub 链接中的代码:

"copyFiles-windows": [
        "libs/*.dll"
    ],
    "lflags-windows": [
        "/LIBPATH:$PACKAGE_DIR/libs"
    ],
    "libs": [
        "pq"
    ]
登录后复制
登录后复制
登录后复制

此代码在 D 中定义了一个模板类 Model。以下是其关键组件的细分:

  1. 模块声明:代码是postgres.model模块的一部分。
  2. 导入:导入各种标准 D 库和自定义模块以在类中使用。
  3. 模板类: Model 类被定义为带有类型参数 T 的模板。这允许该类使用不同的类型。
  4. 类方法: 该类包含几个用于数据库操作的方法,例如 save()、update()、delete() 和 find()。
  5. 编译时反射:代码使用 D 的编译时功能来检查 T 类型的字段并生成适当的 SQL 查询。
  6. SQL 查询生成: getInsertQuery() 和 getUpdateQuery() 等方法根据类型 T 的结构动态创建 SQL 查询。
  7. 数据库交互: 该类使用 Connection 对象与 PostgreSQL 数据库交互。

我们编写了所有工作代码。让我们把它变成一个图书馆。将其添加到您的 dub.json

dub init <project_name>
登录后复制
登录后复制
登录后复制
登录后复制

使用图书馆:

让我们创建一个新项目:

"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"
    ],
登录后复制
登录后复制
登录后复制

将库添加为 dub.json 中的依赖项

"copyFiles-windows": [
        "libs/*.dll"
    ],
    "lflags-windows": [
        "/LIBPATH:$PACKAGE_DIR/libs"
    ],
    "libs": [
        "pq"
    ]
登录后复制
登录后复制
登录后复制

app.d

sudo apt-get install libpq-dev
登录后复制
登录后复制

让我们分解代码并解释其主要组件:

进口

代码从标准库和Sequalized库导入必要的模块:

  • std.stdio:用于基本输入/输出操作
  • postgres._internal.connection:处理数据库连接详细信息
  • postgres.implementation.core:PostgreSQL 操作的核心功能
  • postgres.model:提供用于定义数据库模型的模型混合
  • postgres._internal.consts:包含库中使用的常量值

主要功能

main函数演示了如何使用Sequalized库:

  • 它创建一个包含连接详细信息的 DatabaseConnectionOption 对象
  • 使用这些选项初始化 Postgres 对象
  • 创建Example类的实例
  • 调用sync()在数据库中创建对应的表
  • 设置文本字段的值并将记录插入数据库

示例类

此类定义数据库表的模型:

  • 它使用 Model mixin 来继承 ORM 功能
  • 定义两个字段:id 和 textField
  • 使用 @Type、@PmKey 和 @unique 等属性来指定字段属性

我没有包含完整的过程,供你了解:)

如果您愿意为我的项目做出贡献,这里是存储库的链接:
https://github.com/rodevasia/sequelized

以上是用 D 构建 PostgreSQL 库的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板