用 D 构建 PostgreSQL 库
我总是对新的编程语言及其框架感到好奇。一直以来,我的经验和好奇心都只集中在前端开发上(不过我也做过一些后端开发?)。我挑战自己以扩展我的技能,并找到了 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 语言编译器
要创建新项目,请在终端中使用以下命令:
- 打开终端或命令提示符。
- 导航到您要创建项目的目录。
- 运行命令:
dub init <project_name>
此命令将创建一个具有指定名称的新项目目录,并设置 D 项目的基本结构。
- 系统将提示您输入以下信息:
- 格式 - .sdl 或 .json(我选择了 json )
- 项目描述(可选)
- 作者姓名
- 许可证(例如 MIT、BSD 等)
- 版权字符串
- 添加依赖项(可选)
- 提供信息后,dub 将以您的项目名称创建一个新目录并生成以下文件:
- dub.json:项目的配置文件
- source/app.d:主要源文件
- .gitignore:Git 忽略文件
- 导航到新项目目录:cd
; - 您现在可以开始开发您的 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 模板的主要特点:
- 编译时类型检查:模板在编译时进行检查,确保类型安全。
- 代码生成:您可以使用模板为不同类型或值生成专门的代码。
- 可变参数模板: D 支持可以采用任意数量参数的模板,包括类型和值。
- 静态 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。以下是其关键组件的细分:
- 模块声明:代码是postgres.model模块的一部分。
- 导入:导入各种标准 D 库和自定义模块以在类中使用。
- 模板类: Model 类被定义为带有类型参数 T 的模板。这允许该类使用不同的类型。
- 类方法: 该类包含几个用于数据库操作的方法,例如 save()、update()、delete() 和 find()。
- 编译时反射:代码使用 D 的编译时功能来检查 T 类型的字段并生成适当的 SQL 查询。
- SQL 查询生成: getInsertQuery() 和 getUpdateQuery() 等方法根据类型 T 的结构动态创建 SQL 查询。
- 数据库交互: 该类使用 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中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

C语言数据结构:树和图的数据表示与操作树是一个层次结构的数据结构由节点组成,每个节点包含一个数据元素和指向其子节点的指针二叉树是一种特殊类型的树,其中每个节点最多有两个子节点数据表示structTreeNode{intdata;structTreeNode*left;structTreeNode*right;};操作创建树遍历树(先序、中序、后序)搜索树插入节点删除节点图是一个集合的数据结构,其中的元素是顶点,它们通过边连接在一起边可以是带权或无权的数据表示邻

文件操作难题的真相:文件打开失败:权限不足、路径错误、文件被占用。数据写入失败:缓冲区已满、文件不可写、磁盘空间不足。其他常见问题:文件遍历缓慢、文本文件编码不正确、二进制文件读取错误。

C#和C 的历史与演变各有特色,未来前景也不同。1.C 由BjarneStroustrup在1983年发明,旨在将面向对象编程引入C语言,其演变历程包括多次标准化,如C 11引入auto关键字和lambda表达式,C 20引入概念和协程,未来将专注于性能和系统级编程。2.C#由微软在2000年发布,结合C 和Java的优点,其演变注重简洁性和生产力,如C#2.0引入泛型,C#5.0引入异步编程,未来将专注于开发者的生产力和云计算。

算法是解决问题的指令集,其执行速度和内存占用各不相同。编程中,许多算法都基于数据搜索和排序。本文将介绍几种数据检索和排序算法。线性搜索假设有一个数组[20,500,10,5,100,1,50],需要查找数字50。线性搜索算法会逐个检查数组中的每个元素,直到找到目标值或遍历完整个数组。算法流程图如下:线性搜索的伪代码如下:检查每个元素:如果找到目标值:返回true返回falseC语言实现:#include#includeintmain(void){i

C语言多线程编程指南:创建线程:使用pthread_create()函数,指定线程ID、属性和线程函数。线程同步:通过互斥锁、信号量和条件变量防止数据竞争。实战案例:使用多线程计算斐波那契数,将任务分配给多个线程并同步结果。疑难解答:解决程序崩溃、线程停止响应和性能瓶颈等问题。

如何在 C 语言中输出倒数?回答:使用循环语句。步骤:1. 定义变量 n 存储要输出的倒数数字;2. 使用 while 循环持续打印 n 直到 n 小于 1;3. 在循环体内,打印出 n 的值;4. 在循环末尾,将 n 减去 1 以输出下一个更小的倒数。

C语言函数包含定义、调用和声明。函数定义指定函数名、参数和返回类型,函数体实现功能;函数调用执行函数并提供参数;函数声明告知编译器函数类型。值传递用于参数传递,注意返回类型,保持一致的代码风格,并在函数中处理错误。掌握这些知识有助于编写优雅、健壮的C代码。

整数是编程中最基础的数据类型,堪称编程的基石。程序员的工作就是赋予这些数字意义,无论软件多么复杂,最终都归结于整数运算,因为处理器只理解整数。为了表示负数,我们引入了二进制补码;为了表示小数,我们创造了科学计数法,于是有了浮点数。但归根结底,一切仍然离不开0和1。整数的简史在C语言中,int几乎是默认类型。尽管编译器可能会发出警告,但在许多情况下,你仍然可以写下这样的代码:main(void){return0;}从技术角度来看,这与以下代码等效:intmain(void){return0;}这种
