-- General initialization
CREATE SCHEMA facts;
-- Define predicates
CREATE TABLE facts.edge (id serial PRIMARY KEY, arg0 bigint, arg1 bigint);
CREATE TABLE facts.reachable (id serial PRIMARY KEY, arg0 bigint, arg1 bigint);
CREATE TABLE facts.same_clique (id serial PRIMARY KEY, arg0 bigint, arg1 bigint);
-- Restrict predicates to contain unique facts
CREATE UNIQUE INDEX pred_edge_unique ON facts.edge (arg0,arg1);
CREATE UNIQUE INDEX pred_reachable_unique ON facts.reachable (arg0,arg1);
CREATE UNIQUE INDEX pred_same_clique_unique ON facts.same_clique (arg0,arg1);
-- Add triggers to automate rules

CREATE FUNCTION holmes_rule_reach_edge_0() RETURNS trigger AS $reach_edge$
    BEGIN
    INSERT INTO facts.reachable (arg0, arg1) (SELECT NEW.arg0, NEW.arg1  ) ON CONFLICT DO NOTHING;
    RETURN NULL;
    END;
    $reach_edge$ LANGUAGE plpgsql;
    CREATE TRIGGER holmes_rule_reach_edge_0 AFTER INSERT ON facts.edge FOR EACH ROW EXECUTE PROCEDURE holmes_rule_reach_edge_0();
;

CREATE FUNCTION holmes_rule_reach_trans_0() RETURNS trigger AS $reach_trans$
    BEGIN
    INSERT INTO facts.reachable (arg0, arg1) (SELECT NEW.arg0, t0.arg1 FROM facts.reachable as t0 WHERE NEW.arg1 = t0.arg0) ON CONFLICT DO NOTHING;
    RETURN NULL;
    END;
    $reach_trans$ LANGUAGE plpgsql;
    CREATE TRIGGER holmes_rule_reach_trans_0 AFTER INSERT ON facts.edge FOR EACH ROW EXECUTE PROCEDURE holmes_rule_reach_trans_0();


CREATE FUNCTION holmes_rule_reach_trans_1() RETURNS trigger AS $reach_trans$
    BEGIN
    INSERT INTO facts.reachable (arg0, arg1) (SELECT t0.arg0, NEW.arg1 FROM facts.edge as t0 WHERE t0.arg1 = NEW.arg0) ON CONFLICT DO NOTHING;
    RETURN NULL;
    END;
    $reach_trans$ LANGUAGE plpgsql;
    CREATE TRIGGER holmes_rule_reach_trans_1 AFTER INSERT ON facts.reachable FOR EACH ROW EXECUTE PROCEDURE holmes_rule_reach_trans_1();
;

CREATE FUNCTION holmes_rule_scc_0() RETURNS trigger AS $scc$
    BEGIN
    INSERT INTO facts.same_clique (arg0, arg1) (SELECT NEW.arg0, NEW.arg1 FROM facts.reachable as t0 WHERE NEW.arg1 = t0.arg0 AND NEW.arg0 = t0.arg1) ON CONFLICT DO NOTHING;
    RETURN NULL;
    END;
    $scc$ LANGUAGE plpgsql;
    CREATE TRIGGER holmes_rule_scc_0 AFTER INSERT ON facts.reachable FOR EACH ROW EXECUTE PROCEDURE holmes_rule_scc_0();


CREATE FUNCTION holmes_rule_scc_1() RETURNS trigger AS $scc$
    BEGIN
    INSERT INTO facts.same_clique (arg0, arg1) (SELECT t0.arg0, t0.arg1 FROM facts.reachable as t0 WHERE t0.arg1 = NEW.arg0 AND t0.arg0 = NEW.arg1) ON CONFLICT DO NOTHING;
    RETURN NULL;
    END;
    $scc$ LANGUAGE plpgsql;
    CREATE TRIGGER holmes_rule_scc_1 AFTER INSERT ON facts.reachable FOR EACH ROW EXECUTE PROCEDURE holmes_rule_scc_1();
;

CREATE FUNCTION insert_for_clique(iters int) RETURNS VOID as $$
DECLARE
counter integer := 0;
BEGIN
	LOOP
		EXIT WHEN counter = iters;
		INSERT INTO facts.edge (arg0, arg1) values (counter, counter + 1); 
		counter := counter + 1;
	END LOOP;
	INSERT INTO facts.edge (arg0, arg1) values (counter, 0);
END ; $$ LANGUAGE plpgsql;

SELECT insert_for_clique(1000);
