-- Create product reviews table CREATE TABLE product_reviews ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), product_id UUID NOT NULL REFERENCES products(id) ON DELETE CASCADE, user_id UUID NOT NULL REFERENCES users(id), parent_id UUID REFERENCES product_reviews(id) ON DELETE CASCADE, title VARCHAR(255) NOT NULL, content TEXT, rating decimal CHECK (rating >= 0.0 AND rating <= 5.0), is_approved BOOLEAN DEFAULT FALSE, is_verified_purchase BOOLEAN DEFAULT FALSE, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); -- Add product average rating column to the products table ALTER TABLE products ADD COLUMN IF NOT EXISTS average_rating DECIMAL(3, 2); ALTER TABLE products ADD COLUMN IF NOT EXISTS review_count INTEGER DEFAULT 0; -- Create indexes for performance CREATE INDEX idx_product_reviews_product ON product_reviews(product_id); CREATE INDEX idx_product_reviews_user ON product_reviews(user_id); CREATE INDEX idx_product_reviews_parent ON product_reviews(parent_id); CREATE INDEX idx_product_reviews_approved ON product_reviews(is_approved); CREATE INDEX idx_product_reviews_rating ON product_reviews(rating); -- Create trigger to automatically update the updated_at column CREATE TRIGGER update_product_reviews_modtime BEFORE UPDATE ON product_reviews FOR EACH ROW EXECUTE FUNCTION update_modified_column(); -- Function to update product average rating and review count CREATE OR REPLACE FUNCTION update_product_average_rating() RETURNS TRIGGER AS $$ DECLARE avg_rating DECIMAL(3, 2); rev_count INTEGER; BEGIN -- Calculate average rating and count for approved top-level reviews SELECT AVG(rating)::DECIMAL(3, 2), COUNT(*) INTO avg_rating, rev_count FROM product_reviews WHERE product_id = NEW.product_id AND parent_id IS NULL AND is_approved = TRUE AND rating IS NOT NULL; -- Update the product with new average rating and count UPDATE products SET average_rating = avg_rating, review_count = rev_count WHERE id = NEW.product_id; RETURN NEW; END; $$ LANGUAGE plpgsql; -- Create triggers to recalculate average rating when reviews are added/updated/deleted CREATE TRIGGER update_product_rating_on_insert AFTER INSERT ON product_reviews FOR EACH ROW WHEN (NEW.parent_id IS NULL) -- Only for top-level reviews EXECUTE FUNCTION update_product_average_rating(); CREATE TRIGGER update_product_rating_on_update AFTER UPDATE OF is_approved, rating ON product_reviews FOR EACH ROW WHEN (NEW.parent_id IS NULL) -- Only for top-level reviews EXECUTE FUNCTION update_product_average_rating(); CREATE TRIGGER update_product_rating_on_delete AFTER DELETE ON product_reviews FOR EACH ROW WHEN (OLD.parent_id IS NULL) -- Only for top-level reviews EXECUTE FUNCTION update_product_average_rating();