feat(cache): implement regex101 cache table and queries for API response caching

This commit is contained in:
Sam Chau
2025-12-31 00:58:17 +10:30
parent b360dfbcae
commit af269b030f
5 changed files with 101 additions and 1 deletions

View File

@@ -18,6 +18,7 @@ import { migration as migration013 } from './migrations/013_add_upgrade_dry_run.
import { migration as migration014 } from './migrations/014_create_ai_settings.ts';
import { migration as migration015 } from './migrations/015_create_arr_sync_tables.ts';
import { migration as migration016 } from './migrations/016_add_should_sync_flags.ts';
import { migration as migration017 } from './migrations/017_create_regex101_cache.ts';
export interface Migration {
version: number;
@@ -251,7 +252,8 @@ export function loadMigrations(): Migration[] {
migration013,
migration014,
migration015,
migration016
migration016,
migration017
];
// Sort by version number

View File

@@ -0,0 +1,18 @@
import type { Migration } from '../migrations.ts';
export const migration: Migration = {
version: 17,
name: 'Create regex101 cache table',
up: `
CREATE TABLE IF NOT EXISTS regex101_cache (
regex101_id TEXT PRIMARY KEY,
response TEXT NOT NULL,
fetched_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
`,
down: `
DROP TABLE IF EXISTS regex101_cache;
`
};

View File

@@ -0,0 +1,54 @@
import { db } from '../db.ts';
/**
* Types for regex101_cache table
*/
export interface Regex101Cache {
regex101_id: string;
response: string;
fetched_at: string;
}
/**
* All queries for regex101_cache table
*/
export const regex101CacheQueries = {
/**
* Get cached response by regex101 ID
*/
get(regex101Id: string): Regex101Cache | undefined {
return db.queryFirst<Regex101Cache>(
'SELECT * FROM regex101_cache WHERE regex101_id = ?',
regex101Id
);
},
/**
* Store response in cache (insert or replace)
*/
set(regex101Id: string, response: string): void {
db.execute(
'INSERT OR REPLACE INTO regex101_cache (regex101_id, response) VALUES (?, ?)',
regex101Id,
response
);
},
/**
* Delete a cached entry
*/
delete(regex101Id: string): boolean {
const affected = db.execute(
'DELETE FROM regex101_cache WHERE regex101_id = ?',
regex101Id
);
return affected > 0;
},
/**
* Clear all cached entries
*/
clear(): number {
return db.execute('DELETE FROM regex101_cache');
}
};

View File

@@ -383,3 +383,15 @@ CREATE INDEX idx_upgrade_configs_arr_instance ON upgrade_configs(arr_instance_id
-- Arr sync indexes (Migration: 015_create_arr_sync_tables.ts)
CREATE INDEX idx_arr_sync_quality_profiles_instance ON arr_sync_quality_profiles(instance_id);
CREATE INDEX idx_arr_sync_delay_profiles_instance ON arr_sync_delay_profiles(instance_id);
-- ==============================================================================
-- TABLE: regex101_cache
-- Purpose: Cache regex101 API responses to avoid redundant fetches
-- Migration: 017_create_regex101_cache.ts
-- ==============================================================================
CREATE TABLE regex101_cache (
regex101_id TEXT PRIMARY KEY, -- Versioned ID (e.g., "ABC123/1")
response TEXT NOT NULL, -- Full JSON response with test results
fetched_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

View File

@@ -1,6 +1,7 @@
import { json, error } from '@sveltejs/kit';
import type { RequestHandler } from './$types';
import { logger } from '$logger/logger';
import { regex101CacheQueries } from '$db/queries/regex101Cache.ts';
export interface Regex101UnitTest {
description: string;
@@ -89,6 +90,16 @@ export const GET: RequestHandler = async ({ params, fetch }) => {
throw error(400, 'Missing regex101 ID');
}
// Check cache first
const cached = regex101CacheQueries.get(id);
if (cached) {
await logger.debug('regex101 cache hit', {
source: 'Regex101API',
meta: { id }
});
return json(JSON.parse(cached.response));
}
// Handle ID with optional version (e.g., "ABC123" or "ABC123/1")
const [regexId, version] = id.split('/');
@@ -136,6 +147,9 @@ export const GET: RequestHandler = async ({ params, fetch }) => {
unitTests: testedUnitTests
};
// Cache the result
regex101CacheQueries.set(id, JSON.stringify(result));
return json(result);
} catch (err) {
if (err && typeof err === 'object' && 'status' in err) {