mirror of
https://github.com/better-auth/better-auth.git
synced 2026-10-19 11:24:57 -05:00
fix(kysely-adapter): report affected rows and insert id from bun/node sqlite dialects
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@better-auth/kysely-adapter": patch
|
||||
---
|
||||
|
||||
`deleteMany` and `updateMany` now return the correct number of affected rows on the `bun:sqlite` and `node:sqlite` dialects, which previously always returned `0`.
|
||||
@@ -2,7 +2,7 @@
|
||||
* @see {@link https://github.com/dylanblokhuis/kysely-bun-sqlite} - Fork of the original kysely-bun-sqlite package by @dylanblokhuis
|
||||
*/
|
||||
|
||||
import type { Database } from "bun:sqlite";
|
||||
import type { Database, SQLQueryBindings } from "bun:sqlite";
|
||||
import type {
|
||||
DatabaseConnection,
|
||||
DatabaseIntrospector,
|
||||
@@ -132,8 +132,21 @@ class BunSqliteConnection implements DatabaseConnection {
|
||||
const { sql, parameters } = compiledQuery;
|
||||
const stmt = this.#db.prepare(sql);
|
||||
|
||||
// SELECT and RETURNING statements expose columns and return rows.
|
||||
// A plain mutation reports its row count and insert id only through run().
|
||||
if (stmt.columnNames.length > 0) {
|
||||
return Promise.resolve({
|
||||
rows: stmt.all(...(parameters as SQLQueryBindings[])) as O[],
|
||||
});
|
||||
}
|
||||
|
||||
const { changes, lastInsertRowid } = stmt.run(
|
||||
...(parameters as SQLQueryBindings[]),
|
||||
);
|
||||
return Promise.resolve({
|
||||
rows: stmt.all(parameters as any) as O[],
|
||||
rows: [],
|
||||
numAffectedRows: changes != null ? BigInt(changes) : undefined,
|
||||
insertId: lastInsertRowid != null ? BigInt(lastInsertRowid) : undefined,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
import { DatabaseSync } from "node:sqlite";
|
||||
import type { Generated } from "kysely";
|
||||
import { Kysely } from "kysely";
|
||||
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
||||
import { NodeSqliteDialect } from "./node-sqlite-dialect";
|
||||
|
||||
interface TestDatabase {
|
||||
item: {
|
||||
id: Generated<number>;
|
||||
name: string;
|
||||
};
|
||||
}
|
||||
|
||||
describe("NodeSqliteDialect", () => {
|
||||
let raw: DatabaseSync;
|
||||
let db: Kysely<TestDatabase>;
|
||||
|
||||
beforeEach(async () => {
|
||||
raw = new DatabaseSync(":memory:");
|
||||
db = new Kysely<TestDatabase>({
|
||||
dialect: new NodeSqliteDialect({ database: raw }),
|
||||
});
|
||||
await db.schema
|
||||
.createTable("item")
|
||||
.addColumn("id", "integer", (col) => col.primaryKey().autoIncrement())
|
||||
.addColumn("name", "text")
|
||||
.execute();
|
||||
await db
|
||||
.insertInto("item")
|
||||
.values([{ name: "a" }, { name: "b" }, { name: "c" }])
|
||||
.execute();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await db.destroy();
|
||||
});
|
||||
|
||||
// A mutation without a RETURNING clause must still report how many rows it
|
||||
// touched. updateMany/deleteMany in the adapter read numUpdatedRows /
|
||||
// numDeletedRows, which Kysely derives from the connection's numAffectedRows
|
||||
// (falling back to 0 when absent). A dialect that drops it silently reports 0.
|
||||
it("reports the number of rows affected by a delete", async () => {
|
||||
const result = await db
|
||||
.deleteFrom("item")
|
||||
.where("name", "in", ["a", "b"])
|
||||
.executeTakeFirst();
|
||||
|
||||
expect(Number(result.numDeletedRows)).toBe(2);
|
||||
});
|
||||
|
||||
it("reports the number of rows affected by an update", async () => {
|
||||
const result = await db
|
||||
.updateTable("item")
|
||||
.set({ name: "z" })
|
||||
.executeTakeFirst();
|
||||
|
||||
expect(Number(result.numUpdatedRows)).toBe(3);
|
||||
});
|
||||
|
||||
it("reports the inserted row id when no RETURNING clause is used", async () => {
|
||||
const result = await db
|
||||
.insertInto("item")
|
||||
.values({ name: "d" })
|
||||
.executeTakeFirst();
|
||||
|
||||
expect(result.insertId).toBeDefined();
|
||||
expect(Number(result.insertId)).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
@@ -2,7 +2,7 @@
|
||||
* @see {@link https://nodejs.org/api/sqlite.html} - Node.js SQLite API documentation
|
||||
*/
|
||||
|
||||
import type { DatabaseSync } from "node:sqlite";
|
||||
import type { DatabaseSync, SQLInputValue } from "node:sqlite";
|
||||
import type {
|
||||
DatabaseConnection,
|
||||
DatabaseIntrospector,
|
||||
@@ -132,10 +132,21 @@ class NodeSqliteConnection implements DatabaseConnection {
|
||||
const { sql, parameters } = compiledQuery;
|
||||
const stmt = this.#db.prepare(sql);
|
||||
|
||||
const rows = stmt.all(...(parameters as any[])) as O[];
|
||||
// SELECT and RETURNING statements expose columns and return rows.
|
||||
// A plain mutation reports its row count and insert id only through run().
|
||||
if (stmt.columns().length > 0) {
|
||||
return Promise.resolve({
|
||||
rows: stmt.all(...(parameters as SQLInputValue[])) as O[],
|
||||
});
|
||||
}
|
||||
|
||||
const { changes, lastInsertRowid } = stmt.run(
|
||||
...(parameters as SQLInputValue[]),
|
||||
);
|
||||
return Promise.resolve({
|
||||
rows,
|
||||
rows: [],
|
||||
numAffectedRows: changes != null ? BigInt(changes) : undefined,
|
||||
insertId: lastInsertRowid != null ? BigInt(lastInsertRowid) : undefined,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -20,8 +20,14 @@ function asBunLikeDatabase(db: DatabaseSync) {
|
||||
prepare(sql: string) {
|
||||
const stmt = db.prepare(sql);
|
||||
return {
|
||||
all(params: SQLInputValue[]) {
|
||||
return stmt.all(...(params ?? []));
|
||||
get columnNames() {
|
||||
return stmt.columns().map((column) => column.name);
|
||||
},
|
||||
all(...params: SQLInputValue[]) {
|
||||
return stmt.all(...params);
|
||||
},
|
||||
run(...params: SQLInputValue[]) {
|
||||
return stmt.run(...params);
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user