feat(database): add automatic migration on startup and enhance text analysis cache source
This commit is contained in:
+16
-1
@@ -39,9 +39,10 @@ describe("loadConfig", () => {
|
||||
expect(config.AI_ANALYSIS_DEBOUNCE_MS).toBe(500);
|
||||
expect(config.AI_ANALYSIS_RECOVERY_INTERVAL_MS).toBe(15000);
|
||||
expect(config.AI_ANALYSIS_ERROR_COOLDOWN_MS).toBe(30000);
|
||||
expect(config.AI_ANALYSIS_MAX_BATCH_SIZE).toBe(25);
|
||||
expect(config.AI_ANALYSIS_MAX_BATCH_SIZE).toBe(200);
|
||||
expect(config.AI_ANALYSIS_MAX_CONTEXT_TOKENS).toBe(8000);
|
||||
expect(config.AI_ANALYSIS_CONTEXT_MESSAGE_LIMIT).toBe(20);
|
||||
expect(config.AUTO_MIGRATE_ON_STARTUP).toBe(true);
|
||||
});
|
||||
|
||||
it("coerces AI analysis tuning values", async () => {
|
||||
@@ -107,4 +108,18 @@ describe("loadConfig", () => {
|
||||
expect(config.TEXT_CHANNEL_ID).toBe("text-channel");
|
||||
expect(config.EFFECTIVE_VOICE_GUILD_ID).toBe("voice-guild");
|
||||
});
|
||||
|
||||
it("allows disabling startup migrations explicitly", async () => {
|
||||
process.env = {
|
||||
...originalEnv,
|
||||
DISCORD_TOKEN: "token",
|
||||
AUTO_MIGRATE_ON_STARTUP: "false",
|
||||
NODE_ENV: "test",
|
||||
};
|
||||
|
||||
const { loadConfig } = await import("../src/config");
|
||||
const config = loadConfig(process.env);
|
||||
|
||||
expect(config.AUTO_MIGRATE_ON_STARTUP).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,8 +1,82 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { runMigrations } from "../../src/database/migrate";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const migrateSpy = vi.fn();
|
||||
const initializeDatabaseSpy = vi.fn();
|
||||
const closeDatabaseSpy = vi.fn();
|
||||
const withDatabaseClientSpy = vi.fn();
|
||||
const lockQuerySpy = vi.fn();
|
||||
const unlockQuerySpy = vi.fn();
|
||||
const drizzleSpy = vi.fn();
|
||||
|
||||
vi.mock("drizzle-orm/node-postgres", () => ({
|
||||
drizzle: drizzleSpy,
|
||||
}));
|
||||
|
||||
vi.mock("drizzle-orm/node-postgres/migrator", () => ({
|
||||
migrate: migrateSpy,
|
||||
}));
|
||||
|
||||
vi.mock("../../src/config", () => ({
|
||||
config: {
|
||||
AUTO_MIGRATE_ON_STARTUP: true,
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock("../../src/database/drizzle", () => ({
|
||||
initializeDatabase: initializeDatabaseSpy,
|
||||
closeDatabase: closeDatabaseSpy,
|
||||
withDatabaseClient: withDatabaseClientSpy,
|
||||
}));
|
||||
|
||||
describe("runMigrations", () => {
|
||||
it("exports the PostgreSQL migration runner", () => {
|
||||
beforeEach(() => {
|
||||
migrateSpy.mockResolvedValue(undefined);
|
||||
initializeDatabaseSpy.mockResolvedValue({} as never);
|
||||
closeDatabaseSpy.mockResolvedValue(undefined);
|
||||
drizzleSpy.mockReturnValue({} as never);
|
||||
withDatabaseClientSpy.mockImplementation(
|
||||
async (callback: () => Promise<unknown>) =>
|
||||
callback({
|
||||
query: vi.fn().mockImplementation((sql: string) => {
|
||||
if (sql.includes("pg_advisory_lock")) {
|
||||
return lockQuerySpy(sql);
|
||||
}
|
||||
if (sql.includes("pg_advisory_unlock")) {
|
||||
return unlockQuerySpy(sql);
|
||||
}
|
||||
|
||||
return Promise.resolve({});
|
||||
}),
|
||||
} as never),
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("exports the PostgreSQL migration runner", async () => {
|
||||
const { runMigrations } = await import("../../src/database/migrate");
|
||||
|
||||
expect(runMigrations).toBeTypeOf("function");
|
||||
});
|
||||
|
||||
it("uses a session lock around the migration batch", async () => {
|
||||
const { runMigrations } = await import("../../src/database/migrate");
|
||||
await runMigrations();
|
||||
|
||||
expect(initializeDatabaseSpy).toHaveBeenCalledTimes(1);
|
||||
expect(withDatabaseClientSpy).toHaveBeenCalledTimes(1);
|
||||
expect(migrateSpy).toHaveBeenCalledWith(
|
||||
expect.any(Object),
|
||||
expect.objectContaining({ migrationsFolder: "./drizzle/migrations" }),
|
||||
);
|
||||
expect(lockQuerySpy).toHaveBeenCalledWith(
|
||||
"SELECT pg_advisory_lock($1, $2)",
|
||||
);
|
||||
expect(unlockQuerySpy).toHaveBeenCalledWith(
|
||||
"SELECT pg_advisory_unlock($1, $2)",
|
||||
);
|
||||
expect(closeDatabaseSpy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user