test: expand native sqlite Kysely coverage

Expand the native node:sqlite Kysely dialect tests for connection setup, insert metadata, transaction/savepoint behavior, and streaming.
This commit is contained in:
Peter Steinberger
2026-05-07 13:18:29 +01:00
committed by GitHub
parent 955b025697
commit be33b68fd4

View File

@@ -1,6 +1,6 @@
import { DatabaseSync } from "node:sqlite";
import { Kysely, sql, type Generated } from "kysely";
import { afterEach, describe, expect, it } from "vitest";
import { CompiledQuery, Kysely, sql, type Generated } from "kysely";
import { afterEach, describe, expect, it, vi } from "vitest";
import { NodeSqliteKyselyDialect } from "./kysely-node-sqlite.js";
type TestDatabase = {
@@ -19,19 +19,7 @@ describe("NodeSqliteKyselyDialect", () => {
});
it("uses node:sqlite with raw row-returning queries and returning clauses", async () => {
db = new Kysely<TestDatabase>({
dialect: new NodeSqliteKyselyDialect({
database: new DatabaseSync(":memory:"),
}),
});
await db.schema
.createTable("person")
.addColumn("id", "integer", (col) => col.primaryKey().autoIncrement())
.addColumn("name", "text", (col) => col.notNull())
.execute();
await db.insertInto("person").values({ name: "Ada" }).execute();
db = await createTestDb();
await expect(db.selectFrom("person").selectAll().execute()).resolves.toEqual([
{ id: 1, name: "Ada" },
@@ -60,4 +48,124 @@ describe("NodeSqliteKyselyDialect", () => {
expect(update.insertId).toBeUndefined();
expect(update.numAffectedRows).toBe(1n);
});
it("creates the database lazily and runs the connection hook once", async () => {
const sqlite = new DatabaseSync(":memory:");
const createDatabase = vi.fn(() => sqlite);
const onCreateConnection = vi.fn(async (connection) => {
await connection.executeQuery(CompiledQuery.raw("pragma user_version = 7"));
});
db = new Kysely<TestDatabase>({
dialect: new NodeSqliteKyselyDialect({
database: createDatabase,
onCreateConnection,
}),
});
await expect(
sql<{ user_version: number }>`pragma user_version`.execute(db),
).resolves.toMatchObject({
rows: [{ user_version: 7 }],
});
expect(createDatabase).toHaveBeenCalledTimes(1);
expect(onCreateConnection).toHaveBeenCalledTimes(1);
});
it("returns insert metadata only for changed insert statements", async () => {
db = new Kysely<TestDatabase>({
dialect: new NodeSqliteKyselyDialect({
database: new DatabaseSync(":memory:"),
}),
});
await createPersonTable(db);
const insertResult = await db
.insertInto("person")
.values({ name: "Ada" })
.executeTakeFirstOrThrow();
expect(insertResult.insertId).toBe(1n);
expect(insertResult.numInsertedOrUpdatedRows).toBe(1n);
const updateResult = await db
.updateTable("person")
.set({ name: "Ada Lovelace" })
.where("id", "=", 1)
.executeTakeFirstOrThrow();
expect(updateResult.numUpdatedRows).toBe(1n);
const ignoredInsert = await sql`
insert or ignore into person (id, name) values (${1}, ${"Ada Again"})
`.execute(db);
expect(ignoredInsert.insertId).toBeUndefined();
expect(ignoredInsert.numAffectedRows).toBe(0n);
});
it("rolls back transactions and controlled savepoints", async () => {
db = new Kysely<TestDatabase>({
dialect: new NodeSqliteKyselyDialect({
database: new DatabaseSync(":memory:"),
}),
});
await createPersonTable(db);
await expect(
db.transaction().execute(async (trx) => {
await trx.insertInto("person").values({ name: "Rollback" }).execute();
throw new Error("rollback outer");
}),
).rejects.toThrow("rollback outer");
await expect(db.selectFrom("person").selectAll().execute()).resolves.toEqual([]);
const trx = await db.startTransaction().execute();
await trx.insertInto("person").values({ name: "Ada" }).execute();
const afterAda = await trx.savepoint("after_ada").execute();
await afterAda.insertInto("person").values({ name: "Grace" }).execute();
const afterRollback = await afterAda.rollbackToSavepoint("after_ada").execute();
await afterRollback.insertInto("person").values({ name: "Lin" }).execute();
await afterRollback.commit().execute();
await expect(db.selectFrom("person").select("name").orderBy("id").execute()).resolves.toEqual([
{ name: "Ada" },
{ name: "Lin" },
]);
});
it("streams selected rows through node:sqlite iteration", async () => {
db = await createTestDb();
await db
.insertInto("person")
.values([{ name: "Grace" }, { name: "Lin" }])
.execute();
const rows: Array<{ id: number; name: string }> = [];
for await (const row of db.selectFrom("person").selectAll().orderBy("id").stream(1)) {
rows.push(row);
}
expect(rows).toEqual([
{ id: 1, name: "Ada" },
{ id: 2, name: "Grace" },
{ id: 3, name: "Lin" },
]);
});
});
async function createTestDb(): Promise<Kysely<TestDatabase>> {
const testDb = new Kysely<TestDatabase>({
dialect: new NodeSqliteKyselyDialect({
database: new DatabaseSync(":memory:"),
}),
});
await createPersonTable(testDb);
await testDb.insertInto("person").values({ name: "Ada" }).execute();
return testDb;
}
async function createPersonTable(testDb: Kysely<TestDatabase>): Promise<void> {
await testDb.schema
.createTable("person")
.addColumn("id", "integer", (col) => col.primaryKey().autoIncrement())
.addColumn("name", "text", (col) => col.notNull())
.execute();
}