drop function if exists get_current_operation;

create function get_current_operation() returns integer as
$$
select id from current_operation as result;
$$
language sql;


drop function if exists add_operation;

create function add_operation(redo_sql text, undo_sql text, redo_cs json, undo_cs json) returns void as
$$
declare
    parent_id integer;
    op_id integer;

begin
    parent_id := get_current_operation();

    insert into operation (id, redo, undo, parent, redo_change_set, undo_change_set)
        values (default, redo_sql, undo_sql, parent_id, redo_cs, undo_cs);

    select max(id) into op_id from operation;

    update current_operation set id = op_id where id = parent_id;

end;
$$
language plpgsql;


drop function if exists execute_undo;

create function execute_undo(discard boolean) returns json as
$$
#print_strict_params on

declare
    op_row operation%ROWTYPE;

begin
    select * into strict op_row from operation where id = get_current_operation();
    if op_row.undo = '' then
        return '{}'::json;
    end if;

    execute op_row.undo;

    -- update foreign key
    update current_operation set id = op_row.parent where id = op_row.id;

    if discard then
        -- update foreign key
        update operation set redo_child = null where id = op_row.parent;
        -- on delete cascade => child & snapshot
        delete from operation where id = op_row.id;
    else
        update operation set redo_child = op_row.id where id = op_row.parent;
    end if;

    return op_row.undo_change_set;

end;
$$
language plpgsql;


-- create function execute_redo() returns json as
-- $$
-- #print_strict_params on
-- 
-- declare
--     op_id integer;
--     redo_c integer;
--     redo_row operation%ROWTYPE;
-- 
-- begin
--     op_id := get_current_operation();
-- 
--     select redo_child into redo_c from operation where id = op_id;
-- 
-- end;
-- $$
-- language plpgsql;