Skip to content

Commit a8f6441

Browse files
committed
Load all reversals in background
Rudimentary queue to handle all reversal loading Disable letter button if reversal not loaded yet.
1 parent baa02e7 commit a8f6441

4 files changed

Lines changed: 148 additions & 165 deletions

File tree

src/lib/data/stores/lexicon.svelte.ts

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { LoadEvent } from '@sveltejs/kit';
22
import initSqlJs, { type Database } from 'sql.js';
3+
import { SvelteMap } from 'svelte/reactivity';
34

45
// Store for vernacularLanguage
56
export let vernacularLanguageId = $state({ value: '' });
@@ -31,10 +32,14 @@ export type ReversalWord = {
3132
letter: string;
3233
homonym_index?: never;
3334
};
34-
export let reversalWords: Record<string, ReversalWord[]> = $state({});
3535

36-
// Store for the loaded reversalLetters, keyed by language
37-
export let reversalLetters: Record<string, string[]> = $state({});
36+
/**
37+
* code -> letter -> file -> loaded
38+
*/
39+
export let reversals: SvelteMap<
40+
string,
41+
SvelteMap<string, SvelteMap<string, ReversalWord[]> | undefined> | undefined
42+
> = new SvelteMap();
3843

3944
export type Word = VernacularWord | ReversalWord;
4045

@@ -91,9 +96,21 @@ class CurrentReversal {
9196
// Store for selectedLanguageStore
9297
languageId: string | null = $state(null);
9398
// Derived store to get the current language's reversalWordsList
94-
words = $derived(this.languageId ? reversalWords[this.languageId] || [] : []);
99+
words = $derived(
100+
this.languageId
101+
? reversals
102+
.get(this.languageId)
103+
?.values() // = letters for language
104+
.filter((file) => !!file) // filter letters that don't have a file
105+
.flatMap((file) => file?.values().toArray()) // for each letter, flatten word list
106+
.toArray()
107+
.flat() || [] // return flattened array of all words
108+
: []
109+
);
95110
// Derived store to get the current language's reversalLetters
96-
letters = $derived(new Set(this.languageId ? reversalLetters[this.languageId] || [] : []));
111+
letters = $derived(
112+
new Set(this.languageId ? reversals.get(this.languageId)?.keys() || [] : [])
113+
);
97114
}
98115

99116
export const currentReversal = new CurrentReversal();

src/lib/lexicon/index.ts

Lines changed: 0 additions & 3 deletions
This file was deleted.

src/routes/lexicon/+layout.ts

Lines changed: 108 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,41 @@ import config from '$lib/data/config';
33
import {
44
displayNames,
55
initializeDatabase,
6+
reversals,
67
vernacularLanguageId,
78
vernacularWords,
8-
type VernacularWord
9+
type ReversalWord,
10+
type VernacularWord,
11+
type VernacularWordReference
912
} from '$lib/data/stores/lexicon.svelte';
10-
import type { ReversalIndex } from '$lib/lexicon';
13+
import { SvelteMap } from 'svelte/reactivity';
1114
import type { LayoutLoad } from './$types';
1215

13-
const reversalIndexUrls = import.meta.glob('./**/index.json', {
16+
const reversalURLs = import.meta.glob('./**/*.json', {
1417
import: 'default',
1518
eager: true,
1619
base: '/src/gen-assets/reversal',
1720
query: '?url'
1821
}) as Record<string, string>;
1922

23+
type FetchJob = {
24+
code: string;
25+
letter: string;
26+
file: string;
27+
};
28+
29+
const reversalQueue: FetchJob[] = [];
30+
2031
export const load: LayoutLoad = async ({ fetch }) => {
2132
if (!(config as DictionaryConfig).writingSystems) {
2233
throw new Error('Writing systems configuration not found');
2334
}
2435
const dictionaryConfig = config as DictionaryConfig;
2536

37+
const writingSystems = Object.entries(dictionaryConfig.writingSystems);
38+
2639
const [vernacularLanguage, vernacularWritingSystem] =
27-
Object.entries(dictionaryConfig.writingSystems).find(([_, ws]) =>
28-
ws.type.includes('main')
29-
) ?? [];
40+
writingSystems.find(([_, ws]) => ws.type.includes('main')) ?? [];
3041

3142
if (!(vernacularLanguage && vernacularWritingSystem)) {
3243
throw new Error('Vernacular language not found');
@@ -41,24 +52,35 @@ export const load: LayoutLoad = async ({ fetch }) => {
4152

4253
const vernacularAlphabet = vernacularWritingSystem.alphabet;
4354

44-
const reversalWritingSystems = Object.entries(dictionaryConfig.writingSystems).filter(
45-
([_, ws]) => 'reversalFilename' in ws
46-
);
47-
48-
const reversalAlphabets = reversalWritingSystems.map(([key, ws]) => ({ [key]: ws.alphabet }));
49-
const reversalLanguages = reversalWritingSystems.map(([key, _]) => key);
55+
for (const [code, ws] of writingSystems) {
56+
if ('reversalFilename' in ws) {
57+
reversals.set(
58+
code,
59+
ws.alphabet && new SvelteMap(ws.alphabet.map((letter) => [letter, undefined]))
60+
);
61+
}
62+
}
5063

51-
const reversalIndexes: { [language: string]: ReversalIndex } = {}; // Updated type for reversalIndexes
64+
reversalQueue.length = 0;
5265

53-
for (const [key] of reversalWritingSystems) {
54-
const response = await fetch(reversalIndexUrls[`./${key}/index.json`]);
66+
for (const [code, reversal] of reversals.entries()) {
67+
const response = await fetch(reversalURLs[`./${code}/index.json`]);
5568
if (response.ok) {
56-
reversalIndexes[key] = (await response.json()) as ReversalIndex; // Explicitly cast the JSON response
69+
Object.entries((await response.json()) as Promise<Record<string, string[]>>).forEach(
70+
([letter, files]) => {
71+
reversal?.set(letter, new SvelteMap(files.map((f: string) => [f, []])));
72+
reversalQueue.push(...files.map((file: string) => ({ code, letter, file })));
73+
}
74+
);
5775
} else {
58-
console.warn(`Failed to load reversal index for language: ${key}`);
76+
console.warn(`Failed to load reversal index for language: ${code}`);
5977
}
6078
}
6179

80+
console.log(reversals);
81+
reversalQueue.sort((a, b) => a.letter.localeCompare(b.letter, 'en-US'));
82+
console.log(reversalQueue.slice(0));
83+
6284
let db = await initializeDatabase({ fetch });
6385
let results = db.exec(`SELECT id, name, homonym_index, type, num_senses, summary FROM entries`);
6486

@@ -74,38 +96,86 @@ export const load: LayoutLoad = async ({ fetch }) => {
7496
) as VernacularWord;
7597

7698
let firstLetter = entry.name.charAt(0).toLowerCase();
99+
const startingPosition = firstLetter === '*' || firstLetter === '-' ? 1 : 0;
77100

78-
let firstTwoChars = '';
79-
let startingPosition = 0;
80-
81-
if (firstLetter === '*' || firstLetter === '-') {
82-
startingPosition = 1;
83-
}
84-
firstTwoChars = entry.name
101+
const firstTwoChars = entry.name
85102
.substring(startingPosition, 2 + startingPosition)
86103
.toLowerCase();
87104

88-
if (vernacularAlphabet?.includes(firstTwoChars)) {
89-
firstLetter = firstTwoChars;
90-
} else {
91-
firstLetter = entry.name.charAt(startingPosition).toLowerCase();
92-
}
93-
94-
if (!vernacularAlphabet?.includes(firstLetter)) {
95-
firstLetter = '*';
96-
}
105+
firstLetter = vernacularAlphabet?.includes(firstTwoChars)
106+
? firstTwoChars
107+
: entry.name.charAt(startingPosition).toLowerCase();
97108

98-
entry.letter = firstLetter;
109+
entry.letter = vernacularAlphabet?.includes(firstLetter) ? firstLetter : '*';
99110
return entry;
100111
});
101112
vernacularLanguageId.value = vernacularLanguage;
102113
vernacularWords.value = vernacularWordsList;
103114
}
104115

116+
// start loading reversals in background
117+
loadReversals();
118+
105119
return {
106-
vernacularAlphabet,
107-
reversalAlphabets,
108-
reversalLanguages,
109-
reversalIndexes
120+
vernacularAlphabet
110121
};
111122
};
123+
124+
async function loadReversals() {
125+
const start = new Date().valueOf();
126+
while (reversalQueue.length) {
127+
const job = reversalQueue.shift();
128+
if (job) {
129+
await loadReversal(job);
130+
}
131+
}
132+
console.log(`Loaded all reversals in ${(new Date().valueOf() - start) / 1000}s`);
133+
}
134+
135+
async function loadReversal(job: FetchJob) {
136+
const { code, letter, file } = job;
137+
138+
const key = `./${code}/${file}`;
139+
140+
const reversalFile = reversalURLs[key];
141+
if (!reversalFile) {
142+
console.error(`Reversal file not found in glob: ${key}`);
143+
return;
144+
}
145+
146+
const response = await fetch(reversalFile);
147+
if (response.ok) {
148+
const data: Record<string, { index: number; name: 'string' }[]> = await response.json();
149+
reversals
150+
.get(code)
151+
?.get(letter)
152+
?.set(
153+
file,
154+
Object.entries(data).map(
155+
([name, entries]) =>
156+
({
157+
name,
158+
indexes: entries.map((entry) => entry.index),
159+
vernacularWords: entries
160+
.map((entry) => {
161+
const foundWord: VernacularWord | undefined =
162+
vernacularWords.value.find((vw) => vw.id === entry.index);
163+
if (foundWord) {
164+
return {
165+
name: foundWord.name,
166+
homonym_index: foundWord.homonym_index || 0
167+
} satisfies VernacularWordReference;
168+
} else {
169+
console.log(
170+
`Index ${entry.index} not found in vernacularWords`
171+
);
172+
return null; // Return null for missing indexes
173+
}
174+
})
175+
.filter((index) => index !== null), // Filter out null values
176+
letter: letter
177+
}) satisfies ReversalWord
178+
)
179+
);
180+
}
181+
}

0 commit comments

Comments
 (0)