Bring in hapi-pg-promise
This commit is contained in:
parent
67f7cf8e1b
commit
346b40db98
16 changed files with 3100 additions and 627 deletions
97
packages/hapi-pg-promise/src/index.spec.ts
Normal file
97
packages/hapi-pg-promise/src/index.spec.ts
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
import * as Hapi from "@hapi/hapi";
|
||||
import PgPromisePlugin from ".";
|
||||
|
||||
describe("plugin option validation", () => {
|
||||
let server;
|
||||
beforeEach(async () => {
|
||||
server = new Hapi.Server();
|
||||
});
|
||||
|
||||
it("should throw when no connection details defined", async () => {
|
||||
expect(server.register(PgPromisePlugin)).rejects.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
const defaultOpts = {
|
||||
connection: "postgresql://amigo:amigo@127.0.0.1:5432/postgres",
|
||||
};
|
||||
describe("basic plugin runtime", () => {
|
||||
let server;
|
||||
beforeEach(async () => {
|
||||
server = new Hapi.Server({ port: 0 });
|
||||
await server.register({
|
||||
plugin: PgPromisePlugin,
|
||||
options: defaultOpts,
|
||||
});
|
||||
await server.start();
|
||||
});
|
||||
afterEach(async () => {
|
||||
await server.stop();
|
||||
});
|
||||
|
||||
it("should decorate db and pgp into server and request", async () => {
|
||||
expect.assertions(5);
|
||||
server.route({
|
||||
method: "GET",
|
||||
path: "/",
|
||||
handler(req) {
|
||||
expect(req.db).toBeInstanceOf(Function);
|
||||
expect(req.server.db).toBeInstanceOf(Function);
|
||||
expect(req.pgp).toBeInstanceOf(Function);
|
||||
expect(req.server.pgp).toBeInstanceOf(Function);
|
||||
return "OK";
|
||||
},
|
||||
});
|
||||
|
||||
const { statusCode } = await server.inject({
|
||||
method: "get",
|
||||
url: "/",
|
||||
});
|
||||
expect(statusCode).toBe(200);
|
||||
});
|
||||
});
|
||||
|
||||
describe("plugin runtime", () => {
|
||||
let server;
|
||||
beforeEach(async () => {
|
||||
server = new Hapi.Server({ port: 0 });
|
||||
});
|
||||
afterEach(async () => {
|
||||
await server.stop();
|
||||
});
|
||||
it("should decorate db and pgp into server and request with custom name", async () => {
|
||||
expect.assertions(5);
|
||||
|
||||
await server.register({
|
||||
plugin: PgPromisePlugin,
|
||||
options: {
|
||||
...defaultOpts,
|
||||
logSql: true,
|
||||
decorateAs: {
|
||||
pgp: "foobar",
|
||||
db: "poprocks",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await server.start();
|
||||
|
||||
await server.route({
|
||||
method: "GET",
|
||||
path: "/",
|
||||
handler(req) {
|
||||
expect(req.poprocks).toBeInstanceOf(Function);
|
||||
expect(req.server.poprocks).toBeInstanceOf(Function);
|
||||
expect(req.foobar).toBeInstanceOf(Function);
|
||||
expect(req.server.foobar).toBeInstanceOf(Function);
|
||||
return "OK";
|
||||
},
|
||||
});
|
||||
|
||||
const { statusCode } = await server.inject({
|
||||
method: "get",
|
||||
url: "/",
|
||||
});
|
||||
expect(statusCode).toBe(200);
|
||||
});
|
||||
});
|
||||
103
packages/hapi-pg-promise/src/index.ts
Normal file
103
packages/hapi-pg-promise/src/index.ts
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
import * as Hapi from "@hapi/hapi";
|
||||
import * as Hoek from "@hapi/hoek";
|
||||
import pgPromise from "pg-promise";
|
||||
import * as pgMonitor from "pg-monitor";
|
||||
import type { IConnectionParameters } from "pg-promise/typescript/pg-subset";
|
||||
import type { IMain, IInitOptions } from "pg-promise";
|
||||
|
||||
import { IPGPPluginOptions, ExtendedProtocol } from "./types";
|
||||
|
||||
export * from "./types";
|
||||
const defaultOptions: IPGPPluginOptions<unknown> = {
|
||||
connection: undefined,
|
||||
pgpInit: {},
|
||||
logSql: false,
|
||||
decorateAs: {
|
||||
pgp: "pgp",
|
||||
db: "db",
|
||||
},
|
||||
};
|
||||
|
||||
export const startDiagnostics = <T>(
|
||||
logSql: boolean,
|
||||
initOpts: IInitOptions<T>
|
||||
): void => {
|
||||
if (logSql) {
|
||||
pgMonitor.attach(initOpts);
|
||||
} else {
|
||||
pgMonitor.attach(initOpts, ["error"]);
|
||||
}
|
||||
};
|
||||
|
||||
export const stopDiagnostics = (): void => pgMonitor.detach();
|
||||
|
||||
const startPgp = async <T>(initOptions: IInitOptions<T>): Promise<IMain> => {
|
||||
const pgp: IMain = pgPromise(initOptions);
|
||||
return pgp;
|
||||
};
|
||||
|
||||
const startDb = async <T>(
|
||||
pgp,
|
||||
connection: string | IConnectionParameters
|
||||
): Promise<ExtendedProtocol<T>> => {
|
||||
const db: ExtendedProtocol<T> = pgp(connection);
|
||||
|
||||
return db;
|
||||
};
|
||||
|
||||
const register = async <T>(
|
||||
server: Hapi.Server,
|
||||
userOpts?: IPGPPluginOptions<T>
|
||||
): Promise<void> => {
|
||||
const options: IPGPPluginOptions<T> = Hoek.applyToDefaults(
|
||||
defaultOptions,
|
||||
userOpts
|
||||
) as IPGPPluginOptions<T>;
|
||||
|
||||
if (!options.connection) {
|
||||
throw new Error(
|
||||
"hapi-pg-promise: connection details are not defined. You must specify a valid connection for the plugin to boot."
|
||||
);
|
||||
}
|
||||
|
||||
if ("pgp" in options && "pgpInit" in options) {
|
||||
throw new Error(
|
||||
"hapi-pg-promise: options pgp and pgpInit are mutually exclusive"
|
||||
);
|
||||
}
|
||||
|
||||
let pgp: IMain;
|
||||
if ("pgp" in options) {
|
||||
pgp = options.pgp;
|
||||
} else {
|
||||
pgp = await startPgp(options.pgpInit);
|
||||
startDiagnostics(options.logSql, options.pgpInit);
|
||||
}
|
||||
|
||||
const db = await startDb(pgp, options.connection);
|
||||
|
||||
if (options.decorateAs) {
|
||||
if (options.decorateAs) {
|
||||
server.decorate("request", options.decorateAs.pgp, pgp);
|
||||
server.decorate("server", options.decorateAs.pgp, pgp);
|
||||
}
|
||||
|
||||
if (options.decorateAs.db) {
|
||||
server.decorate("server", options.decorateAs.db, () => db);
|
||||
server.decorate("request", options.decorateAs.db, () => db);
|
||||
}
|
||||
}
|
||||
|
||||
server.ext("onPostStop", async () => {
|
||||
stopDiagnostics();
|
||||
await db.$pool.end();
|
||||
});
|
||||
};
|
||||
|
||||
const pgPromisePlugin = {
|
||||
register,
|
||||
name: "pg-promise",
|
||||
version: "0.0.1",
|
||||
};
|
||||
|
||||
export default pgPromisePlugin;
|
||||
13
packages/hapi-pg-promise/src/types.ts
Normal file
13
packages/hapi-pg-promise/src/types.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import type { IMain, IInitOptions, IDatabase } from "pg-promise";
|
||||
import type { IConnectionParameters } from "pg-promise/typescript/pg-subset";
|
||||
|
||||
export type ExtendedProtocol<T> = IDatabase<T> & T;
|
||||
|
||||
export type IPGPPluginOptions<T> = {
|
||||
connection: string | IConnectionParameters;
|
||||
logSql?: boolean;
|
||||
decorateAs?: {
|
||||
pgp: string;
|
||||
db: string;
|
||||
};
|
||||
} & ({ pgpInit: IInitOptions<T> } | { pgp: IMain<T> });
|
||||
Loading…
Add table
Add a link
Reference in a new issue