|
1 | | --- Migration to add price fields to foods and cigarettes tables |
2 | | --- Run this SQL in your Supabase SQL Editor |
| 1 | +-- Enable UUID generation (safe if already enabled) |
| 2 | +CREATE EXTENSION IF NOT EXISTS "pgcrypto"; |
3 | 3 |
|
4 | 4 | -- ============================================================================ |
5 | | --- 1. CREATE FOODS TABLE (if it doesn't exist) |
| 5 | +-- 1. FOODS TABLE |
6 | 6 | -- ============================================================================ |
7 | 7 |
|
8 | | -CREATE TABLE IF NOT EXISTS foods ( |
| 8 | +CREATE TABLE IF NOT EXISTS public.foods ( |
9 | 9 | id UUID PRIMARY KEY DEFAULT gen_random_uuid(), |
10 | | - spot_id UUID NOT NULL REFERENCES spots(id) ON DELETE CASCADE, |
| 10 | + spot_id UUID NOT NULL REFERENCES public.spots(id) ON DELETE CASCADE, |
11 | 11 | name TEXT NOT NULL, |
12 | | - image_url TEXT NOT NULL, |
13 | | - added_by UUID NOT NULL REFERENCES profiles(id) ON DELETE CASCADE, |
14 | | - price NUMERIC DEFAULT NULL, |
15 | | - created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), |
16 | | - updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() |
| 12 | + image_url TEXT, |
| 13 | + added_by UUID NOT NULL REFERENCES public.profiles(id) ON DELETE CASCADE, |
| 14 | + price NUMERIC, |
| 15 | + created_at TIMESTAMPTZ DEFAULT now(), |
| 16 | + updated_at TIMESTAMPTZ DEFAULT now() |
17 | 17 | ); |
18 | 18 |
|
19 | | -CREATE INDEX IF NOT EXISTS foods_spot_id_idx ON foods(spot_id); |
20 | | -CREATE INDEX IF NOT EXISTS foods_added_by_idx ON foods(added_by); |
21 | | -ALTER TABLE foods ENABLE ROW LEVEL SECURITY; |
22 | | - |
23 | | --- Drop existing policies |
24 | | -DO $$ |
25 | | -BEGIN |
26 | | - DROP POLICY IF EXISTS "Everyone can read foods" ON foods; |
27 | | - DROP POLICY IF EXISTS "Users can create foods" ON foods; |
28 | | - DROP POLICY IF EXISTS "Users can update foods" ON foods; |
29 | | - DROP POLICY IF EXISTS "Users can delete foods" ON foods; |
30 | | - DROP POLICY IF EXISTS "Admins can update food prices" ON foods; |
31 | | -END $$; |
32 | | - |
33 | | -CREATE POLICY "Everyone can read foods" ON foods FOR SELECT USING (true); |
34 | | -CREATE POLICY "Users can create foods" ON foods FOR INSERT WITH CHECK (true); |
35 | | -CREATE POLICY "Users can update own foods" ON foods FOR UPDATE USING (added_by = auth.uid()::text OR EXISTS ( |
36 | | - SELECT 1 FROM profiles WHERE profiles.id::text = auth.uid()::text AND profiles.role = 'admin' |
37 | | -)); |
38 | | -CREATE POLICY "Users can delete own foods" ON foods FOR DELETE USING (added_by = auth.uid()::text OR EXISTS ( |
39 | | - SELECT 1 FROM profiles WHERE profiles.id::text = auth.uid()::text AND profiles.role = 'admin' |
40 | | -)); |
| 19 | +CREATE INDEX IF NOT EXISTS foods_spot_id_idx ON public.foods(spot_id); |
| 20 | +CREATE INDEX IF NOT EXISTS foods_added_by_idx ON public.foods(added_by); |
| 21 | + |
| 22 | +ALTER TABLE public.foods ENABLE ROW LEVEL SECURITY; |
| 23 | + |
| 24 | +-- Drop old policies safely |
| 25 | +DROP POLICY IF EXISTS "foods_read" ON public.foods; |
| 26 | +DROP POLICY IF EXISTS "foods_insert" ON public.foods; |
| 27 | +DROP POLICY IF EXISTS "foods_update" ON public.foods; |
| 28 | +DROP POLICY IF EXISTS "foods_delete" ON public.foods; |
| 29 | + |
| 30 | +-- Read: everyone |
| 31 | +CREATE POLICY "foods_read" |
| 32 | +ON public.foods |
| 33 | +FOR SELECT |
| 34 | +USING (true); |
| 35 | + |
| 36 | +-- Insert: any authenticated user |
| 37 | +CREATE POLICY "foods_insert" |
| 38 | +ON public.foods |
| 39 | +FOR INSERT |
| 40 | +WITH CHECK (auth.uid() IS NOT NULL); |
| 41 | + |
| 42 | +-- Update: owner or admin |
| 43 | +CREATE POLICY "foods_update" |
| 44 | +ON public.foods |
| 45 | +FOR UPDATE |
| 46 | +USING ( |
| 47 | + added_by = auth.uid() |
| 48 | + OR EXISTS ( |
| 49 | + SELECT 1 FROM public.profiles |
| 50 | + WHERE profiles.id = auth.uid() |
| 51 | + AND profiles.role = 'admin' |
| 52 | + ) |
| 53 | +); |
| 54 | + |
| 55 | +-- Delete: owner or admin |
| 56 | +CREATE POLICY "foods_delete" |
| 57 | +ON public.foods |
| 58 | +FOR DELETE |
| 59 | +USING ( |
| 60 | + added_by = auth.uid() |
| 61 | + OR EXISTS ( |
| 62 | + SELECT 1 FROM public.profiles |
| 63 | + WHERE profiles.id = auth.uid() |
| 64 | + AND profiles.role = 'admin' |
| 65 | + ) |
| 66 | +); |
41 | 67 |
|
42 | 68 | -- ============================================================================ |
43 | | --- 2. ADD PRICE AND NAME FIELDS TO CIGARETTES TABLE |
| 69 | +-- 2. CIGARETTES TABLE UPDATES |
44 | 70 | -- ============================================================================ |
45 | 71 |
|
46 | | -ALTER TABLE cigarettes |
| 72 | +ALTER TABLE public.cigarettes |
47 | 73 | ADD COLUMN IF NOT EXISTS name TEXT, |
48 | | -ADD COLUMN IF NOT EXISTS price NUMERIC DEFAULT NULL; |
49 | | - |
50 | | --- Update existing cigarettes to have a default name if null |
51 | | -UPDATE cigarettes SET name = 'Cigarette Pack' WHERE name IS NULL; |
52 | | - |
53 | | --- Make name NOT NULL for new entries (but allow existing NULLs) |
54 | | --- We'll handle this in application code |
55 | | - |
56 | | --- Drop existing policies |
57 | | -DO $$ |
58 | | -BEGIN |
59 | | - DROP POLICY IF EXISTS "Everyone can read cigarettes" ON cigarettes; |
60 | | - DROP POLICY IF EXISTS "Users can create cigarettes" ON cigarettes; |
61 | | - DROP POLICY IF EXISTS "Users can update cigarettes" ON cigarettes; |
62 | | - DROP POLICY IF EXISTS "Users can delete cigarettes" ON cigarettes; |
63 | | -END $$; |
64 | | - |
65 | | -CREATE POLICY "Everyone can read cigarettes" ON cigarettes FOR SELECT USING (true); |
66 | | -CREATE POLICY "Users can create cigarettes" ON cigarettes FOR INSERT WITH CHECK (true); |
67 | | -CREATE POLICY "Users can update own cigarettes" ON cigarettes FOR UPDATE USING (added_by = auth.uid()::text OR EXISTS ( |
68 | | - SELECT 1 FROM profiles WHERE profiles.id::text = auth.uid()::text AND profiles.role = 'admin' |
69 | | -)); |
70 | | -CREATE POLICY "Users can delete own cigarettes" ON cigarettes FOR DELETE USING (added_by = auth.uid()::text OR EXISTS ( |
71 | | - SELECT 1 FROM profiles WHERE profiles.id::text = auth.uid()::text AND profiles.role = 'admin' |
72 | | -)); |
| 74 | +ADD COLUMN IF NOT EXISTS price NUMERIC; |
| 75 | + |
| 76 | +UPDATE public.cigarettes |
| 77 | +SET name = 'Cigarette Pack' |
| 78 | +WHERE name IS NULL; |
| 79 | + |
| 80 | +ALTER TABLE public.cigarettes ENABLE ROW LEVEL SECURITY; |
| 81 | + |
| 82 | +DROP POLICY IF EXISTS "cigarettes_read" ON public.cigarettes; |
| 83 | +DROP POLICY IF EXISTS "cigarettes_insert" ON public.cigarettes; |
| 84 | +DROP POLICY IF EXISTS "cigarettes_update" ON public.cigarettes; |
| 85 | +DROP POLICY IF EXISTS "cigarettes_delete" ON public.cigarettes; |
| 86 | + |
| 87 | +CREATE POLICY "cigarettes_read" |
| 88 | +ON public.cigarettes |
| 89 | +FOR SELECT |
| 90 | +USING (true); |
| 91 | + |
| 92 | +CREATE POLICY "cigarettes_insert" |
| 93 | +ON public.cigarettes |
| 94 | +FOR INSERT |
| 95 | +WITH CHECK (auth.uid() IS NOT NULL); |
| 96 | + |
| 97 | +CREATE POLICY "cigarettes_update" |
| 98 | +ON public.cigarettes |
| 99 | +FOR UPDATE |
| 100 | +USING ( |
| 101 | + added_by = auth.uid() |
| 102 | + OR EXISTS ( |
| 103 | + SELECT 1 FROM public.profiles |
| 104 | + WHERE profiles.id = auth.uid() |
| 105 | + AND profiles.role = 'admin' |
| 106 | + ) |
| 107 | +); |
| 108 | + |
| 109 | +CREATE POLICY "cigarettes_delete" |
| 110 | +ON public.cigarettes |
| 111 | +FOR DELETE |
| 112 | +USING ( |
| 113 | + added_by = auth.uid() |
| 114 | + OR EXISTS ( |
| 115 | + SELECT 1 FROM public.profiles |
| 116 | + WHERE profiles.id = auth.uid() |
| 117 | + AND profiles.role = 'admin' |
| 118 | + ) |
| 119 | +); |
73 | 120 |
|
74 | 121 | -- ============================================================================ |
75 | | --- 3. ADD PRICE FIELD TO DRINKS TABLE (for user-suggested drinks) |
| 122 | +-- 3. DRINKS TABLE PRICE FIELD |
76 | 123 | -- ============================================================================ |
77 | 124 |
|
78 | | -ALTER TABLE drinks |
79 | | -ADD COLUMN IF NOT EXISTS price NUMERIC DEFAULT NULL; |
| 125 | +ALTER TABLE public.drinks |
| 126 | +ADD COLUMN IF NOT EXISTS price NUMERIC; |
| 127 | + |
| 128 | +-- ============================================================================ |
| 129 | +-- DONE |
| 130 | +-- ============================================================================ |
80 | 131 |
|
81 | | -SELECT 'Price migration completed successfully! Foods, cigarettes, and drinks now support prices.' as status; |
| 132 | +SELECT 'Migration completed successfully. UUID issues fixed.' AS status; |
0 commit comments