pg-promise (Part 1)
Vitaly Tomilov's pg-promise is a fantastic example of a well ran, well written open source project. This is part 1 of this set where we go through Tomilov's code and learn about how pg-promise is put together and architected.
Vitaly Tomilov's pg-promise[1] is a fantastic example of a well ran, well written open source project. Vitaly is extremely responsive to issues and his documentation is top notch.
I hesitate in using it as a write up for tOSU as I want to gain some experience and sort out a strategy for doing these. But, yet pg-promise is such great open source, it's hard to leave it on the back burner.
What is it?
pg-promise is a Postgres library for Node written on top of the brianc/node-postgres library. It's technically a wrapper for node-postgres and converts the callback interface into a promises based interface.
Following is a very simple example (taken from the projects' "Learn By Example" page -- a very effective way to learn the library.)
db.any("select * from users where active=$1", [true])
.then(data => {
// success;
})
.catch(error => {
// error;
});
Index of Dependencies
I find it helpful to be familiar with the dependencies a given program uses when learning the codebase.
Following is a summary of the dependencies that pg-promise uses.
- pg: Node/Postgres library.
- spex[2]: A Specialized Promise extension
- pg-minify[2:1]: Postgres SQL minifier.
- manakin[2:2]: Provides colorized output on
console.log
,console.error
, etc
Noteworthy Components
Compared to my last write up on Bouncy, this has a significantly larger codebase.
It is not practical to go through every module; so instead, I'll go through noteworthy components and describe those.
database.js
Contains the code that manages the database connection. This is considered a singleton as only one instance -- one DB connection -- should exist.
This effectively exposes the API. From here, the user can perform the desired database actions.
Details of this module will be in the forthcoming "part 2".
result.js
An implementation of a bit mask. The concept leverages binary representation of an integer. In a nutshell and for pg-promise's purpose, it's a means to describe a set of options where some options can have combinations.
The concept works because of binary flags and how you combine them. The pg-promise documentation notes that
Any combination of flags is supported, except for
one + many
.
one
is defined as 1 (0001
) and many
is defined as 2 (0010
). Think of these as flags, flags in a column. Therefore, one + many
is 0011
. Not the greatest example since this isn't valid but the idea is the same.
You can then use the bitwise operations to manipulate or combine the values.
array.js
This module is interesting because it contains custom "faster" implementations of some common array operations. The following implementations were in the version I reviewed:
map
forEach
filter
It's interesting that the author elects to replace the stock Node JS implementations which work perfectly well. But, pg-promise is designed to be fast and I figure implementing faster versions of these basic array methods will improve overall performance.
Code Patterns I Love
Following are code patterns of note that I find intriguing or discussion worthy.
$npm
This is a container for (most) required modules -- whether local or external (despite the name). An example from /lib/main.js
.
var $npm = {
con: require('manakin').local,
path: require('path'),
pg: require('pg'),
minify: require('pg-minify'),
array: require('./array'),
adapter: require('./adapter'),
result: require('./result'),
promise: require('./promise'),
formatting: require('./formatting'),
helpers: require('./helpers'),
queryFile: require('./queryFile'),
errors: require('./errors'),
utils: require('./utils'),
pubUtils: require('./utils/public'),
mode: require('./txMode'),
types: require('./types'),
package: require('../package.json')
};
The use of $npm
to hold required
'd libraries is something I've adopted for my own use. I find it makes organizing imported modules easier to keep track of -- especially given my use of WebStorm.
Documentation
An aspect that I really love about pg-promise is something that seems to be overlooked in private codebases (whereas Open Source, by necessity, tends to do really well at) and that is documentation. jsdoc
is used but it's not the software that is used but the the attention to detail that I want to highlight. If you contribute or create your own open source project, you'd do well to follow the example set forth in this project.
Documentation can't be overlooked. A new user isn't going to dig around your source code to figure out how to do something. Having quality documentation like this, i'm sure, improves adoption and answers a lot of basic questions that most developers won't answer for themselves.
Part 2
That is it for now. I expect to post part 2 next week which is the second week of Match 2017 (I'm giving myself a deadline). For now, please comment below on what you think and how an article series like this can be improved.
Update: Part 2 has been posted per schedule!