Skip to content

Commit 0870b6d

Browse files
committed
fix(state-pg): add changeset and tighten setIfNotExists expiry test
1 parent 0768137 commit 0870b6d

2 files changed

Lines changed: 7 additions & 12 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@chat-adapter/state-pg": patch
3+
---
4+
5+
Fix `setIfNotExists()` so it can claim a cache key whose existing row has expired. Previously the query used `ON CONFLICT DO NOTHING`, so an expired row in `chat_state_cache` still blocked acquisition until opportunistic cleanup deleted it — diverging from the memory and Redis adapters, which treat expired entries as absent. Keys stored without a TTL remain permanent and are never overwritten.

packages/state-pg/src/index.test.ts

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -446,21 +446,11 @@ describe("PostgresStateAdapter", () => {
446446
expect(result).toBe(true);
447447
expect(pool.query).toHaveBeenCalledWith(
448448
expect.stringContaining(
449-
"ON CONFLICT (key_prefix, cache_key) DO UPDATE"
449+
`WHERE chat_state_cache.expires_at IS NOT NULL
450+
AND chat_state_cache.expires_at <= now()`
450451
),
451452
["chat-sdk", "key", '"value"', expect.any(Date)]
452453
);
453-
454-
const calls = (pool.query as ReturnType<typeof vi.fn>).mock.calls;
455-
const setIfNotExistsCall = calls.find(
456-
(c: unknown[]) =>
457-
typeof c[0] === "string" &&
458-
c[0].includes("INSERT INTO chat_state_cache") &&
459-
c[0].includes("WHERE chat_state_cache.expires_at IS NOT NULL") &&
460-
c[0].includes("chat_state_cache.expires_at <= now()")
461-
);
462-
463-
expect(setIfNotExistsCall).toBeTruthy();
464454
});
465455

466456
it("should delete a value without throwing", async () => {

0 commit comments

Comments
 (0)