Skip to content

Commit 3502182

Browse files
committed
executable.
apply executable @ select. test suite prep. ?? best bench results. ... update qb. merge qb. insert qb. delete qb. kysely. raw builder. fix regression in takeFirst. more core. abort. ... ... ... ... ... ... ... ... ... executeQuery. ... ... ... ... ... ... ... ...
1 parent 22aa3f7 commit 3502182

19 files changed

Lines changed: 815 additions & 251 deletions

src/dialect/postgres/postgres-driver.ts

Lines changed: 55 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import {
2+
ControlConnectionProvider,
23
DatabaseConnection,
4+
QueryOptions,
35
QueryResult,
46
} from '../../driver/database-connection.js'
57
import { Driver, TransactionSettings } from '../../driver/driver.js'
68
import { parseSavepointCommand } from '../../parser/savepoint-parser.js'
79
import { CompiledQuery } from '../../query-compiler/compiled-query.js'
810
import { QueryCompiler } from '../../query-compiler/query-compiler.js'
11+
import { logOnce } from '../../util/log-once.js'
912
import { isFunction, freeze } from '../../util/object-utils.js'
1013
import { createQueryId } from '../../util/query-id.js'
1114
import { extendStackTrace } from '../../util/stack-trace-utils.js'
@@ -144,20 +147,45 @@ interface PostgresConnectionOptions {
144147
}
145148

146149
class PostgresConnection implements DatabaseConnection {
147-
#client: PostgresPoolClient
148-
#options: PostgresConnectionOptions
150+
readonly #client: PostgresPoolClient
151+
readonly #options: PostgresConnectionOptions
152+
#pid: unknown
149153

150154
constructor(client: PostgresPoolClient, options: PostgresConnectionOptions) {
151155
this.#client = client
152156
this.#options = options
153157
}
154158

155-
async executeQuery<O>(compiledQuery: CompiledQuery): Promise<QueryResult<O>> {
156-
try {
157-
const { command, rowCount, rows } = await this.#client.query<O>(
158-
compiledQuery.sql,
159-
[...compiledQuery.parameters],
159+
async cancelQuery(
160+
controlConnectionProvider: ControlConnectionProvider,
161+
): Promise<void> {
162+
if (!this.#pid) {
163+
return logOnce(
164+
'kysely:warning: cannot cancel query because the connection has not been made cancelable.',
165+
)
166+
}
167+
168+
return await controlConnectionProvider(async (controlConnection) => {
169+
await controlConnection.executeQuery(
170+
CompiledQuery.raw('select pg_cancel_backend($1)', [this.#pid]),
160171
)
172+
})
173+
}
174+
175+
async executeQuery<O>(
176+
compiledQuery: CompiledQuery,
177+
options?: QueryOptions,
178+
): Promise<QueryResult<O>> {
179+
try {
180+
if (options?.cancelable) {
181+
await this.#setupCancelability()
182+
}
183+
184+
const result = await this.#client.query<O>(compiledQuery.sql, [
185+
...compiledQuery.parameters,
186+
])
187+
188+
const { command, rowCount, rows } = result
161189

162190
return {
163191
numAffectedRows:
@@ -177,6 +205,7 @@ class PostgresConnection implements DatabaseConnection {
177205
async *streamQuery<O>(
178206
compiledQuery: CompiledQuery,
179207
chunkSize: number,
208+
options?: QueryOptions,
180209
): AsyncIterableIterator<QueryResult<O>> {
181210
if (!this.#options.cursor) {
182211
throw new Error(
@@ -188,6 +217,10 @@ class PostgresConnection implements DatabaseConnection {
188217
throw new Error('chunkSize must be a positive integer')
189218
}
190219

220+
if (options?.cancelable) {
221+
await this.#setupCancelability()
222+
}
223+
191224
const cursor = this.#client.query(
192225
new this.#options.cursor<O>(
193226
compiledQuery.sql,
@@ -215,4 +248,19 @@ class PostgresConnection implements DatabaseConnection {
215248
[PRIVATE_RELEASE_METHOD](): void {
216249
this.#client.release()
217250
}
251+
252+
async #setupCancelability(): Promise<void> {
253+
if (this.#pid) {
254+
return
255+
}
256+
257+
const {
258+
rows: [row],
259+
} = await this.#client.query<{ pid: unknown }>(
260+
'select pg_backend_pid() as pid',
261+
[],
262+
)
263+
264+
this.#pid = row.pid
265+
}
218266
}

src/driver/database-connection.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,30 @@ import { CompiledQuery } from '../query-compiler/compiled-query.js'
66
* These are created by an instance of {@link Driver}.
77
*/
88
export interface DatabaseConnection {
9-
executeQuery<R>(compiledQuery: CompiledQuery): Promise<QueryResult<R>>
9+
cancelQuery?(
10+
controlConnectionProvider: ControlConnectionProvider,
11+
): Promise<void>
12+
13+
executeQuery<R>(
14+
compiledQuery: CompiledQuery,
15+
options?: QueryOptions,
16+
): Promise<QueryResult<R>>
17+
1018
streamQuery<R>(
1119
compiledQuery: CompiledQuery,
12-
chunkSize?: number,
20+
chunkSize: number,
21+
options?: QueryOptions,
1322
): AsyncIterableIterator<QueryResult<R>>
1423
}
1524

25+
export interface QueryOptions {
26+
cancelable?: boolean
27+
}
28+
29+
export type ControlConnectionProvider = (
30+
consumer: (connection: DatabaseConnection) => Promise<void>,
31+
) => Promise<void>
32+
1633
export interface QueryResult<O> {
1734
/**
1835
* This is defined for insert, update, delete and merge queries and contains

src/driver/runtime-driver.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,12 +167,13 @@ export class RuntimeDriver implements Driver {
167167

168168
connection.executeQuery = async (
169169
compiledQuery,
170+
options,
170171
): Promise<QueryResult<any>> => {
171172
let caughtError: unknown
172173
const startTime = performanceNow()
173174

174175
try {
175-
return await executeQuery.call(connection, compiledQuery)
176+
return await executeQuery.call(connection, compiledQuery, options)
176177
} catch (error) {
177178
caughtError = error
178179
await dis.#logError(error, compiledQuery, startTime)
@@ -187,6 +188,7 @@ export class RuntimeDriver implements Driver {
187188
connection.streamQuery = async function* (
188189
compiledQuery,
189190
chunkSize,
191+
options,
190192
): AsyncIterableIterator<QueryResult<any>> {
191193
let caughtError: unknown
192194
const startTime = performanceNow()
@@ -196,6 +198,7 @@ export class RuntimeDriver implements Driver {
196198
connection,
197199
compiledQuery,
198200
chunkSize,
201+
options,
199202
)) {
200203
yield result
201204
}

src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ export * from './util/column-type.js'
224224
export * from './util/compilable.js'
225225
export * from './util/explainable.js'
226226
export * from './util/streamable.js'
227+
export * from './util/executable.js'
227228
export * from './util/log.js'
228229
export {
229230
AnyAliasedColumn,
@@ -240,6 +241,7 @@ export {
240241
export * from './util/infer-result.js'
241242
export { logOnce } from './util/log-once.js'
242243
export { createQueryId, QueryId } from './util/query-id.js'
244+
export * from './util/abort.js'
243245

244246
export {
245247
SelectExpression,

src/kysely.ts

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ import { Dialect } from './dialect/dialect.js'
22
import { SchemaModule } from './schema/schema.js'
33
import { DynamicModule } from './dynamic/dynamic.js'
44
import { DefaultConnectionProvider } from './driver/default-connection-provider.js'
5-
import { QueryExecutor } from './query-executor/query-executor.js'
5+
import {
6+
ExecuteQueryOptions,
7+
QueryExecutor,
8+
} from './query-executor/query-executor.js'
69
import { QueryCreator, QueryCreatorProps } from './query-creator.js'
710
import { KyselyPlugin } from './plugin/kysely-plugin.js'
811
import { DefaultQueryExecutor } from './query-executor/default-query-executor.js'
@@ -48,7 +51,7 @@ import {
4851
provideControlledConnection,
4952
} from './util/provide-controlled-connection.js'
5053
import { ConnectionProvider } from './driver/connection-provider.js'
51-
import { logOnce } from './util/log-once.js'
54+
import { ExecuteOptions } from './util/executable.js'
5255

5356
// @ts-ignore
5457
Symbol.asyncDispose ??= Symbol('Symbol.asyncDispose')
@@ -538,20 +541,13 @@ export class Kysely<DB>
538541
*
539542
* See {@link https://github.com/kysely-org/kysely/blob/master/site/docs/recipes/0004-splitting-query-building-and-execution.md#execute-compiled-queries splitting build, compile and execute code recipe} for more information.
540543
*/
541-
executeQuery<R>(
544+
async executeQuery<R>(
542545
query: CompiledQuery<R> | Compilable<R>,
543-
// TODO: remove this in the future. deprecated in 0.28.x
544-
queryId?: QueryId,
546+
options?: ExecuteOptions,
545547
): Promise<QueryResult<R>> {
546-
if (queryId !== undefined) {
547-
logOnce(
548-
'Passing `queryId` in `db.executeQuery` is deprecated and will result in a compile-time error in the future.',
549-
)
550-
}
551-
552548
const compiledQuery = isCompilable(query) ? query.compile() : query
553549

554-
return this.getExecutor().executeQuery<R>(compiledQuery)
550+
return await this.getExecutor().executeQuery<R>(compiledQuery, options)
555551
}
556552

557553
async [Symbol.asyncDispose]() {
@@ -1177,17 +1173,21 @@ class NotCommittedOrRolledBackAssertingExecutor implements QueryExecutor {
11771173
return this.#executor.provideConnection(consumer)
11781174
}
11791175

1180-
executeQuery<R>(compiledQuery: CompiledQuery<R>): Promise<QueryResult<R>> {
1176+
executeQuery<R>(
1177+
compiledQuery: CompiledQuery<R>,
1178+
options?: ExecuteQueryOptions,
1179+
): Promise<QueryResult<R>> {
11811180
assertNotCommittedOrRolledBack(this.#state)
1182-
return this.#executor.executeQuery(compiledQuery)
1181+
return this.#executor.executeQuery(compiledQuery, options)
11831182
}
11841183

11851184
stream<R>(
11861185
compiledQuery: CompiledQuery<R>,
11871186
chunkSize: number,
1187+
options?: ExecuteQueryOptions,
11881188
): AsyncIterableIterator<QueryResult<R>> {
11891189
assertNotCommittedOrRolledBack(this.#state)
1190-
return this.#executor.stream(compiledQuery, chunkSize)
1190+
return this.#executor.stream(compiledQuery, chunkSize, options)
11911191
}
11921192

11931193
withConnectionProvider(

0 commit comments

Comments
 (0)