"use server"; import pdb from "@/lib/db/prosodydb"; import { WordData } from "@/zoom/logic/types"; export async function getOnsets(onset: string) { const data = pdb.fetchOnsets(onset); return data; } // Helper to extract tone from prosody - assuming prosody is an array of objects like [{tone: number}, ...] const getTonesFromProsody = (prosody: any): number[] | null => { if (Array.isArray(prosody) && prosody.length > 0) { return prosody.map((p) => p.tone).filter((t) => typeof t === "number"); } return null; }; export async function fetchWordsByToneAndSyllables( syllableCount: number, tones: (number | null)[], // Array of tones, one for each syllable. null means any tone. ): Promise { if (syllableCount !== tones.length) { console.error("Syllable count and tones array length mismatch"); return null; } const queryParams: (string | number)[] = ["th", syllableCount, syllableCount]; // lang, syllables (for WHERE), syllables (for json_array_length) let toneConditions = ""; const toneClauses: string[] = []; tones.forEach((tone, index) => { if (tone !== null && typeof tone === "number") { // Assumes SQLite's json_extract function is available and prosody is like: [{"tone": 1}, {"tone": 3}, ...] // Path for first syllable's tone: '$[0].tone' toneClauses.push(`json_extract(prosody, '$[${index}].tone') = ?`); queryParams.push(tone); } }); if (toneClauses.length > 0) { toneConditions = `AND ${toneClauses.join(" AND ")}`; } const queryString = ` SELECT id, spelling, prosody, syllables, lang, type, frequency, confidence, ipa, (SELECT json_group_array(json_object( 'pos', pos, 'senses', s.senses, 'forms', forms, 'etymology', etymology, 'related', related) ) FROM senses s WHERE s.parent_id = expressions.id ) as senses_array FROM expressions WHERE lang = ? AND syllables = ? AND type = 'word' AND json_valid(prosody) AND json_array_length(prosody) = ? -- Ensures prosody array has correct number of elements ${toneConditions} ORDER BY RANDOM() -- Get a random word matching criteria LIMIT 1 `; try { const query = db.db.query(queryString); const row = query.get(...queryParams) as any; if (!row) return null; // Map to WordData (simplified, similar to initial fetch in tones.tsx or db.fetchWordBySpelling) // This mapping might need to be more robust depending on actual WordData requirements. const word: WordData = { id: row.id, spelling: row.spelling, prosody: JSON.parse(row.prosody), syllables: row.syllables, lang: row.lang, type: row.type, frequency: row.frequency, confidence: row.confidence, ipa: row.ipa ? JSON.parse(row.ipa) : [], // Senses parsing is simplified here. Adjust if full sense data is needed. senses: row.senses_array ? JSON.parse(row.senses_array).map((s: any) => ({ pos: s.pos, senses: typeof s.senses === "string" ? JSON.parse(s.senses) : s.senses, forms: typeof s.forms === "string" ? JSON.parse(s.forms) : s.forms, etymology: s.etymology, related: typeof s.related === "string" ? JSON.parse(s.related) : s.related, })) : [], }; return word; } catch (error) { console.error("Error fetching word by tone and syllables:", error); console.error("Query:", queryString); console.error("Params:", queryParams); return null; } }