codemonth.dk

One project every month - making stuff better ...

plsql promises - chaining and thenables

So last blog entry Do or do not. on the promises library, covered the basics of what promises can give us.

This entry will cover more around chaining of promises and how you can easily run your code in parallel and still make sure they run in the right order, when needed.

Promises by definition has a method called [then]. What this method does, is that it will take the value of the promise once it is fulfilled, and use that as input to a new function defined by us. The input to then is, either a function to run when fulfilled or a function to run if rejected or both. Although not in the standard there are more and more libraries implementing a method called [done]. It has the same input options as the [then] method but it does not return a new promise. So only use this method when you do not care about the result of the chain call. Since we are in Oracle I cannot name the method [then] since it is a reserved word, so I had to add an _f to the name, so it becomes [then_f].

So here is the first example. We create a promise based on the function p_multiplier, that takes a number and multiplies it by 2. We then say that if this promise is fulfilled we want to execute the function called p_multi_convert. This function takes the previous promise result, and will return a text that will tell us if the output is less or more than 50.


declare
test_promise promise;
begin
test_promise := promise('p_multiplier', 42);
test_promise := test_promise.then_f('p_multi_convert');
promises_ninja.promise_wait(test_promise);
dbms_output.put_line('Value of test_promise2 is: ' || test_promise.getanyvalue);
end;
/

When we call then on a promise object, we always get a new promise back. That allows us to immediately expand the chain in any way we want to, and this in a way that is much more intuitive and easier compared to building this in either dbms_scheduler or dbms_rules.

So to build on the previous example, we will add an extra then call that will take the output of p_multi_convert and insert it into a table:


declare
test_promise promise;
begin
test_promise := promise('p_multiplier', 42);
test_promise := test_promise.then_f('p_multi_convert');
test_promise := test_promise.then_f('p_end_run');
promises_ninja.promise_wait(test_promise);
end;
/

Not only can we chain on the new promises. If we keep the old promises stored in variable(s) we can always step back and add a new chain to an older step as we want. Not only that, but execution order will be preserved across chains and steps. So we can go back to an older promise with the value from a future promise, and we can take an old promise and re-use in a new chain later on.

We can also run a method called [then_p]. This method allows us to chain based on a specific promise. The input is the promise we want to chain onto and then the on fulfilled function and on rejected function as in the the other method.


declare
test_promise promise;
begin
test_promise := promise('p_multiplier', 10);
test_promise.then_p(test_promise, 'p_multiplier');
promises_ninja.promise_wait(test_promise);
dbms_output.put_line('Value of test_promise is: ' || test_promise.getanyvalue);
end;
/

At first the difference between the two [then_*] methods, does not seem obvious, but all will be revealed in my next blog post, where I will cover the [all] method and the [race] method.

The database objects used for the tests can found in this github gist

Tagged in : Advanced Queuing, DBMS_SCHEDULER, Object types, PL/SQL, sys.anydata