mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-16 12:37:20 +00:00
256 lines
8.1 KiB
TypeScript
256 lines
8.1 KiB
TypeScript
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
import type { Kysely, Transaction } from "kysely";
|
|
import { TextField } from "data/fields";
|
|
import { em as $em, entity as $entity, text as $text } from "data/prototype";
|
|
import { Entity, EntityManager } from "data/entities";
|
|
import { ManyToOneRelation } from "data/relations";
|
|
import { RepositoryEvents } from "data/events";
|
|
import { getDummyConnection } from "../helper";
|
|
import { disableConsoleLog, enableConsoleLog } from "core/utils/test";
|
|
|
|
type E = Kysely<any> | Transaction<any>;
|
|
|
|
const { dummyConnection, afterAllCleanup } = getDummyConnection();
|
|
beforeAll(() => disableConsoleLog());
|
|
afterAll(async () => (await afterAllCleanup()) && enableConsoleLog());
|
|
|
|
async function sleep(ms: number) {
|
|
return new Promise((resolve) => {
|
|
setTimeout(resolve, ms);
|
|
});
|
|
}
|
|
|
|
describe("[Repository]", async () => {
|
|
test("count & exists", async () => {
|
|
const items = new Entity("items", [new TextField("label")]);
|
|
const em = new EntityManager([items], dummyConnection);
|
|
|
|
await em.connection.kysely.schema
|
|
.createTable("items")
|
|
.ifNotExists()
|
|
.addColumn("id", "integer", (col) => col.primaryKey().autoIncrement().notNull())
|
|
.addColumn("label", "text")
|
|
.execute();
|
|
|
|
// fill
|
|
await em.connection.kysely
|
|
.insertInto("items")
|
|
.values([{ label: "a" }, { label: "b" }, { label: "c" }])
|
|
.execute();
|
|
|
|
// count all
|
|
const res = await em.repository(items).count();
|
|
expect(res.sql).toBe('select count(*) as "count" from "items"');
|
|
expect(res.data.count).toBe(3);
|
|
|
|
//
|
|
{
|
|
const res = await em.repository(items).findMany();
|
|
expect(res.count).toBe(3);
|
|
}
|
|
|
|
{
|
|
const res = await em
|
|
.repository(items, {
|
|
includeCounts: true,
|
|
})
|
|
.findMany();
|
|
expect(res.count).toBe(3);
|
|
}
|
|
|
|
// count filtered
|
|
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.data.count).toBe(2);
|
|
|
|
// check exists
|
|
const res3 = await em.repository(items).exists({ label: "a" });
|
|
expect(res3.data.exists).toBe(true);
|
|
|
|
const res4 = await em.repository(items).exists({ label: "d" });
|
|
expect(res4.data.exists).toBe(false);
|
|
|
|
// for now, allow empty filter
|
|
const res5 = await em.repository(items).exists({});
|
|
expect(res5.data.exists).toBe(true);
|
|
});
|
|
|
|
test("option: silent", async () => {
|
|
const em = $em({
|
|
items: $entity("items", {
|
|
label: $text(),
|
|
}),
|
|
}).proto.withConnection(getDummyConnection().dummyConnection);
|
|
|
|
// 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 })
|
|
.findMany({})
|
|
.then((r) => r.data),
|
|
).resolves.toEqual([]);
|
|
});
|
|
|
|
test("option: includeCounts", async () => {
|
|
const em = $em({
|
|
items: $entity("items", {
|
|
label: $text(),
|
|
}),
|
|
}).proto.withConnection(getDummyConnection().dummyConnection);
|
|
await em.schema().sync({ force: true });
|
|
|
|
expect(
|
|
em
|
|
.repo("items", { includeCounts: true })
|
|
.findMany({})
|
|
.then((r) => [r.count, r.total]),
|
|
).resolves.toEqual([0, 0]);
|
|
|
|
expect(
|
|
em
|
|
.repo("items", { includeCounts: false })
|
|
.findMany({})
|
|
.then((r) => [r.count, r.total]),
|
|
).resolves.toEqual([undefined, undefined]);
|
|
});
|
|
|
|
test("auto join", async () => {
|
|
const schema = $em(
|
|
{
|
|
posts: $entity("posts", {
|
|
title: $text(),
|
|
content: $text(),
|
|
}),
|
|
comments: $entity("comments", {
|
|
content: $text(),
|
|
}),
|
|
another: $entity("another", {
|
|
title: $text(),
|
|
}),
|
|
},
|
|
({ relation }, { posts, comments }) => {
|
|
relation(comments).manyToOne(posts);
|
|
},
|
|
);
|
|
const em = schema.proto.withConnection(getDummyConnection().dummyConnection);
|
|
await em.schema().sync({ force: true });
|
|
|
|
await em.mutator("posts").insertOne({ title: "post1", content: "content1" });
|
|
await em
|
|
.mutator("comments")
|
|
.insertMany([{ content: "comment1", posts_id: 1 }, { content: "comment2" }] as any);
|
|
|
|
const res = await em.repo("comments").findMany({
|
|
where: {
|
|
"posts.title": "post1",
|
|
},
|
|
});
|
|
expect(res.data as any).toEqual([
|
|
{
|
|
id: 1,
|
|
content: "comment1",
|
|
posts_id: 1,
|
|
},
|
|
]);
|
|
|
|
{
|
|
// manual join should still work
|
|
const res = await em.repo("comments").findMany({
|
|
join: ["posts"],
|
|
where: {
|
|
"posts.title": "post1",
|
|
},
|
|
});
|
|
expect(res.data as any).toEqual([
|
|
{
|
|
id: 1,
|
|
content: "comment1",
|
|
posts_id: 1,
|
|
},
|
|
]);
|
|
}
|
|
|
|
// inexistent should be detected and thrown
|
|
expect(
|
|
em.repo("comments").findMany({
|
|
where: {
|
|
"random.title": "post1",
|
|
},
|
|
}),
|
|
).rejects.toThrow(/Invalid where field/);
|
|
|
|
// existing alias, but not a relation should throw
|
|
expect(
|
|
em.repo("comments").findMany({
|
|
where: {
|
|
"another.title": "post1",
|
|
},
|
|
}),
|
|
).rejects.toThrow(/Invalid where field/);
|
|
});
|
|
});
|
|
|
|
describe("[data] Repository (Events)", async () => {
|
|
const items = new Entity("items", [new TextField("label")]);
|
|
const categories = new Entity("categories", [new TextField("label")]);
|
|
const em = new EntityManager([items, categories], dummyConnection, [
|
|
new ManyToOneRelation(categories, items),
|
|
]);
|
|
await em.schema().sync({ force: true });
|
|
const events = new Map<string, any>();
|
|
|
|
em.repository(items).emgr.onAny((event) => {
|
|
// @ts-ignore
|
|
events.set(event.constructor.slug, event);
|
|
});
|
|
em.repository(categories).emgr.onAny((event) => {
|
|
// @ts-ignore
|
|
events.set(event.constructor.slug, event);
|
|
});
|
|
|
|
test("events were fired", async () => {
|
|
const repo = em.repository(items);
|
|
await repo.findId(1);
|
|
await repo.emgr.executeAsyncs();
|
|
expect(events.has(RepositoryEvents.RepositoryFindOneBefore.slug)).toBeTrue();
|
|
expect(events.has(RepositoryEvents.RepositoryFindOneAfter.slug)).toBeTrue();
|
|
events.clear();
|
|
|
|
await repo.findOne({ id: 1 });
|
|
await repo.emgr.executeAsyncs();
|
|
expect(events.has(RepositoryEvents.RepositoryFindOneBefore.slug)).toBeTrue();
|
|
expect(events.has(RepositoryEvents.RepositoryFindOneAfter.slug)).toBeTrue();
|
|
events.clear();
|
|
|
|
await repo.findMany({ where: { id: 1 } });
|
|
await repo.emgr.executeAsyncs();
|
|
expect(events.has(RepositoryEvents.RepositoryFindManyBefore.slug)).toBeTrue();
|
|
expect(events.has(RepositoryEvents.RepositoryFindManyAfter.slug)).toBeTrue();
|
|
events.clear();
|
|
|
|
await repo.findManyByReference(1, "categories");
|
|
await repo.emgr.executeAsyncs();
|
|
expect(events.has(RepositoryEvents.RepositoryFindManyBefore.slug)).toBeTrue();
|
|
expect(events.has(RepositoryEvents.RepositoryFindManyAfter.slug)).toBeTrue();
|
|
events.clear();
|
|
|
|
// check find one on findMany with limit 1
|
|
await repo.findMany({ where: { id: 1 }, limit: 1 });
|
|
await repo.emgr.executeAsyncs();
|
|
expect(events.has(RepositoryEvents.RepositoryFindOneBefore.slug)).toBeTrue();
|
|
expect(events.has(RepositoryEvents.RepositoryFindOneAfter.slug)).toBeTrue();
|
|
events.clear();
|
|
});
|
|
});
|