var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
import { generateApolloClient } from '@deep-foundation/hasura/client.js';
import Debug from 'debug';
import { api, TABLE_NAME as LINKS_TABLE_NAME } from './1616701513782-links.js';
import { sql } from '@deep-foundation/hasura/sql.js';
import { DeepClient } from '../imports/client.js';
import { promiseTriggersUp, promiseTriggersDown } from '../imports/type-table.js';
const debug = Debug('deeplinks:migrations:promises');
const log = debug.extend('log');
const error = debug.extend('error');
const client = generateApolloClient({
    path: `${process.env.MIGRATIONS_HASURA_PATH}/v1/graphql`,
    ssl: !!+(process.env.MIGRATIONS_HASURA_SSL || 0),
    secret: process.env.MIGRATIONS_HASURA_SECRET,
});
const deep = new DeepClient({
    apolloClient: client,
});
export const up = () => __awaiter(void 0, void 0, void 0, function* () {
    log('up');
    const promiseTypeId = deep.idLocal('@deep-foundation/core', 'Promise');
    const thenTypeId = deep.idLocal('@deep-foundation/core', 'Then');
    const handleInsertTypeId = deep.idLocal('@deep-foundation/core', 'HandleInsert');
    const handleUpdateTypeId = deep.idLocal('@deep-foundation/core', 'HandleUpdate');
    const handleScheduleTypeId = deep.idLocal('@deep-foundation/core', 'HandleSchedule');
    const dockerIsolationProviderTypeId = deep.idLocal('@deep-foundation/core', 'DockerIsolationProvider');
    yield api.sql(sql `CREATE TYPE public.values_operation_type AS ENUM ('INSERT', 'UPDATE', 'DELETE');`);
    yield api.sql(sql `CREATE TABLE IF NOT EXISTS public.promise_links (
    id bigserial PRIMARY KEY,
    promise_id bigint NOT NULL,
    old_link_id bigint,
    old_link_type_id bigint,
    old_link_from_id bigint,
    old_link_to_id bigint,
    new_link_id bigint,
    new_link_type_id bigint,
    new_link_from_id bigint,
    new_link_to_id bigint,
    selector_id bigint,
    handle_operation_id bigint NOT NULL,
    handle_operation_type_id bigint NOT NULL,
    handler_id bigint NOT NULL,
    isolation_provider_image_name text NOT NULL,
    code text NOT NULL,
    values_operation public.values_operation_type
  );`);
    yield api.sql(sql `select create_btree_indexes_for_all_columns('public', 'promise_links');`);
    yield api.query({
        type: 'track_table',
        args: {
            schema: 'public',
            name: 'promise_links',
        },
    });
    yield api.sql(sql `CREATE OR REPLACE FUNCTION get_handle_operation_details(
    handle_operation_id bigint
    , OUT handler_id bigint
    , OUT isolation_provider_image_name text
    , OUT code text
  )
  AS $$   
  DECLARE
    supports_id bigint;
    isolation_id bigint;
    file_id bigint;
  BEGIN
    SELECT "to_id" INTO handler_id FROM "links" WHERE "id" = handle_operation_id;
    SELECT "from_id" INTO supports_id FROM "links" WHERE "id" = handler_id;
    SELECT "from_id" INTO isolation_id FROM "links" WHERE "id" = supports_id;
    SELECT "to_id" INTO file_id FROM "links" WHERE "id" = handler_id;
    SELECT "value" INTO isolation_provider_image_name FROM "strings" WHERE "link_id" = isolation_id;
    SELECT "value" INTO code FROM "strings" WHERE "link_id" = file_id;
  END; $$ LANGUAGE plpgsql;`);
    yield api.sql(sql `CREATE OR REPLACE FUNCTION insert_promise(
    promise_source_id bigint,
    handle_operation_id bigint,
    handle_operation_type_id bigint,
    old_link links default null,
    new_link links default null,
    selector_id bigint default null,
    values_operation public.values_operation_type default null
  )
  RETURNS VOID AS $$   
  DECLARE
    PROMISE bigint;
    handler_id bigint;
    isolation_provider_image_name text;
    code text;
  BEGIN
    SELECT * INTO handler_id, isolation_provider_image_name, code FROM get_handle_operation_details(handle_operation_id);
    INSERT INTO links ("type_id") VALUES (${promiseTypeId}) RETURNING id INTO PROMISE;
    INSERT INTO links ("type_id", "from_id", "to_id") VALUES (${thenTypeId}, promise_source_id, PROMISE);
    INSERT INTO promise_links ("promise_id", "old_link_id", "old_link_type_id", "old_link_from_id", "old_link_to_id", "new_link_id", "new_link_type_id", "new_link_from_id", "new_link_to_id", "handle_operation_id", "handle_operation_type_id", "handler_id", "isolation_provider_image_name", "code", "selector_id", "values_operation") VALUES (PROMISE, old_link."id", old_link."type_id", old_link."from_id", old_link."to_id", new_link."id", new_link."type_id", new_link."from_id", new_link."to_id", handle_operation_id, handle_operation_type_id, handler_id, isolation_provider_image_name, code, selector_id, values_operation);
  END; $$ LANGUAGE plpgsql;`);
    yield api.sql(sql `CREATE OR REPLACE FUNCTION ${LINKS_TABLE_NAME}__promise__insert__function() RETURNS TRIGGER AS $$ 
  DECLARE 
    PROMISE bigint;
    SELECTOR record;
    HANDLE_INSERT record;
    user_id bigint;
    hasura_session json;
  BEGIN
    FOR HANDLE_INSERT IN
      SELECT id, type_id FROM links l
      WHERE
          "from_id" = NEW."type_id"
      AND "type_id" = ${handleInsertTypeId}
      AND EXISTS(select true from links handlers, links supports, links isolation_providers where handlers.id = l."to_id" AND supports.
     id = handlers.from_id AND supports.from_id = isolation_providers.id AND isolation_providers.type_id = ${dockerIsolationProviderTypeId})
    LOOP
      PERFORM insert_promise(NEW."id", HANDLE_INSERT."id", HANDLE_INSERT."type_id", null, NEW);
    END LOOP;

    IF (
      NEW."type_id" = ${handleScheduleTypeId}
    ) THEN
      INSERT INTO links ("type_id") VALUES (${promiseTypeId}) RETURNING id INTO PROMISE;
      INSERT INTO links ("type_id", "from_id", "to_id") VALUES (${thenTypeId}, NEW.from_id, PROMISE);
    END IF;

    hasura_session := current_setting('hasura.user', 't');
    user_id := hasura_session::json->>'x-hasura-user-id';

    FOR SELECTOR IN
      SELECT s.selector_id, h.id as handle_operation_id, h.type_id as handle_operation_type_id, s.query_id
      FROM selectors s, links h
      WHERE
          s.item_id = NEW."id"
      AND s.selector_id = h.from_id
      AND h.type_id = ${handleInsertTypeId}
      AND EXISTS(select true from links handlers, links supports, links isolation_providers where handlers.id = h."to_id" AND supports.
      id = handlers.from_id AND supports.from_id = isolation_providers.id AND isolation_providers.type_id = ${dockerIsolationProviderTypeId})
    LOOP
      IF SELECTOR.query_id = 0 OR bool_exp_execute(NEW."id", SELECTOR.query_id, user_id) THEN
        PERFORM insert_promise(NEW."id", SELECTOR.handle_operation_id, SELECTOR.handle_operation_type_id, null, NEW, SELECTOR.selector_id);
      END IF;
    END LOOP;
    RETURN NEW;
  END; $$ LANGUAGE plpgsql;`);
    yield api.sql(sql `CREATE TRIGGER z_${LINKS_TABLE_NAME}__promise__insert__trigger AFTER INSERT ON "links" FOR EACH ROW EXECUTE PROCEDURE ${LINKS_TABLE_NAME}__promise__insert__function();`);
    yield api.sql(sql `CREATE OR REPLACE FUNCTION ${LINKS_TABLE_NAME}__promise__update__function() RETURNS TRIGGER AS $$ 
  DECLARE 
    PROMISE bigint;
    SELECTOR record;
    HANDLE_UPDATE record;
    user_id bigint;
    hasura_session json;
  BEGIN
    FOR HANDLE_UPDATE IN
      SELECT id, type_id FROM links l
      WHERE
          "from_id" = NEW."type_id"
      AND "type_id" = ${handleUpdateTypeId} 
      AND EXISTS(select true from links handlers, links supports, links isolation_providers where handlers.id = l."to_id" AND supports.
     id = handlers.from_id AND supports.from_id = isolation_providers.id AND isolation_providers.type_id = ${dockerIsolationProviderTypeId})
    LOOP
      PERFORM insert_promise(NEW."id", HANDLE_UPDATE."id", HANDLE_UPDATE."type_id", OLD, NEW);
    END LOOP;

    IF (
      NEW."type_id" = ${handleScheduleTypeId}
    ) THEN
      INSERT INTO links ("type_id") VALUES (${promiseTypeId}) RETURNING id INTO PROMISE;
      INSERT INTO links ("type_id", "from_id", "to_id") VALUES (${thenTypeId}, NEW.from_id, PROMISE);
    END IF;

    hasura_session := current_setting('hasura.user', 't');
    user_id := hasura_session::json->>'x-hasura-user-id';

    FOR SELECTOR IN
      SELECT s.selector_id, h.id as handle_operation_id, h.type_id as handle_operation_type_id, s.query_id
      FROM selectors s, links h
      WHERE
          s.item_id = NEW."id"
      AND s.selector_id = h.from_id
      AND h.type_id = ${handleUpdateTypeId}
      AND EXISTS(select true from links handlers, links supports, links isolation_providers where handlers.id = h."to_id" AND supports.
     id = handlers.from_id AND supports.from_id = isolation_providers.id AND isolation_providers.type_id = ${dockerIsolationProviderTypeId})
    LOOP
      IF SELECTOR.query_id = 0 OR bool_exp_execute(NEW."id", SELECTOR.query_id, user_id) THEN
        PERFORM insert_promise(NEW."id", SELECTOR.handle_operation_id, SELECTOR.handle_operation_type_id, OLD, NEW, SELECTOR.selector_id);
      END IF;
    END LOOP;
    RETURN NEW;
  END; $$ LANGUAGE plpgsql;`);
    yield api.sql(sql `CREATE TRIGGER z_${LINKS_TABLE_NAME}__promise__update__trigger AFTER UPDATE ON "links" FOR EACH ROW EXECUTE PROCEDURE ${LINKS_TABLE_NAME}__promise__update__function();`);
    const handleDeleteTypeId = deep.idLocal('@deep-foundation/core', 'HandleDelete');
    yield api.sql(sql `CREATE OR REPLACE FUNCTION ${LINKS_TABLE_NAME}__promise__delete__function() RETURNS TRIGGER AS $trigger$ 
  DECLARE
    PROMISE bigint;
    SELECTOR record;
    HANDLE_DELETE record;
    user_id bigint;
    hasura_session json;
    handler_id bigint;
    isolation_provider_image_name text;
    code text;
  BEGIN
    FOR HANDLE_DELETE IN
      SELECT id, type_id FROM links l
      WHERE
          "from_id" = OLD."type_id"
      AND "type_id" = ${handleDeleteTypeId} 
      AND EXISTS(select true from links handlers, links supports, links isolation_providers where handlers.id = l."to_id" AND supports.
     id = handlers.from_id AND supports.from_id = isolation_providers.id AND isolation_providers.type_id = ${dockerIsolationProviderTypeId})
    LOOP
      PERFORM insert_promise(OLD."id", HANDLE_DELETE."id", HANDLE_DELETE."type_id", OLD);
    END LOOP;

    hasura_session := current_setting('hasura.user', 't');
    user_id := hasura_session::json->>'x-hasura-user-id';
    
    FOR SELECTOR IN
      SELECT s.selector_id, h.id as handle_operation_id, h.type_id as handle_operation_type_id, s.query_id
      FROM selectors s, links h
      WHERE
          s.item_id = OLD."id"
      AND s.selector_id = h.from_id
      AND h.type_id = ${handleDeleteTypeId}
      AND EXISTS(select true from links handlers, links supports, links isolation_providers where handlers.id = h."to_id" AND supports.
      id = handlers.from_id AND supports.from_id = isolation_providers.id AND isolation_providers.type_id = ${dockerIsolationProviderTypeId})
    LOOP
      IF SELECTOR.query_id = 0 OR bool_exp_execute(OLD."id", SELECTOR.query_id, user_id) THEN
        PERFORM insert_promise(OLD."id", SELECTOR.handle_operation_id, SELECTOR.handle_operation_type_id, OLD, null, SELECTOR.selector_id);
      END IF;
    END LOOP;
    RETURN OLD;
  END; $trigger$ LANGUAGE plpgsql;`);
    yield api.sql(sql `CREATE TRIGGER ${LINKS_TABLE_NAME}__promise__delete__trigger BEFORE DELETE ON "links" FOR EACH ROW EXECUTE PROCEDURE ${LINKS_TABLE_NAME}__promise__delete__function();`);
    yield (promiseTriggersUp({
        schemaName: 'public',
        tableName: 'strings',
        valueType: 'TEXT',
        customColumnsSql: 'value text',
        linkRelation: 'string',
        linksTableName: 'links',
        api,
        deep,
    })());
    yield (promiseTriggersUp({
        schemaName: 'public',
        tableName: 'numbers',
        valueType: 'float8',
        customColumnsSql: 'value bigint',
        linkRelation: 'number',
        linksTableName: 'links',
        api,
        deep,
    })());
    yield (promiseTriggersUp({
        schemaName: 'public',
        tableName: 'objects',
        valueType: 'jsonb',
        customColumnsSql: 'value jsonb',
        linkRelation: 'object',
        linksTableName: 'links',
        api,
        deep,
    })());
});
export const down = () => __awaiter(void 0, void 0, void 0, function* () {
    log('down');
    yield (promiseTriggersDown({
        schemaName: 'public',
        tableName: 'strings',
        valueType: 'TEXT',
        customColumnsSql: 'value text',
        linkRelation: 'string',
        linksTableName: 'links',
        api,
        deep,
    })());
    yield (promiseTriggersDown({
        schemaName: 'public',
        tableName: 'numbers',
        valueType: 'float8',
        customColumnsSql: 'value bigint',
        linkRelation: 'number',
        linksTableName: 'links',
        api,
        deep,
    })());
    yield (promiseTriggersDown({
        schemaName: 'public',
        tableName: 'objects',
        valueType: 'jsonb',
        customColumnsSql: 'value jsonb',
        linkRelation: 'object',
        linksTableName: 'links',
        api,
        deep,
    })());
    yield api.sql(sql `DROP TRIGGER IF EXISTS z_${LINKS_TABLE_NAME}__promise__insert__trigger ON "${LINKS_TABLE_NAME}";`);
    yield api.sql(sql `DROP FUNCTION IF EXISTS ${LINKS_TABLE_NAME}__promise__insert__function CASCADE;`);
    yield api.sql(sql `DROP TRIGGER IF EXISTS ${LINKS_TABLE_NAME}__promise__update__trigger ON "${LINKS_TABLE_NAME}";`);
    yield api.sql(sql `DROP FUNCTION IF EXISTS ${LINKS_TABLE_NAME}__promise__update__function CASCADE;`);
    yield api.sql(sql `DROP TRIGGER IF EXISTS ${LINKS_TABLE_NAME}__promise__delete__trigger ON "${LINKS_TABLE_NAME}";`);
    yield api.sql(sql `DROP FUNCTION IF EXISTS ${LINKS_TABLE_NAME}__promise__delete__function CASCADE;`);
    yield api.sql(sql `DROP FUNCTION IF EXISTS get_handle_operation_details CASCADE;`);
    yield api.sql(sql `DROP FUNCTION IF EXISTS insert_promise CASCADE;`);
    yield api.query({
        type: 'untrack_table',
        args: {
            table: {
                schema: 'public',
                name: 'promise_links',
            },
            cascade: true,
        },
    });
    yield api.sql(sql `DROP TABLE IF EXISTS "public"."promise_links" CASCADE;`);
    yield api.sql(sql `DROP TYPE IF EXISTS values_operation_type CASCADE;`);
});
//# sourceMappingURL=1637975150590-promises.js.map