From 7dce8c587a01c102dc2064577c75abd36038774a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 17 Jan 2026 22:43:47 +0000 Subject: [PATCH] Phase 1: Extract db-mapper helper to reduce duplication in db.ts Co-authored-by: johndoe6345789 <224850594+johndoe6345789@users.noreply.github.com> --- src/lib/db-mapper.ts | 43 ++++++++++++++++++ src/lib/db.ts | 105 +++---------------------------------------- 2 files changed, 50 insertions(+), 98 deletions(-) create mode 100644 src/lib/db-mapper.ts diff --git a/src/lib/db-mapper.ts b/src/lib/db-mapper.ts new file mode 100644 index 0000000..a25aa2d --- /dev/null +++ b/src/lib/db-mapper.ts @@ -0,0 +1,43 @@ +/** + * Database row-to-object mapping utilities + * Handles conversion of SQL query results to typed objects + */ + +/** + * Maps a SQL query result row to a typed object + * Handles special conversions for boolean and JSON fields + */ +export function mapRowToObject(row: any[], columns: string[]): T { + const obj: any = {} + + columns.forEach((col, idx) => { + const value = row[idx] + + // Convert integer boolean fields to actual booleans + if (col === 'hasPreview' || col === 'isDefault') { + obj[col] = value === 1 + } + // Parse JSON string fields + else if (col === 'inputParameters') { + obj[col] = value ? JSON.parse(value as string) : undefined + } + // All other fields pass through as-is + else { + obj[col] = value + } + }) + + return obj as T +} + +/** + * Maps multiple SQL result rows to an array of typed objects + */ +export function mapRowsToObjects(results: any[]): T[] { + if (results.length === 0) return [] + + const columns = results[0].columns + const values = results[0].values + + return values.map(row => mapRowToObject(row, columns)) +} diff --git a/src/lib/db.ts b/src/lib/db.ts index 1cf35ab..db4de79 100644 --- a/src/lib/db.ts +++ b/src/lib/db.ts @@ -1,6 +1,7 @@ import initSqlJs, { Database } from 'sql.js' import type { Snippet, SnippetTemplate } from './types' import { getStorageConfig, FlaskStorageAdapter, loadStorageConfig } from './storage' +import { mapRowToObject, mapRowsToObjects } from './db-mapper' let dbInstance: Database | null = null let sqlInstance: any = null @@ -304,27 +305,9 @@ export async function getAllSnippets(): Promise { } const db = await initDB() - const results = db.exec('SELECT * FROM snippets ORDER BY updatedAt DESC') - if (results.length === 0) return [] - - const columns = results[0].columns - const values = results[0].values - - return values.map(row => { - const snippet: any = {} - columns.forEach((col, idx) => { - if (col === 'hasPreview') { - snippet[col] = row[idx] === 1 - } else if (col === 'inputParameters') { - snippet[col] = row[idx] ? JSON.parse(row[idx] as string) : undefined - } else { - snippet[col] = row[idx] - } - }) - return snippet as Snippet - }) + return mapRowsToObjects(results) } export async function getSnippet(id: string): Promise { @@ -334,7 +317,6 @@ export async function getSnippet(id: string): Promise { } const db = await initDB() - const results = db.exec('SELECT * FROM snippets WHERE id = ?', [id]) if (results.length === 0 || results[0].values.length === 0) return null @@ -342,18 +324,7 @@ export async function getSnippet(id: string): Promise { const columns = results[0].columns const row = results[0].values[0] - const snippet: any = {} - columns.forEach((col, idx) => { - if (col === 'hasPreview') { - snippet[col] = row[idx] === 1 - } else if (col === 'inputParameters') { - snippet[col] = row[idx] ? JSON.parse(row[idx] as string) : undefined - } else { - snippet[col] = row[idx] - } - }) - - return snippet as Snippet + return mapRowToObject(row, columns) } export async function createSnippet(snippet: Snippet): Promise { @@ -431,27 +402,9 @@ export async function deleteSnippet(id: string): Promise { export async function getAllTemplates(): Promise { const db = await initDB() - const results = db.exec('SELECT * FROM snippet_templates') - if (results.length === 0) return [] - - const columns = results[0].columns - const values = results[0].values - - return values.map(row => { - const template: any = {} - columns.forEach((col, idx) => { - if (col === 'hasPreview') { - template[col] = row[idx] === 1 - } else if (col === 'inputParameters') { - template[col] = row[idx] ? JSON.parse(row[idx] as string) : undefined - } else { - template[col] = row[idx] - } - }) - return template as SnippetTemplate - }) + return mapRowsToObjects(results) } export async function createTemplate(template: SnippetTemplate): Promise { @@ -957,25 +910,9 @@ export async function getAllNamespaces(): Promise } const db = await initDB() - const results = db.exec('SELECT * FROM namespaces ORDER BY isDefault DESC, name ASC') - if (results.length === 0) return [] - - const columns = results[0].columns - const values = results[0].values - - return values.map(row => { - const namespace: any = {} - columns.forEach((col, idx) => { - if (col === 'isDefault') { - namespace[col] = row[idx] === 1 - } else { - namespace[col] = row[idx] - } - }) - return namespace - }) + return mapRowsToObjects(results) } export async function createNamespace(name: string): Promise { @@ -1057,32 +994,13 @@ export async function ensureDefaultNamespace(): Promise { export async function getSnippetsByNamespace(namespaceId: string): Promise { const db = await initDB() - const results = db.exec('SELECT * FROM snippets WHERE namespaceId = ? OR (namespaceId IS NULL AND ? = (SELECT id FROM namespaces WHERE isDefault = 1)) ORDER BY updatedAt DESC', [namespaceId, namespaceId]) - if (results.length === 0) return [] - - const columns = results[0].columns - const values = results[0].values - - return values.map(row => { - const snippet: any = {} - columns.forEach((col, idx) => { - if (col === 'hasPreview') { - snippet[col] = row[idx] === 1 - } else if (col === 'inputParameters') { - snippet[col] = row[idx] ? JSON.parse(row[idx] as string) : undefined - } else { - snippet[col] = row[idx] - } - }) - return snippet as Snippet - }) + return mapRowsToObjects(results) } export async function getNamespaceById(id: string): Promise { const db = await initDB() - const results = db.exec('SELECT * FROM namespaces WHERE id = ?', [id]) if (results.length === 0 || results[0].values.length === 0) return null @@ -1090,16 +1008,7 @@ export async function getNamespaceById(id: string): Promise { - if (col === 'isDefault') { - namespace[col] = row[idx] === 1 - } else { - namespace[col] = row[idx] - } - }) - - return namespace + return mapRowToObject(row, columns) } export async function moveSnippetToNamespace(snippetId: string, targetNamespaceId: string): Promise {