From 2746325af4ccf4a4f34df38b63a43a0b43ac3a0e Mon Sep 17 00:00:00 2001 From: Jeremy Moseley Date: Wed, 7 Aug 2024 16:08:58 -0700 Subject: [PATCH 1/3] Use Planetscale Client instead of raw Connection, to enable concurrent queries. --- src/index.ts | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/index.ts b/src/index.ts index d7a6a92..d80ce93 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,4 @@ -import {cast, Config, connect, Connection, Field} from '@planetscale/database' +import {Client, Config, Connection, Field, cast} from '@planetscale/database' import {parseJSON} from 'date-fns' import { CompiledQuery, @@ -71,7 +71,7 @@ export class PlanetScaleDialect implements Dialect { return new MysqlQueryCompiler() } - createIntrospector(db: Kysely): DatabaseIntrospector { + createIntrospector(db: Kysely): DatabaseIntrospector { return new MysqlIntrospector(db) } } @@ -110,15 +110,24 @@ const sharedConnections = new WeakMap() class PlanetScaleConnection implements DatabaseConnection { #config: PlanetScaleDialectConfig - #conn: Connection + #client: Client #transactionClient?: PlanetScaleConnection + get #conn(): Connection { + if (this.#transactionClient) return this.#transactionClient.#conn + if (this.#useSharedConnection) return sharedConnections.get(this.#config) as Connection + return this.#client.connection() + } + + get #useSharedConnection(): boolean { + return Boolean(this.#config.useSharedConnection && !this.#transactionClient) + } + constructor(config: PlanetScaleDialectConfig, isForTransaction = false) { this.#config = config const useSharedConnection = config.useSharedConnection && !isForTransaction - const sharedConnection = useSharedConnection ? sharedConnections.get(config) : undefined - this.#conn = sharedConnection ?? connect({cast: inflateDates, ...config}) - if (useSharedConnection) sharedConnections.set(config, this.#conn) + this.#client = new Client({cast: inflateDates, ...config}) + if (useSharedConnection) sharedConnections.set(config, this.#client.connection()) } async executeQuery(compiledQuery: CompiledQuery): Promise> { From 586d6b8c13372d02c3ae513c6a076a1a6eaf3e35 Mon Sep 17 00:00:00 2001 From: Jeremy Moseley Date: Wed, 14 Aug 2024 16:11:51 -0700 Subject: [PATCH 2/3] Refactor to have a single Client, and more carefully maintain connection for transaction. --- src/index.ts | 55 ++++++++++++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/src/index.ts b/src/index.ts index d80ce93..208459a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -77,16 +77,16 @@ export class PlanetScaleDialect implements Dialect { } class PlanetScaleDriver implements Driver { - #config: PlanetScaleDialectConfig + #client: Client constructor(config: PlanetScaleDialectConfig) { - this.#config = config + this.#client = new Client({cast: inflateDates, ...config}) } async init(): Promise {} async acquireConnection(): Promise { - return new PlanetScaleConnection(this.#config) + return new PlanetScaleConnection(this.#client) } async beginTransaction(conn: PlanetScaleConnection): Promise { @@ -109,36 +109,35 @@ class PlanetScaleDriver implements Driver { const sharedConnections = new WeakMap() class PlanetScaleConnection implements DatabaseConnection { - #config: PlanetScaleDialectConfig #client: Client - #transactionClient?: PlanetScaleConnection + #transactionConn?: Connection + #useSharedConnection: boolean - get #conn(): Connection { - if (this.#transactionClient) return this.#transactionClient.#conn - if (this.#useSharedConnection) return sharedConnections.get(this.#config) as Connection - return this.#client.connection() + get #config(): Config { + return this.#client.config } - get #useSharedConnection(): boolean { - return Boolean(this.#config.useSharedConnection && !this.#transactionClient) - } - - constructor(config: PlanetScaleDialectConfig, isForTransaction = false) { - this.#config = config - const useSharedConnection = config.useSharedConnection && !isForTransaction - this.#client = new Client({cast: inflateDates, ...config}) - if (useSharedConnection) sharedConnections.set(config, this.#client.connection()) + constructor(client: Client, useSharedConnection = false, isForTransaction = false) { + this.#client = client + this.#useSharedConnection = useSharedConnection && !isForTransaction + if (this.#useSharedConnection) sharedConnections.set(this.#config, this.#client.connection()) } async executeQuery(compiledQuery: CompiledQuery): Promise> { - if (this.#transactionClient) return this.#transactionClient.executeQuery(compiledQuery) + if (this.#transactionConn) return this.execute(compiledQuery, this.#transactionConn) + + return this.#useSharedConnection + ? this.execute(compiledQuery, sharedConnections.get(this.#config) || this.#client) + : this.execute(compiledQuery, this.#client) + } + private async execute(compiledQuery: CompiledQuery, conn: Pick): Promise> { // If no custom formatter is provided, format dates as DB date strings const parameters = this.#config.format ? compiledQuery.parameters : compiledQuery.parameters.map((param) => (param instanceof Date ? formatDate(param) : param)) - const results = await this.#conn.execute(compiledQuery.sql, parameters) + const results = await conn.execute(compiledQuery.sql, parameters) // @planetscale/database versions older than 1.3.0 return errors directly, rather than throwing if ((results as any).error) { @@ -159,25 +158,25 @@ class PlanetScaleConnection implements DatabaseConnection { } async beginTransaction() { - this.#transactionClient = this.#transactionClient ?? new PlanetScaleConnection(this.#config, true) - await this.#transactionClient.#conn.execute('BEGIN') + this.#transactionConn = this.#transactionConn ?? this.#client.connection() + await this.#transactionConn.execute('BEGIN') } async commitTransaction() { - if (!this.#transactionClient) throw new Error('No transaction to commit') + if (!this.#transactionConn) throw new Error('No transaction to commit') try { - await this.#transactionClient.#conn.execute('COMMIT') + await this.#transactionConn.execute('COMMIT') } finally { - this.#transactionClient = undefined + this.#transactionConn = undefined } } async rollbackTransaction() { - if (!this.#transactionClient) throw new Error('No transaction to rollback') + if (!this.#transactionConn) throw new Error('No transaction to rollback') try { - await this.#transactionClient.#conn.execute('ROLLBACK') + await this.#transactionConn.execute('ROLLBACK') } finally { - this.#transactionClient = undefined + this.#transactionConn = undefined } } From d9a4e78b0e3824760c28de46c71826c0c6a21d3a Mon Sep 17 00:00:00 2001 From: Jeremy Moseley Date: Thu, 15 Aug 2024 08:22:24 -0700 Subject: [PATCH 3/3] Update src/index.ts Co-authored-by: Jacob Gillespie --- src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index 208459a..cb355f0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -120,7 +120,7 @@ class PlanetScaleConnection implements DatabaseConnection { constructor(client: Client, useSharedConnection = false, isForTransaction = false) { this.#client = client this.#useSharedConnection = useSharedConnection && !isForTransaction - if (this.#useSharedConnection) sharedConnections.set(this.#config, this.#client.connection()) + if (this.#useSharedConnection) sharedConnections.set(this.#config, sharedConnections.get(this.#config) ?? this.#client.connection()) } async executeQuery(compiledQuery: CompiledQuery): Promise> {