Refactor database interactions to use Drizzle ORM
- Replaced direct SQLite database calls with Drizzle ORM methods in `top-monthly-sold-by-category.ts`, `writer.ts`, and `upc-file-analysis.ts`. - Updated test cases in `top-monthly-sold-by-category.test.ts` to mock the new database interactions. - Removed unnecessary database initialization and cleanup code. - Improved code readability and maintainability by using ORM features for inserting and updating records.
This commit is contained in:
@@ -1,8 +1,41 @@
|
||||
import { test, expect, beforeAll, afterAll, beforeEach, mock } from "bun:test";
|
||||
import { Database } from "bun:sqlite";
|
||||
import { getDb, initDb, closeDb } from "./database.ts";
|
||||
import path from "node:path";
|
||||
import { rmSync, mkdirSync } from "node:fs";
|
||||
import { test, expect, beforeEach, mock } from "bun:test";
|
||||
|
||||
let nextId = 0;
|
||||
|
||||
function chainable(resolveWith: any[] = []): any {
|
||||
const p: any = Promise.resolve(resolveWith);
|
||||
p.limit = (_n: any) => chainable(resolveWith);
|
||||
p.where = (_cond: any) => chainable(resolveWith);
|
||||
p.from = (_table: any) => chainable(resolveWith);
|
||||
return p;
|
||||
}
|
||||
|
||||
const makeMockDb = (): any => ({
|
||||
insert: (_table: any) => ({
|
||||
values: (_vals: any) => ({
|
||||
returning: (_sel: any) => Promise.resolve([{ id: ++nextId }]),
|
||||
onConflictDoUpdate: (_conf: any) => Promise.resolve([]),
|
||||
}),
|
||||
}),
|
||||
update: (_table: any) => ({
|
||||
set: (_vals: any) => ({
|
||||
where: (_cond: any) => Promise.resolve([]),
|
||||
}),
|
||||
}),
|
||||
select: (_sel?: any) => ({
|
||||
from: (_table: any) => ({
|
||||
where: (_cond: any) => chainable(),
|
||||
limit: (_n: any) => chainable(),
|
||||
}),
|
||||
}),
|
||||
selectDistinct: (_sel: any) => ({
|
||||
from: (_table: any) => chainable(),
|
||||
}),
|
||||
execute: (_query: any) => Promise.resolve([]),
|
||||
transaction: async (fn: (tx: any) => Promise<any>) => fn(makeMockDb()),
|
||||
});
|
||||
|
||||
mock.module("./db/index.ts", () => ({ db: makeMockDb(), client: {} }));
|
||||
|
||||
const fetchSellabilityBatchMock = mock(async (asins: string[]) => {
|
||||
return new Map(
|
||||
@@ -47,40 +80,17 @@ mock.module("./llm.ts", () => ({
|
||||
|
||||
const modulePromise = import("./bestsellers-by-category.ts");
|
||||
|
||||
const DB_TEST_PATH = path.join(
|
||||
process.cwd(),
|
||||
"test_output",
|
||||
"test_analysis.sqlite",
|
||||
);
|
||||
|
||||
let db: Database;
|
||||
let processCategory: (db: Database, runId: number, category: any, perCategoryTop: number) => Promise<any>;
|
||||
let insertCategoryRunSummary: (db: Database, summary: any, runTimestamp: string) => Promise<number>;
|
||||
let processCategory: (runId: number, category: any, perCategoryTop: number) => Promise<any>;
|
||||
let insertCategoryRunSummary: (summary: any, runTimestamp: string) => Promise<number>;
|
||||
let originalFetch: typeof globalThis.fetch;
|
||||
|
||||
beforeAll(async () => {
|
||||
const mod = await modulePromise;
|
||||
processCategory = mod.processCategory;
|
||||
insertCategoryRunSummary = mod.insertCategoryRunSummary;
|
||||
|
||||
rmSync(path.dirname(DB_TEST_PATH), { recursive: true, force: true });
|
||||
mkdirSync(path.dirname(DB_TEST_PATH), { recursive: true });
|
||||
initDb(DB_TEST_PATH);
|
||||
db = getDb(DB_TEST_PATH);
|
||||
|
||||
originalFetch = globalThis.fetch;
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
globalThis.fetch = originalFetch;
|
||||
closeDb();
|
||||
rmSync(path.dirname(DB_TEST_PATH), { recursive: true, force: true });
|
||||
});
|
||||
const mod = await modulePromise;
|
||||
processCategory = mod.processCategory;
|
||||
insertCategoryRunSummary = mod.insertCategoryRunSummary;
|
||||
originalFetch = globalThis.fetch;
|
||||
|
||||
beforeEach(() => {
|
||||
db.run("DELETE FROM product_analysis_results");
|
||||
db.run("DELETE FROM category_analysis_runs");
|
||||
|
||||
nextId = 0;
|
||||
globalThis.fetch = mock(async (input: string | URL | Request) => {
|
||||
const rawUrl =
|
||||
typeof input === "string"
|
||||
@@ -139,39 +149,34 @@ test("processCategory function test", async () => {
|
||||
childCount: 0,
|
||||
};
|
||||
|
||||
const runId = await insertCategoryRunSummary(db, {
|
||||
categoryId: mockCategory.id,
|
||||
categoryLabel: mockCategory.label,
|
||||
topAsinsChecked: 0,
|
||||
availableAsins: 0,
|
||||
fba: 0,
|
||||
fbm: 0,
|
||||
skip: 0,
|
||||
status: "running",
|
||||
error: "",
|
||||
results: [],
|
||||
}, new Date().toISOString());
|
||||
const summary = await processCategory(db, runId, mockCategory, 2);
|
||||
const runId = await insertCategoryRunSummary(
|
||||
{
|
||||
categoryId: mockCategory.id,
|
||||
categoryLabel: mockCategory.label,
|
||||
topAsinsChecked: 0,
|
||||
availableAsins: 0,
|
||||
fba: 0,
|
||||
fbm: 0,
|
||||
skip: 0,
|
||||
status: "running",
|
||||
error: "",
|
||||
results: [],
|
||||
},
|
||||
new Date().toISOString(),
|
||||
);
|
||||
|
||||
const categoryRun = db.query("SELECT * FROM category_analysis_runs").all() as any[];
|
||||
expect(categoryRun.length).toBe(1);
|
||||
expect(categoryRun[0].category_label).toBe("Category 1");
|
||||
expect(categoryRun[0].top_asins_checked).toBe(2);
|
||||
expect(categoryRun[0].available_asins).toBe(2);
|
||||
expect(categoryRun[0].fba_count).toBe(1);
|
||||
expect(categoryRun[0].fbm_count).toBe(1);
|
||||
expect(categoryRun[0].status).toBe("ok");
|
||||
const summary = await processCategory(runId, mockCategory, 2);
|
||||
|
||||
const productResults = db.query("SELECT * FROM product_analysis_results ORDER BY asin").all() as any[];
|
||||
expect(productResults.length).toBe(2);
|
||||
expect(summary.status).toBe("ok");
|
||||
expect(summary.topAsinsChecked).toBe(2);
|
||||
expect(summary.availableAsins).toBe(2);
|
||||
expect(summary.fba).toBe(1);
|
||||
expect(summary.fbm).toBe(1);
|
||||
expect(summary.results?.length).toBe(2);
|
||||
expect(summary.results?.[0]?.product.record.asin).toBe("B000000001");
|
||||
expect(summary.results?.[0]?.verdict.verdict).toBe("FBA");
|
||||
expect(summary.results?.[1]?.product.record.asin).toBe("B000000002");
|
||||
expect(summary.results?.[1]?.verdict.verdict).toBe("FBM");
|
||||
|
||||
expect(productResults[0].asin).toBe("B000000001");
|
||||
expect(productResults[0].name).toBe("Product One");
|
||||
expect(productResults[0].verdict).toBe("FBA");
|
||||
expect(productResults[0].run_id).toBe(categoryRun[0].id);
|
||||
|
||||
expect(productResults[1].asin).toBe("B000000002");
|
||||
expect(productResults[1].name).toBe("Product Two");
|
||||
expect(productResults[1].verdict).toBe("FBM");
|
||||
expect(productResults[1].run_id).toBe(categoryRun[0].id);
|
||||
globalThis.fetch = originalFetch;
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user