/* Polymorphic foreign keys */

CREATE OR REPLACE FUNCTION null_zero(anyelement)
RETURNS INTEGER
LANGUAGE SQL
AS $$
    SELECT CASE WHEN $1 IS NULL THEN 0 ELSE 1 END;
$$;

CREATE TABLE r1 (
  r1_id SERIAL PRIMARY KEY
, r1_text TEXT
);

INSERT INTO r1 (r1_text)
VALUES ('foo bar')

CREATE TABLE r2 (
  r2_id SERIAL PRIMARY KEY
, r2_text_array TEXT[]
);

INSERT INTO r2 (r2_text_array)
VALUES ('{"baz","blurf"}');

CREATE TABLE r3 (
  r3_id SERIAL PRIMARY KEY
, r3_poly POLYGON
);
INSERT INTO r3 (r3_poly)
VALUES ( '((1,2),(3,4),(5,6),(7,8))' );

CREATE TABLE flex_key_shadow (
  flex_key_shadow_id SERIAL PRIMARY KEY
, r1_id INTEGER REFERENCES r1(r1_id)
, r2_id INTEGER REFERENCES r2(r2_id)
, r3_id INTEGER REFERENCES r3(r3_id)
);

ALTER TABLE flex_key_shadow ADD CONSTRAINT only_one_r
    CHECK(
      null_zero(r1_id)
    + null_zero(r2_id)
    + null_zero(r3_id)
    = 1)
;

CREATE VIEW flex_key AS
SELECT
  flex_key_shadow_id
, CASE
  WHEN r1_id IS NOT NULL THEN 'r1'
  WHEN r2_id IS NOT NULL THEN 'r2'
  WHEN r3_id IS NOT NULL THEN 'r3'
  ELSE 'wtf?!?'
  END AS "referenced_table"
, CASE
  WHEN r1_id IS NOT NULL THEN r1_id
  WHEN r2_id IS NOT NULL THEN r2_id
  WHEN r3_id IS NOT NULL THEN r3_id
  ELSE NULL
  END AS "referenced_id"
FROM flex_key_shadow
;

