refactor: extract findKeyInCacheOrDb to DRY up DB fallback pattern (TDD)
All checks were successful
Build & Deploy to Staging / Build & Deploy to Staging (push) Successful in 20m17s

- New shared helper findKeyInCacheOrDb(column, value) for DB lookups
- Refactored downgradeByCustomer, updateKeyEmail, updateEmailByCustomer,
  and findKeyByCustomerId to use the shared helper
- Eliminated ~60 lines of duplicated SELECT/row-mapping code
- 3 TDD tests added (keys-db-fallback-helper.test.ts)
- 636 tests passing, 0 tsc errors
This commit is contained in:
DocFast CEO 2026-03-10 14:06:44 +01:00
parent 4e00feb860
commit 25cb5e2e94
2 changed files with 103 additions and 64 deletions

View file

@ -0,0 +1,68 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
vi.unmock("../services/keys.js");
// The DB mock is set up in setup.ts — we need to control queryWithRetry
const mockQueryWithRetry = vi.fn();
vi.mock("../services/db.js", () => ({
default: { query: vi.fn(), end: vi.fn() },
pool: { query: vi.fn(), end: vi.fn() },
queryWithRetry: (...args: unknown[]) => mockQueryWithRetry(...args),
connectWithRetry: vi.fn(),
initDatabase: vi.fn(),
cleanupStaleData: vi.fn(),
}));
import { findKeyInCacheOrDb } from "../services/keys.js";
describe("findKeyInCacheOrDb", () => {
beforeEach(() => {
mockQueryWithRetry.mockReset();
});
it("returns null when DB finds no row", async () => {
mockQueryWithRetry.mockResolvedValue({ rows: [] });
const result = await findKeyInCacheOrDb("stripe_customer_id", "cus_nonexistent");
expect(result).toBeNull();
expect(mockQueryWithRetry).toHaveBeenCalledWith(
expect.stringContaining("WHERE stripe_customer_id = $1"),
["cus_nonexistent"]
);
});
it("returns ApiKey when DB finds a row", async () => {
mockQueryWithRetry.mockResolvedValue({
rows: [{
key: "df_pro_abc",
tier: "pro",
email: "test@example.com",
created_at: "2026-01-01T00:00:00.000Z",
stripe_customer_id: "cus_123",
}],
});
const result = await findKeyInCacheOrDb("stripe_customer_id", "cus_123");
expect(result).toEqual({
key: "df_pro_abc",
tier: "pro",
email: "test@example.com",
createdAt: "2026-01-01T00:00:00.000Z",
stripeCustomerId: "cus_123",
});
});
it("handles Date objects in created_at", async () => {
mockQueryWithRetry.mockResolvedValue({
rows: [{
key: "df_pro_abc",
tier: "pro",
email: "test@example.com",
created_at: new Date("2026-01-01T00:00:00.000Z"),
stripe_customer_id: null,
}],
});
const result = await findKeyInCacheOrDb("key", "df_pro_abc");
expect(result).not.toBeNull();
expect(result!.createdAt).toBe("2026-01-01T00:00:00.000Z");
expect(result!.stripeCustomerId).toBeUndefined();
});
});