diff options
author | polwex <polwex@sortug.com> | 2025-05-29 12:10:22 +0700 |
---|---|---|
committer | polwex <polwex@sortug.com> | 2025-05-29 12:10:22 +0700 |
commit | a3f24ea79b14394b24c4b60a010651eb29eeb872 (patch) | |
tree | cb1c4937084116f66a59727ee752afd974714c8e /src/actions/tones.ts | |
parent | 7abf2227438362ad30820ee236405ec1b57a40b6 (diff) |
glorious new db
Diffstat (limited to 'src/actions/tones.ts')
-rw-r--r-- | src/actions/tones.ts | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/src/actions/tones.ts b/src/actions/tones.ts new file mode 100644 index 0000000..8089453 --- /dev/null +++ b/src/actions/tones.ts @@ -0,0 +1,87 @@ +'use server'; + +import db from '@/lib/db'; +import { WordData } from '@/zoom/logic/types'; + +// 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<WordData | null> { + 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, 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; + } +} |