graphile-build-pg
Version:
Build a GraphQL schema by reflection over a PostgreSQL schema. Easy to customize since it's built with plugins on graphile-build
68 lines (64 loc) • 1.91 kB
Flow
//@flow
import { createHash } from "crypto";
import LRU from "@graphile/lru";
import type { PoolClient } from "pg";
const cacheSizeFromEnv = parseInt(
process.env.POSTGRAPHILE_PREPARED_STATEMENT_CACHE_SIZE,
10
);
const POSTGRAPHILE_PREPARED_STATEMENT_CACHE_SIZE =
!!cacheSizeFromEnv || cacheSizeFromEnv === 0 ? cacheSizeFromEnv : 100;
let lastString: string;
let lastHash: string;
const hash = (str: string): string => {
if (str !== lastString) {
lastString = str;
lastHash = createHash("sha1").update(str).digest("base64");
}
return lastHash;
};
export default function pgPrepareAndRun(
pgClient: PoolClient,
text: string,
// eslint-disable-next-line flowtype/no-weak-types
values: any
) {
const connection = pgClient.connection;
if (
!values ||
POSTGRAPHILE_PREPARED_STATEMENT_CACHE_SIZE < 2 ||
!connection ||
!connection.parsedStatements
) {
return pgClient.query(text, values);
} else {
const name = hash(text);
if (!connection._graphilePreparedStatementCache) {
connection._graphilePreparedStatementCache = new LRU({
maxLength: POSTGRAPHILE_PREPARED_STATEMENT_CACHE_SIZE,
dispose(key) {
if (connection.parsedStatements[key]) {
pgClient
.query(`deallocate ${pgClient.escapeIdentifier(key)}`)
.then(() => {
delete connection.parsedStatements[key];
})
.catch(e => {
// eslint-disable-next-line no-console
console.error("Error releasing prepared query", e);
});
}
},
});
}
if (!connection._graphilePreparedStatementCache.get(name)) {
// We're relying on dispose to clear out the old ones.
connection._graphilePreparedStatementCache.set(name, true);
}
return pgClient.query({
name,
text,
values,
});
}
}