fix(catch-records): stop bulk upserts clobbering fields a toggle never touched

Toggling one checkbox sent the whole record, so a stale copy of the other fields
could overwrite newer values. Send only the fields that changed, group rows by
the columns they carry, and upsert each group with defaultToNull: false so
omitted columns keep their stored value. Results are returned in the caller's
order rather than whatever order the groups came back in.
This commit is contained in:
Josh Creek
2026-09-15 17:48:34 +01:00
parent 2042e5a65a
commit 54eaa6d776
2 changed files with 33 additions and 18 deletions
@@ -38,9 +38,9 @@
value: string | CatchInformationItem
): value is CatchInformationItem => typeof value !== 'string';
function updateCatchRecord(source: UpdateCatchSource) {
function updateCatchRecord(source: UpdateCatchSource, changes?: Partial<CatchRecord>) {
if (readOnly) return;
dispatch('updateCatch', { pokedexEntry, catchRecord, source });
dispatch('updateCatch', { pokedexEntry, catchRecord, source, changes });
}
function onCaughtChange() {
@@ -50,7 +50,10 @@
if (catchRecord.caught) {
catchRecord.haveToEvolve = false;
}
updateCatchRecord('toggle');
updateCatchRecord('toggle', {
caught: catchRecord.caught,
haveToEvolve: catchRecord.haveToEvolve
});
}
function onNeedsToEvolveChange() {
@@ -60,7 +63,10 @@
if (catchRecord.haveToEvolve) {
catchRecord.caught = false;
}
updateCatchRecord('toggle');
updateCatchRecord('toggle', {
caught: catchRecord.caught,
haveToEvolve: catchRecord.haveToEvolve
});
}
</script>
@@ -154,7 +160,7 @@
type="checkbox"
bind:checked={catchRecord.inHome}
class="checkbox checkbox-primary"
on:change={() => updateCatchRecord('toggle')}
on:change={() => updateCatchRecord('toggle', { inHome: catchRecord?.inHome })}
/>
</label>
</div>
@@ -168,7 +174,8 @@
type="checkbox"
bind:checked={catchRecord.hasGigantamaxed}
class="checkbox checkbox-primary"
on:change={() => updateCatchRecord('toggle')}
on:change={() =>
updateCatchRecord('toggle', { hasGigantamaxed: catchRecord?.hasGigantamaxed })}
/>
</label>
</div>
+17 -9
View File
@@ -90,19 +90,27 @@ class CatchRecordRepository {
return mapped;
});
const { data: result, error } = await this.supabase
const groups = new Map<string, Partial<CatchRecordDB>[]>();
for (const row of dbRows) {
const key = Object.keys(row).sort().join(',');
const group = groups.get(key) ?? [];
group.push(row);
groups.set(key, group);
}
const saved: CatchRecord[] = [];
for (const group of groups.values()) {
const { data, error } = await this.supabase
.from('catch_records')
.upsert(dbRows, {
onConflict: '"userId","pokedexId","pokemonId"'
.upsert(group, {
onConflict: '"userId","pokedexId","pokemonId"',
defaultToNull: false
})
.select();
if (error) {
console.error('Supabase error bulk upserting catch records:', error);
throw new Error(`Failed to bulk upsert catch records: ${error.message}`);
if (error) throw new Error(`Failed to bulk upsert catch records: ${error.message}`);
saved.push(...(data ?? []).map((row) => this.transformCatchRecord(row)));
}
return (result ?? []).map((row) => this.transformCatchRecord(row));
const byPokemon = new Map(saved.map((row) => [row.pokemonId, row]));
return records.map((row) => byPokemon.get(row.pokemonId)!);
}
async findById(id: string): Promise<CatchRecord | null> {