1

This question is for pg-promise, its recommended usage pattern & based on following assumption,

It does-not make sense to create more than a single pgp instance, if they are connecting to same DB(also enforced by the good warning message of "Creating a duplicate database object for the same connection.")

Given: I have 2 individual packages which need DB connection, currently they take connection string in constructor from outside and create connection object inside them, which leads to the warning of duplicate connection object and is fair as they both talk to same DB and there is a possibility for optimisation here(since i am in control of those packages).

Then: To prevent this, i thought of implementing dependency injection, for which i pass a resolve function in libraries constructor which gives them the DB connection object.

Issue: There are some settings which are at top level like parsers and helpers and transaction modes which may be different for each of these packages what is the recommendation for such settings or is there a better patterns to address these issues. EG:

const pg = require('pg-promise');
const instance = pg({"schema": "public"});
instance.pg.types.setTypeParser(1114, str => str);//UTC Date which one library requires other doesnt
const constring = "";
const resolveFunctionPackage1 = ()=>instance(constring);
const resolveFunctionPackage2 = ()=>instance(constring);

To sum up: What is the best way to implement dependency injection for pg-promise?

Laukik
  • 424
  • 4
  • 13
  • [Have you seen this?](https://stackoverflow.com/questions/34382796/where-should-i-initialize-pg-promise). Any good package should be able to accept not only a connection string, but also an instantiated `db` object, so it can be shared, and then there won't be any problem. If a library cannot accept an existing `db` object, it is no good, avoid using it. – vitaly-t Oct 07 '20 at 06:57
  • I am with you for accepting instantiated db object thats exactly what i am trying to do, but the problem is what happens when they want to set conflicting typeparsers? – Laukik Oct 07 '20 at 07:31

1 Answers1

0

I have 2 individual packages which need DB connection, currently they take connection string in constructor from outside and create connection object inside them

That is a serious design flaw, and it's is never gonna work well. Any independent package that uses a database must be able to reuse an existing connection pool, which is the most valuable resource when it comes to connection usage. Head-on duplication of a connection pool inside an independent module will use up existing physical connections, and hinder performance of all other modules that need to use the same physical connection.

If a third-party library supports pg-promise, it should be able to accept instantiated db object for accessing the database.

And if the third-party library supports the base driver only, it should at least accept an instantiated Pool object. In pg-promise, db object exposes the underlying Pool object via db.$pool.

what happens when they want to set conflicting typeparsers?

There will be a conflict, because pg.types is a singleton from the underlying driver, so it can only be configured in one way. It is an unfortunate limitation.

The only way to avoid it, is for reusable modules to never re-configure the parsers. It should only be done within the actual client application.

UPDATE

Strictly speaking, one should avoid splitting a database-access layer of an application into multiple modules, there can be a number of problems to follow that.

But specifically for separation of type parsers, the library supports setting custom type parsers on the pool level. See example here. Note that the update is just for TypeScript, i.e. in JavaScript clients it has been working for awhile.

So you still can have your separate module create its own db object, but I would advise that you limit its connection pool size to the minimum then, like 1:

const moduleDb = pgp({
    // ...connection details...

    max: 1, // set pool size to just 1 connection

    types: /* your custom type parsers */
});
vitaly-t
  • 24,279
  • 15
  • 116
  • 138
  • I am with you for accepting instantiated db object thats exactly what i am trying to do, but the problem is what happens when they want to set conflicting typeparsers? or can be setup type parsers at individual query level.. – Laukik Oct 07 '20 at 07:40
  • @Laukik But just to be sure, [I have opened an issue for this](https://github.com/brianc/node-postgres/issues/2363). – vitaly-t Oct 07 '20 at 08:02
  • Thanks for the update , but client app may not be well versed with what 'package A' requires and 'package B', this may lay the onus on the client app to understand what packages do which seems like a smell, yes the issue will help – Laukik Oct 07 '20 at 08:12
  • Sorry if i am bugging you on this, assuming a package is using QueryFile and have created 2 instances of of the package it gives a warn message of creating same object twice, do you think Query File Objects should also be DI into the instances?? – Laukik Oct 07 '20 at 13:35
  • @Laukik Why would you want to access the same file independently? Sounds more and more of a module architecture issue. – vitaly-t Oct 07 '20 at 15:38
  • Its like this the package creates its own schema on init, now assume you have 2 instances of the same package both will try to do same operation which will cause this issue, just for clarity this is the package https://github.com/LRagji/pg-queue you can have 2 instances of the que with different name they will try to load the same file cause they are instances, or is there any better way to achieve this ? – Laukik Oct 07 '20 at 16:25
  • @Laukik A single module should implement the entire database layer in an application. And you are trying to split it into multiple inter-dependent modules, and thus finding all sorts of problems. This should give you an idea to rethink that approach ;) – vitaly-t Oct 07 '20 at 23:39
  • I understand what you are saying and it works for typical apps, i was thinking, how will it work for package owners, cause each pacakage may have its own functionality like PG based que in this case how would they manage to provide such a functionality in a package, one idea could be to make these files static or singleton properties(may just solve my problem). but i still find there are some missing bits which inhibit isolated package developement i may have not agumented the statement correctly with facts but just a feel it seems as an after thought.. but anyway you helped a lot Thanks – Laukik Oct 08 '20 at 03:58
  • @Laukik But I gave you the solution in the update. And as for query files, those modules can use option `noWarnings` when creating `QueryFile` objects. – vitaly-t Oct 08 '20 at 04:28
  • Oh yes, 'noWarnings' is a solution, but thats like suppressing your compiler warnings, dont get me wrong it will still works and yes like i said your answers have helped me – Laukik Oct 08 '20 at 05:28