mirror of
https://gitlab.com/soapbox-pub/ditto.git
synced 2025-12-06 03:19:46 +00:00
74 lines
2.1 KiB
TypeScript
74 lines
2.1 KiB
TypeScript
import {
|
|
type BinaryOperationNode,
|
|
FunctionNode,
|
|
Kysely,
|
|
OperatorNode,
|
|
PostgresAdapter,
|
|
PostgresIntrospector,
|
|
PostgresQueryCompiler,
|
|
PrimitiveValueListNode,
|
|
ValueNode,
|
|
} from 'kysely';
|
|
import { type PostgresJSDialectConfig, PostgresJSDriver } from 'kysely-postgres-js';
|
|
import postgres from 'postgres';
|
|
|
|
import { KyselyLogger } from '../KyselyLogger.ts';
|
|
|
|
import type { DittoDatabase, DittoDatabaseOpts } from '../DittoDatabase.ts';
|
|
import type { DittoTables } from '../DittoTables.ts';
|
|
|
|
export class DittoPostgres {
|
|
static create(databaseUrl: string, opts?: DittoDatabaseOpts): DittoDatabase {
|
|
const pg = postgres(databaseUrl, { max: opts?.poolSize });
|
|
|
|
const kysely = new Kysely<DittoTables>({
|
|
dialect: {
|
|
createAdapter() {
|
|
return new PostgresAdapter();
|
|
},
|
|
createDriver() {
|
|
return new PostgresJSDriver({
|
|
postgres: pg as unknown as PostgresJSDialectConfig['postgres'],
|
|
});
|
|
},
|
|
createIntrospector(db) {
|
|
return new PostgresIntrospector(db);
|
|
},
|
|
createQueryCompiler() {
|
|
return new DittoPostgresQueryCompiler();
|
|
},
|
|
},
|
|
log: KyselyLogger,
|
|
});
|
|
|
|
const listen = (channel: string, callback: (payload: string) => void): void => {
|
|
pg.listen(channel, callback);
|
|
};
|
|
|
|
return {
|
|
kysely,
|
|
get poolSize() {
|
|
return pg.connections.open;
|
|
},
|
|
get availableConnections() {
|
|
return pg.connections.idle;
|
|
},
|
|
listen,
|
|
};
|
|
}
|
|
}
|
|
|
|
/** Converts `in` queries to `any` to improve prepared statements on Postgres. */
|
|
class DittoPostgresQueryCompiler extends PostgresQueryCompiler {
|
|
protected override visitBinaryOperation(node: BinaryOperationNode): void {
|
|
if (
|
|
OperatorNode.is(node.operator) && node.operator.operator === 'in' && PrimitiveValueListNode.is(node.rightOperand)
|
|
) {
|
|
this.visitNode(node.leftOperand);
|
|
this.append(' = ');
|
|
this.visitNode(FunctionNode.create('any', [ValueNode.create(node.rightOperand.values)]));
|
|
} else {
|
|
super.visitBinaryOperation(node);
|
|
}
|
|
}
|
|
}
|