Print the declared predicates in a module function, not a store method
The store's coverage test lists every method on PostgresStore as an operation the workload must call, and the private predicate printer counted as one. It is a helper of checkSchema, not a store operation, so it becomes a function of the pool. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
eff5098c23
commit
97632b7cfa
1 changed files with 31 additions and 31 deletions
|
|
@ -363,6 +363,36 @@ export function samePredicate(declared: string, actual: string, keyColumns: stri
|
||||||
return left.length === right.length && left.every((condition, index) => condition === right[index]);
|
return left.length === right.length && left.every((condition, index) => condition === right[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Each REQUIRED_KEYS predicate as Postgres prints it back (empty for none).
|
||||||
|
* One simple-protocol round trip on one connection: a transaction that
|
||||||
|
* builds a temporary copy of each keyed table's declared columns, indexes
|
||||||
|
* it with the declared predicate, reads the printed form and rolls back.
|
||||||
|
* The names and SQL are the schema's own constants, never input.
|
||||||
|
*/
|
||||||
|
async function printedDeclaredPredicates(pool: Pick<Pool, "query">): Promise<string[]> {
|
||||||
|
const partial = REQUIRED_KEYS.flatMap((required, index) => (required.predicate ? [{ ...required, index }] : []));
|
||||||
|
if (partial.length === 0) return REQUIRED_KEYS.map(() => "");
|
||||||
|
const statements = partial.flatMap(({ table, columns, predicate, index }) => {
|
||||||
|
const probe = `heimdall_key_probe_${index}`;
|
||||||
|
const declared = REQUIRED_COLUMNS.filter((column) => column.table === table)
|
||||||
|
.map((column) => `${column.column} ${column.type}`)
|
||||||
|
.join(", ");
|
||||||
|
return [
|
||||||
|
`CREATE TEMP TABLE ${probe} (${declared}) ON COMMIT DROP`,
|
||||||
|
`CREATE UNIQUE INDEX ${probe}_idx ON ${probe} (${columns}) WHERE ${predicate}`,
|
||||||
|
];
|
||||||
|
});
|
||||||
|
const select = partial
|
||||||
|
.map(({ index }) => `SELECT ${index} AS key, pg_get_expr(indpred, indrelid) AS predicate FROM pg_index WHERE indexrelid = 'pg_temp.heimdall_key_probe_${index}_idx'::regclass`)
|
||||||
|
.join(" UNION ALL ");
|
||||||
|
const results = (await pool.query(["BEGIN", ...statements, select, "ROLLBACK"].join(";\n"))) as unknown as Array<{
|
||||||
|
rows: Array<{ key: number; predicate: string }>;
|
||||||
|
}>;
|
||||||
|
const printed = results[results.length - 2]!.rows;
|
||||||
|
return REQUIRED_KEYS.map((_, index) => printed.find((row) => row.key === index)?.predicate ?? "");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* What the store's statements do to each table, and so the privileges its
|
* What the store's statements do to each table, and so the privileges its
|
||||||
* database role needs: it reads what it returns or looks up, inserts what it
|
* database role needs: it reads what it returns or looks up, inserts what it
|
||||||
|
|
@ -411,7 +441,7 @@ export class PostgresStore implements HeimdallStore {
|
||||||
* temporary copy of the table in a transaction that is rolled back.
|
* temporary copy of the table in a transaction that is rolled back.
|
||||||
*/
|
*/
|
||||||
async checkSchema(): Promise<void> {
|
async checkSchema(): Promise<void> {
|
||||||
const declaredPredicates = await this.printedDeclaredPredicates();
|
const declaredPredicates = await printedDeclaredPredicates(this.pool);
|
||||||
const privileges = Object.entries(STORE_TABLE_PRIVILEGES).flatMap(([table, wanted]) =>
|
const privileges = Object.entries(STORE_TABLE_PRIVILEGES).flatMap(([table, wanted]) =>
|
||||||
wanted.map((privilege) => ({ table, privilege }))
|
wanted.map((privilege) => ({ table, privilege }))
|
||||||
);
|
);
|
||||||
|
|
@ -497,36 +527,6 @@ export class PostgresStore implements HeimdallStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Each REQUIRED_KEYS predicate as Postgres prints it back (empty for none).
|
|
||||||
* One simple-protocol round trip on one connection: a transaction that
|
|
||||||
* builds a temporary copy of each keyed table's declared columns, indexes
|
|
||||||
* it with the declared predicate, reads the printed form and rolls back.
|
|
||||||
* The names and SQL are the schema's own constants, never input.
|
|
||||||
*/
|
|
||||||
private async printedDeclaredPredicates(): Promise<string[]> {
|
|
||||||
const partial = REQUIRED_KEYS.flatMap((required, index) => (required.predicate ? [{ ...required, index }] : []));
|
|
||||||
if (partial.length === 0) return REQUIRED_KEYS.map(() => "");
|
|
||||||
const statements = partial.flatMap(({ table, columns, predicate, index }) => {
|
|
||||||
const probe = `heimdall_key_probe_${index}`;
|
|
||||||
const declared = REQUIRED_COLUMNS.filter((column) => column.table === table)
|
|
||||||
.map((column) => `${column.column} ${column.type}`)
|
|
||||||
.join(", ");
|
|
||||||
return [
|
|
||||||
`CREATE TEMP TABLE ${probe} (${declared}) ON COMMIT DROP`,
|
|
||||||
`CREATE UNIQUE INDEX ${probe}_idx ON ${probe} (${columns}) WHERE ${predicate}`,
|
|
||||||
];
|
|
||||||
});
|
|
||||||
const select = partial
|
|
||||||
.map(({ index }) => `SELECT ${index} AS key, pg_get_expr(indpred, indrelid) AS predicate FROM pg_index WHERE indexrelid = 'pg_temp.heimdall_key_probe_${index}_idx'::regclass`)
|
|
||||||
.join(" UNION ALL ");
|
|
||||||
const results = (await this.pool.query(["BEGIN", ...statements, select, "ROLLBACK"].join(";\n"))) as unknown as Array<{
|
|
||||||
rows: Array<{ key: number; predicate: string }>;
|
|
||||||
}>;
|
|
||||||
const printed = results[results.length - 2]!.rows;
|
|
||||||
return REQUIRED_KEYS.map((_, index) => printed.find((row) => row.key === index)?.predicate ?? "");
|
|
||||||
}
|
|
||||||
|
|
||||||
async close(): Promise<void> {
|
async close(): Promise<void> {
|
||||||
await this.pool.end();
|
await this.pool.end();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue