import knex, { Knex } from "knex"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; import { BatchCacheManager } from "./batch-cache-manager.js"; import { ERPObjType } from "../../types/erp-types.js"; function woOp(fields: Record) { return { ...fields, toRESTApiObject: () => ({ ...fields }), } as unknown as object; } const BASE = { workOrderId: "J1", lot: "", split: "", sub: "" }; async function createSchema(db: Knex): Promise { await db.schema.createTable("sdk_cache", (table) => { table.increments("id"); table.string("type").notNullable().index(); table.string("entity_key").notNullable(); table.string("content_hash").notNullable(); table.bigInteger("updated_at").notNullable(); table.unique(["type", "entity_key"]); }); } describe("BatchCacheManager per-entity dedupe", () => { let db: Knex; let batch: BatchCacheManager; beforeEach(async () => { db = knex({ client: "better-sqlite3", connection: { filename: ":memory:" }, useNullAsDefault: true, }); await createSchema(db); batch = new BatchCacheManager({ ttl: 3600, db }); }); afterEach(async () => { await batch.destroy(); await db.destroy(); }); it("splits a batch into changed (non-duplicate) and unchanged (duplicate) records", async () => { const op10 = woOp({ ...BASE, sequenceNumber: "10", status: "RELEASED" }); const op20 = woOp({ ...BASE, sequenceNumber: "20", status: "RELEASED" }); // Prime op10 into the cache; op20 is new. await batch.storeBatch(ERPObjType.WORK_ORDER_OPERATIONS, [op10]); const { duplicates, nonDuplicates } = await batch.dedupeBatch( ERPObjType.WORK_ORDER_OPERATIONS, [op10, op20] ); expect(duplicates).toEqual([op10]); expect(nonDuplicates).toEqual([op20]); }); it("re-flags a record after its content changed and back (oscillation) across store cycles", async () => { const released = woOp({ ...BASE, sequenceNumber: "10", status: "RELEASED" }); const completed = woOp({ ...BASE, sequenceNumber: "10", status: "COMPLETED", }); await batch.storeBatch(ERPObjType.WORK_ORDER_OPERATIONS, [released]); await batch.storeBatch(ERPObjType.WORK_ORDER_OPERATIONS, [completed]); const { nonDuplicates } = await batch.dedupeBatch( ERPObjType.WORK_ORDER_OPERATIONS, [released] ); // released differs from the last stored content (completed) -> not a duplicate. expect(nonDuplicates).toEqual([released]); }); });