UNPKG

@nic-jennings/sql-datasource

Version:
82 lines (81 loc) 2.93 kB
import { createHash } from "crypto"; import DataLoader from "dataloader"; import knex from "knex"; import knexTinyLogger from "knex-tiny-logger"; import { InMemoryLRUCache } from "@apollo/utils.keyvaluecache"; const { DEBUG } = process.env; let hasCache = false; let hasLogger = false; let hasBatch = false; export class BatchedSQLDataSource { cache; context; db; constructor(config) { this.cache = config.cache ? config.cache : new InMemoryLRUCache(); this.context = config.context; const { queryConnection, writeConnection } = this._connectToDatabase(config); this.db = { query: queryConnection, write: writeConnection, }; this._extendKnex(); } _extendKnex() { const _this = this; const knexQueryBuilder = knex.QueryBuilder; if (!this.db.query.cache && !hasCache) { knexQueryBuilder.extend("cache", function (ttl) { return _this._cacheQuery(this, ttl); }); hasCache = true; } if (!this.db.query.batch && !hasBatch) { knexQueryBuilder.extend("batch", function (callback) { const query = this.clone(); return _this._batchQuery(query, callback); }); hasBatch = true; } } _connectToDatabase(config) { let seperateInstances = true; const queryConnection = typeof config.knexConfig === "function" ? config.knexConfig : knex(config.knexConfig); if (!config.writeKnexConfig) { seperateInstances = false; config.writeKnexConfig = queryConnection; } const writeConnection = typeof config.writeKnexConfig === "function" ? config.writeKnexConfig : knex(config.writeKnexConfig); if (DEBUG && !hasLogger) { hasLogger = true; // Prevent duplicate loggers knexTinyLogger(queryConnection); // Add a logging utility for debugging if (seperateInstances) knexTinyLogger(writeConnection); // Add a logging utility for debugging } return { queryConnection, writeConnection }; } _batchQuery(query, callback) { return new DataLoader((keys) => { const finalQuery = query.clone(); return callback(finalQuery, keys); }); } _cacheQuery(query, ttl = 5) { const cacheKey = createHash("sha1") .update(query.toString()) .digest("base64"); return this.cache?.get(cacheKey).then((entry) => { if (entry) return Promise.resolve(JSON.parse(entry)); return query.then((rows) => { if (rows) this.cache?.set(cacheKey, JSON.stringify(rows), { ttl }); return Promise.resolve(rows); }); }); } }