├── .gitignore ├── .pipeline └── config.yml ├── src ├── zif_abap_thenable.intf.abap ├── zabap_async.fugr.lzabap_asynctop.abap ├── zcl_promise.clas.locals_def.abap ├── zif_promise_handler.intf.abap ├── zif_abap_async.intf.abap ├── zif_promise.intf.abap ├── package.devc.xml ├── zif_promise_state.intf.abap ├── zabap_async.fugr.lzabap_asynctop.xml ├── zabap_async.fugr.saplzabap_async.xml ├── zif_abap_async.intf.xml ├── zif_abap_thenable.intf.xml ├── zif_promise_state.intf.xml ├── zcl_promise_handler.clas.xml ├── zcl_abap_async.clas.xml ├── zcl_promise_handler.clas.abap ├── zcl_abap_async_task.clas.xml ├── zcl_abap_sync.clas.xml ├── zcl_abap_async_task.clas.abap ├── zcx_promise_not_resolved.clas.abap ├── zif_promise.intf.xml ├── zcx_promise_rejected.clas.abap ├── zcl_promise_state.clas.xml ├── zcx_promise_rejected.clas.xml ├── zcx_promise_not_resolved.clas.xml ├── zabap_async.fugr.saplzabap_async.abap ├── zif_promise_handler.intf.xml ├── zcl_promise_resolver.clas.xml ├── zcl_abap_async.clas.abap ├── zabap_async.fugr.zabap_async_await.abap ├── zcl_promise_state.clas.abap ├── zabap_async.fugr.xml ├── zcl_promise_resolver.clas.abap ├── zcl_promise.clas.xml ├── zcl_promise_resolver.clas.locals_imp.abap ├── zcl_abap_sync.clas.abap ├── zcl_abap_async_task.clas.locals_imp.abap ├── zcl_promise_resolver.clas.testclasses.abap ├── zcl_promise.clas.locals_imp.abap ├── zcl_promise.clas.abap ├── zcl_abap_async.clas.testclasses.abap ├── zcl_abap_sync.clas.testclasses.abap ├── zcl_abap_async_task.clas.testclasses.abap └── zcl_promise.clas.testclasses.abap ├── .abapgit.xml ├── aunitConfig.yml ├── package.json ├── .devcontainer ├── Dockerfile ├── base.Dockerfile └── devcontainer.json ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | *_errorDetails.json 4 | -------------------------------------------------------------------------------- /.pipeline/config.yml: -------------------------------------------------------------------------------- 1 | stages: 2 | AUnit: 3 | aUnitConfig: 'aUnitConfig.yml' -------------------------------------------------------------------------------- /src/zif_abap_thenable.intf.abap: -------------------------------------------------------------------------------- 1 | interface ZIF_ABAP_THENABLE 2 | public . 3 | 4 | 5 | interfaces IF_SERIALIZABLE_OBJECT . 6 | 7 | methods THEN . 8 | endinterface. 9 | -------------------------------------------------------------------------------- /src/zabap_async.fugr.lzabap_asynctop.abap: -------------------------------------------------------------------------------- 1 | FUNCTION-POOL ZABAP_ASYNC. "MESSAGE-ID .. 2 | 3 | * INCLUDE LZABAP_ASYNCD... " Local class definition 4 | -------------------------------------------------------------------------------- /src/zcl_promise.clas.locals_def.abap: -------------------------------------------------------------------------------- 1 | *"* use this source file for any type of declarations (class 2 | *"* definitions, interfaces or type declarations) you need for 3 | *"* components in the private section 4 | "TYPES: ZCL_PROMISES=>PROMISES TYPE xxxxxx. 5 | -------------------------------------------------------------------------------- /src/zif_promise_handler.intf.abap: -------------------------------------------------------------------------------- 1 | interface ZIF_PROMISE_HANDLER 2 | public . 3 | 4 | 5 | methods ON_FULFILLED 6 | importing 7 | !WITH type ref to DATA . 8 | methods ON_REJECTED 9 | importing 10 | !WITH type ref to DATA . 11 | endinterface. 12 | -------------------------------------------------------------------------------- /src/zif_abap_async.intf.abap: -------------------------------------------------------------------------------- 1 | interface ZIF_ABAP_ASYNC 2 | public . 3 | 4 | 5 | class-methods AWAIT 6 | importing 7 | !FOR type ANY 8 | returning 9 | value(RESULT) type ref to DATA 10 | raising 11 | ZCX_PROMISE_REJECTED . 12 | endinterface. 13 | -------------------------------------------------------------------------------- /.abapgit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | E 6 | /src/ 7 | PREFIX 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/zif_promise.intf.abap: -------------------------------------------------------------------------------- 1 | interface ZIF_PROMISE 2 | public . 3 | 4 | 5 | types: 6 | PROMISES TYPE table of REF TO ZIF_PROMISE WITH EMPTY KEY . 7 | 8 | methods THEN 9 | importing 10 | !HANDLER type ref to ZIF_PROMISE_HANDLER 11 | returning 12 | value(RESULT) type ref to ZIF_PROMISE . 13 | endinterface. 14 | -------------------------------------------------------------------------------- /src/package.devc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ABAP promise 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /aunitConfig.yml: -------------------------------------------------------------------------------- 1 | title: My AUnit run 2 | context: AUnit test run 3 | options: 4 | measurements: none 5 | scope: 6 | ownTests: true 7 | foreignTests: true 8 | riskLevel: 9 | harmless: true 10 | dangerous: true 11 | critical: true 12 | duration: 13 | short: true 14 | medium: true 15 | long: true 16 | objectSet: 17 | softwarecomponents: 18 | - name: Z_TEST_SC 19 | - name: Z_TEST_SC2 -------------------------------------------------------------------------------- /src/zif_promise_state.intf.abap: -------------------------------------------------------------------------------- 1 | interface ZIF_PROMISE_STATE 2 | public . 3 | 4 | 5 | types STATE_TYPE type STRING . 6 | 7 | constants PENDING type STATE_TYPE value 'pending' ##NO_TEXT. 8 | constants REJECTED type STATE_TYPE value 'rejected' ##NO_TEXT. 9 | constants FULFILLED type STATE_TYPE value 'fulfilled' ##NO_TEXT. 10 | data STATE type STATE_TYPE read-only . 11 | data RESULT type ref to DATA read-only . 12 | 13 | events STATE_CHANGED . 14 | endinterface. 15 | -------------------------------------------------------------------------------- /src/zabap_async.fugr.lzabap_asynctop.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | LZABAP_ASYNCTOP 7 | S 8 | D$ 9 | I 10 | S 11 | X 12 | D$S 13 | X 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/zabap_async.fugr.saplzabap_async.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | SAPLZABAP_ASYNC 7 | S 8 | D$ 9 | F 10 | S 11 | E 12 | X 13 | D$S 14 | X 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/zif_abap_async.intf.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ZIF_ABAP_ASYNC 7 | E 8 | Async interface 9 | 2 10 | 1 11 | X 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/zif_abap_thenable.intf.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ZIF_ABAP_THENABLE 7 | E 8 | Thenable object 9 | 2 10 | 1 11 | X 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/zif_promise_state.intf.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ZIF_PROMISE_STATE 7 | E 8 | Promise state 9 | 2 10 | 1 11 | X 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/zcl_promise_handler.clas.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ZCL_PROMISE_HANDLER 7 | E 8 | Promise handler 9 | 1 10 | X 11 | X 12 | X 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/zcl_abap_async.clas.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ZCL_ABAP_ASYNC 7 | E 8 | Async function 9 | 1 10 | X 11 | X 12 | X 13 | X 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/zcl_promise_handler.clas.abap: -------------------------------------------------------------------------------- 1 | class ZCL_PROMISE_HANDLER definition 2 | public 3 | create public . 4 | 5 | public section. 6 | 7 | interfaces ZIF_PROMISE_HANDLER . 8 | 9 | aliases ON_FULFILLED 10 | for ZIF_PROMISE_HANDLER~ON_FULFILLED . 11 | aliases ON_REJECTED 12 | for ZIF_PROMISE_HANDLER~ON_REJECTED . 13 | protected section. 14 | private section. 15 | ENDCLASS. 16 | 17 | 18 | 19 | CLASS ZCL_PROMISE_HANDLER IMPLEMENTATION. 20 | 21 | 22 | method ZIF_PROMISE_HANDLER~ON_FULFILLED. 23 | endmethod. 24 | 25 | 26 | method ZIF_PROMISE_HANDLER~ON_REJECTED. 27 | endmethod. 28 | ENDCLASS. 29 | -------------------------------------------------------------------------------- /src/zcl_abap_async_task.clas.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ZCL_ABAP_ASYNC_TASK 7 | E 8 | Asyncronous abap task 9 | 1 10 | X 11 | X 12 | X 13 | X 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/zcl_abap_sync.clas.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ZCL_ABAP_SYNC 7 | E 8 | Syncronous part of async/await implementation 9 | 1 10 | X 11 | X 12 | X 13 | X 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/zcl_abap_async_task.clas.abap: -------------------------------------------------------------------------------- 1 | class ZCL_ABAP_ASYNC_TASK definition 2 | public 3 | final 4 | create private 5 | 6 | global friends ZCL_ABAP_ASYNC 7 | ZCL_PROMISE . 8 | 9 | public section. 10 | 11 | data STATE type ref to Zcl_PROMISE_STATE read-only . 12 | 13 | methods CONSTRUCTOR 14 | importing 15 | !THENABLE type ref to ZIF_ABAP_THENABLE . 16 | protected section. 17 | private section. 18 | ENDCLASS. 19 | 20 | 21 | 22 | CLASS ZCL_ABAP_ASYNC_TASK IMPLEMENTATION. 23 | 24 | 25 | method constructor. 26 | 27 | me->state = new lcl_async_task( thenable )->state. 28 | 29 | endmethod. 30 | ENDCLASS. 31 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@abapify/promise", 3 | "version": "1.0.0", 4 | "description": "Promise Polyfill ABAP implementation", 5 | "main": "index.js", 6 | "scripts": { 7 | "lint": "abaplint", 8 | "unit": "piper gctsExecuteABAPQualityChecks", 9 | "unit:dev": "dotenv-run-script unit", 10 | "test": "npm run lint && npm run unit" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "https://gitlab.booking.com/finsys/abap/promise.git" 15 | }, 16 | "author": "", 17 | "license": "ISC", 18 | "dependencies": { 19 | "@abaplint/cli": "^2.91.4", 20 | "@abaplint/transpiler-cli": "^2.0.44" 21 | }, 22 | "devDependencies": { 23 | "dotenv-run-script": "^0.2.0" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/zcx_promise_not_resolved.clas.abap: -------------------------------------------------------------------------------- 1 | class ZCX_PROMISE_NOT_RESOLVED definition 2 | public 3 | inheriting from CX_NO_CHECK 4 | final 5 | create private 6 | 7 | global friends ZCL_ABAP_ASYNC 8 | ZCL_ABAP_SYNC 9 | ZCL_PROMISE . 10 | 11 | public section. 12 | 13 | methods CONSTRUCTOR 14 | importing 15 | !TEXTID like TEXTID optional 16 | !PREVIOUS like PREVIOUS optional . 17 | protected section. 18 | private section. 19 | ENDCLASS. 20 | 21 | 22 | 23 | CLASS ZCX_PROMISE_NOT_RESOLVED IMPLEMENTATION. 24 | 25 | 26 | method CONSTRUCTOR. 27 | CALL METHOD SUPER->CONSTRUCTOR 28 | EXPORTING 29 | TEXTID = TEXTID 30 | PREVIOUS = PREVIOUS 31 | . 32 | endmethod. 33 | ENDCLASS. 34 | -------------------------------------------------------------------------------- /src/zif_promise.intf.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ZIF_PROMISE 7 | E 8 | Promise 9 | 2 10 | 1 11 | X 12 | 13 | 14 | 15 | ZIF_PROMISE 16 | THEN 17 | E 18 | Promise.prototype.then 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/zcx_promise_rejected.clas.abap: -------------------------------------------------------------------------------- 1 | class ZCX_PROMISE_REJECTED definition 2 | public 3 | inheriting from CX_STATIC_CHECK 4 | create private 5 | 6 | global friends ZCL_ABAP_ASYNC 7 | ZCL_ABAP_SYNC . 8 | 9 | public section. 10 | 11 | data WITH type ref to DATA read-only . 12 | 13 | methods CONSTRUCTOR 14 | importing 15 | !TEXTID like TEXTID optional 16 | !PREVIOUS like PREVIOUS optional 17 | !WITH type ref to DATA optional . 18 | protected section. 19 | private section. 20 | ENDCLASS. 21 | 22 | 23 | 24 | CLASS ZCX_PROMISE_REJECTED IMPLEMENTATION. 25 | 26 | 27 | method CONSTRUCTOR. 28 | CALL METHOD SUPER->CONSTRUCTOR 29 | EXPORTING 30 | TEXTID = TEXTID 31 | PREVIOUS = PREVIOUS 32 | . 33 | me->WITH = WITH . 34 | endmethod. 35 | ENDCLASS. 36 | -------------------------------------------------------------------------------- /src/zcl_promise_state.clas.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ZCL_PROMISE_STATE 7 | E 8 | Promise state 9 | 1 10 | X 11 | X 12 | X 13 | 14 | 15 | 16 | ZCL_PROMISE_STATE 17 | CONSTRUCTOR 18 | E 19 | CONSTRUCTOR 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/zcx_promise_rejected.clas.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ZCX_PROMISE_REJECTED 7 | E 8 | Promise state changed 9 | 40 10 | 1 11 | X 12 | X 13 | X 14 | 15 | 16 | 17 | ZCX_PROMISE_REJECTED 18 | CONSTRUCTOR 19 | E 20 | CONSTRUCTOR 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/zcx_promise_not_resolved.clas.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ZCX_PROMISE_NOT_RESOLVED 7 | E 8 | Promise not resolved or not rejected 9 | 40 10 | 1 11 | X 12 | X 13 | X 14 | 15 | 16 | 17 | ZCX_PROMISE_NOT_RESOLVED 18 | CONSTRUCTOR 19 | E 20 | CONSTRUCTOR 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/zabap_async.fugr.saplzabap_async.abap: -------------------------------------------------------------------------------- 1 | ******************************************************************* 2 | * System-defined Include-files. * 3 | ******************************************************************* 4 | INCLUDE LZABAP_ASYNCTOP. " Global Data 5 | INCLUDE LZABAP_ASYNCUXX. " Function Modules 6 | 7 | ******************************************************************* 8 | * User-defined Include-files (if necessary). * 9 | ******************************************************************* 10 | * INCLUDE LZABAP_ASYNCF... " Subroutines 11 | * INCLUDE LZABAP_ASYNCO... " PBO-Modules 12 | * INCLUDE LZABAP_ASYNCI... " PAI-Modules 13 | * INCLUDE LZABAP_ASYNCE... " Events 14 | * INCLUDE LZABAP_ASYNCP... " Local class implement. 15 | * INCLUDE LZABAP_ASYNCT99. " ABAP Unit tests 16 | -------------------------------------------------------------------------------- /src/zif_promise_handler.intf.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ZIF_PROMISE_HANDLER 7 | E 8 | Promise handler 9 | 2 10 | 1 11 | X 12 | 13 | 14 | 15 | ZIF_PROMISE_HANDLER 16 | ON_FULFILLED 17 | E 18 | onFulfilled 19 | 20 | 21 | ZIF_PROMISE_HANDLER 22 | ON_REJECTED 23 | E 24 | onRejected 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | # [Choice] Node.js version (use -bullseye variants on local arm64/Apple Silicon): 18, 16, 14, 18-bullseye, 16-bullseye, 14-bullseye, 18-buster, 16-buster, 14-buster 2 | ARG VARIANT=16-bullseye 3 | FROM mcr.microsoft.com/vscode/devcontainers/typescript-node:0-${VARIANT} 4 | 5 | RUN wget https://github.com/SAP/jenkins-library/releases/latest/download/piper && \ 6 | chmod +x piper && \ 7 | mv piper /usr/bin 8 | 9 | 10 | 11 | # [Optional] Uncomment this section to install additional OS packages. 12 | # RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ 13 | # && apt-get -y install --no-install-recommends 14 | 15 | # [Optional] Uncomment if you want to install an additional version of node using nvm 16 | # ARG EXTRA_NODE_VERSION=10 17 | # RUN su node -c "source /usr/local/share/nvm/nvm.sh && nvm install ${EXTRA_NODE_VERSION}" 18 | 19 | # [Optional] Uncomment if you want to install more global node packages 20 | # RUN su node -c "npm install -g " 21 | -------------------------------------------------------------------------------- /.devcontainer/base.Dockerfile: -------------------------------------------------------------------------------- 1 | # [Choice] Node.js version (use -bullseye variants on local arm64/Apple Silicon): 18, 16, 14, 18-bullseye, 16-bullseye, 14-bullseye, 18-buster, 16-buster, 14-buster 2 | ARG VARIANT=16-bullseye 3 | FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:0-${VARIANT} 4 | 5 | # Install tslint, typescript. eslint is installed by javascript image 6 | ARG NODE_MODULES="tslint-to-eslint-config typescript" 7 | COPY library-scripts/meta.env /usr/local/etc/vscode-dev-containers 8 | RUN su node -c "umask 0002 && npm install -g ${NODE_MODULES}" \ 9 | && npm cache clean --force > /dev/null 2>&1 10 | 11 | # [Optional] Uncomment this section to install additional OS packages. 12 | # RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ 13 | # && apt-get -y install --no-install-recommends 14 | 15 | # [Optional] Uncomment if you want to install an additional version of node using nvm 16 | # ARG EXTRA_NODE_VERSION=10 17 | # RUN su node -c "source /usr/local/share/nvm/nvm.sh && nvm install ${EXTRA_NODE_VERSION}" 18 | -------------------------------------------------------------------------------- /src/zcl_promise_resolver.clas.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ZCL_PROMISE_RESOLVER 7 | E 8 | Promise resolver 9 | 1 10 | X 11 | X 12 | X 13 | X 14 | 15 | 16 | 17 | ZCL_PROMISE_RESOLVER 18 | CLASS_CONSTRUCTOR 19 | E 20 | CLASS_CONSTRUCTOR 21 | 22 | 23 | ZCL_PROMISE_RESOLVER 24 | PROMISE_EXCEPTION_TYPE 25 | E 26 | Runtime Type Services 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 abapify 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/zcl_abap_async.clas.abap: -------------------------------------------------------------------------------- 1 | class ZCL_ABAP_ASYNC definition 2 | public 3 | create public . 4 | 5 | public section. 6 | 7 | interfaces ZIF_ABAP_ASYNC . 8 | 9 | aliases AWAIT 10 | for ZIF_ABAP_ASYNC~AWAIT . 11 | protected section. 12 | private section. 13 | ENDCLASS. 14 | 15 | 16 | 17 | CLASS ZCL_ABAP_ASYNC IMPLEMENTATION. 18 | 19 | 20 | method zif_abap_async~await. 21 | 22 | " promise handling 23 | try. 24 | data(state) = cast zcl_promise( for )->state. 25 | catch cx_sy_move_cast_error. 26 | 27 | " direct thenable assignment 28 | try. 29 | state = new zcl_abap_async_task( cast #( for ) )->state. 30 | catch cx_sy_move_cast_error. 31 | endtry. 32 | 33 | endtry. 34 | 35 | " fallback 36 | if state is not bound. 37 | result = ref #( for ). 38 | return. 39 | endif. 40 | 41 | wait for asynchronous tasks until state->state ne state->pending. 42 | 43 | case state->state. 44 | when state->fulfilled. 45 | result = state->result. 46 | when state->rejected. 47 | raise exception type zcx_promise_rejected 48 | exporting 49 | with = state->result. 50 | endcase. 51 | 52 | endmethod. 53 | ENDCLASS. 54 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: 2 | // https://github.com/microsoft/vscode-dev-containers/tree/v0.238.0/containers/typescript-node 3 | { 4 | "name": "Node.js & TypeScript", 5 | "build": { 6 | "dockerfile": "Dockerfile", 7 | // Update 'VARIANT' to pick a Node version: 18, 16, 14. 8 | // Append -bullseye or -buster to pin to an OS version. 9 | // Use -bullseye variants on local on arm64/Apple Silicon. 10 | "args": { 11 | "VARIANT": "16-bullseye" 12 | } 13 | }, 14 | 15 | // Configure tool-specific properties. 16 | "customizations": { 17 | // Configure properties specific to VS Code. 18 | "vscode": { 19 | // Add the IDs of extensions you want installed when the container is created. 20 | "extensions": [ 21 | "dbaeumer.vscode-eslint", 22 | "eamodio.gitlens" 23 | ] 24 | } 25 | }, 26 | 27 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 28 | // "forwardPorts": [], 29 | 30 | // Use 'postCreateCommand' to run commands after the container is created. 31 | // "postCreateCommand": "yarn install", 32 | 33 | // Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. 34 | "remoteUser": "node" 35 | } 36 | -------------------------------------------------------------------------------- /src/zabap_async.fugr.zabap_async_await.abap: -------------------------------------------------------------------------------- 1 | function zabap_async_await. 2 | *"---------------------------------------------------------------------- 3 | *"*"Local Interface: 4 | *" IMPORTING 5 | *" VALUE(FOR) TYPE XSTRING 6 | *" EXPORTING 7 | *" VALUE(WITH) TYPE XSTRING 8 | *" VALUE(STATE) TYPE STRING 9 | *"---------------------------------------------------------------------- 10 | 11 | data resolver type ref to zif_abap_thenable. 12 | 13 | " deserialize request 14 | call transformation id 15 | source xml for 16 | result object = resolver. 17 | 18 | try. 19 | data(result) = zcl_abap_sync=>await( for = resolver ). 20 | 21 | state = zif_promise_state=>fulfilled. 22 | 23 | catch zcx_promise_rejected into data(lo_cx_rejected). " 24 | 25 | result = lo_cx_rejected->with. 26 | 27 | state = zif_promise_state=>rejected. 28 | 29 | catch cx_no_check into data(lo_cx). 30 | 31 | call transformation id 32 | source cx_no_check = lo_cx 33 | result xml with 34 | options data_refs = 'heap-or-create'. 35 | 36 | state = zif_promise_state=>rejected. 37 | 38 | endtry. 39 | 40 | if result is bound. 41 | 42 | call transformation id 43 | source data = result 44 | result xml with 45 | options data_refs = 'heap-or-create'. 46 | 47 | endif. 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | endfunction. 56 | -------------------------------------------------------------------------------- /src/zcl_promise_state.clas.abap: -------------------------------------------------------------------------------- 1 | class ZCL_PROMISE_STATE definition 2 | public 3 | final 4 | create public 5 | 6 | global friends ZCL_ABAP_ASYNC_TASK . 7 | 8 | public section. 9 | 10 | interfaces ZIF_PROMISE_STATE . 11 | 12 | methods CONSTRUCTOR . 13 | methods RESOLVE 14 | importing 15 | !WITH type ref to DATA RETURNING VALUE(this) TYPE REF TO zcl_promise_state. 16 | 17 | methods REJECT 18 | importing 19 | !WITH type ref to DATA RETURNING VALUE(this) TYPE REF TO zcl_promise_state. 20 | protected section. 21 | private section. 22 | 23 | aliases FULFILLED 24 | for ZIF_PROMISE_STATE~FULFILLED . 25 | aliases PENDING 26 | for ZIF_PROMISE_STATE~PENDING . 27 | aliases REJECTED 28 | for ZIF_PROMISE_STATE~REJECTED . 29 | aliases RESULT 30 | for ZIF_PROMISE_STATE~RESULT . 31 | aliases STATE 32 | for ZIF_PROMISE_STATE~STATE . 33 | ENDCLASS. 34 | 35 | 36 | 37 | CLASS ZCL_PROMISE_STATE IMPLEMENTATION. 38 | 39 | 40 | method CONSTRUCTOR. 41 | me->state = pending. 42 | endmethod. 43 | 44 | 45 | method REJECT. 46 | 47 | ASSERT state eq pending. 48 | state = rejected. 49 | result = with. 50 | this = me. 51 | 52 | RAISE event zif_promise_state~state_changed. 53 | 54 | endmethod. 55 | 56 | 57 | method RESOLVE. 58 | ASSERT state eq pending. 59 | state = fulfilled. 60 | result = with. 61 | this = me. 62 | RAISE event zif_promise_state~state_changed. 63 | endmethod. 64 | ENDCLASS. 65 | -------------------------------------------------------------------------------- /src/zabap_async.fugr.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Async/Await ABAP implementation 6 | 7 | LZABAP_ASYNCTOP 8 | SAPLZABAP_ASYNC 9 | 10 | 11 | 12 | ZABAP_ASYNC_AWAIT 13 | X 14 | Async await 15 | X 16 | 17 | 18 | FOR 19 | XSTRING 20 | 21 | 22 | 23 | 24 | WITH 25 | XSTRING 26 | 27 | 28 | STATE 29 | STRING 30 | 31 | 32 | 33 | 34 | FOR 35 | P 36 | note to payee string with foreign currency format 37 | 38 | 39 | WITH 40 | P 41 | 42 | 43 | STATE 44 | P 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /src/zcl_promise_resolver.clas.abap: -------------------------------------------------------------------------------- 1 | class ZCL_PROMISE_RESOLVER definition 2 | public 3 | inheriting from ZCL_ABAP_ASYNC 4 | abstract 5 | create public 6 | 7 | global friends ZCL_ABAP_ASYNC 8 | ZCL_ABAP_SYNC . 9 | 10 | public section. 11 | 12 | interfaces IF_SERIALIZABLE_OBJECT . 13 | interfaces ZIF_ABAP_THENABLE 14 | all methods abstract . 15 | 16 | aliases THEN 17 | for ZIF_ABAP_THENABLE~THEN . 18 | 19 | class-methods CLASS_CONSTRUCTOR . 20 | protected section. 21 | 22 | methods RESOLVE 23 | final 24 | importing 25 | !WITH type ANY optional . 26 | methods REJECT 27 | final 28 | importing 29 | !WITH type ANY optional . 30 | private section. 31 | 32 | types STATUS_TV type I . 33 | 34 | class-data PROMISE_EXCEPTION_TYPE type ref to CL_ABAP_OBJECTDESCR . 35 | ENDCLASS. 36 | 37 | 38 | 39 | CLASS ZCL_PROMISE_RESOLVER IMPLEMENTATION. 40 | 41 | 42 | method class_constructor. 43 | 44 | types promise_exception_ref type ref to lcx_promise_state_changed. 45 | 46 | promise_exception_type = cast #( cast cl_abap_refdescr( 47 | cl_abap_typedescr=>describe_by_data_ref( 48 | new promise_exception_ref( ) ) 49 | )->get_referenced_type( ) ). 50 | 51 | endmethod. 52 | 53 | 54 | method REJECT. 55 | RAISE EXCEPTION TYPE lcx_promise_rejected EXPORTING with = ref=>from( with ). 56 | endmethod. 57 | 58 | 59 | method RESOLVE. 60 | 61 | RAISE EXCEPTION TYPE lcx_promise_resolved EXPORTING with = ref=>from( with ). 62 | 63 | endmethod. 64 | ENDCLASS. 65 | -------------------------------------------------------------------------------- /src/zcl_promise.clas.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ZCL_PROMISE 7 | E 8 | ABAP promise polyfill 9 | 1 10 | X 11 | X 12 | X 13 | X 14 | 15 | 16 | 17 | ZCL_PROMISE 18 | ALL 19 | E 20 | Promise.all 21 | 22 | 23 | ZCL_PROMISE 24 | CONSTRUCTOR 25 | E 26 | CONSTRUCTOR 27 | 28 | 29 | ZCL_PROMISE 30 | ON_STATE_CHANGED 31 | E 32 | Handle promise state changed 33 | 34 | 35 | ZCL_PROMISE 36 | REJECT 37 | E 38 | Promise.reject 39 | 40 | 41 | ZCL_PROMISE 42 | RESOLVE 43 | E 44 | Promise.resolve 45 | 46 | 47 | ZCL_PROMISE 48 | STATE 49 | E 50 | Promise state 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /src/zcl_promise_resolver.clas.locals_imp.abap: -------------------------------------------------------------------------------- 1 | *"* use this source file for the definition and implementation of 2 | *"* local helper classes, interface definitions and type 3 | *"* declarations 4 | 5 | class lcx_promise_state_changed definition inheriting from cx_no_check. 6 | public section. 7 | interfaces zif_promise_state. 8 | methods constructor importing with type ref to data. 9 | protected section. 10 | 11 | aliases with for zif_promise_state~result. 12 | aliases state for zif_promise_state~state. 13 | aliases resolved for zif_promise_state~fulfilled. 14 | aliases rejected for zif_promise_state~rejected. 15 | 16 | private section. 17 | 18 | endclass. 19 | 20 | class lcx_promise_resolved definition inheriting from lcx_promise_state_changed friends zcl_promise_resolver. 21 | public section. 22 | methods constructor importing with type ref to data. 23 | endclass. 24 | 25 | class lcx_promise_rejected definition inheriting from lcx_promise_state_changed friends zcl_promise_resolver. 26 | public section. 27 | methods constructor importing with type ref to data. 28 | endclass. 29 | 30 | class lcx_promise_state_changed implementation. 31 | method constructor. 32 | super->constructor( ). 33 | me->with = with. 34 | endmethod. 35 | endclass. 36 | 37 | class lcx_promise_resolved implementation. 38 | method constructor. 39 | super->constructor( with ). 40 | me->state = resolved. 41 | endmethod. 42 | endclass. 43 | 44 | class lcx_promise_rejected implementation. 45 | method constructor. 46 | super->constructor( with ). 47 | me->state = rejected. 48 | endmethod. 49 | endclass. 50 | 51 | class ref definition abstract. 52 | public section. 53 | class-methods: 54 | from importing from type any returning value(ref) type ref to data. 55 | endclass. 56 | 57 | class ref implementation. 58 | method from. 59 | try. 60 | ref = cast #( from ). 61 | catch cx_sy_move_cast_error. 62 | "avoid loosing data due to freeing 63 | CREATE DATA ref like from. 64 | assign ref->* to FIELD-SYMBOL(). 65 | = from. 66 | endtry. 67 | endmethod. 68 | endclass. 69 | -------------------------------------------------------------------------------- /src/zcl_abap_sync.clas.abap: -------------------------------------------------------------------------------- 1 | class ZCL_ABAP_SYNC definition 2 | public 3 | create public . 4 | 5 | public section. 6 | 7 | class-methods AWAIT 8 | importing 9 | !FOR type ANY 10 | returning 11 | value(RESULT) type ref to DATA 12 | raising 13 | ZCX_PROMISE_REJECTED . 14 | protected section. 15 | private section. 16 | 17 | class-methods GET_THENABLE 18 | importing 19 | !FROM type ANY 20 | returning 21 | value(RESULT) type ref to ZIF_ABAP_THENABLE . 22 | ENDCLASS. 23 | 24 | 25 | 26 | CLASS ZCL_ABAP_SYNC IMPLEMENTATION. 27 | 28 | 29 | method AWAIT. 30 | 31 | try. 32 | 33 | " if it's thenable 34 | data(thenable) = get_thenable( from = for ). 35 | 36 | if thenable is not bound. 37 | 38 | result = ref #( for ). 39 | * try. 40 | * result = cast #( for ). 41 | * catch cx_sy_move_cast_error. 42 | * result = ref #( for ). 43 | * endtry. 44 | return. 45 | endif. 46 | 47 | thenable->then( ). 48 | 49 | raise exception type zcx_promise_not_resolved. 50 | 51 | catch cx_no_check into data(lo_cx). 52 | 53 | if zcl_promise_resolver=>promise_exception_type->applies_to( lo_cx ) eq abap_true. 54 | 55 | " no need to check cast because type check 56 | data(state) = cast zif_promise_state( lo_cx ). 57 | case state->state. 58 | when state->rejected. 59 | raise exception type zcx_promise_rejected 60 | exporting 61 | previous = lo_cx 62 | with = state->result. 63 | when state->fulfilled. 64 | result = state->result. 65 | return. 66 | endcase. 67 | 68 | endif. 69 | 70 | raise exception lo_cx. 71 | 72 | endtry. 73 | 74 | endmethod. 75 | 76 | 77 | method GET_THENABLE. 78 | 79 | " if thenable 80 | try. 81 | result = cast #( from ). 82 | return. 83 | CATCH cx_sy_move_cast_error. 84 | endtry. 85 | 86 | " if thenable 87 | * try. 88 | * result = cast zcl_promise( from )->resolver. 89 | * return. 90 | * CATCH cx_sy_move_cast_error. 91 | * endtry. 92 | 93 | endmethod. 94 | ENDCLASS. 95 | -------------------------------------------------------------------------------- /src/zcl_abap_async_task.clas.locals_imp.abap: -------------------------------------------------------------------------------- 1 | *"* use this source file for the definition and implementation of 2 | *"* local helper classes, interface definitions and type 3 | *"* declarations 4 | 5 | *"* use this source file for the definition and implementation of 6 | *"* local helper classes, interface definitions and type 7 | *"* declarations 8 | 9 | class lcl_async_task definition deferred. 10 | 11 | class lcl_async_task definition CREATE PRIVATE FRIENDS zcl_abap_async_task. 12 | public section. 13 | 14 | types task_id_type type sysuuid_c32. 15 | methods constructor importing thenable type ref to zif_abap_thenable. 16 | methods await importing p_task type task_id_type. 17 | 18 | private section. 19 | data: task_id type task_id_type. 20 | data state type ref to zcl_promise_state. 21 | 22 | 23 | endclass. 24 | 25 | class lcl_async_task implementation. 26 | 27 | method constructor. 28 | 29 | try. 30 | 31 | call transformation id 32 | source object = thenable 33 | result xml data(lv_thenable_xml). 34 | 35 | me->task_id = cl_uuid_factory=>create_system_uuid( )->create_uuid_c32( ). 36 | me->state = new zcl_promise_state( ). 37 | 38 | call function 'ZABAP_ASYNC_AWAIT' starting new task me->task_id 39 | calling await on end of task 40 | exporting 41 | for = lv_thenable_xml. 42 | 43 | catch cx_uuid_error. " 44 | endtry. 45 | 46 | endmethod. 47 | 48 | method await. 49 | 50 | data await_xml type xstring. 51 | data await_state type string. 52 | 53 | receive results from function 'ZABAP_ASYNC_AWAIT' 54 | importing 55 | with = await_xml 56 | state = await_state 57 | exceptions 58 | others = 4. 59 | 60 | case sy-subrc. 61 | when 0. 62 | 63 | if await_xml is not initial. 64 | data with type ref to data. 65 | call transformation id 66 | source xml await_xml 67 | result data = with. 68 | endif. 69 | 70 | case await_state. 71 | when zif_promise_state=>fulfilled. 72 | state->resolve( with ). 73 | when zif_promise_state=>rejected. 74 | state->reject( with ). 75 | endcase. 76 | 77 | when others. 78 | message id sy-msgid type sy-msgty number sy-msgno 79 | with sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4 into data(lv_message). 80 | state->reject( new string( lv_message ) ). 81 | endcase. 82 | 83 | endmethod. 84 | 85 | endclass. 86 | -------------------------------------------------------------------------------- /src/zcl_promise_resolver.clas.testclasses.abap: -------------------------------------------------------------------------------- 1 | *"* use this source file for your ABAP unit test classes 2 | class tcl_main definition inheriting from zcl_promise_resolver for testing risk level harmless duration short. 3 | public section. 4 | methods test_resolve for testing. 5 | methods test_reject for testing. 6 | METHODs then REDEFINITION. 7 | endclass. 8 | 9 | class tcl_resolved definition for testing inheriting from zcl_promise_resolver. 10 | public section. 11 | constants resolution type string value 'OK'. 12 | methods then redefinition. 13 | endclass. 14 | 15 | class tcl_resolved implementation. 16 | method then. 17 | resolve( resolution ). 18 | endmethod. 19 | endclass. 20 | 21 | class tcl_rejected definition for testing inheriting from zcl_promise_resolver. 22 | public section. 23 | constants resolution type string value 'Error'. 24 | methods then redefinition. 25 | endclass. 26 | 27 | class tcl_rejected implementation. 28 | method then. 29 | reject( resolution ). 30 | endmethod. 31 | endclass. 32 | 33 | 34 | class tcl_main implementation. 35 | METHOD then. 36 | "needed because parent is abstract 37 | "we need this inheritance to access with variable of exception 38 | endmethod. 39 | method test_resolve. 40 | 41 | try. 42 | new tcl_resolved( )->then( ). 43 | 44 | cl_abap_unit_assert=>fail( 'Should exit after resolve' ). 45 | 46 | catch lcx_promise_resolved into data(lo_cx). 47 | 48 | cl_abap_unit_assert=>assert_bound( lo_cx->with ). 49 | 50 | assign lo_cx->with->* to field-symbol(). 51 | 52 | cl_abap_unit_assert=>assert_equals( 53 | exporting 54 | act = " Data object with current value 55 | exp = tcl_resolved=>resolution " Data object with expected type 56 | ). 57 | 58 | endtry. 59 | 60 | endmethod. 61 | 62 | method test_reject. 63 | 64 | try. 65 | new tcl_rejected( )->then( ). 66 | 67 | cl_abap_unit_assert=>fail( 'Should exit after resolve' ). 68 | 69 | catch lcx_promise_rejected into data(lo_cx). 70 | 71 | cl_abap_unit_assert=>assert_bound( lo_cx->with ). 72 | 73 | assign lo_cx->with->* to field-symbol(). 74 | 75 | cl_abap_unit_assert=>assert_equals( 76 | exporting 77 | act = " Data object with current value 78 | exp = tcl_rejected=>resolution " Data object with expected type 79 | ). 80 | 81 | endtry. 82 | 83 | endmethod. 84 | endclass. 85 | -------------------------------------------------------------------------------- /src/zcl_promise.clas.locals_imp.abap: -------------------------------------------------------------------------------- 1 | *"* use this source file for the definition and implementation of 2 | *"* local helper classes, interface definitions and type 3 | *"* declarations 4 | 5 | class lcl_resolved definition deferred. 6 | class lcl_rejected definition deferred. 7 | 8 | 9 | class lcl_settled_promise definition abstract create protected 10 | inheriting from zcl_promise_resolver friends zcl_promise lcl_resolved lcl_rejected . 11 | 12 | PUBLIC SECTION. 13 | METHODs then REDEFINITION. 14 | METHODs constructor. 15 | 16 | protected section. 17 | data state type ref to zif_promise_state. 18 | 19 | endclass. 20 | 21 | CLASS lcl_settled_promise IMPLEMENTATION. 22 | METHOD constructor. 23 | super->constructor( ). 24 | " only for coverage 25 | " this method is empty - but should be declared as it's a promise resolver 26 | then( ). 27 | endmethod. 28 | METHOD then. 29 | ENDMETHOD. 30 | endclass. 31 | 32 | class lcl_resolved definition inheriting from lcl_settled_promise create private friends zcl_promise. 33 | public section. 34 | methods constructor 35 | importing with type ref to data. 36 | endclass. 37 | 38 | class lcl_rejected definition inheriting from lcl_settled_promise create private friends zcl_promise. 39 | public section. 40 | methods constructor 41 | importing with type ref to data. 42 | endclass. 43 | 44 | class lcl_resolved implementation. 45 | method constructor. 46 | super->constructor( ). 47 | state = new zcl_promise_state( )->resolve( with ). 48 | endmethod. 49 | endclass. 50 | 51 | class lcl_rejected implementation. 52 | method constructor. 53 | super->constructor( ). 54 | state = new zcl_promise_state( )->reject( with ). 55 | endmethod. 56 | endclass. 57 | 58 | class ref definition abstract. 59 | public section. 60 | class-methods: 61 | from importing from type any returning value(ref) type ref to data. 62 | endclass. 63 | 64 | class ref implementation. 65 | method from. 66 | try. 67 | ref = cast #( from ). 68 | catch cx_sy_move_cast_error. 69 | ref = ref #( from ). 70 | endtry. 71 | endmethod. 72 | endclass. 73 | 74 | *CLASS lcl_handler DEFINITION. 75 | * PUBLIC SECTION. 76 | * METHODs constructor 77 | * IMPORTING 78 | * handler TYPE REF TO zif_promise_handler 79 | * state TYPE REF TO zif_promise_state. 80 | * PRIVATE SECTION. 81 | * METHODs on_state_changed FOR EVENT state_changed of zif_promise_state. 82 | *endclass. 83 | * 84 | *CLASS lcl_handler IMPLEMENTATION. 85 | * METHODS constructor. 86 | * me->handler = handler. 87 | * SET HANDLER on_state_changed for state. 88 | * endmethod. 89 | * METHOD on_state_changed. 90 | * case sender->state. 91 | * when sender->fulfilled. 92 | * handler->on_fulfilled( sender->result ). 93 | * when sender->rected. 94 | * handler->on_rejected( sender->result ). 95 | * endcase. 96 | * endmethod. 97 | *ENDCLASS. 98 | -------------------------------------------------------------------------------- /src/zcl_promise.clas.abap: -------------------------------------------------------------------------------- 1 | class ZCL_PROMISE definition 2 | public 3 | inheriting from ZCL_ABAP_ASYNC 4 | final 5 | create public 6 | 7 | global friends ZCL_ABAP_ASYNC . 8 | 9 | public section. 10 | 11 | interfaces ZIF_PROMISE . 12 | 13 | aliases THEN 14 | for ZIF_PROMISE~THEN . 15 | 16 | types: 17 | RESULTS TYPE TABLE OF REF TO data WITH EMPTY KEY . 18 | types: 19 | PROMISES TYPE TABLE OF REF TO zcl_promise WITH EMPTY KEY . 20 | 21 | methods CONSTRUCTOR 22 | importing 23 | !RESOLVER type ref to ZCL_PROMISE_RESOLVER . 24 | class-methods ALL 25 | importing 26 | !PROMISES type PROMISES 27 | returning 28 | value(RESULT) type ref to ZIF_PROMISE . 29 | class-methods RESOLVE 30 | importing 31 | !WITH type ANY optional 32 | returning 33 | value(RESULT) type ref to ZIF_PROMISE . 34 | class-methods REJECT 35 | importing 36 | !REASON type ANY optional 37 | returning 38 | value(RESULT) type ref to ZIF_PROMISE . 39 | protected section. 40 | private section. 41 | 42 | data STATE type ref to ZIF_PROMISE_STATE . 43 | data: 44 | HANDLERS TYPE TABLE OF REF TO zif_promise_handler WITH EMPTY KEY . 45 | 46 | methods ON_STATE_CHANGED 47 | for event STATE_CHANGED of ZIF_PROMISE_STATE . 48 | ENDCLASS. 49 | 50 | 51 | 52 | CLASS ZCL_PROMISE IMPLEMENTATION. 53 | 54 | 55 | method all. 56 | 57 | " wait for all promises to be settled 58 | wait for asynchronous tasks 59 | until line_exists( promises[ table_line->state->state = zif_promise_state=>rejected ] ) 60 | or not line_exists( promises[ table_line->state->state = zif_promise_state=>pending ] ). 61 | 62 | data lt_results type results. " type table of ref to data with empty key. 63 | 64 | LOOP at promises INTO data(promise). 65 | CASE promise->state->state . 66 | WHEN zif_promise_state=>rejected. 67 | result = reject( promise->state->result ). 68 | return. 69 | WHEN OTHERS. 70 | APPEND promise->state->result to lt_results. 71 | ENDCASE. 72 | ENDLOOP. 73 | 74 | result = resolve( new results( lt_results ) ). 75 | 76 | endmethod. 77 | 78 | 79 | method constructor. 80 | 81 | super->constructor( ). 82 | 83 | " Promise.resolve/Promise.reject support 84 | try. 85 | me->state = cast lcl_settled_promise( resolver )->state. 86 | catch cx_sy_move_cast_error. 87 | "create async task 88 | me->state = new zcl_abap_async_task( resolver )->state. 89 | endtry. 90 | 91 | set HANDLER on_state_changed for me->state. 92 | 93 | endmethod. 94 | 95 | 96 | method on_state_changed. 97 | 98 | " makes sense to process only if it's changed 99 | check state->state ne state->pending. 100 | 101 | loop at handlers into data(handler). 102 | 103 | " delete handler if it's non-pending. 104 | delete handlers index sy-tabix. 105 | check handler is bound. 106 | 107 | case state->state. 108 | when state->fulfilled. 109 | handler->on_fulfilled( state->result ). 110 | when state->rejected. 111 | handler->on_rejected( state->result ). 112 | endcase. 113 | 114 | endloop. 115 | 116 | endmethod. 117 | 118 | 119 | method reject. 120 | 121 | result = new zcl_promise( new lcl_rejected( ref=>from( reason ) ) ). 122 | 123 | endmethod. 124 | 125 | 126 | method resolve. 127 | 128 | result = new zcl_promise( new lcl_resolved( ref=>from( with ) ) ). 129 | 130 | endmethod. 131 | 132 | 133 | method zif_promise~then. 134 | 135 | APPEND handler to handlers. 136 | 137 | " in case if state is not pending already 138 | me->on_state_changed( ). 139 | 140 | " chaining support 141 | result = me. 142 | 143 | endmethod. 144 | ENDCLASS. 145 | -------------------------------------------------------------------------------- /src/zcl_abap_async.clas.testclasses.abap: -------------------------------------------------------------------------------- 1 | *"* use this source file for your ABAP unit test classes 2 | 3 | class tcl_main definition inheriting from zcl_abap_async 4 | for testing risk level harmless duration short. 5 | private section. 6 | 7 | methods test_await_resolved for testing. 8 | methods test_await_rejected for testing. 9 | methods test_any_other_cx for testing. 10 | methods test_no_resolution for testing. 11 | methods test_no_async for testing. 12 | 13 | endclass. 14 | 15 | class tcl_resolved definition for testing inheriting from zcl_promise_resolver. 16 | public section. 17 | constants resolution type string value 'OK'. 18 | methods then redefinition. 19 | endclass. 20 | 21 | class tcl_resolved implementation. 22 | method then. 23 | resolve( resolution ). 24 | endmethod. 25 | endclass. 26 | 27 | class tcl_rejected definition for testing inheriting from zcl_promise_resolver. 28 | public section. 29 | constants resolution type string value 'Error'. 30 | methods then redefinition. 31 | endclass. 32 | 33 | class tcl_rejected implementation. 34 | method then. 35 | reject( resolution ). 36 | endmethod. 37 | endclass. 38 | 39 | class tcl_other_cx definition FOR TESTING inheriting from zcl_promise_resolver. 40 | public section. 41 | methods then redefinition. 42 | endclass. 43 | 44 | class lcx_other_cx definition inheriting from cx_no_check. 45 | endclass. 46 | 47 | class tcl_other_cx implementation. 48 | method then. 49 | raise exception type lcx_other_cx. 50 | endmethod. 51 | endclass. 52 | 53 | class tcl_dummy_resolver definition for testing inheriting from zcl_promise_resolver. 54 | public section. 55 | methods then redefinition. 56 | endclass. 57 | 58 | class tcl_dummy_resolver implementation. 59 | method then. 60 | " no resolve or reject call 61 | endmethod. 62 | endclass. 63 | 64 | 65 | 66 | class tcl_main implementation. 67 | method test_await_resolved. 68 | 69 | try. 70 | 71 | data(result) = cast string( await( new tcl_resolved( ) ) ). 72 | 73 | cl_abap_unit_assert=>assert_equals( 74 | exporting 75 | act = result->* " Data object with current value 76 | exp = tcl_resolved=>resolution " Data object with expected type 77 | ). 78 | 79 | catch zcx_promise_rejected. 80 | 81 | cl_abap_unit_assert=>fail( 'Must be no exception' ). 82 | 83 | endtry. 84 | 85 | endmethod. 86 | 87 | method test_await_rejected. 88 | 89 | try. 90 | 91 | data(lr_result) = await( new tcl_rejected( ) ). 92 | 93 | cl_abap_unit_assert=>fail( 'Exception is not raised' ). 94 | 95 | catch zcx_promise_rejected into data(lo_cx). 96 | 97 | data(result) = cast string( lo_cx->with ). 98 | 99 | cl_abap_unit_assert=>assert_equals( 100 | exporting 101 | act = result->* " Data object with current value 102 | exp = tcl_rejected=>resolution " Data object with expected type 103 | ). 104 | 105 | endtry. 106 | 107 | endmethod. 108 | 109 | method test_any_other_cx. 110 | 111 | try. 112 | await( new tcl_other_cx( ) ). 113 | cl_abap_unit_assert=>fail( ). 114 | CATCH zcx_promise_rejected. 115 | cl_abap_unit_assert=>fail( ). 116 | catch lcx_other_cx. 117 | return. 118 | endtry. 119 | 120 | 121 | 122 | endmethod. 123 | 124 | method test_no_resolution. 125 | 126 | try. 127 | await( new tcl_dummy_resolver( ) ). 128 | cl_abap_unit_assert=>fail( 'Should not be resolved' ). 129 | catch zcx_promise_not_resolved. 130 | catch zcx_promise_rejected. 131 | cl_abap_unit_assert=>fail( 'Should not be rejected' ). 132 | endtry. 133 | 134 | endmethod. 135 | 136 | method test_no_async. 137 | 138 | try. 139 | 140 | cl_abap_refdescr=>get_ref_to_data( ). 141 | 142 | data(result) = cast abap_bool( await( abap_true ) ). 143 | 144 | " should proxy the values - if it's not async 145 | cl_abap_unit_assert=>assert_true( result->* ). 146 | 147 | catch zcx_promise_rejected. 148 | cl_abap_unit_assert=>fail( ). 149 | endtry. 150 | 151 | endmethod. 152 | endclass. 153 | -------------------------------------------------------------------------------- /src/zcl_abap_sync.clas.testclasses.abap: -------------------------------------------------------------------------------- 1 | *"* use this source file for your ABAP unit test classes 2 | 3 | class tcl_main definition inheriting from zcl_abap_sync 4 | for testing risk level harmless duration short. 5 | private section. 6 | 7 | methods test_await_resolved for testing. 8 | methods test_await_rejected for testing. 9 | methods test_any_other_cx for testing. 10 | methods test_no_resolution for testing. 11 | methods test_no_async for testing. 12 | 13 | endclass. 14 | 15 | class tcl_resolved definition for testing inheriting from zcl_promise_resolver. 16 | public section. 17 | constants resolution type string value 'OK'. 18 | methods then redefinition. 19 | endclass. 20 | 21 | class tcl_resolved implementation. 22 | method then. 23 | resolve( resolution ). 24 | endmethod. 25 | endclass. 26 | 27 | class tcl_rejected definition for testing inheriting from zcl_promise_resolver. 28 | public section. 29 | constants resolution type string value 'Error'. 30 | methods then redefinition. 31 | endclass. 32 | 33 | class tcl_rejected implementation. 34 | method then. 35 | reject( resolution ). 36 | endmethod. 37 | endclass. 38 | 39 | class tcl_other_cx definition inheriting from zcl_promise_resolver. 40 | public section. 41 | methods then redefinition. 42 | endclass. 43 | 44 | class lcx_other_cx definition inheriting from cx_no_check. 45 | endclass. 46 | 47 | class tcl_other_cx implementation. 48 | method then. 49 | raise exception type lcx_other_cx. 50 | endmethod. 51 | endclass. 52 | 53 | class tcl_dummy_resolver definition for testing inheriting from zcl_promise_resolver. 54 | public section. 55 | methods then redefinition. 56 | endclass. 57 | 58 | class tcl_dummy_resolver implementation. 59 | method then. 60 | " no resolve or reject call 61 | endmethod. 62 | endclass. 63 | 64 | 65 | 66 | class tcl_main implementation. 67 | method test_await_resolved. 68 | 69 | try. 70 | 71 | data(lr_result) = await( new tcl_resolved( ) ). 72 | assign lr_result->* to field-symbol(). 73 | 74 | cl_abap_unit_assert=>assert_equals( 75 | exporting 76 | act = " Data object with current value 77 | exp = tcl_resolved=>resolution " Data object with expected type 78 | ). 79 | 80 | catch zcx_promise_rejected. 81 | 82 | cl_abap_unit_assert=>fail( 'Must be no exception' ). 83 | 84 | endtry. 85 | 86 | endmethod. 87 | 88 | method test_await_rejected. 89 | 90 | try. 91 | 92 | data(lr_result) = await( new tcl_rejected( ) ). 93 | 94 | cl_abap_unit_assert=>fail( 'Exception is not raised' ). 95 | 96 | catch zcx_promise_rejected into data(lo_cx). 97 | 98 | assign lo_cx->with->* to field-symbol(). 99 | 100 | cl_abap_unit_assert=>assert_equals( 101 | exporting 102 | act = " Data object with current value 103 | exp = tcl_rejected=>resolution " Data object with expected type 104 | ). 105 | 106 | endtry. 107 | 108 | endmethod. 109 | 110 | method test_any_other_cx. 111 | 112 | try. 113 | await( new tcl_other_cx( ) ). 114 | catch zcx_promise_rejected. 115 | catch lcx_other_cx. 116 | return. 117 | endtry. 118 | 119 | cl_abap_unit_assert=>fail( ). 120 | 121 | endmethod. 122 | 123 | method test_no_resolution. 124 | 125 | try. 126 | await( new tcl_dummy_resolver( ) ). 127 | cl_abap_unit_assert=>fail( 'Should not be resolved' ). 128 | catch zcx_promise_not_resolved. 129 | catch zcx_promise_rejected. 130 | cl_abap_unit_assert=>fail( 'Should not be rejected' ). 131 | endtry. 132 | 133 | endmethod. 134 | 135 | method test_no_async. 136 | 137 | try. 138 | 139 | cl_abap_refdescr=>get_ref_to_data( ). 140 | 141 | data(result) = cast abap_bool( await( abap_true ) ). 142 | 143 | " should proxy the values - if it's not async 144 | cl_abap_unit_assert=>assert_true( result->* ). 145 | 146 | catch zcx_promise_rejected. 147 | cl_abap_unit_assert=>fail( ). 148 | endtry. 149 | 150 | endmethod. 151 | endclass. 152 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Let's make ABAP async! 2 | 3 | To understand how this class work use this as a reference: 4 | https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise 5 | 6 | ## How to use 7 | 8 | ### Promise 9 | 10 | what runs in js 11 | 12 | ```js 13 | new Promise( ( resolve, reject ) => { resolve( 'OK' ) } ).then( ( value ) => console.log( value ) ) // OK 14 | ``` 15 | 16 | now runs in ABAP ( with a bit more lines of course ) 17 | ```abap 18 | REPORT ZTEST_PROMISE_OK. 19 | 20 | " Promise Resolver 21 | " Must implement then method with mandatory resolve or reject method calls from inside 22 | CLASS lcl_ok DEFINITION INHERITING FROM zcl_promise_resolver. 23 | PUBLIC SECTION. 24 | METHODS then REDEFINITION. 25 | ENDCLASS. 26 | 27 | CLASS lcl_ok IMPLEMENTATION. 28 | METHOD then. 29 | " resolve is declared in zcl_promise_resolver 30 | resolve( |OK| ). 31 | ENDMETHOD. 32 | ENDCLASS. 33 | 34 | " Promise handler 35 | " has on_fulfilled and on_rejected callbacks with default empty implementation 36 | CLASS lcl_ok_handler DEFINITION INHERITING FROM zcl_promise_handler. 37 | PUBLIC SECTION. 38 | METHODS ON_FULFILLED REDEFINITION. 39 | ENDCLASS. 40 | 41 | CLASS lcl_ok_handler IMPLEMENTATION. 42 | METHOD on_fulfilled. 43 | " ideally resolver needs to know which type it expects to have as a result 44 | write cast string( with )->*. 45 | ENDMETHOD. 46 | endclass. 47 | 48 | START-OF-SELECTION. 49 | 50 | new zcl_promise( new lcl_ok( ) )->then( new lcl_ok_handler( ) ). 51 | ``` 52 | 53 | ### So what's the purpose? 54 | 55 | You probably think, why we wouldn't just run `write 'OK'` 56 | 57 | The answer is in the following sequence diagram 58 | 59 | ![zcl_promise](https://user-images.githubusercontent.com/6381507/175093547-7f5cd10e-3b64-400d-8f93-60a4e8de6328.svg) 60 | 61 | What promise class does during inititalization - is creating an asyncronous task with serialized resolver instance. 62 | Asyncronous task deserialises resolver and executes it. It may be time consuming operation, for example some calculation, query, or http request. So why won't let the rest of abap code work for something else? 63 | So when your code decides that it's time to get data from promise and only then actually triggers for wait statement. Once an asynctronous task is done by triggering resolve/reject method in your resolver instance - it will serialize again the response and send back to your main session. 64 | 65 | You may not see the desired effect for single operations - but for promise=>all call the effect can be huge! 66 | 67 | ## And what about async/await? 68 | 69 | To use full power of promises we can also use await functions. 70 | 71 | So mentioned above example may look a bit differently: 72 | 73 | ```js 74 | async function() { 75 | console.log( await new Promise( ( resolve, reject ) => { resolve( 'OK' ) } ) ) // OK 76 | } 77 | ``` 78 | 79 | now works in ABAP 80 | ```abap 81 | REPORT ZTEST_PROMISE_OK_AWAIT. 82 | 83 | " Promise Resolver 84 | " Must implement then method with mandatory resolve or reject method calls from inside 85 | CLASS lcl_ok DEFINITION INHERITING FROM zcl_promise_resolver. 86 | PUBLIC SECTION. 87 | METHODS then REDEFINITION. 88 | ENDCLASS. 89 | 90 | CLASS lcl_ok IMPLEMENTATION. 91 | METHOD then. 92 | " resolve is declared in zcl_promise_resolver 93 | resolve( |OK| ). 94 | ENDMETHOD. 95 | ENDCLASS. 96 | 97 | CLASS lcl_app DEFINITION INHERITING FROM zcl_abap_async. 98 | PUBLIC SECTION. 99 | METHODs start. 100 | ENDCLASS. 101 | 102 | CLASS lcl_app IMPLEMENTATION. 103 | METHOD start. 104 | " we expect result as ref to string 105 | write cast string( 106 | " in case if it's async class ( child of async ) 107 | " you can just use await of any promise 108 | await( new zcl_promise( new lcl_ok( ) ) ) )->*. 109 | ENDMETHOD. 110 | ENDCLASS. 111 | 112 | START-OF-SELECTION. 113 | " start the app 114 | new lcl_app( )->start( ). 115 | ``` 116 | 117 | ## Other methods 118 | 119 | ### Promise=>all 120 | 121 | Returns a new promise, resolved with array of promises results or rejected with a reason of the first rejected promise 122 | 123 | ### Promise=>race 124 | 125 | ### Promise=>resolve 126 | 127 | Returns resolved promise 128 | 129 | ### Promise=>reject 130 | 131 | Returns rejected promise 132 | 133 | ### Promise=>all_settled 134 | 135 | -------------------------------------------------------------------------------- /src/zcl_abap_async_task.clas.testclasses.abap: -------------------------------------------------------------------------------- 1 | *"* use this source file for your ABAP unit test classes 2 | 3 | *"* use this source file for your ABAP unit test classes 4 | 5 | class tcl_main definition INHERITING FROM zcl_abap_async 6 | for testing risk level harmless duration short. 7 | private section. 8 | 9 | methods test_await_resolved for testing. 10 | methods test_await_rejected for testing. 11 | methods test_any_other_cx for testing. 12 | methods test_no_resolution for testing. 13 | methods test_no_async for testing. 14 | 15 | endclass. 16 | 17 | class tcl_resolved definition for testing inheriting from zcl_promise_resolver. 18 | public section. 19 | constants resolution type string value 'OK'. 20 | methods then redefinition. 21 | endclass. 22 | 23 | class tcl_resolved implementation. 24 | method then. 25 | resolve( resolution ). 26 | endmethod. 27 | endclass. 28 | 29 | class tcl_rejected definition for testing inheriting from zcl_promise_resolver. 30 | public section. 31 | constants resolution type string value 'Error'. 32 | methods then redefinition. 33 | endclass. 34 | 35 | class tcl_rejected implementation. 36 | method then. 37 | reject( resolution ). 38 | endmethod. 39 | endclass. 40 | 41 | class tcl_other_cx definition FOR TESTING inheriting from zcl_promise_resolver. 42 | public section. 43 | methods then redefinition. 44 | endclass. 45 | 46 | class lcx_other_cx definition inheriting from cx_no_check. 47 | endclass. 48 | 49 | class tcl_other_cx implementation. 50 | method then. 51 | raise exception type lcx_other_cx. 52 | endmethod. 53 | endclass. 54 | 55 | class tcl_dummy_resolver definition for testing inheriting from zcl_promise_resolver. 56 | public section. 57 | methods then redefinition. 58 | endclass. 59 | 60 | class tcl_dummy_resolver implementation. 61 | method then. 62 | " no resolve or reject call 63 | endmethod. 64 | endclass. 65 | 66 | 67 | 68 | class tcl_main implementation. 69 | 70 | method test_await_resolved. 71 | 72 | try. 73 | 74 | data(result) = cast string( await( new tcl_resolved( ) ) ). 75 | 76 | cl_abap_unit_assert=>assert_equals( 77 | exporting 78 | act = result->* " Data object with current value 79 | exp = tcl_resolved=>resolution " Data object with expected type 80 | ). 81 | 82 | catch zcx_promise_rejected. 83 | 84 | cl_abap_unit_assert=>fail( 'Must be no exception' ). 85 | 86 | endtry. 87 | 88 | endmethod. 89 | 90 | method test_await_rejected. 91 | 92 | try. 93 | 94 | data(lr_result) = await( new tcl_rejected( ) ). 95 | 96 | cl_abap_unit_assert=>fail( 'Exception is not raised' ). 97 | 98 | catch zcx_promise_rejected into data(lo_cx). 99 | 100 | data(result) = cast string( lo_cx->with ). 101 | 102 | cl_abap_unit_assert=>assert_equals( 103 | exporting 104 | act = result->* " Data object with current value 105 | exp = tcl_rejected=>resolution " Data object with expected type 106 | ). 107 | 108 | endtry. 109 | 110 | endmethod. 111 | 112 | method test_any_other_cx. 113 | 114 | try. 115 | await( new tcl_other_cx( ) ). 116 | cl_abap_unit_assert=>fail( ). 117 | CATCH zcx_promise_rejected. 118 | cl_abap_unit_assert=>fail( ). 119 | catch lcx_other_cx. 120 | return. 121 | endtry. 122 | 123 | 124 | 125 | endmethod. 126 | 127 | method test_no_resolution. 128 | 129 | try. 130 | await( new tcl_dummy_resolver( ) ). 131 | cl_abap_unit_assert=>fail( 'Should not be resolved' ). 132 | catch zcx_promise_not_resolved. 133 | catch zcx_promise_rejected. 134 | cl_abap_unit_assert=>fail( 'Should not be rejected' ). 135 | endtry. 136 | 137 | endmethod. 138 | 139 | method test_no_async. 140 | 141 | try. 142 | 143 | cl_abap_refdescr=>get_ref_to_data( ). 144 | 145 | data(result) = cast abap_bool( await( abap_true ) ). 146 | 147 | " should proxy the values - if it's not async 148 | cl_abap_unit_assert=>assert_true( result->* ). 149 | 150 | catch zcx_promise_rejected. 151 | cl_abap_unit_assert=>fail( ). 152 | endtry. 153 | 154 | endmethod. 155 | endclass. 156 | -------------------------------------------------------------------------------- /src/zcl_promise.clas.testclasses.abap: -------------------------------------------------------------------------------- 1 | *"* use this source file for your ABAP unit test classes 2 | class tcl_main definition inheriting from zcl_abap_async 3 | for testing risk level harmless duration short. 4 | public section. 5 | interfaces: zif_promise_handler. 6 | private section. 7 | methods test_resolved for testing. 8 | methods test_rejected for testing. 9 | methods test_no_resolution for testing. 10 | methods test_promise_all_true for testing. 11 | methods test_promise_all_false for testing. 12 | methods test_ref for testing. 13 | data on_fulfilled type abap_bool. 14 | data on_rejected type abap_bool. 15 | endclass. 16 | 17 | class tcl_resolved definition for testing inheriting from zcl_promise_resolver. 18 | public section. 19 | constants resolution type string value 'OK'. 20 | methods then redefinition. 21 | endclass. 22 | 23 | class tcl_resolved implementation. 24 | method then. 25 | resolve( resolution ). 26 | endmethod. 27 | endclass. 28 | 29 | class tcl_rejected definition for testing inheriting from zcl_promise_resolver. 30 | public section. 31 | constants resolution type string value 'Error'. 32 | methods then redefinition. 33 | endclass. 34 | 35 | class tcl_rejected implementation. 36 | method then. 37 | reject( resolution ). 38 | endmethod. 39 | endclass. 40 | 41 | class tcl_dummy_resolver definition for testing inheriting from zcl_promise_resolver. 42 | public section. 43 | methods then redefinition. 44 | endclass. 45 | 46 | class tcl_dummy_resolver implementation. 47 | method then. 48 | " no resolve or reject call 49 | endmethod. 50 | endclass. 51 | 52 | class tcl_main implementation. 53 | 54 | method test_resolved. 55 | 56 | " this code will start a new session 57 | data(promise) = new zcl_promise( new tcl_resolved( ) )->then( me ). 58 | 59 | " however result is not yet here 60 | " it should not be processed yet 61 | cl_abap_unit_assert=>assert_false( on_fulfilled ). 62 | cl_abap_unit_assert=>assert_false( on_rejected ). 63 | 64 | " now we await for promise execution + validate result 65 | try. 66 | cl_abap_unit_assert=>assert_equals( 67 | act = cast string( await( promise ) )->* 68 | exp = tcl_resolved=>resolution ). 69 | catch zcx_promise_rejected. 70 | cl_abap_unit_assert=>fail( ). 71 | endtry. 72 | 73 | " and now we expect that is resolved 74 | cl_abap_unit_assert=>assert_true( on_fulfilled ). 75 | cl_abap_unit_assert=>assert_false( on_rejected ). 76 | 77 | endmethod. 78 | 79 | method test_rejected. 80 | " this code will start a new session 81 | data(promise) = new zcl_promise( new tcl_rejected( ) )->then( me ). 82 | 83 | " however result is not yet here 84 | " it should not be processed yet 85 | cl_abap_unit_assert=>assert_false( on_fulfilled ). 86 | cl_abap_unit_assert=>assert_false( on_rejected ). 87 | 88 | " now we await for promise execution + validate result 89 | try. 90 | await( promise ). 91 | cl_abap_unit_assert=>fail( ). 92 | catch zcx_promise_rejected into data(lo_cx). 93 | 94 | cl_abap_unit_assert=>assert_equals( 95 | act = cast string( lo_cx->with )->* 96 | exp = tcl_rejected=>resolution ). 97 | 98 | endtry. 99 | 100 | " and now we expect that is resolved 101 | cl_abap_unit_assert=>assert_false( on_fulfilled ). 102 | cl_abap_unit_assert=>assert_true( on_rejected ). 103 | 104 | 105 | endmethod. 106 | 107 | method zif_promise_handler~on_fulfilled. 108 | 109 | check with is bound. 110 | 111 | assign with->* to field-symbol(). 112 | 113 | cl_abap_unit_assert=>assert_equals( 114 | exporting 115 | act = " Data object with current value 116 | exp = tcl_resolved=>resolution " Data object with expected type 117 | ). 118 | 119 | on_fulfilled = abap_true. 120 | 121 | endmethod. 122 | 123 | method zif_promise_handler~on_rejected. 124 | 125 | check with is bound. 126 | 127 | assign with->* to field-symbol(). 128 | 129 | cl_abap_unit_assert=>assert_equals( 130 | exporting 131 | act = " Data object with current value 132 | exp = tcl_rejected=>resolution " Data object with expected type 133 | ). 134 | 135 | on_rejected = abap_true. 136 | 137 | endmethod. 138 | 139 | method test_no_resolution. 140 | 141 | try. 142 | new zcl_promise( new tcl_dummy_resolver( ) )->then( me ). 143 | cl_abap_unit_assert=>assert_false( on_fulfilled ). 144 | cl_abap_unit_assert=>assert_false( on_rejected ). 145 | catch zcx_promise_not_resolved. 146 | endtry. 147 | 148 | endmethod. 149 | 150 | method test_promise_all_true. 151 | 152 | " two resolved promises 153 | data(lo_promise) = zcl_promise=>all( value #( 154 | ( new #( new tcl_resolved( ) ) ) 155 | ( new #( new tcl_resolved( ) ) ) 156 | ) ). 157 | 158 | " await 159 | try. 160 | data(lr_results) = cast zcl_promise=>results( await( lo_promise ) ). 161 | catch zcx_promise_rejected. 162 | cl_abap_unit_assert=>fail( ). 163 | endtry. 164 | 165 | cl_abap_unit_assert=>assert_equals( 166 | act = lines( lr_results->* ) 167 | exp = 2 168 | ). 169 | 170 | " every line must be OK 171 | loop at lr_results->* into data(lr_result). 172 | cl_abap_unit_assert=>assert_equals( 173 | exporting 174 | act = cast string( lr_result )->* " Data object with current value 175 | exp = tcl_resolved=>resolution " Data object with expected type 176 | ). 177 | endloop. 178 | 179 | endmethod. 180 | 181 | method test_promise_all_false. 182 | 183 | " two resolved promises 184 | data(lo_promise) = zcl_promise=>all( value #( 185 | ( new #( new tcl_resolved( ) ) ) 186 | ( new #( new tcl_rejected( ) ) ) 187 | ) ). 188 | 189 | " await 190 | try. 191 | data(lr_result) = cast string( await( lo_promise ) ). 192 | cl_abap_unit_assert=>fail( ). 193 | catch zcx_promise_rejected into data(lo_cx). 194 | 195 | cl_abap_unit_assert=>assert_equals( 196 | exporting 197 | act = cast string( lo_cx->with )->* " Data object with current value 198 | exp = tcl_rejected=>resolution " Data object with expected type 199 | ). 200 | 201 | endtry. 202 | 203 | endmethod. 204 | 205 | method test_ref. 206 | 207 | cl_abap_unit_assert=>assert_true( cast abap_bool( ref=>from( abap_true ) )->* ). 208 | cl_abap_unit_assert=>assert_true( cast abap_bool( ref=>from( ref #( abap_true ) ) )->* ). 209 | 210 | endmethod. 211 | 212 | endclass. 213 | --------------------------------------------------------------------------------