import { addExpireAt, ensureIdentifier, } from "../../../src/cosmos/impl/postgresql/PostgresDatabaseImpl"; describe("PostgresDatabaseImpl addExpireAt", () => { const fixedNow = 1_700_000_000_000; beforeEach(() => { jest.spyOn(Date, "now").mockReturnValue(fixedNow); }); afterEach(() => { jest.restoreAllMocks(); }); it("returns undefined when ttl is absent", () => { const data: Record = { id: "id1" }; const expireAt = addExpireAt(data); expect(expireAt).toBeUndefined(); expect(data._expireAt).toBeUndefined(); }); it("returns undefined when ttl is null", () => { const data: Record = { id: "id1", ttl: null }; const expireAt = addExpireAt(data); expect(expireAt).toBeUndefined(); expect(data._expireAt).toBeUndefined(); }); it("returns undefined when ttl is not parsable", () => { const data: Record = { id: "id1", ttl: "invalid" }; const expireAt = addExpireAt(data); expect(expireAt).toBeUndefined(); expect(data._expireAt).toBeUndefined(); }); it("returns undefined when ttl is not a number type", () => { const data: Record = { id: "id1", ttl: BigInt(60) }; const expireAt = addExpireAt(data); expect(expireAt).toBeUndefined(); expect(data._expireAt).toBeUndefined(); }); it("adds expireAt when ttl is an integer", () => { const ttl = 60; const data: Record = { id: "id1", ttl }; const expireAt = addExpireAt(data); expect(expireAt).toEqual(Math.floor(fixedNow / 1000) + ttl); expect(data._expireAt).toEqual(expireAt); }); it("adds expireAt when ttl is zero or negative", () => { const zeroTtl: Record = { id: "zero", ttl: 0 }; const zeroExpire = addExpireAt(zeroTtl); expect(zeroExpire).toEqual(Math.floor(fixedNow / 1000)); expect(zeroTtl._expireAt).toEqual(zeroExpire); const negativeTtl: Record = { id: "negative", ttl: -30 }; const negativeExpire = addExpireAt(negativeTtl); expect(negativeExpire).toEqual(Math.floor(fixedNow / 1000) - 30); expect(negativeTtl._expireAt).toEqual(negativeExpire); }); it("handles large ttl values (30 days and beyond)", () => { const thirtyDays = 30 * 24 * 60 * 60; const data30 = { id: "id30", ttl: thirtyDays }; const expire30 = addExpireAt(data30); expect(expire30).toEqual(Math.floor(fixedNow / 1000) + thirtyDays); const almostIntMax = Math.floor((2147483647 - 1) / 1000); const dataLong = { id: "idLong", ttl: almostIntMax }; const expireLong = addExpireAt(dataLong); expect(expireLong).toEqual(Math.floor(fixedNow / 1000) + almostIntMax); }); }); describe("PostgresDatabaseImpl ensureIdentifier", () => { it("allows identifiers that do not contain invalid characters", () => { expect(() => ensureIdentifier("valid_name-123", "identifier")).not.toThrow(); expect(() => ensureIdentifier("_hiddenTable42", "identifier")).not.toThrow(); }); it("throws when the identifier is empty", () => { expect(() => ensureIdentifier("", "emptyField")).toThrow( "Expected 'emptyField' to be nonempty", ); }); it.each(["bad;name", "bad(name)", "bad&name"])( "throws when identifier contains invalid characters: %s", (badIdentifier) => { expect(() => ensureIdentifier(badIdentifier, "table")).toThrow( `table should not contain invalid characters: ${badIdentifier}`, ); }, ); it("throws when identifier contains new line characters", () => { expect(() => ensureIdentifier("bad\nname", "schema")).toThrow( "schema should not contain invalid characters: bad\nname", ); }); it("throws when identifier contains '--'", () => { expect(() => ensureIdentifier("bad--name", "schema")).toThrow( "schema should not contain '--': bad--name", ); }); });