Skip to content

Commit ebe8d1b

Browse files
committed
Add getLastChanges().
1 parent 02c4c5b commit ebe8d1b

File tree

6 files changed

+85
-23
lines changed

6 files changed

+85
-23
lines changed

packages/better-sqlite3-driver/src/sync-driver.ts

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
SqliteDriverConnectionPool,
66
SqliteDriverStatement,
77
SqliteParameterBinding,
8-
SqliteRunResult,
8+
SqliteChanges,
99
SqliteStepResult,
1010
SqliteValue,
1111
StepOptions,
@@ -35,7 +35,7 @@ import { BetterSqliteDriverOptions } from './driver.js';
3535
interface InternalStatement extends SqliteDriverStatement {
3636
getColumnsSync(): string[];
3737
stepSync(n?: number, options?: StepOptions): SqliteStepResult;
38-
runSync(options?: StepOptions): SqliteRunResult;
38+
runSync(options?: StepOptions): SqliteChanges;
3939

4040
readonly source: string;
4141

@@ -63,7 +63,7 @@ class ErrorStatement implements InternalStatement {
6363
stepSync(n?: number, options?: StepOptions): SqliteStepResult {
6464
throw this.error;
6565
}
66-
runSync(options?: StepOptions): SqliteRunResult {
66+
runSync(options?: StepOptions): SqliteChanges {
6767
throw this.error;
6868
}
6969
async getColumns(): Promise<string[]> {
@@ -76,7 +76,7 @@ class ErrorStatement implements InternalStatement {
7676
throw this.error;
7777
}
7878

79-
async run(options?: StepOptions): Promise<SqliteRunResult> {
79+
async run(options?: StepOptions): Promise<SqliteChanges> {
8080
throw this.error;
8181
}
8282

@@ -167,15 +167,15 @@ class BetterSqlitePreparedStatement implements InternalStatement {
167167
}
168168
}
169169

170-
async run(options?: StepOptions): Promise<SqliteRunResult> {
170+
async run(options?: StepOptions): Promise<SqliteChanges> {
171171
try {
172172
return this.runSync(options);
173173
} catch (e) {
174174
throw mapError(e);
175175
}
176176
}
177177

178-
runSync(options?: StepOptions): SqliteRunResult {
178+
runSync(options?: StepOptions): SqliteChanges {
179179
if (options?.requireTransaction) {
180180
if (!this.statement.database.inTransaction) {
181181
throw new Error('Transaction has been rolled back');
@@ -274,6 +274,8 @@ export class BetterSqliteConnection implements SqliteDriverConnection {
274274
con: bsqlite.Database;
275275
private statements = new Map<number, InternalStatement>();
276276

277+
private changeStatement: bsqlite.Statement;
278+
277279
static open(
278280
path: string,
279281
options?: bsqlite.Options & BetterSqliteDriverOptions
@@ -292,6 +294,23 @@ export class BetterSqliteConnection implements SqliteDriverConnection {
292294

293295
constructor(con: bsqlite.Database) {
294296
this.con = con;
297+
298+
this.changeStatement = this.con.prepare(
299+
'select last_insert_rowid() as l, changes() as c'
300+
);
301+
this.changeStatement.safeIntegers(true);
302+
}
303+
304+
async getLastChanges(): Promise<SqliteChanges> {
305+
return this._getLastChangesSync();
306+
}
307+
308+
_getLastChangesSync(): SqliteChanges {
309+
const r = this.changeStatement.get() as any;
310+
return {
311+
lastInsertRowId: r!.l,
312+
changes: Number(r!.c)
313+
};
295314
}
296315

297316
async close() {
@@ -358,7 +377,7 @@ export class BetterSqliteConnection implements SqliteDriverConnection {
358377
return statement.stepSync(n, { requireTransaction });
359378
}
360379

361-
private _run(command: SqliteRun): SqliteRunResult {
380+
private _run(command: SqliteRun): SqliteChanges {
362381
const { id, requireTransaction } = command;
363382
const statement = this.requireStatement(id);
364383
return statement.runSync({ requireTransaction });
@@ -396,6 +415,8 @@ export class BetterSqliteConnection implements SqliteDriverConnection {
396415
return this._finalize(command);
397416
case SqliteCommandType.parse:
398417
return this._parse(command);
418+
case SqliteCommandType.changes:
419+
return this._getLastChangesSync();
399420
default:
400421
throw new Error(`Unknown command: ${command.type}`);
401422
}

packages/driver-tests/src/driver-tests.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,11 @@ export function describeDriverTests(
106106

107107
expect(rows).toEqual([{ id: 1 }]);
108108

109+
expect(await connection.connection.getLastChanges()).toEqual({
110+
changes: 1,
111+
lastInsertRowId: 1n
112+
});
113+
109114
if (features.getColumns) {
110115
const columns = await s2.getColumns();
111116
expect(columns).toEqual(['id']);

packages/driver/src/driver-api.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ export interface SqliteDriverConnection {
3232
options?: { tables?: string[]; batchLimit?: number }
3333
): () => void;
3434

35+
getLastChanges(): Promise<SqliteChanges>;
36+
3537
close(): Promise<void>;
3638
}
3739

@@ -59,7 +61,7 @@ export interface SqliteDriverStatement {
5961
*
6062
* Avoids the need to use a separate statement to get changes.
6163
*/
62-
run(options?: StepOptions): Promise<SqliteRunResult>;
64+
run(options?: StepOptions): Promise<SqliteChanges>;
6365

6466
[Symbol.dispose](): void;
6567
}
@@ -117,7 +119,7 @@ export interface ReserveConnectionOptions {
117119
signal?: AbortSignal;
118120
}
119121

120-
export interface SqliteRunResult {
122+
export interface SqliteChanges {
121123
changes: number;
122124
lastInsertRowId: bigint;
123125
}

packages/driver/src/node/impl.ts

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
SqliteDriverStatement,
99
SqliteParameterBinding,
1010
SqliteRow,
11-
SqliteRunResult,
11+
SqliteChanges,
1212
SqliteStepResult,
1313
SqliteValue,
1414
StepOptions,
@@ -49,7 +49,7 @@ export function nodeSqlitePool(path: string): SqliteDriverConnectionPool {
4949
interface InternalStatement extends SqliteDriverStatement {
5050
getColumnsSync(): string[];
5151
stepSync(n?: number, options?: StepOptions): SqliteStepResult;
52-
runSync(options?: StepOptions): SqliteRunResult;
52+
runSync(options?: StepOptions): SqliteChanges;
5353

5454
readonly source: string;
5555

@@ -87,11 +87,11 @@ class ErrorStatement implements InternalStatement {
8787
throw this.error;
8888
}
8989

90-
runSync(options?: StepOptions): SqliteRunResult {
90+
runSync(options?: StepOptions): SqliteChanges {
9191
throw this.error;
9292
}
9393

94-
async run(options?: StepOptions): Promise<SqliteRunResult> {
94+
async run(options?: StepOptions): Promise<SqliteChanges> {
9595
throw this.error;
9696
}
9797

@@ -168,15 +168,15 @@ class NodeSqliteSyncStatement implements InternalStatement {
168168
}
169169
}
170170

171-
async run(options?: StepOptions): Promise<SqliteRunResult> {
171+
async run(options?: StepOptions): Promise<SqliteChanges> {
172172
try {
173173
return this.runSync(options);
174174
} catch (e) {
175175
throw mapError(e);
176176
}
177177
}
178178

179-
runSync(options?: StepOptions): SqliteRunResult {
179+
runSync(options?: StepOptions): SqliteChanges {
180180
if (options?.requireTransaction) {
181181
// TODO: Implement
182182
}
@@ -270,6 +270,8 @@ export class NodeSqliteConnection implements SqliteDriverConnection {
270270
statements = new Map<number, InternalStatement>();
271271
name: string;
272272

273+
changeStatement: sqlite.StatementSync;
274+
273275
constructor(
274276
db: sqlite.DatabaseSync,
275277
options?: { readonly?: boolean; name?: string }
@@ -282,6 +284,22 @@ export class NodeSqliteConnection implements SqliteDriverConnection {
282284
this.con.exec('PRAGMA query_only = true');
283285
}
284286
this.name = options?.name ?? '';
287+
this.changeStatement = this.con.prepare(
288+
'select last_insert_rowid() as l, changes() as c'
289+
);
290+
this.changeStatement.setReadBigInts(true);
291+
}
292+
293+
async getLastChanges(): Promise<SqliteChanges> {
294+
return this._getLastChangesSync();
295+
}
296+
297+
_getLastChangesSync(): SqliteChanges {
298+
const r = this.changeStatement.get() as any;
299+
return {
300+
lastInsertRowId: r!.l,
301+
changes: Number(r!.c)
302+
};
285303
}
286304

287305
async close() {
@@ -349,7 +367,7 @@ export class NodeSqliteConnection implements SqliteDriverConnection {
349367
return statement.stepSync(n, { requireTransaction });
350368
}
351369

352-
private _run(command: SqliteRun): SqliteRunResult {
370+
private _run(command: SqliteRun): SqliteChanges {
353371
const { id } = command;
354372
const statement = this.requireStatement(id);
355373
return statement.runSync(command);
@@ -384,6 +402,8 @@ export class NodeSqliteConnection implements SqliteDriverConnection {
384402
return this._finalize(command);
385403
case SqliteCommandType.parse:
386404
return this._parse(command);
405+
case SqliteCommandType.changes:
406+
return this._getLastChangesSync();
387407
default:
388408
throw new Error(`Unknown command: ${command.type}`);
389409
}

packages/driver/src/worker_threads/async-commands.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {
22
SqliteParameterBinding,
3-
SqliteRunResult,
3+
SqliteChanges,
44
SqliteStepResult
55
} from '../driver-api.js';
66
import { SerializedDriverError } from '../sqlite-error.js';
@@ -13,7 +13,8 @@ export enum SqliteCommandType {
1313
finalize = 5,
1414
sync = 6,
1515
parse = 7,
16-
run = 8
16+
run = 8,
17+
changes = 9
1718
}
1819

1920
export type SqliteDriverError = SerializedDriverError;
@@ -84,6 +85,10 @@ export interface SqliteSync {
8485
type: SqliteCommandType.sync;
8586
}
8687

88+
export interface SqliteGetChanges {
89+
type: SqliteCommandType.changes;
90+
}
91+
8792
export type SqliteCommand =
8893
| SqlitePrepare
8994
| SqliteBind
@@ -92,15 +97,18 @@ export type SqliteCommand =
9297
| SqliteReset
9398
| SqliteFinalize
9499
| SqliteSync
95-
| SqliteParse;
100+
| SqliteParse
101+
| SqliteGetChanges;
96102

97103
export type InferCommandResult<T extends SqliteCommand> = T extends SqliteRun
98-
? SqliteRunResult
104+
? SqliteChanges
99105
: T extends SqliteStep
100106
? SqliteStepResult
101107
: T extends SqliteParse
102108
? SqliteParseResult
103-
: void;
109+
: T extends SqliteGetChanges
110+
? SqliteChanges
111+
: void;
104112

105113
export type InferBatchResult<T extends SqliteCommand[]> = {
106114
[i in keyof T]:

packages/driver/src/worker_threads/worker-driver.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
SqliteDriverConnection,
66
SqliteDriverStatement,
77
SqliteParameterBinding,
8-
SqliteRunResult,
8+
SqliteChanges,
99
SqliteStepResult,
1010
StepOptions,
1111
UpdateListener
@@ -87,6 +87,12 @@ export class WorkerDriverConnection implements SqliteDriverConnection {
8787
return new WorkerDriverStatement(this, id);
8888
}
8989

90+
async getLastChanges(): Promise<SqliteChanges> {
91+
return await this._push({
92+
type: SqliteCommandType.changes
93+
});
94+
}
95+
9096
async sync(): Promise<void> {
9197
await this._push({
9298
type: SqliteCommandType.sync
@@ -227,7 +233,7 @@ class WorkerDriverStatement implements SqliteDriverStatement {
227233
});
228234
}
229235

230-
async run(options?: StepOptions): Promise<SqliteRunResult> {
236+
async run(options?: StepOptions): Promise<SqliteChanges> {
231237
return this.driver._push({
232238
type: SqliteCommandType.run,
233239
id: this.id,

0 commit comments

Comments
 (0)