mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-16 04:27:21 +00:00
connection: rewrote query execution, batching, added generic sqlite, added node/bun sqlite, aligned repo/mutator results
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { afterAll, describe, expect, test } from "bun:test";
|
||||
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
||||
import type { EventManager } from "../../../src/core/events";
|
||||
import {
|
||||
Entity,
|
||||
@@ -12,11 +12,14 @@ import {
|
||||
TextField,
|
||||
} from "../../../src/data";
|
||||
import * as proto from "../../../src/data/prototype";
|
||||
import { getDummyConnection } from "../helper";
|
||||
import { getDummyConnection, disableConsoleLog, enableConsoleLog } from "../../helper";
|
||||
|
||||
const { dummyConnection, afterAllCleanup } = getDummyConnection();
|
||||
afterAll(afterAllCleanup);
|
||||
|
||||
beforeAll(() => disableConsoleLog(["log", "warn"]));
|
||||
afterAll(async () => (await afterAllCleanup()) && enableConsoleLog());
|
||||
|
||||
describe("[data] Mutator (base)", async () => {
|
||||
const entity = new Entity("items", [
|
||||
new TextField("label", { required: true }),
|
||||
|
||||
@@ -26,120 +26,6 @@ async function sleep(ms: number) {
|
||||
}
|
||||
|
||||
describe("[Repository]", async () => {
|
||||
test.skip("bulk", async () => {
|
||||
//const connection = dummyConnection;
|
||||
//const connection = getLocalLibsqlConnection();
|
||||
const credentials = null as any; // @todo: determine what to do here
|
||||
const connection = new LibsqlConnection(credentials);
|
||||
|
||||
const em = new EntityManager([], connection);
|
||||
/*const emLibsql = new EntityManager([], {
|
||||
url: connection.url.replace("https", "libsql"),
|
||||
authToken: connection.authToken,
|
||||
});*/
|
||||
const table = "posts";
|
||||
|
||||
const client = connection.getClient();
|
||||
if (!client) {
|
||||
console.log("Cannot perform test without libsql connection");
|
||||
return;
|
||||
}
|
||||
|
||||
const conn = em.connection.kysely;
|
||||
const selectQ = (e: E) => e.selectFrom(table).selectAll().limit(2);
|
||||
const countQ = (e: E) => e.selectFrom(table).select(e.fn.count("*").as("count"));
|
||||
|
||||
async function executeTransaction(em: EntityManager<any>) {
|
||||
return await em.connection.kysely.transaction().execute(async (e) => {
|
||||
const res = await selectQ(e).execute();
|
||||
const count = await countQ(e).execute();
|
||||
|
||||
return [res, count];
|
||||
});
|
||||
}
|
||||
|
||||
async function executeBatch(em: EntityManager<any>) {
|
||||
const queries = [selectQ(conn), countQ(conn)];
|
||||
return await em.connection.batchQuery(queries);
|
||||
}
|
||||
|
||||
async function executeSingleKysely(em: EntityManager<any>) {
|
||||
const res = await selectQ(conn).execute();
|
||||
const count = await countQ(conn).execute();
|
||||
return [res, count];
|
||||
}
|
||||
|
||||
async function executeSingleClient(em: EntityManager<any>) {
|
||||
const q1 = selectQ(conn).compile();
|
||||
const res = await client.execute({
|
||||
sql: q1.sql,
|
||||
args: q1.parameters as any,
|
||||
});
|
||||
|
||||
const q2 = countQ(conn).compile();
|
||||
const count = await client.execute({
|
||||
sql: q2.sql,
|
||||
args: q2.parameters as any,
|
||||
});
|
||||
return [res, count];
|
||||
}
|
||||
|
||||
const transaction = await executeTransaction(em);
|
||||
const batch = await executeBatch(em);
|
||||
|
||||
expect(batch).toEqual(transaction as any);
|
||||
|
||||
const testperf = false;
|
||||
if (testperf) {
|
||||
const times = 5;
|
||||
|
||||
const exec = async (
|
||||
name: string,
|
||||
fn: (em: EntityManager<any>) => Promise<any>,
|
||||
em: EntityManager<any>,
|
||||
) => {
|
||||
const res = await Perf.execute(() => fn(em), times);
|
||||
await sleep(1000);
|
||||
const info = {
|
||||
name,
|
||||
total: res.total.toFixed(2),
|
||||
avg: (res.total / times).toFixed(2),
|
||||
first: res.marks[0].time.toFixed(2),
|
||||
last: res.marks[res.marks.length - 1].time.toFixed(2),
|
||||
};
|
||||
console.log(info.name, info, res.marks);
|
||||
return info;
|
||||
};
|
||||
|
||||
const data: any[] = [];
|
||||
data.push(await exec("transaction.http", executeTransaction, em));
|
||||
data.push(await exec("bulk.http", executeBatch, em));
|
||||
data.push(await exec("singleKy.http", executeSingleKysely, em));
|
||||
data.push(await exec("singleCl.http", executeSingleClient, em));
|
||||
|
||||
/*data.push(await exec("transaction.libsql", executeTransaction, emLibsql));
|
||||
data.push(await exec("bulk.libsql", executeBatch, emLibsql));
|
||||
data.push(await exec("singleKy.libsql", executeSingleKysely, emLibsql));
|
||||
data.push(await exec("singleCl.libsql", executeSingleClient, emLibsql));*/
|
||||
|
||||
console.table(data);
|
||||
/**
|
||||
* ┌───┬────────────────────┬────────┬────────┬────────┬────────┐
|
||||
* │ │ name │ total │ avg │ first │ last │
|
||||
* ├───┼────────────────────┼────────┼────────┼────────┼────────┤
|
||||
* │ 0 │ transaction.http │ 681.29 │ 136.26 │ 136.46 │ 396.09 │
|
||||
* │ 1 │ bulk.http │ 164.82 │ 32.96 │ 32.95 │ 99.91 │
|
||||
* │ 2 │ singleKy.http │ 330.01 │ 66.00 │ 65.86 │ 195.41 │
|
||||
* │ 3 │ singleCl.http │ 326.17 │ 65.23 │ 61.32 │ 198.08 │
|
||||
* │ 4 │ transaction.libsql │ 856.79 │ 171.36 │ 132.31 │ 595.24 │
|
||||
* │ 5 │ bulk.libsql │ 180.63 │ 36.13 │ 35.39 │ 107.71 │
|
||||
* │ 6 │ singleKy.libsql │ 347.11 │ 69.42 │ 65.00 │ 207.14 │
|
||||
* │ 7 │ singleCl.libsql │ 328.60 │ 65.72 │ 62.19 │ 195.04 │
|
||||
* └───┴────────────────────┴────────┴────────┴────────┴────────┘
|
||||
*/
|
||||
}
|
||||
});
|
||||
|
||||
test("count & exists", async () => {
|
||||
const items = new Entity("items", [new TextField("label")]);
|
||||
const em = new EntityManager([items], dummyConnection);
|
||||
@@ -160,25 +46,44 @@ describe("[Repository]", async () => {
|
||||
// count all
|
||||
const res = await em.repository(items).count();
|
||||
expect(res.sql).toBe('select count(*) as "count" from "items"');
|
||||
expect(res.count).toBe(3);
|
||||
expect(res.data.count).toBe(3);
|
||||
|
||||
//
|
||||
{
|
||||
const res = await em.repository(items).findMany();
|
||||
expect(res.count).toBeUndefined();
|
||||
}
|
||||
|
||||
{
|
||||
const res = await em
|
||||
.repository(items, {
|
||||
includeCounts: true,
|
||||
})
|
||||
.findMany();
|
||||
expect(res.count).toBe(3);
|
||||
}
|
||||
|
||||
// count filtered
|
||||
const res2 = await em.repository(items).count({ label: { $in: ["a", "b"] } });
|
||||
const res2 = await em
|
||||
.repository(items, {
|
||||
includeCounts: true,
|
||||
})
|
||||
.count({ label: { $in: ["a", "b"] } });
|
||||
|
||||
expect(res2.sql).toBe('select count(*) as "count" from "items" where "label" in (?, ?)');
|
||||
expect(res2.parameters).toEqual(["a", "b"]);
|
||||
expect(res2.count).toBe(2);
|
||||
expect(res2.data.count).toBe(2);
|
||||
|
||||
// check exists
|
||||
const res3 = await em.repository(items).exists({ label: "a" });
|
||||
expect(res3.exists).toBe(true);
|
||||
expect(res3.data.exists).toBe(true);
|
||||
|
||||
const res4 = await em.repository(items).exists({ label: "d" });
|
||||
expect(res4.exists).toBe(false);
|
||||
expect(res4.data.exists).toBe(false);
|
||||
|
||||
// for now, allow empty filter
|
||||
const res5 = await em.repository(items).exists({});
|
||||
expect(res5.exists).toBe(true);
|
||||
expect(res5.data.exists).toBe(true);
|
||||
});
|
||||
|
||||
test("option: silent", async () => {
|
||||
@@ -191,6 +96,9 @@ describe("[Repository]", async () => {
|
||||
// should throw because table doesn't exist
|
||||
expect(em.repo("items").findMany({})).rejects.toThrow(/no such table/);
|
||||
// should silently return empty result
|
||||
em.repo("items", { silent: true })
|
||||
.findMany({})
|
||||
.then((r) => r.data);
|
||||
expect(
|
||||
em
|
||||
.repo("items", { silent: true })
|
||||
@@ -209,16 +117,16 @@ describe("[Repository]", async () => {
|
||||
|
||||
expect(
|
||||
em
|
||||
.repo("items")
|
||||
.repo("items", { includeCounts: true })
|
||||
.findMany({})
|
||||
.then((r) => [r.meta.count, r.meta.total]),
|
||||
.then((r) => [r.count, r.total]),
|
||||
).resolves.toEqual([0, 0]);
|
||||
|
||||
expect(
|
||||
em
|
||||
.repo("items", { includeCounts: false })
|
||||
.findMany({})
|
||||
.then((r) => [r.meta.count, r.meta.total]),
|
||||
.then((r) => [r.count, r.total]),
|
||||
).resolves.toEqual([undefined, undefined]);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user