GET log (engagements and listens, keyset over at/kind/id), listChanges title and intoTitle, listCopies workTitle, all via batched lookups. Co-Authored-By: Claude Opus 5.5 <[email protected]>
96 lines
4.0 KiB
TypeScript
96 lines
4.0 KiB
TypeScript
import { expect, test } from "bun:test";
|
|
import type { Db } from "@sttracker/db/db";
|
|
import { newId, nowIso } from "@sttracker/db/ids";
|
|
import { toJson } from "@sttracker/db/json";
|
|
import { forEachDialect } from "@sttracker/db/testing";
|
|
import { addEngagement } from "../../src/engagements.ts";
|
|
import { upsertEntry } from "../../src/entries.ts";
|
|
import { createList } from "../../src/lists.ts";
|
|
import { listChanges } from "../../src/sync/changes.ts";
|
|
import { makeConnection, makeUser, makeWork } from "./helpers.ts";
|
|
|
|
async function event(
|
|
db: Db,
|
|
userId: string,
|
|
connectionId: string,
|
|
e: { type: "changed" | "removed" | "merged"; targetEntity: string; targetId: string; payload?: Record<string, unknown> },
|
|
): Promise<string> {
|
|
const id = newId();
|
|
await db.k
|
|
.insertInto("change_events")
|
|
.values({
|
|
id,
|
|
user_id: userId,
|
|
connection_id: connectionId,
|
|
run_id: null,
|
|
record_id: null,
|
|
type: e.type,
|
|
target_entity: e.targetEntity,
|
|
target_id: e.targetId,
|
|
payload: toJson(e.payload ?? {}),
|
|
status: "pending",
|
|
created_at: nowIso(),
|
|
})
|
|
.execute();
|
|
return id;
|
|
}
|
|
|
|
async function record(db: Db, connectionId: string, key: string, targetEntity: string, targetId: string): Promise<void> {
|
|
const now = nowIso();
|
|
await db.k
|
|
.insertInto("source_records")
|
|
.values({
|
|
id: newId(),
|
|
connection_id: connectionId,
|
|
key,
|
|
kind: targetEntity,
|
|
current_hash: "h",
|
|
first_seen: now,
|
|
last_seen: now,
|
|
deleted_at: null,
|
|
merged_into_key: null,
|
|
target_entity: targetEntity,
|
|
target_id: targetId,
|
|
})
|
|
.execute();
|
|
}
|
|
|
|
forEachDialect("change titles", (getDb) => {
|
|
test("events carry their target's title, and merged events the merge target's", async () => {
|
|
const db = getDb();
|
|
const userId = await makeUser(db);
|
|
const conn = await makeConnection(db, userId, "hardcover");
|
|
const dune = await upsertEntry(db, userId, await makeWork(db, { title: "Dune" }), { overrides: { title: "Dune (1965)" } }, "user");
|
|
const piranesi = await upsertEntry(db, userId, await makeWork(db, { title: "Piranesi" }), {}, "user");
|
|
const deluxe = await upsertEntry(db, userId, await makeWork(db, { title: "Piranesi (Deluxe)" }), {}, "user");
|
|
const read = await addEngagement(db, userId, piranesi.id, {}, "user");
|
|
const list = await createList(db, userId, { name: "Want to read" });
|
|
await record(db, conn, "b:deluxe", "entry", deluxe.id);
|
|
|
|
const onEntry = await event(db, userId, conn, { type: "changed", targetEntity: "entry", targetId: dune.id, payload: { field: "rating", from: 80, to: 60 } });
|
|
const onRead = await event(db, userId, conn, { type: "removed", targetEntity: "engagement", targetId: read.id });
|
|
const onList = await event(db, userId, conn, { type: "removed", targetEntity: "list", targetId: list.id });
|
|
const merged = await event(db, userId, conn, { type: "merged", targetEntity: "entry", targetId: piranesi.id, payload: { key: "b:p", intoKey: "b:deluxe" } });
|
|
const unknownMerge = await event(db, userId, conn, { type: "merged", targetEntity: "entry", targetId: piranesi.id, payload: { key: "b:p", intoKey: "b:nope" } });
|
|
|
|
const byId = new Map((await listChanges(db, userId)).items.map((c) => [c.id, c]));
|
|
expect(byId.get(onEntry)!.title).toBe("Dune (1965)");
|
|
expect(byId.get(onRead)!.title).toBe("Piranesi");
|
|
expect(byId.get(onList)!.title).toBe("Want to read");
|
|
expect(byId.get(merged)!.title).toBe("Piranesi");
|
|
expect(byId.get(merged)!.intoTitle).toBe("Piranesi (Deluxe)");
|
|
expect(byId.get(unknownMerge)!.intoTitle).toBeNull();
|
|
expect(byId.get(onEntry)!.intoTitle).toBeUndefined();
|
|
});
|
|
|
|
test("a missing target gives a null title", async () => {
|
|
const db = getDb();
|
|
const userId = await makeUser(db);
|
|
const conn = await makeConnection(db, userId, "hardcover");
|
|
const id = await event(db, userId, conn, { type: "removed", targetEntity: "entry", targetId: newId() });
|
|
const [c] = (await listChanges(db, userId)).items;
|
|
expect(c!.id).toBe(id);
|
|
expect(c!.title).toBeNull();
|
|
});
|
|
});
|