├── .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 | 
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 |
--------------------------------------------------------------------------------
]