Convert IN operators to = ANY() operators on Postgres

This commit is contained in:
Alex Gleason
2024-07-31 12:52:03 -05:00
parent 7860dd2a0c
commit d73370cc68
5 changed files with 52 additions and 7 deletions

View File

@@ -1,5 +1,15 @@
import { Kysely } from 'kysely';
import { PostgresJSDialect, PostgresJSDialectConfig } from 'kysely-postgres-js';
import {
BinaryOperationNode,
FunctionNode,
Kysely,
OperatorNode,
PostgresAdapter,
PostgresIntrospector,
PostgresQueryCompiler,
PrimitiveValueListNode,
ValueNode,
} from 'kysely';
import { PostgresJSDialectConfig, PostgresJSDriver } from 'kysely-postgres-js';
import postgres from 'postgres';
import { Conf } from '@/config.ts';
@@ -18,9 +28,22 @@ export class DittoPostgres {
if (!this.db) {
this.db = new Kysely({
dialect: new PostgresJSDialect({
postgres: this.postgres as unknown as PostgresJSDialectConfig['postgres'],
}),
dialect: {
createAdapter() {
return new PostgresAdapter();
},
createDriver() {
return new PostgresJSDriver({
postgres: DittoPostgres.postgres as unknown as PostgresJSDialectConfig['postgres'],
});
},
createIntrospector(db) {
return new PostgresIntrospector(db);
},
createQueryCompiler() {
return new DittoPostgresQueryCompiler();
},
},
log: KyselyLogger,
});
}
@@ -36,3 +59,18 @@ export class DittoPostgres {
return this.postgres?.connections.idle ?? 0;
}
}
/** 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);
}
}
}

View File

@@ -15,6 +15,7 @@ export class DittoSQLite {
await sqliteWorker.open(this.path);
this.db = new Kysely<DittoTables>({
// @ts-ignore Kysely version mismatch.
dialect: new PolySqliteDialect({
database: sqliteWorker,
}),

View File

@@ -43,6 +43,7 @@ class EventsDB implements NStore {
};
constructor(private kysely: Kysely<DittoTables>) {
// @ts-ignore Kysely version mismatch.
this.store = new NDatabase(kysely, {
fts: Conf.db.dialect,
timeoutStrategy: Conf.db.dialect === 'postgres' ? 'setStatementTimeout' : undefined,