Create a UNIQUE multicolumn index on (product_id, variant_id):
CREATE UNIQUE INDEX line_items_prod_var_idx ON line_items (product_id, variant_id);
However, this allows multiple entries of (1, null) for (product_id, variant_id) by default, because null values are not considered to be distinct values.
To make up for that, additionally create a partial UNIQUE index on product_id:
CREATE UNIQUE INDEX line_items_prod_var_null_idx ON line_items (product_id)
WHERE variant_id IS NULL;
This way you can enter (1,2), (1,3) and (1, null), but neither of them a second time. Also speeds up queries with conditions on one or both column.
Or use the NULLS NOT DISTINCT clause in Postgres 15 or later. See: