CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "ltree";
CREATE TABLE IF NOT EXISTS products (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
name TEXT NOT NULL,
description TEXT,
price NUMERIC(10, 2) NOT NULL CHECK (price >= 0),
compare_at_price NUMERIC(10, 2) CHECK (compare_at_price >= 0),
sku TEXT,
inventory_quantity INTEGER NOT NULL DEFAULT 0 CHECK (inventory_quantity >= 0),
is_active BOOLEAN NOT NULL DEFAULT true,
image_1 TEXT,
image_2 TEXT,
image_3 TEXT,
image_4 TEXT,
image_5 TEXT,
price_id TEXT,
categories TEXT[] DEFAULT '{}',
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS categories (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
name TEXT NOT NULL UNIQUE,
slug TEXT NOT NULL UNIQUE,
description TEXT,
parent_id UUID REFERENCES categories(id),
path ltree,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS cart_items (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID,
product_id UUID NOT NULL REFERENCES products(id) ON DELETE CASCADE,
quantity INTEGER NOT NULL DEFAULT 1 CHECK (quantity > 0),
added_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now()
);
CREATE INDEX IF NOT EXISTS cart_items_user_id_idx ON cart_items(user_id);
CREATE INDEX IF NOT EXISTS cart_items_product_id_idx ON cart_items(product_id);
CREATE INDEX IF NOT EXISTS products_categories_idx ON products USING gin (categories);
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = now();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER update_products_updated_at
BEFORE UPDATE ON products
FOR EACH ROW
EXECUTE PROCEDURE update_updated_at_column();
CREATE TRIGGER update_categories_updated_at
BEFORE UPDATE ON categories
FOR EACH ROW
EXECUTE PROCEDURE update_updated_at_column();
ALTER TABLE products ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Anyone can view active products"
ON products FOR SELECT
USING (is_active = true);
CREATE POLICY "Authenticated users can manage products"
ON products FOR ALL
TO authenticated
USING (true)
WITH CHECK (true);
ALTER TABLE cart_items ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Users can view their own cart items"
ON cart_items FOR SELECT
USING (user_id = auth.uid() OR user_id::text = coalesce(current_setting('request.headers.x-anonymous-id', true), ''));
CREATE POLICY "Users can insert their own cart items"
ON cart_items FOR INSERT
WITH CHECK (user_id = auth.uid() OR user_id::text = coalesce(current_setting('request.headers.x-anonymous-id', true), ''));
CREATE POLICY "Users can update their own cart items"
ON cart_items FOR UPDATE
USING (user_id = auth.uid() OR user_id::text = coalesce(current_setting('request.headers.x-anonymous-id', true), ''));
CREATE POLICY "Users can delete their own cart items"
ON cart_items FOR DELETE
USING (user_id = auth.uid() OR user_id::text = coalesce(current_setting('request.headers.x-anonymous-id', true), ''));
ALTER TABLE categories ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Anyone can view categories"
ON categories FOR SELECT
USING (true);
CREATE POLICY "Authenticated users can manage categories"
ON categories FOR ALL
TO authenticated
USING (true)
WITH CHECK (true);
CREATE OR REPLACE FUNCTION update_product_categories(
product_id UUID,
category_ids UUID[]
)
RETURNS VOID AS $$
DECLARE
category_names TEXT[];
BEGIN
SELECT array_agg(name) INTO category_names
FROM categories
WHERE id = ANY(category_ids);
UPDATE products
SET categories = category_names
WHERE id = product_id;
END;
$$ LANGUAGE plpgsql;
INSERT INTO categories (name, slug, description, path)
VALUES
('Electronics', 'electronics', 'Electronic devices', 'electronics'),
('Clothing', 'clothing', 'Apparel and accessories', 'clothing'),
('Home & Kitchen', 'home-kitchen', 'Products for home and kitchen', 'home_kitchen'),
('Books', 'books', 'Books and publications', 'books'),
('Sports', 'sports', 'Sports equipment and accessories', 'sports')
ON CONFLICT (name) DO NOTHING;
DROP POLICY IF EXISTS "Users can view their own cart items" ON cart_items;
DROP POLICY IF EXISTS "Anyone can insert cart items" ON cart_items;
DROP POLICY IF EXISTS "Users can update their own cart items" ON cart_items;
DROP POLICY IF EXISTS "Users can delete their own cart items" ON cart_items;
CREATE POLICY "Users can view their own cart items"
ON cart_items FOR SELECT USING (
user_id = auth.uid() OR
(auth.role() IS NULL AND user_id = (current_setting('request.headers.x-anonymous-id', true))::uuid)
);
CREATE POLICY "Anyone can insert cart items"
ON cart_items FOR INSERT WITH CHECK (true);
CREATE POLICY "Users can update their own cart items"
ON cart_items FOR UPDATE USING (
user_id = auth.uid() OR
(auth.role() IS NULL AND user_id = (current_setting('request.headers.x-anonymous-id', true))::uuid)
);
CREATE POLICY "Users can delete their own cart items"
ON cart_items FOR DELETE USING (
user_id = auth.uid() OR
(auth.role() IS NULL AND user_id = (current_setting('request.headers.x-anonymous-id', true))::uuid)
)