CREATE FUNCTION jsonb_dasherize(j jsonb) RETURNS jsonb IMMUTABLE AS $$ DECLARE t text; ret jsonb; BEGIN

t := jsonb_typeof(j);
IF t = 'object' THEN
  SELECT  COALESCE(jsonb_object_agg(replace(lower(regexp_replace(k, '([A-Z])', '_\1', 'g')), '_', '-'), jsonb_dasherize(v)), '{}')
  INTO    ret
  FROM    jsonb_each(j) AS t(k, v);
  RETURN ret;
ELSIF t = 'array' THEN
  SELECT  COALESCE(jsonb_agg(jsonb_dasherize(elem)), '[]')
  INTO    ret
  FROM    jsonb_array_elements(j) AS t(elem);
  RETURN ret;
ELSIF t IS NULL THEN
  -- This should never happen internally
  -- (thankfully, lest jsonb_set return NULL and destroy everything),
  -- but only from a passed-in NULL.
  RETURN NULL;
ELSE
  -- string/number/null:
  RETURN j;
END IF;

END; $$ LANGUAGE plpgsql;