Skip to content

Commit f243bdf

Browse files
Make palette id required
1 parent 32a4d5e commit f243bdf

2 files changed

Lines changed: 23 additions & 13 deletions

File tree

app/data-sources/remote.ts

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ interface SupabasePalette {
3636
interface SupabaseColor {
3737
id: string;
3838
user_id: string;
39-
palette_id: string;
39+
palette_id: string; // NOT NULL - colors must always belong to a palette
4040
created_at: string;
4141
updated_at: string;
4242
name: string | null;
@@ -340,9 +340,16 @@ export class SupabaseSource extends Source {
340340
relatedRecord: RecordIdentity | null
341341
): Promise<void> {
342342
if (record.type === 'color' && relationship === 'palette') {
343+
const paletteId = relatedRecord?.id;
344+
345+
assert(
346+
'Colors must always belong to a palette - cannot set palette to null',
347+
!!paletteId
348+
);
349+
343350
const { error } = await this.supabase
344351
.from('colors')
345-
.update({ palette_id: relatedRecord?.id ?? null })
352+
.update({ palette_id: paletteId })
346353
.eq('id', record.id);
347354

348355
if (error) throw new Error(`Supabase update error: ${error.message}`);
@@ -372,13 +379,15 @@ export class SupabaseSource extends Source {
372379
relatedRecord: RecordIdentity
373380
): Promise<void> {
374381
if (record.type === 'palette' && relationship === 'colors') {
375-
// Set palette_id to null (orphan the color)
382+
// Colors cannot exist without a palette, so delete the color entirely
383+
// The database will handle this via ON DELETE CASCADE when the palette is deleted,
384+
// but for explicit removal operations, we delete the color record
376385
const { error } = await this.supabase
377386
.from('colors')
378-
.update({ palette_id: null })
387+
.delete()
379388
.eq('id', relatedRecord.id);
380389

381-
if (error) throw new Error(`Supabase update error: ${error.message}`);
390+
if (error) throw new Error(`Supabase delete error: ${error.message}`);
382391
}
383392
}
384393

@@ -423,9 +432,7 @@ export class SupabaseSource extends Source {
423432
},
424433
relationships: {
425434
palette: {
426-
data: color.palette_id
427-
? { type: 'palette', id: color.palette_id }
428-
: null,
435+
data: { type: 'palette', id: color.palette_id },
429436
},
430437
},
431438
};
@@ -459,9 +466,14 @@ export class SupabaseSource extends Source {
459466
const paletteRel = record.relationships?.['palette']?.data as
460467
| RecordIdentity
461468
| undefined;
469+
470+
const paletteId = paletteRel?.id;
471+
472+
assert('Colors must always belong to a palette', !!paletteId);
473+
462474
return {
463475
...base,
464-
palette_id: paletteRel?.id ?? null,
476+
palette_id: paletteId,
465477
name: attrs['name'] ?? null,
466478
r: attrs['r'] ?? 0,
467479
g: attrs['g'] ?? 0,

supabase-schema.sql

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ CREATE TABLE IF NOT EXISTS palettes (
3131
-- ============================================
3232
CREATE TABLE IF NOT EXISTS colors (
3333
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
34-
user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE,
35-
palette_id UUID REFERENCES palettes(id) ON DELETE CASCADE,
34+
user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
35+
palette_id UUID NOT NULL REFERENCES palettes(id) ON DELETE CASCADE,
3636
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
3737
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
3838
name TEXT,
@@ -42,8 +42,6 @@ CREATE TABLE IF NOT EXISTS colors (
4242
a REAL DEFAULT 1.0 CHECK (a >= 0.0 AND a <= 1.0),
4343

4444
-- Constraints
45-
CONSTRAINT colors_user_not_null CHECK (user_id IS NOT NULL),
46-
CONSTRAINT colors_palette_not_null CHECK (palette_id IS NOT NULL),
4745
CONSTRAINT colors_name_length CHECK (char_length(name) <= 255)
4846
);
4947

0 commit comments

Comments
 (0)