mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-01 21:02:12 +03:00
feat(db): add playgroundPresets CRUD module
Implements listPlaygroundPresets, getPlaygroundPreset, createPlaygroundPreset,
updatePlaygroundPreset, and deletePlaygroundPreset using db.prepare() (never
raw db.exec or string interpolation). randomUUID() from node:crypto for IDs;
params serialized via JSON.stringify/JSON.parse with fallback to {}.
This commit is contained in:
167
src/lib/db/playgroundPresets.ts
Normal file
167
src/lib/db/playgroundPresets.ts
Normal file
@@ -0,0 +1,167 @@
|
||||
/**
|
||||
* db/playgroundPresets.ts — Playground Studio preset persistence.
|
||||
*
|
||||
* CRUD operations for the playground_presets table (migration 076).
|
||||
* All queries use db.prepare() (better-sqlite3) — never raw db.exec() or
|
||||
* string interpolation.
|
||||
*
|
||||
* @module lib/db/playgroundPresets
|
||||
*/
|
||||
|
||||
import { getDbInstance } from "./core";
|
||||
import { randomUUID } from "node:crypto";
|
||||
|
||||
// TODO(F1-merge): swap to import from "@/shared/schemas/playground" after F1 lands
|
||||
export interface PlaygroundPresetListItem {
|
||||
id: string;
|
||||
name: string;
|
||||
endpoint: string;
|
||||
model: string;
|
||||
system: string | null;
|
||||
params: Record<string, unknown>;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
type PlaygroundPresetRow = {
|
||||
id: string;
|
||||
name: string;
|
||||
endpoint: string;
|
||||
model: string;
|
||||
system: string | null;
|
||||
params_json: string;
|
||||
created_at: string;
|
||||
};
|
||||
|
||||
function rowToItem(row: PlaygroundPresetRow): PlaygroundPresetListItem {
|
||||
let params: Record<string, unknown> = {};
|
||||
try {
|
||||
const parsed = JSON.parse(row.params_json);
|
||||
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
||||
params = parsed as Record<string, unknown>;
|
||||
}
|
||||
} catch {
|
||||
params = {};
|
||||
}
|
||||
return {
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
endpoint: row.endpoint,
|
||||
model: row.model,
|
||||
system: row.system,
|
||||
params,
|
||||
created_at: row.created_at,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all presets ordered by created_at descending (newest first).
|
||||
*/
|
||||
export function listPlaygroundPresets(): PlaygroundPresetListItem[] {
|
||||
const db = getDbInstance();
|
||||
const rows = db
|
||||
.prepare("SELECT * FROM playground_presets ORDER BY created_at DESC")
|
||||
.all() as PlaygroundPresetRow[];
|
||||
return rows.map(rowToItem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a single preset by id, or null when not found.
|
||||
*/
|
||||
export function getPlaygroundPreset(id: string): PlaygroundPresetListItem | null {
|
||||
const db = getDbInstance();
|
||||
const row = db
|
||||
.prepare("SELECT * FROM playground_presets WHERE id = ? LIMIT 1")
|
||||
.get(id) as PlaygroundPresetRow | undefined;
|
||||
if (!row) return null;
|
||||
return rowToItem(row);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new preset. Generates a UUID v4 for the id.
|
||||
* Returns the persisted row via getPlaygroundPreset.
|
||||
*/
|
||||
export function createPlaygroundPreset(input: {
|
||||
name: string;
|
||||
endpoint: string;
|
||||
model: string;
|
||||
system: string | null | undefined;
|
||||
params: Record<string, unknown>;
|
||||
}): PlaygroundPresetListItem {
|
||||
const db = getDbInstance();
|
||||
const id = randomUUID();
|
||||
const params_json = JSON.stringify(input.params ?? {});
|
||||
const system = input.system ?? null;
|
||||
|
||||
db.prepare(
|
||||
"INSERT INTO playground_presets (id, name, endpoint, model, system, params_json) VALUES (?, ?, ?, ?, ?, ?)"
|
||||
).run(id, input.name, input.endpoint, input.model, system, params_json);
|
||||
|
||||
const created = getPlaygroundPreset(id);
|
||||
// created cannot be null here — we just inserted the row
|
||||
return created as PlaygroundPresetListItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates only the supplied fields on an existing preset.
|
||||
* Returns the updated row, or null when the id does not exist.
|
||||
*/
|
||||
export function updatePlaygroundPreset(
|
||||
id: string,
|
||||
patch: Partial<{
|
||||
name: string;
|
||||
endpoint: string;
|
||||
model: string;
|
||||
system: string | null;
|
||||
params: Record<string, unknown>;
|
||||
}>
|
||||
): PlaygroundPresetListItem | null {
|
||||
const db = getDbInstance();
|
||||
|
||||
// Verify row exists before building the dynamic UPDATE
|
||||
const existing = getPlaygroundPreset(id);
|
||||
if (!existing) return null;
|
||||
|
||||
const setClauses: string[] = [];
|
||||
const values: unknown[] = [];
|
||||
|
||||
if (patch.name !== undefined) {
|
||||
setClauses.push("name = ?");
|
||||
values.push(patch.name);
|
||||
}
|
||||
if (patch.endpoint !== undefined) {
|
||||
setClauses.push("endpoint = ?");
|
||||
values.push(patch.endpoint);
|
||||
}
|
||||
if (patch.model !== undefined) {
|
||||
setClauses.push("model = ?");
|
||||
values.push(patch.model);
|
||||
}
|
||||
if ("system" in patch) {
|
||||
setClauses.push("system = ?");
|
||||
values.push(patch.system ?? null);
|
||||
}
|
||||
if (patch.params !== undefined) {
|
||||
setClauses.push("params_json = ?");
|
||||
values.push(JSON.stringify(patch.params));
|
||||
}
|
||||
|
||||
if (setClauses.length === 0) {
|
||||
// Empty patch — return current row unchanged
|
||||
return existing;
|
||||
}
|
||||
|
||||
values.push(id);
|
||||
db.prepare(`UPDATE playground_presets SET ${setClauses.join(", ")} WHERE id = ?`).run(...values);
|
||||
|
||||
return getPlaygroundPreset(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a preset by id.
|
||||
* Returns true when a row was deleted, false when the id did not exist.
|
||||
*/
|
||||
export function deletePlaygroundPreset(id: string): boolean {
|
||||
const db = getDbInstance();
|
||||
const result = db.prepare("DELETE FROM playground_presets WHERE id = ?").run(id);
|
||||
return result.changes > 0;
|
||||
}
|
||||
Reference in New Issue
Block a user