Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/src/packages/database/postgres/util.ts
Views: 687
/*1* This file is part of CoCalc: Copyright © 2021 Sagemath, Inc.2* License: MS-RSL – see LICENSE.md for details3*/45import { reuseInFlight } from "@cocalc/util/reuse-in-flight";6import LRU from "lru-cache";7import { Pool } from "pg";8import { sha1 } from "@cocalc/backend/misc_node";9import getPool from "@cocalc/database/pool";10import { is_array } from "@cocalc/util/misc";11import lodash from "lodash";1213/* Some random little utils */1415// Convert timestamp fields as returned from postgresql queries16// into ms since the epoch, as a number.17export function toEpoch(rows: object | object[], fields: string[]): void {18if (!is_array(rows)) {19rows = [rows];20}21// @ts-ignore22for (const row of rows) {23for (const field of fields) {24if (row[field]) {25row[field] = new Date(row[field]).valueOf();26}27}28}29}3031interface LRUQueryCacheOpts {32size?: number;33ttl_s?: number;34}3536/**37* A simple LRU cache for postgres queries. This is better than getPool("some string"),38* because you're more in control, sha1 key sums to avoid sticking large keys in the cache,39* and you can clear the cache any time if you want.40*/41export class LRUQueryCache {42private cache: LRU<string, any>;43private pool: Pool;4445/**46* Create a new LRU cache for postgres queries.47*48* @param size number of queries to cache49* @param ttl_s time to live in seconds50*/51constructor(opts: LRUQueryCacheOpts = {}) {52const { size = 100, ttl_s = 60 } = opts;5354this.cache = new LRU({55max: size,56ttl: ttl_s * 1000,57});5859this.pool = getPool();60}6162public query = reuseInFlight(63async (64query: string,65args: (string | number | Date)[] = [],66cached = true,67) => {68const key = sha1(JSON.stringify([query, ...args]));6970if (cached) {71let value = this.cache.get(key);72if (value != null) return value;73}7475const { rows } = await this.pool.query(query, args);76this.cache.set(key, rows);77return rows;78},79);8081public async queryOne<T = any>(82query: string,83args: (string | number | Date)[] = [],84cached = true,85): Promise<T | null> {86const rows = await this.query(query, args, cached);87// NOTE: fallback to "null" is there to avoid serialization errors with next.js88return rows[0] ?? null;89}9091public clear(): void {92this.cache.clear();93}94}9596// removes the field:null to reduce bandwidth usage97export function stripNullFields(rows) {98return rows.map((row) => lodash.omitBy(row, lodash.isNull)) as any[];99}100101102