@clickup/ent-framework
Version:
A PostgreSQL graph-database-alike library with microsharding and row-level security
87 lines (78 loc) • 2.57 kB
text/typescript
import type { QueryAnnotation } from "../abstract/QueryAnnotation";
import { QueryBase } from "../abstract/QueryBase";
import type { Schema } from "../abstract/Schema";
import type { LoadByInput, Row, Table, UniqueKey } from "../types";
import type { PgClient } from "./PgClient";
import { PgRunner } from "./PgRunner";
export class PgQueryLoadBy<
TTable extends Table,
TUniqueKey extends UniqueKey<TTable>,
> extends QueryBase<
TTable,
LoadByInput<TTable, TUniqueKey>,
Row<TTable> | null,
PgClient
> {
/** @ignore */
readonly RUNNER_CLASS = PgRunnerLoadBy;
}
class PgRunnerLoadBy<
TTable extends Table,
TUniqueKey extends UniqueKey<TTable>,
> extends PgRunner<
TTable,
LoadByInput<TTable, TUniqueKey>,
Row<TTable> | null
> {
static override readonly IS_WRITE = false;
private builders;
readonly op = "SELECT_UNIQ";
override readonly maxBatchSize = 200; // Select by unique key is cheap, so we can have much bigger load batches to accumulate more data from e.g. Shard 0 for the next multi-Shard requests.
readonly default = null; // If no row is found, returns null.
constructor(schema: Schema<TTable>, client: PgClient) {
super(schema, client);
this.builders = this.createWhereBuildersFieldsEq<
LoadByInput<TTable, TUniqueKey>
>({
prefix: this.fmt("SELECT %SELECT_FIELDS FROM %T "),
fields: this.schema.uniqueKey,
suffix: this.fmt(""),
});
}
override key(input: LoadByInput<TTable, TUniqueKey>): string {
return JSON.stringify(this.schema.uniqueKey.map((field) => input[field]));
}
async runSingle(
input: LoadByInput<TTable, TUniqueKey>,
annotations: QueryAnnotation[],
): Promise<Row<TTable> | undefined> {
const sql =
this.builders.plain.prefix +
this.builders.plain.func([["", input]]) +
this.builders.plain.suffix;
const rows = await this.clientQuery<Row<TTable>>(sql, annotations, 1);
return rows[0];
}
async runBatch(
inputs: Map<string, LoadByInput<TTable, TUniqueKey>>,
annotations: QueryAnnotation[],
): Promise<Map<string, Row<TTable>>> {
const sql =
this.builders.optimized.prefix +
this.builders.optimized.func(inputs) +
this.builders.optimized.suffix;
const rows = await this.clientQuery<Row<TTable>>(
sql,
annotations,
inputs.size,
);
const output = new Map<string, Row<TTable>>();
for (const row of rows) {
output.set(
this.key(row as unknown as LoadByInput<TTable, TUniqueKey>),
row,
);
}
return output;
}
}