UNPKG

@clickup/pg-microsharding

Version:
91 lines (88 loc) 2.81 kB
import partition from "lodash/partition"; import { sql } from "./quote"; import { runSql } from "./runSql"; export interface TableInfo { /** Raw schema name (unquoted). */ schema: string; /** Raw table name (unquoted). */ name: string; /** Raw owner name (unquoted). */ owner: string; /** Whether this is a base table for a partitioned table. Such tables have no * data and must not be mentioned in publications. */ isPartitioned: boolean; /** Existing index that can be used on the subscriber end to identify the rows * for received updates and deletes. */ identity: { /** Index name. */ indexName: string; /** Whether the index is a replica identity. */ isReplIdent: boolean; /** Whether the index is a primary key. */ isPrimaryKey: boolean; /** Index definition. */ def: string; } | null; } /** * Returns all tables in a given schema on fromDsn. * * For logical subscription purposes, we only need the `tables` that may * potentially contain data (e.g. regular tables, or partitions). But we also * return the base tables for partitioned tables in `partitionedTables`, since * we validate the primary key coverage in `validatePrimaryKeysFromDump()` for sanity * checking purposes. */ export async function getTablesInSchema({ fromDsn, schema, }: { fromDsn: string; schema: string; }): Promise<{ tables: TableInfo[]; partitionedTables: TableInfo[] }> { const rows = await runSql( fromDsn, sql` SELECT DISTINCT ON (pg_namespace.nspname, pg_class.relname, pg_roles.rolname) pg_namespace.nspname, pg_class.relname, pg_roles.rolname, pg_class.relkind, idx_class.relname, pg_index.indisreplident, pg_index.indisprimary, pg_get_indexdef(idx_class.oid) FROM pg_class JOIN pg_namespace ON relnamespace = pg_namespace.oid JOIN pg_roles ON relowner = pg_roles.oid LEFT JOIN pg_index ON indrelid = pg_class.oid AND (indisreplident OR indisprimary) LEFT JOIN pg_class idx_class ON idx_class.oid = pg_index.indexrelid WHERE pg_class.relkind IN ('r', 'p') AND nspname = ${schema} ORDER BY pg_namespace.nspname, pg_class.relname, pg_roles.rolname, pg_index.indisreplident DESC, pg_index.indisprimary DESC `, ); const res = rows.map((row) => ({ schema: row[0], name: row[1], owner: row[2], isPartitioned: row[3] === "p", identity: row[4] ? { indexName: row[4], isReplIdent: row[5] === "t", isPrimaryKey: row[6] === "t", def: row[7], } : null, })); const [partitionedTables, tables] = partition( res, (table) => table.isPartitioned, ); return { tables, partitionedTables }; }