Initial commit - Route Commerce platform
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
-- Migration 042: Product Import RPC + upsert_product
|
||||
-- Idempotent: CREATE OR REPLACE FUNCTION
|
||||
|
||||
-- ── 1. upsert_product ─────────────────────────────────────────────────────────
|
||||
-- Upserts a single product by name (within brand). Returns the product id.
|
||||
-- Used by the CSV import tool to create or update products in bulk.
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.upsert_product(
|
||||
p_brand_id UUID,
|
||||
p_name TEXT,
|
||||
p_price NUMERIC,
|
||||
p_type TEXT,
|
||||
p_description TEXT DEFAULT '',
|
||||
p_active BOOLEAN DEFAULT true,
|
||||
p_image_url TEXT DEFAULT NULL
|
||||
)
|
||||
RETURNS JSONB
|
||||
LANGUAGE plpgsql SECURITY DEFINER SET search_path = public
|
||||
AS $$
|
||||
DECLARE
|
||||
v_product_id UUID;
|
||||
v_is_update BOOLEAN := false;
|
||||
BEGIN
|
||||
-- Check if product with same name exists in this brand
|
||||
SELECT id INTO v_product_id
|
||||
FROM products
|
||||
WHERE brand_id = p_brand_id AND name = p_name
|
||||
LIMIT 1;
|
||||
|
||||
IF v_product_id IS NOT NULL THEN
|
||||
-- Update existing
|
||||
UPDATE products SET
|
||||
name = p_name,
|
||||
description = p_description,
|
||||
price = p_price,
|
||||
type = p_type,
|
||||
active = p_active,
|
||||
image_url = COALESCE(p_image_url, image_url),
|
||||
updated_at = now()
|
||||
WHERE id = v_product_id
|
||||
RETURNING id INTO v_product_id;
|
||||
v_is_update := true;
|
||||
ELSE
|
||||
-- Insert new
|
||||
INSERT INTO products (brand_id, name, description, price, type, active, image_url)
|
||||
VALUES (p_brand_id, p_name, p_description, p_price, p_type, p_active, p_image_url)
|
||||
RETURNING id INTO v_product_id;
|
||||
END IF;
|
||||
|
||||
RETURN jsonb_build_object(
|
||||
'id', v_product_id,
|
||||
'is_update', v_is_update,
|
||||
'name', p_name
|
||||
);
|
||||
END;
|
||||
$$;
|
||||
|
||||
-- ── 2. bulk_upsert_products ──────────────────────────────────────────────────
|
||||
-- Takes an array of product records and upserts them all within a brand.
|
||||
-- Returns a summary: { created, updated, errors }.
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.bulk_upsert_products(
|
||||
p_brand_id UUID,
|
||||
p_products JSONB -- array of { name, description, price, type, active, image_url }
|
||||
)
|
||||
RETURNS JSONB
|
||||
LANGUAGE plpgsql SECURITY DEFINER SET search_path = public
|
||||
AS $$
|
||||
DECLARE
|
||||
v_entry JSONB;
|
||||
v_result JSONB := '{"created": 0, "updated": 0, "errors": []}'::JSONB;
|
||||
v_name TEXT;
|
||||
v_desc TEXT;
|
||||
v_price NUMERIC;
|
||||
v_type TEXT;
|
||||
v_active BOOLEAN;
|
||||
v_img TEXT;
|
||||
v_was_new BOOLEAN;
|
||||
BEGIN
|
||||
FOR v_entry IN SELECT * FROM jsonb_array_elements(p_products)
|
||||
LOOP
|
||||
BEGIN
|
||||
v_name := nullif(v_entry->>'name', '');
|
||||
v_desc := coalesce(nullif(v_entry->>'description', ''), '');
|
||||
v_price := nullif((v_entry->>'price')::TEXT, '')::NUMERIC;
|
||||
v_type := nullif(v_entry->>'type', '');
|
||||
v_active := coalesce((v_entry->>'active')::BOOLEAN, true);
|
||||
v_img := nullif(v_entry->>'image_url', '');
|
||||
|
||||
IF v_name IS NULL OR v_name = '' THEN
|
||||
RAISE EXCEPTION 'Product name is required';
|
||||
END IF;
|
||||
|
||||
IF v_price IS NULL OR v_price < 0 THEN
|
||||
RAISE EXCEPTION 'Invalid price for product: %', v_name;
|
||||
END IF;
|
||||
|
||||
IF v_type NOT IN ('Pickup', 'Shipping', 'Pickup & Shipping') THEN
|
||||
RAISE EXCEPTION 'Invalid type for product: %. Must be Pickup, Shipping, or Pickup & Shipping', v_name;
|
||||
END IF;
|
||||
|
||||
v_was_new := NOT EXISTS (
|
||||
SELECT 1 FROM products WHERE brand_id = p_brand_id AND name = v_name
|
||||
);
|
||||
|
||||
PERFORM upsert_product(p_brand_id, v_name, v_desc, v_price, v_type, v_active, v_img);
|
||||
|
||||
IF v_was_new THEN
|
||||
v_result := jsonb_set(v_result, '{created}',
|
||||
to_jsonb((v_result->>'created')::INTEGER + 1));
|
||||
ELSE
|
||||
v_result := jsonb_set(v_result, '{updated}',
|
||||
to_jsonb((v_result->>'updated')::INTEGER + 1));
|
||||
END IF;
|
||||
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
v_result := jsonb_set(
|
||||
v_result, '{errors}',
|
||||
v_result->'errors' || jsonb_build_array(
|
||||
jsonb_build_object('product', v_name, 'error', SQLERRM)
|
||||
)
|
||||
);
|
||||
END;
|
||||
END LOOP;
|
||||
|
||||
RETURN v_result;
|
||||
END;
|
||||
$$;
|
||||
|
||||
NOTIFY pgrst, 'reload schema';
|
||||
Reference in New Issue
Block a user