I was always curious about new programming languages and its frameworks. All of these time my experience and curiosity spread over only in front-end development ( I’ve done some backend though ?). I challenged myself to expand my skills and I found D programming language. D is in simple words is the advanced version of C and CPP.
What is D? the website say “**D is a general-purpose programming language with static typing, systems-level access, and C-like syntax. With the D Programming Language, write fast, read fast, and run fast.”
I have used PostgreSQL as my database for my works, and that’s why I chose it for this library as well. PostgreSQL is one of the major open source SQL database system that companies using now and its features are expanding even more.
When messing with D language I couldn’t find one package that satisfies my, either the packages are stopped maintenance or can be used as for direct query. From a JavaScript background I used Sequalize ORM. That light me an idea, How about similar one in D.
So, I did some research and I found Postgres provides library for C. Then I thought, how about use the C bindings in D and use it for developing the ORM. I found the source code from https://github.com/adamdruppe/arsd/blob/master/postgres.d for binding the C library to D.
Requirements:
To create a new project, use the following command in your terminal:
dub init <project_name>
This command will create a new project directory with the specified name and set up the basic structure for a D project.
With these steps completed, you'll have a basic D project structure set up and ready for development.
In Windows the below section needs to be added on the dub.json.
dub init <project_name>
or
The way I did is copied all the necessary DLL files to lib ( manually created) folder and then added the below code:
"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" ],
In Linux or macOS, you need to ensure that the PostgreSQL development libraries are installed and properly linked. You can typically do this by installing the appropriate packages through your system's package manager. For example, on Ubuntu or Debian-based systems, you might use:
"copyFiles-windows": [ "libs/*.dll" ], "lflags-windows": [ "/LIBPATH:$PACKAGE_DIR/libs" ], "libs": [ "pq" ]
Once you have the necessary libraries installed and properly linked, you can proceed with setting up your D project to work with PostgreSQL.
Here is the C bindings for D.
sudo apt-get install libpq-dev
Now we can easily use these functions in D.
This is the code for some basic exception handling:
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); }
I will be adding more exceptions and other situations as I work on this project
Now create create a implementation/core/core.d file for writing the connection code.
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); } }
Key points of the above code:
This implementation provides a high-level interface for D applications to interact with PostgreSQL databases, abstracting away many of the low-level details of the C API.
You might have an IDE warning/error now that “connection module not found”
Let’s create connection module:
Create _internal/connection.d file add this code:
dub init <project_name>
Add constants and other options for 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 supports template metaprogramming, a feature that allows you to write highly generic code. This means that D has templates similar to those in C but more powerful and flexible.
The ABC’s of Templates in D | The D Blog
Now lets create a template class.
model.d
Now use the code from https://github.com/rodevasia/sequelized/blob/main/source/postgres/model.d paste to your file
Let's examine the code from the provided GitHub link:
"copyFiles-windows": [ "libs/*.dll" ], "lflags-windows": [ "/LIBPATH:$PACKAGE_DIR/libs" ], "libs": [ "pq" ]
This code defines a template class Model in D. Here's a breakdown of its key components:
We written all the code for working. Let’s make this a library. add this on your dub.json
dub init <project_name>
Let create a new project:
"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" ],
add the the library as dependency in dub.json
"copyFiles-windows": [ "libs/*.dll" ], "lflags-windows": [ "/LIBPATH:$PACKAGE_DIR/libs" ], "libs": [ "pq" ]
app.d
sudo apt-get install libpq-dev
Let's break down the code and explain its main components:
The code imports necessary modules from the standard library and the Sequalized library:
The main function demonstrates how to use the Sequalized library:
This class defines a model for the database table:
I haven't included full process, and that is for you to find out :)
If you'd love to contribute to my project here is the link for the repo:
https://github.com/rodevasia/sequelized
The above is the detailed content of Building a PostgreSQL Library in D. For more information, please follow other related articles on the PHP Chinese website!