mirror of
https://github.com/abapGit/abapGit.git
synced 2025-04-30 20:03:20 +08:00
ajson, Automatic Update (#5966)
This commit is contained in:
parent
0ea950c938
commit
95389c532b
|
@ -164,7 +164,9 @@
|
|||
"cyclic_oo": false,
|
||||
"fully_type_constants": true,
|
||||
"keep_single_parameter_on_one_line": true,
|
||||
"prefer_returning_to_exporting": true,
|
||||
"prefer_returning_to_exporting": {
|
||||
"exclude": ["/json/"]
|
||||
},
|
||||
"selection_screen_naming": true,
|
||||
"sicf_consistency": true,
|
||||
"sql_escape_host_variables": true,
|
||||
|
@ -291,7 +293,7 @@
|
|||
},
|
||||
"line_length": {
|
||||
"length": 120,
|
||||
"exclude": ["zcl_abapgit_object_pdts.clas.testclasses.abap"]
|
||||
"exclude": ["zcl_abapgit_object_pdts.clas.testclasses.abap", "/json/"]
|
||||
},
|
||||
"line_only_punc": {
|
||||
"ignoreExceptions": true
|
||||
|
|
|
@ -26,12 +26,12 @@
|
|||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@abaplint/cli": "^2.94.10",
|
||||
"@abaplint/cli": "^2.94.13",
|
||||
"@abaplint/database-sqlite": "^2.3.93",
|
||||
"@abaplint/runtime": "^2.3.93",
|
||||
"@abaplint/transpiler-cli": "^2.3.93",
|
||||
"@abaplint/runtime": "^2.3.94",
|
||||
"@abaplint/transpiler-cli": "^2.3.94",
|
||||
"abapmerge": "^0.14.8",
|
||||
"c8": "^7.12.0",
|
||||
"eslint": "^8.30.0"
|
||||
"eslint": "^8.31.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
CLASS zcl_abapgit_ajson DEFINITION
|
||||
PUBLIC
|
||||
CREATE PRIVATE .
|
||||
CREATE PUBLIC .
|
||||
|
||||
PUBLIC SECTION.
|
||||
|
||||
|
@ -24,6 +24,7 @@ CLASS zcl_abapgit_ajson DEFINITION
|
|||
ALIASES:
|
||||
clear FOR zif_abapgit_ajson~clear,
|
||||
set FOR zif_abapgit_ajson~set,
|
||||
setx FOR zif_abapgit_ajson~setx,
|
||||
set_boolean FOR zif_abapgit_ajson~set_boolean,
|
||||
set_string FOR zif_abapgit_ajson~set_string,
|
||||
set_integer FOR zif_abapgit_ajson~set_integer,
|
||||
|
@ -35,6 +36,11 @@ CLASS zcl_abapgit_ajson DEFINITION
|
|||
push FOR zif_abapgit_ajson~push,
|
||||
stringify FOR zif_abapgit_ajson~stringify.
|
||||
|
||||
ALIASES:
|
||||
clone FOR zif_abapgit_ajson~clone,
|
||||
filter FOR zif_abapgit_ajson~filter,
|
||||
map FOR zif_abapgit_ajson~map.
|
||||
|
||||
ALIASES:
|
||||
mt_json_tree FOR zif_abapgit_ajson~mt_json_tree,
|
||||
keep_item_order FOR zif_abapgit_ajson~keep_item_order,
|
||||
|
@ -51,33 +57,44 @@ CLASS zcl_abapgit_ajson DEFINITION
|
|||
RAISING
|
||||
zcx_abapgit_ajson_error .
|
||||
|
||||
CLASS-METHODS create_empty
|
||||
CLASS-METHODS create_empty " Might be deprecated, prefer using new( ) or create object
|
||||
IMPORTING
|
||||
!ii_custom_mapping TYPE REF TO zif_abapgit_ajson_mapping OPTIONAL
|
||||
iv_keep_item_order TYPE abap_bool DEFAULT abap_false
|
||||
iv_format_datetime TYPE abap_bool DEFAULT abap_true
|
||||
RETURNING
|
||||
VALUE(ro_instance) TYPE REF TO zcl_abapgit_ajson.
|
||||
|
||||
" Experimental ! May change
|
||||
CLASS-METHODS create_from
|
||||
CLASS-METHODS create_from " TODO, rename to 'from' ?
|
||||
IMPORTING
|
||||
!ii_source_json TYPE REF TO zif_abapgit_ajson
|
||||
!ii_filter TYPE REF TO zif_abapgit_ajson_filter OPTIONAL
|
||||
!ii_filter TYPE REF TO zif_abapgit_ajson_filter OPTIONAL " Might be deprecated, use filter() instead
|
||||
!ii_mapper TYPE REF TO zif_abapgit_ajson_mapping OPTIONAL " Might be deprecated, use map() instead
|
||||
RETURNING
|
||||
VALUE(ro_instance) TYPE REF TO zcl_abapgit_ajson
|
||||
RAISING
|
||||
zcx_abapgit_ajson_error .
|
||||
|
||||
METHODS constructor.
|
||||
METHODS constructor
|
||||
IMPORTING
|
||||
iv_keep_item_order TYPE abap_bool DEFAULT abap_false
|
||||
iv_format_datetime TYPE abap_bool DEFAULT abap_true.
|
||||
CLASS-METHODS new
|
||||
IMPORTING
|
||||
iv_keep_item_order TYPE abap_bool DEFAULT abap_false
|
||||
iv_format_datetime TYPE abap_bool DEFAULT abap_true
|
||||
RETURNING
|
||||
VALUE(ro_instance) TYPE REF TO zcl_abapgit_ajson.
|
||||
|
||||
PROTECTED SECTION.
|
||||
|
||||
PRIVATE SECTION.
|
||||
|
||||
DATA mv_read_only TYPE abap_bool.
|
||||
DATA mi_custom_mapping TYPE REF TO zif_abapgit_ajson_mapping.
|
||||
DATA mv_keep_item_order TYPE abap_bool.
|
||||
DATA mv_format_datetime TYPE abap_bool.
|
||||
" TODO restructure into zif_ajson=>ty_opts
|
||||
CLASS-DATA go_float_regex TYPE REF TO cl_abap_regex.
|
||||
|
||||
DATA ms_opts TYPE zif_abapgit_ajson=>ty_opts.
|
||||
DATA mi_custom_mapping TYPE REF TO zif_abapgit_ajson_mapping. " DEPRECATED, will be removed
|
||||
|
||||
METHODS get_item
|
||||
IMPORTING
|
||||
|
@ -107,44 +124,51 @@ ENDCLASS.
|
|||
|
||||
CLASS zcl_abapgit_ajson IMPLEMENTATION.
|
||||
|
||||
METHOD zif_abapgit_ajson~opts.
|
||||
rs_opts-read_only = mv_read_only.
|
||||
rs_opts-format_datetime = mv_format_datetime.
|
||||
rs_opts-keep_item_order = mv_keep_item_order.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD constructor.
|
||||
format_datetime( abap_true ).
|
||||
ms_opts-keep_item_order = iv_keep_item_order.
|
||||
format_datetime( iv_format_datetime ).
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD create_empty.
|
||||
CREATE OBJECT ro_instance.
|
||||
CREATE OBJECT ro_instance
|
||||
EXPORTING
|
||||
iv_format_datetime = iv_format_datetime
|
||||
iv_keep_item_order = iv_keep_item_order.
|
||||
ro_instance->mi_custom_mapping = ii_custom_mapping.
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD create_from.
|
||||
|
||||
DATA lo_filter_runner TYPE REF TO lcl_filter_runner.
|
||||
DATA lo_mutator_queue TYPE REF TO lcl_mutator_queue.
|
||||
|
||||
IF ii_source_json IS NOT BOUND.
|
||||
zcx_abapgit_ajson_error=>raise( 'Source not bound' ).
|
||||
ENDIF.
|
||||
|
||||
CREATE OBJECT ro_instance.
|
||||
CREATE OBJECT ro_instance
|
||||
EXPORTING
|
||||
iv_format_datetime = ii_source_json->opts( )-format_datetime
|
||||
iv_keep_item_order = ii_source_json->opts( )-keep_item_order.
|
||||
|
||||
IF ii_filter IS BOUND.
|
||||
CREATE OBJECT lo_filter_runner.
|
||||
lo_filter_runner->run(
|
||||
EXPORTING
|
||||
ii_filter = ii_filter
|
||||
it_source_tree = ii_source_json->mt_json_tree
|
||||
CHANGING
|
||||
ct_dest_tree = ro_instance->mt_json_tree ).
|
||||
ELSE.
|
||||
IF ii_filter IS NOT BOUND AND ii_mapper IS NOT BOUND.
|
||||
ro_instance->mt_json_tree = ii_source_json->mt_json_tree.
|
||||
" Copy keep order and custom mapping ???
|
||||
ELSE.
|
||||
CREATE OBJECT lo_mutator_queue.
|
||||
IF ii_mapper IS BOUND.
|
||||
" Mapping goes first. But maybe it should be a freely definable queue of processors ?
|
||||
lo_mutator_queue->add( lcl_mapper_runner=>new( ii_mapper ) ).
|
||||
ENDIF.
|
||||
IF ii_filter IS BOUND.
|
||||
lo_mutator_queue->add( lcl_filter_runner=>new( ii_filter ) ).
|
||||
ENDIF.
|
||||
lo_mutator_queue->lif_mutator_runner~run(
|
||||
EXPORTING
|
||||
it_source_tree = ii_source_json->mt_json_tree
|
||||
IMPORTING
|
||||
et_dest_tree = ro_instance->mt_json_tree ).
|
||||
ENDIF.
|
||||
|
||||
ENDMETHOD.
|
||||
|
@ -201,6 +225,14 @@ CLASS zcl_abapgit_ajson IMPLEMENTATION.
|
|||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD new.
|
||||
CREATE OBJECT ro_instance
|
||||
EXPORTING
|
||||
iv_format_datetime = iv_format_datetime
|
||||
iv_keep_item_order = iv_keep_item_order.
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD parse.
|
||||
|
||||
DATA lo_parser TYPE REF TO lcl_json_parser.
|
||||
|
@ -260,7 +292,7 @@ CLASS zcl_abapgit_ajson IMPLEMENTATION.
|
|||
|
||||
|
||||
METHOD read_only_watchdog.
|
||||
IF mv_read_only = abap_true.
|
||||
IF ms_opts-read_only = abap_true.
|
||||
zcx_abapgit_ajson_error=>raise( 'This json instance is read only' ).
|
||||
ENDIF.
|
||||
ENDMETHOD.
|
||||
|
@ -313,6 +345,11 @@ CLASS zcl_abapgit_ajson IMPLEMENTATION.
|
|||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD zif_abapgit_ajson~clone.
|
||||
ri_json = create_from( me ).
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD zif_abapgit_ajson~delete.
|
||||
|
||||
read_only_watchdog( ).
|
||||
|
@ -334,14 +371,21 @@ CLASS zcl_abapgit_ajson IMPLEMENTATION.
|
|||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD zif_abapgit_ajson~filter.
|
||||
ri_json = create_from(
|
||||
ii_source_json = me
|
||||
ii_filter = ii_filter ).
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD zif_abapgit_ajson~format_datetime.
|
||||
mv_format_datetime = iv_use_iso.
|
||||
ms_opts-format_datetime = iv_use_iso.
|
||||
ri_json = me.
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD zif_abapgit_ajson~freeze.
|
||||
mv_read_only = abap_true.
|
||||
ms_opts-read_only = abap_true.
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
|
@ -462,11 +506,18 @@ CLASS zcl_abapgit_ajson IMPLEMENTATION.
|
|||
|
||||
|
||||
METHOD zif_abapgit_ajson~keep_item_order.
|
||||
mv_keep_item_order = abap_true.
|
||||
ms_opts-keep_item_order = abap_true.
|
||||
ri_json = me.
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD zif_abapgit_ajson~map.
|
||||
ri_json = create_from(
|
||||
ii_source_json = me
|
||||
ii_mapper = ii_mapper ).
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD zif_abapgit_ajson~members.
|
||||
|
||||
DATA lv_normalized_path TYPE string.
|
||||
|
@ -481,6 +532,11 @@ CLASS zcl_abapgit_ajson IMPLEMENTATION.
|
|||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD zif_abapgit_ajson~opts.
|
||||
rs_opts = ms_opts.
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD zif_abapgit_ajson~push.
|
||||
|
||||
DATA lr_parent TYPE REF TO zif_abapgit_ajson=>ty_node.
|
||||
|
@ -507,7 +563,7 @@ CLASS zcl_abapgit_ajson IMPLEMENTATION.
|
|||
ls_new_path-name = |{ lv_new_index }|.
|
||||
|
||||
lt_new_nodes = lcl_abap_to_json=>convert(
|
||||
iv_keep_item_order = mv_keep_item_order
|
||||
is_opts = ms_opts
|
||||
iv_data = iv_val
|
||||
is_prefix = ls_new_path ).
|
||||
READ TABLE lt_new_nodes INDEX 1 REFERENCE INTO lr_new_node. " assume first record is the array item - not ideal !
|
||||
|
@ -547,16 +603,14 @@ CLASS zcl_abapgit_ajson IMPLEMENTATION.
|
|||
IF ls_split_path IS INITIAL. " Assign root, exceptional processing
|
||||
IF iv_node_type IS NOT INITIAL.
|
||||
mt_json_tree = lcl_abap_to_json=>insert_with_type(
|
||||
iv_format_datetime = mv_format_datetime
|
||||
iv_keep_item_order = mv_keep_item_order
|
||||
is_opts = ms_opts
|
||||
iv_data = iv_val
|
||||
iv_type = iv_node_type
|
||||
is_prefix = ls_split_path
|
||||
ii_custom_mapping = mi_custom_mapping ).
|
||||
ELSE.
|
||||
mt_json_tree = lcl_abap_to_json=>convert(
|
||||
iv_format_datetime = mv_format_datetime
|
||||
iv_keep_item_order = mv_keep_item_order
|
||||
is_opts = ms_opts
|
||||
iv_data = iv_val
|
||||
is_prefix = ls_split_path
|
||||
ii_custom_mapping = mi_custom_mapping ).
|
||||
|
@ -586,8 +640,7 @@ CLASS zcl_abapgit_ajson IMPLEMENTATION.
|
|||
|
||||
IF iv_node_type IS NOT INITIAL.
|
||||
lt_new_nodes = lcl_abap_to_json=>insert_with_type(
|
||||
iv_format_datetime = mv_format_datetime
|
||||
iv_keep_item_order = mv_keep_item_order
|
||||
is_opts = ms_opts
|
||||
iv_item_order = ls_deleted_node-order
|
||||
iv_data = iv_val
|
||||
iv_type = iv_node_type
|
||||
|
@ -596,8 +649,7 @@ CLASS zcl_abapgit_ajson IMPLEMENTATION.
|
|||
ii_custom_mapping = mi_custom_mapping ).
|
||||
ELSE.
|
||||
lt_new_nodes = lcl_abap_to_json=>convert(
|
||||
iv_format_datetime = mv_format_datetime
|
||||
iv_keep_item_order = mv_keep_item_order
|
||||
is_opts = ms_opts
|
||||
iv_item_order = ls_deleted_node-order
|
||||
iv_data = iv_val
|
||||
iv_array_index = lv_array_index
|
||||
|
@ -614,6 +666,74 @@ CLASS zcl_abapgit_ajson IMPLEMENTATION.
|
|||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD zif_abapgit_ajson~setx.
|
||||
|
||||
DATA lv_path TYPE string.
|
||||
DATA lv_val TYPE string.
|
||||
DATA lv_int TYPE i.
|
||||
DATA lv_dec TYPE decfloat34.
|
||||
DATA lv_last TYPE i.
|
||||
|
||||
IF iv_param IS INITIAL.
|
||||
RETURN.
|
||||
ENDIF.
|
||||
|
||||
SPLIT iv_param AT ':' INTO lv_path lv_val.
|
||||
CONDENSE lv_path.
|
||||
CONDENSE lv_val.
|
||||
|
||||
IF lv_val IS INITIAL.
|
||||
RETURN. " Hmm ? or empty string ? or null ?
|
||||
ENDIF.
|
||||
|
||||
IF go_float_regex IS NOT BOUND.
|
||||
CREATE OBJECT go_float_regex EXPORTING pattern = '^([1-9][0-9]*|0)\.[0-9]+$'.
|
||||
" expects fractional, because ints are detected separately
|
||||
ENDIF.
|
||||
|
||||
IF lv_val = 'null'.
|
||||
zif_abapgit_ajson~set_null( lv_path ).
|
||||
ELSEIF lv_val = 'true'.
|
||||
zif_abapgit_ajson~set_boolean(
|
||||
iv_path = lv_path
|
||||
iv_val = abap_true ).
|
||||
ELSEIF lv_val = 'false'.
|
||||
zif_abapgit_ajson~set_boolean(
|
||||
iv_path = lv_path
|
||||
iv_val = abap_false ).
|
||||
ELSEIF lv_val CO '0123456789'.
|
||||
lv_int = lv_val.
|
||||
zif_abapgit_ajson~set_integer(
|
||||
iv_path = lv_path
|
||||
iv_val = lv_int ).
|
||||
ELSEIF lv_val CO '0123456789.' AND go_float_regex->create_matcher( text = lv_val )->match( ) = abap_true.
|
||||
lv_dec = lv_val.
|
||||
zif_abapgit_ajson~set(
|
||||
iv_path = lv_path
|
||||
iv_val = lv_dec ).
|
||||
ELSEIF lv_val+0(1) = '{' OR lv_val+0(1) = '['.
|
||||
"Expect object/array, but no further checks, parser will catch errors
|
||||
zif_abapgit_ajson~set(
|
||||
iv_path = lv_path
|
||||
iv_val = parse( lv_val ) ).
|
||||
ELSE. " string
|
||||
lv_last = strlen( lv_val ) - 1.
|
||||
IF lv_val+0(1) = '"' AND lv_val+lv_last(1) = '"'.
|
||||
lv_val = substring(
|
||||
val = lv_val
|
||||
off = 1
|
||||
len = lv_last - 1 ).
|
||||
ENDIF.
|
||||
zif_abapgit_ajson~set_string(
|
||||
iv_path = lv_path
|
||||
iv_val = lv_val ).
|
||||
ENDIF.
|
||||
|
||||
ri_json = me.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD zif_abapgit_ajson~set_boolean.
|
||||
|
||||
ri_json = me.
|
||||
|
@ -733,7 +853,7 @@ CLASS zcl_abapgit_ajson IMPLEMENTATION.
|
|||
|
||||
rv_json = lcl_json_serializer=>stringify(
|
||||
it_json_tree = mt_json_tree
|
||||
iv_keep_item_order = mv_keep_item_order
|
||||
iv_keep_item_order = ms_opts-keep_item_order
|
||||
iv_indent = iv_indent ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
@ -777,7 +897,7 @@ CLASS zcl_abapgit_ajson IMPLEMENTATION.
|
|||
ls_new_node-name = ls_split_path-name.
|
||||
ls_new_node-type = zif_abapgit_ajson=>node_type-array.
|
||||
|
||||
IF mv_keep_item_order = abap_true AND ls_deleted_node IS NOT INITIAL.
|
||||
IF ms_opts-keep_item_order = abap_true AND ls_deleted_node IS NOT INITIAL.
|
||||
ls_new_node-order = ls_deleted_node-order.
|
||||
ENDIF.
|
||||
|
||||
|
|
|
@ -1073,8 +1073,7 @@ CLASS lcl_abap_to_json DEFINITION FINAL.
|
|||
is_prefix TYPE zif_abapgit_ajson=>ty_path_name OPTIONAL
|
||||
iv_array_index TYPE i DEFAULT 0
|
||||
ii_custom_mapping TYPE REF TO zif_abapgit_ajson_mapping OPTIONAL
|
||||
iv_keep_item_order TYPE abap_bool DEFAULT abap_false
|
||||
iv_format_datetime TYPE abap_bool DEFAULT abap_false
|
||||
is_opts TYPE zif_abapgit_ajson=>ty_opts OPTIONAL
|
||||
iv_item_order TYPE i DEFAULT 0
|
||||
RETURNING
|
||||
VALUE(rt_nodes) TYPE zif_abapgit_ajson=>ty_nodes_tt
|
||||
|
@ -1088,8 +1087,7 @@ CLASS lcl_abap_to_json DEFINITION FINAL.
|
|||
is_prefix TYPE zif_abapgit_ajson=>ty_path_name OPTIONAL
|
||||
iv_array_index TYPE i DEFAULT 0
|
||||
ii_custom_mapping TYPE REF TO zif_abapgit_ajson_mapping OPTIONAL
|
||||
iv_keep_item_order TYPE abap_bool DEFAULT abap_false
|
||||
iv_format_datetime TYPE abap_bool DEFAULT abap_false
|
||||
is_opts TYPE zif_abapgit_ajson=>ty_opts OPTIONAL
|
||||
iv_item_order TYPE i DEFAULT 0
|
||||
RETURNING
|
||||
VALUE(rt_nodes) TYPE zif_abapgit_ajson=>ty_nodes_tt
|
||||
|
@ -1226,8 +1224,8 @@ CLASS lcl_abap_to_json IMPLEMENTATION.
|
|||
|
||||
CREATE OBJECT lo_converter.
|
||||
lo_converter->mi_custom_mapping = ii_custom_mapping.
|
||||
lo_converter->mv_keep_item_order = iv_keep_item_order.
|
||||
lo_converter->mv_format_datetime = iv_format_datetime.
|
||||
lo_converter->mv_keep_item_order = is_opts-keep_item_order.
|
||||
lo_converter->mv_format_datetime = is_opts-format_datetime.
|
||||
|
||||
lo_converter->convert_any(
|
||||
EXPORTING
|
||||
|
@ -1623,8 +1621,8 @@ CLASS lcl_abap_to_json IMPLEMENTATION.
|
|||
|
||||
CREATE OBJECT lo_converter.
|
||||
lo_converter->mi_custom_mapping = ii_custom_mapping.
|
||||
lo_converter->mv_keep_item_order = iv_keep_item_order.
|
||||
lo_converter->mv_format_datetime = iv_format_datetime.
|
||||
lo_converter->mv_keep_item_order = is_opts-keep_item_order.
|
||||
lo_converter->mv_format_datetime = is_opts-format_datetime.
|
||||
|
||||
lo_converter->insert_value_with_type(
|
||||
EXPORTING
|
||||
|
@ -1689,20 +1687,35 @@ CLASS lcl_abap_to_json IMPLEMENTATION.
|
|||
|
||||
ENDCLASS.
|
||||
|
||||
**********************************************************************
|
||||
* MUTATOR INTERFACE
|
||||
**********************************************************************
|
||||
|
||||
INTERFACE lif_mutator_runner.
|
||||
METHODS run
|
||||
IMPORTING
|
||||
it_source_tree TYPE zif_abapgit_ajson=>ty_nodes_ts
|
||||
EXPORTING
|
||||
et_dest_tree TYPE zif_abapgit_ajson=>ty_nodes_ts
|
||||
RAISING
|
||||
zcx_abapgit_ajson_error.
|
||||
ENDINTERFACE.
|
||||
|
||||
**********************************************************************
|
||||
* FILTER RUNNER
|
||||
**********************************************************************
|
||||
|
||||
CLASS lcl_filter_runner DEFINITION FINAL.
|
||||
PUBLIC SECTION.
|
||||
METHODS run
|
||||
INTERFACES lif_mutator_runner.
|
||||
CLASS-METHODS new
|
||||
IMPORTING
|
||||
ii_filter TYPE REF TO zif_abapgit_ajson_filter
|
||||
it_source_tree TYPE zif_abapgit_ajson=>ty_nodes_ts
|
||||
CHANGING
|
||||
ct_dest_tree TYPE zif_abapgit_ajson=>ty_nodes_ts
|
||||
RAISING
|
||||
zcx_abapgit_ajson_error.
|
||||
RETURNING
|
||||
VALUE(ro_instance) TYPE REF TO lcl_filter_runner.
|
||||
METHODS constructor
|
||||
IMPORTING
|
||||
ii_filter TYPE REF TO zif_abapgit_ajson_filter.
|
||||
|
||||
PRIVATE SECTION.
|
||||
DATA mi_filter TYPE REF TO zif_abapgit_ajson_filter.
|
||||
|
@ -1721,14 +1734,20 @@ ENDCLASS.
|
|||
|
||||
CLASS lcl_filter_runner IMPLEMENTATION.
|
||||
|
||||
METHOD run.
|
||||
METHOD new.
|
||||
CREATE OBJECT ro_instance EXPORTING ii_filter = ii_filter.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD constructor.
|
||||
ASSERT ii_filter IS BOUND.
|
||||
mi_filter = ii_filter.
|
||||
CLEAR ct_dest_tree.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD lif_mutator_runner~run.
|
||||
|
||||
CLEAR et_dest_tree.
|
||||
GET REFERENCE OF it_source_tree INTO mr_source_tree.
|
||||
GET REFERENCE OF ct_dest_tree INTO mr_dest_tree.
|
||||
GET REFERENCE OF et_dest_tree INTO mr_dest_tree.
|
||||
|
||||
walk( iv_path = '' ).
|
||||
|
||||
|
@ -1788,3 +1807,187 @@ CLASS lcl_filter_runner IMPLEMENTATION.
|
|||
ENDMETHOD.
|
||||
|
||||
ENDCLASS.
|
||||
|
||||
**********************************************************************
|
||||
* MAPPER RUNNER
|
||||
**********************************************************************
|
||||
|
||||
CLASS lcl_mapper_runner DEFINITION FINAL.
|
||||
PUBLIC SECTION.
|
||||
INTERFACES lif_mutator_runner.
|
||||
CLASS-METHODS new
|
||||
IMPORTING
|
||||
ii_mapper TYPE REF TO zif_abapgit_ajson_mapping
|
||||
RETURNING
|
||||
VALUE(ro_instance) TYPE REF TO lcl_mapper_runner.
|
||||
METHODS constructor
|
||||
IMPORTING
|
||||
ii_mapper TYPE REF TO zif_abapgit_ajson_mapping.
|
||||
|
||||
PRIVATE SECTION.
|
||||
DATA mi_mapper TYPE REF TO zif_abapgit_ajson_mapping.
|
||||
DATA mr_source_tree TYPE REF TO zif_abapgit_ajson=>ty_nodes_ts.
|
||||
DATA mr_dest_tree TYPE REF TO zif_abapgit_ajson=>ty_nodes_ts.
|
||||
|
||||
METHODS process_deep_node
|
||||
IMPORTING
|
||||
iv_path TYPE string
|
||||
iv_renamed_path TYPE string
|
||||
iv_node_type TYPE zif_abapgit_ajson=>ty_node-type
|
||||
RAISING
|
||||
zcx_abapgit_ajson_error.
|
||||
|
||||
ENDCLASS.
|
||||
|
||||
CLASS lcl_mapper_runner IMPLEMENTATION.
|
||||
|
||||
METHOD new.
|
||||
CREATE OBJECT ro_instance EXPORTING ii_mapper = ii_mapper.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD constructor.
|
||||
ASSERT ii_mapper IS BOUND.
|
||||
mi_mapper = ii_mapper.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD lif_mutator_runner~run.
|
||||
|
||||
FIELD-SYMBOLS <root> LIKE LINE OF it_source_tree.
|
||||
|
||||
READ TABLE it_source_tree WITH KEY path = `` name = `` ASSIGNING <root>.
|
||||
IF sy-subrc <> 0 OR NOT ( <root>-type = zif_abapgit_ajson=>node_type-array OR <root>-type = zif_abapgit_ajson=>node_type-object ).
|
||||
" empty or one-value-only tree
|
||||
et_dest_tree = it_source_tree.
|
||||
RETURN.
|
||||
ENDIF.
|
||||
|
||||
CLEAR et_dest_tree.
|
||||
GET REFERENCE OF it_source_tree INTO mr_source_tree.
|
||||
GET REFERENCE OF et_dest_tree INTO mr_dest_tree.
|
||||
INSERT <root> INTO TABLE et_dest_tree.
|
||||
|
||||
process_deep_node(
|
||||
iv_path = `/`
|
||||
iv_renamed_path = `/`
|
||||
iv_node_type = <root>-type ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD process_deep_node.
|
||||
|
||||
|
||||
FIELD-SYMBOLS <item> LIKE LINE OF mr_source_tree->*.
|
||||
DATA ls_renamed_node LIKE <item>.
|
||||
|
||||
LOOP AT mr_source_tree->* ASSIGNING <item> WHERE path = iv_path.
|
||||
ls_renamed_node = <item>.
|
||||
IF iv_node_type <> zif_abapgit_ajson=>node_type-array.
|
||||
" don't rename array item names -> they are numeric index
|
||||
mi_mapper->rename_node(
|
||||
EXPORTING
|
||||
is_node = <item>
|
||||
CHANGING
|
||||
cv_name = ls_renamed_node-name ).
|
||||
IF ls_renamed_node-name IS INITIAL.
|
||||
zcx_abapgit_ajson_error=>raise(
|
||||
iv_msg = 'Renamed node name cannot be empty'
|
||||
is_node = <item> ).
|
||||
ENDIF.
|
||||
ENDIF.
|
||||
ls_renamed_node-path = iv_renamed_path.
|
||||
|
||||
INSERT ls_renamed_node INTO TABLE mr_dest_tree->*.
|
||||
IF sy-subrc <> 0. " = 4 ?
|
||||
zcx_abapgit_ajson_error=>raise(
|
||||
iv_msg = 'Renamed node has a duplicate'
|
||||
is_node = ls_renamed_node ).
|
||||
ENDIF.
|
||||
|
||||
" maybe also catch CX_SY_ITAB_DUPLICATE_KEY but secondary keys are not changed here, so not for now
|
||||
|
||||
IF <item>-type = zif_abapgit_ajson=>node_type-array OR <item>-type = zif_abapgit_ajson=>node_type-object.
|
||||
process_deep_node(
|
||||
iv_path = iv_path && <item>-name && `/`
|
||||
iv_renamed_path = iv_renamed_path && ls_renamed_node-name && `/`
|
||||
iv_node_type = <item>-type ).
|
||||
ENDIF.
|
||||
|
||||
ENDLOOP.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
ENDCLASS.
|
||||
|
||||
**********************************************************************
|
||||
* MUTATOR QUEUE
|
||||
**********************************************************************
|
||||
|
||||
CLASS lcl_mutator_queue DEFINITION FINAL.
|
||||
PUBLIC SECTION.
|
||||
INTERFACES lif_mutator_runner.
|
||||
CLASS-METHODS new
|
||||
RETURNING
|
||||
VALUE(ro_instance) TYPE REF TO lcl_mutator_queue.
|
||||
METHODS add
|
||||
IMPORTING
|
||||
ii_mutator TYPE REF TO lif_mutator_runner
|
||||
RETURNING
|
||||
VALUE(ro_self) TYPE REF TO lcl_mutator_queue.
|
||||
|
||||
PRIVATE SECTION.
|
||||
DATA mt_queue TYPE STANDARD TABLE OF REF TO lif_mutator_runner.
|
||||
|
||||
ENDCLASS.
|
||||
|
||||
CLASS lcl_mutator_queue IMPLEMENTATION.
|
||||
|
||||
METHOD add.
|
||||
IF ii_mutator IS BOUND.
|
||||
APPEND ii_mutator TO mt_queue.
|
||||
ENDIF.
|
||||
ro_self = me.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD new.
|
||||
CREATE OBJECT ro_instance.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD lif_mutator_runner~run.
|
||||
|
||||
DATA li_mutator TYPE REF TO lif_mutator_runner.
|
||||
DATA lv_qsize TYPE i.
|
||||
FIELD-SYMBOLS <from> LIKE it_source_tree.
|
||||
FIELD-SYMBOLS <to> LIKE it_source_tree.
|
||||
DATA lr_buf TYPE REF TO zif_abapgit_ajson=>ty_nodes_ts.
|
||||
|
||||
lv_qsize = lines( mt_queue ).
|
||||
|
||||
IF lv_qsize = 0.
|
||||
et_dest_tree = it_source_tree.
|
||||
RETURN.
|
||||
ENDIF.
|
||||
|
||||
LOOP AT mt_queue INTO li_mutator.
|
||||
IF sy-tabix = 1.
|
||||
ASSIGN it_source_tree TO <from>.
|
||||
ELSE.
|
||||
ASSIGN lr_buf->* TO <from>.
|
||||
ENDIF.
|
||||
|
||||
IF sy-tabix = lv_qsize.
|
||||
ASSIGN et_dest_tree TO <to>.
|
||||
ELSE.
|
||||
CREATE DATA lr_buf.
|
||||
ASSIGN lr_buf->* TO <to>.
|
||||
ENDIF.
|
||||
|
||||
li_mutator->run(
|
||||
EXPORTING
|
||||
it_source_tree = <from>
|
||||
IMPORTING
|
||||
et_dest_tree = <to> ).
|
||||
ENDLOOP.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
ENDCLASS.
|
||||
|
|
|
@ -1976,6 +1976,9 @@ CLASS ltcl_writer_test DEFINITION FINAL
|
|||
METHODS set_with_type FOR TESTING RAISING zcx_abapgit_ajson_error.
|
||||
METHODS overwrite_w_keep_order_touch FOR TESTING RAISING zcx_abapgit_ajson_error.
|
||||
METHODS overwrite_w_keep_order_set FOR TESTING RAISING zcx_abapgit_ajson_error.
|
||||
METHODS setx FOR TESTING RAISING zcx_abapgit_ajson_error.
|
||||
METHODS setx_float FOR TESTING RAISING zcx_abapgit_ajson_error.
|
||||
METHODS setx_complex FOR TESTING RAISING zcx_abapgit_ajson_error.
|
||||
|
||||
METHODS set_with_type_slice
|
||||
IMPORTING
|
||||
|
@ -3083,6 +3086,112 @@ CLASS ltcl_writer_test IMPLEMENTATION.
|
|||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD setx.
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = zcl_abapgit_ajson=>new( )->setx( '/a:1' )->stringify( )
|
||||
exp = '{"a":1}' ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = zcl_abapgit_ajson=>new( )->setx( '/a : 1' )->stringify( )
|
||||
exp = '{"a":1}' ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = zcl_abapgit_ajson=>new( )->setx( '/a:"1"' )->stringify( )
|
||||
exp = '{"a":"1"}' ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = zcl_abapgit_ajson=>new( )->setx( '/a:abc' )->stringify( )
|
||||
exp = '{"a":"abc"}' ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = zcl_abapgit_ajson=>new( )->setx( '/a:null' )->stringify( )
|
||||
exp = '{"a":null}' ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = zcl_abapgit_ajson=>new( )->setx( '/a:true' )->stringify( )
|
||||
exp = '{"a":true}' ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = zcl_abapgit_ajson=>new( )->setx( '/a:"true"' )->stringify( )
|
||||
exp = '{"a":"true"}' ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = zcl_abapgit_ajson=>new( )->setx( '/a:false' )->stringify( )
|
||||
exp = '{"a":false}' ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = zcl_abapgit_ajson=>new( )->setx( '/a/b:1' )->stringify( )
|
||||
exp = '{"a":{"b":1}}' ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = zcl_abapgit_ajson=>new( )->setx( '/:1' )->stringify( )
|
||||
exp = '1' ). " Hmmm ?
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = zcl_abapgit_ajson=>new( )->setx( ':1' )->stringify( )
|
||||
exp = '1' ). " Hmmm ?
|
||||
|
||||
" TODO some negative tests like "/a:", ""
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD setx_float.
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = zcl_abapgit_ajson=>new( )->setx( '/a:1.123' )->stringify( )
|
||||
exp = '{"a":1.123}' ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = zcl_abapgit_ajson=>new( )->setx( '/a:00.123' )->stringify( )
|
||||
exp = '{"a":"00.123"}' ). " hmmm
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = zcl_abapgit_ajson=>new( )->setx( '/a:.123' )->stringify( )
|
||||
exp = '{"a":".123"}' ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = zcl_abapgit_ajson=>new( )->setx( '/a:123.' )->stringify( )
|
||||
exp = '{"a":"123."}' ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = zcl_abapgit_ajson=>new( )->setx( '/a:1..123' )->stringify( )
|
||||
exp = '{"a":"1..123"}' ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD setx_complex.
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = zcl_abapgit_ajson=>new( )->setx( '/a:{"b" : 1}' )->stringify( )
|
||||
exp = '{"a":{"b":1}}' ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = zcl_abapgit_ajson=>new( )->setx( '/a:{}' )->stringify( )
|
||||
exp = '{"a":{}}' ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = zcl_abapgit_ajson=>new( )->setx( '/a:[1, 2]' )->stringify( )
|
||||
exp = '{"a":[1,2]}' ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = zcl_abapgit_ajson=>new( )->setx( '/a:[]' )->stringify( )
|
||||
exp = '{"a":[]}' ).
|
||||
|
||||
TRY.
|
||||
zcl_abapgit_ajson=>new( )->setx( '/a:{"b" : 1' ).
|
||||
cl_abap_unit_assert=>fail( ).
|
||||
CATCH zcx_abapgit_ajson_error.
|
||||
ENDTRY.
|
||||
|
||||
TRY.
|
||||
zcl_abapgit_ajson=>new( )->setx( '/a:[1, 2' ).
|
||||
cl_abap_unit_assert=>fail( ).
|
||||
CATCH zcx_abapgit_ajson_error.
|
||||
ENDTRY.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
|
@ -3999,3 +4108,400 @@ CLASS ltcl_filter_test IMPLEMENTATION.
|
|||
ENDMETHOD.
|
||||
|
||||
ENDCLASS.
|
||||
|
||||
**********************************************************************
|
||||
* MAPPER TEST
|
||||
**********************************************************************
|
||||
|
||||
CLASS ltcl_mapper_test DEFINITION FINAL
|
||||
FOR TESTING
|
||||
DURATION SHORT
|
||||
RISK LEVEL HARMLESS.
|
||||
|
||||
PUBLIC SECTION.
|
||||
INTERFACES zif_abapgit_ajson_mapping.
|
||||
|
||||
PRIVATE SECTION.
|
||||
|
||||
METHODS simple_test FOR TESTING RAISING zcx_abapgit_ajson_error.
|
||||
METHODS array_test FOR TESTING RAISING zcx_abapgit_ajson_error.
|
||||
METHODS duplication_test FOR TESTING RAISING zcx_abapgit_ajson_error.
|
||||
METHODS empty_name_test FOR TESTING RAISING zcx_abapgit_ajson_error.
|
||||
METHODS trivial FOR TESTING RAISING zcx_abapgit_ajson_error.
|
||||
|
||||
ENDCLASS.
|
||||
|
||||
CLASS ltcl_mapper_test IMPLEMENTATION.
|
||||
|
||||
METHOD zif_abapgit_ajson_mapping~rename_node.
|
||||
IF cv_name+0(1) = 'a'.
|
||||
cv_name = to_upper( cv_name ).
|
||||
ENDIF.
|
||||
IF cv_name = 'set_this_empty'.
|
||||
CLEAR cv_name.
|
||||
ENDIF.
|
||||
" watch dog for array
|
||||
IF is_node-index <> 0.
|
||||
cl_abap_unit_assert=>fail( 'rename must not be called for direct array items' ).
|
||||
ENDIF.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD zif_abapgit_ajson_mapping~to_abap.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD zif_abapgit_ajson_mapping~to_json.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD simple_test.
|
||||
|
||||
DATA lo_json TYPE REF TO zcl_abapgit_ajson.
|
||||
DATA lo_json_filtered TYPE REF TO zcl_abapgit_ajson.
|
||||
DATA lo_nodes_exp TYPE REF TO lcl_nodes_helper.
|
||||
|
||||
lo_json = zcl_abapgit_ajson=>create_empty( ).
|
||||
lo_json->set(
|
||||
iv_path = '/ab'
|
||||
iv_val = 1 ).
|
||||
lo_json->set(
|
||||
iv_path = '/bc'
|
||||
iv_val = 2 ).
|
||||
lo_json->set(
|
||||
iv_path = '/c/ax'
|
||||
iv_val = 3 ).
|
||||
lo_json->set(
|
||||
iv_path = '/c/by'
|
||||
iv_val = 4 ).
|
||||
lo_json->set(
|
||||
iv_path = '/a/ax'
|
||||
iv_val = 5 ).
|
||||
lo_json->set(
|
||||
iv_path = '/a/by'
|
||||
iv_val = 6 ).
|
||||
|
||||
lo_json_filtered = zcl_abapgit_ajson=>create_from(
|
||||
ii_source_json = lo_json
|
||||
ii_mapper = me ).
|
||||
|
||||
CREATE OBJECT lo_nodes_exp.
|
||||
lo_nodes_exp->add( ' | |object | | |4' ).
|
||||
lo_nodes_exp->add( '/ |AB |num |1 | |0' ).
|
||||
lo_nodes_exp->add( '/ |bc |num |2 | |0' ).
|
||||
lo_nodes_exp->add( '/ |c |object | | |2' ).
|
||||
lo_nodes_exp->add( '/c/ |AX |num |3 | |0' ).
|
||||
lo_nodes_exp->add( '/c/ |by |num |4 | |0' ).
|
||||
lo_nodes_exp->add( '/ |A |object | | |2' ).
|
||||
lo_nodes_exp->add( '/A/ |AX |num |5 | |0' ).
|
||||
lo_nodes_exp->add( '/A/ |by |num |6 | |0' ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = lo_json_filtered->mt_json_tree
|
||||
exp = lo_nodes_exp->sorted( ) ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD array_test.
|
||||
|
||||
DATA lo_json TYPE REF TO zcl_abapgit_ajson.
|
||||
DATA lo_json_filtered TYPE REF TO zcl_abapgit_ajson.
|
||||
DATA lo_nodes_exp TYPE REF TO lcl_nodes_helper.
|
||||
|
||||
lo_json = zcl_abapgit_ajson=>create_empty( ).
|
||||
lo_json->touch_array( iv_path = '/' ).
|
||||
lo_json->set(
|
||||
iv_path = '/1/ab'
|
||||
iv_val = 1 ).
|
||||
lo_json->set(
|
||||
iv_path = '/1/bc'
|
||||
iv_val = 2 ).
|
||||
lo_json->set(
|
||||
iv_path = '/2/ax'
|
||||
iv_val = 3 ).
|
||||
lo_json->set(
|
||||
iv_path = '/2/by'
|
||||
iv_val = 4 ).
|
||||
|
||||
lo_json_filtered = zcl_abapgit_ajson=>create_from(
|
||||
ii_source_json = lo_json
|
||||
ii_mapper = me ).
|
||||
|
||||
CREATE OBJECT lo_nodes_exp.
|
||||
lo_nodes_exp->add( ' | |array | | |2' ).
|
||||
lo_nodes_exp->add( '/ |1 |object | |1|2' ).
|
||||
lo_nodes_exp->add( '/ |2 |object | |2|2' ).
|
||||
lo_nodes_exp->add( '/1/ |AB |num |1 | |0' ).
|
||||
lo_nodes_exp->add( '/1/ |bc |num |2 | |0' ).
|
||||
lo_nodes_exp->add( '/2/ |AX |num |3 | |0' ).
|
||||
lo_nodes_exp->add( '/2/ |by |num |4 | |0' ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = lo_json_filtered->mt_json_tree
|
||||
exp = lo_nodes_exp->sorted( ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD duplication_test.
|
||||
|
||||
DATA lo_json TYPE REF TO zcl_abapgit_ajson.
|
||||
DATA lx_err TYPE REF TO zcx_abapgit_ajson_error.
|
||||
|
||||
lo_json = zcl_abapgit_ajson=>create_empty( ).
|
||||
lo_json->set(
|
||||
iv_path = '/ab'
|
||||
iv_val = 1 ).
|
||||
lo_json->set(
|
||||
iv_path = '/AB'
|
||||
iv_val = 2 ).
|
||||
|
||||
TRY.
|
||||
zcl_abapgit_ajson=>create_from(
|
||||
ii_source_json = lo_json
|
||||
ii_mapper = me ).
|
||||
cl_abap_unit_assert=>fail( ).
|
||||
CATCH zcx_abapgit_ajson_error INTO lx_err.
|
||||
cl_abap_unit_assert=>assert_char_cp(
|
||||
act = lx_err->get_text( )
|
||||
exp = 'Renamed node has a duplicate @/AB' ).
|
||||
ENDTRY.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD trivial.
|
||||
|
||||
DATA lo_json TYPE REF TO zcl_abapgit_ajson.
|
||||
DATA lo_json_filtered TYPE REF TO zcl_abapgit_ajson.
|
||||
DATA lo_nodes_exp TYPE REF TO lcl_nodes_helper.
|
||||
|
||||
lo_json = zcl_abapgit_ajson=>create_empty( ).
|
||||
lo_json_filtered = zcl_abapgit_ajson=>create_from(
|
||||
ii_source_json = lo_json
|
||||
ii_mapper = me ).
|
||||
cl_abap_unit_assert=>assert_initial( lo_json_filtered->mt_json_tree ).
|
||||
|
||||
lo_json->set(
|
||||
iv_path = '/'
|
||||
iv_val = 1 ).
|
||||
lo_json_filtered = zcl_abapgit_ajson=>create_from(
|
||||
ii_source_json = lo_json
|
||||
ii_mapper = me ).
|
||||
|
||||
CREATE OBJECT lo_nodes_exp.
|
||||
lo_nodes_exp->add( ' | |num |1 | |0' ).
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = lo_json_filtered->mt_json_tree
|
||||
exp = lo_nodes_exp->sorted( ) ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD empty_name_test.
|
||||
|
||||
DATA lo_json TYPE REF TO zcl_abapgit_ajson.
|
||||
DATA lx_err TYPE REF TO zcx_abapgit_ajson_error.
|
||||
|
||||
lo_json = zcl_abapgit_ajson=>create_empty( ).
|
||||
lo_json->set(
|
||||
iv_path = '/set_this_empty'
|
||||
iv_val = 1 ).
|
||||
|
||||
TRY.
|
||||
zcl_abapgit_ajson=>create_from(
|
||||
ii_source_json = lo_json
|
||||
ii_mapper = me ).
|
||||
cl_abap_unit_assert=>fail( ).
|
||||
CATCH zcx_abapgit_ajson_error INTO lx_err.
|
||||
cl_abap_unit_assert=>assert_char_cp(
|
||||
act = lx_err->get_text( )
|
||||
exp = 'Renamed node name cannot be empty @/set_this_empty' ).
|
||||
ENDTRY.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
ENDCLASS.
|
||||
|
||||
**********************************************************************
|
||||
* CLONING TEST
|
||||
**********************************************************************
|
||||
|
||||
CLASS ltcl_cloning_test DEFINITION FINAL
|
||||
FOR TESTING
|
||||
DURATION SHORT
|
||||
RISK LEVEL HARMLESS.
|
||||
|
||||
PUBLIC SECTION.
|
||||
INTERFACES zif_abapgit_ajson_mapping.
|
||||
INTERFACES zif_abapgit_ajson_filter.
|
||||
|
||||
PRIVATE SECTION.
|
||||
|
||||
METHODS clone_test FOR TESTING RAISING zcx_abapgit_ajson_error.
|
||||
METHODS filter_test FOR TESTING RAISING zcx_abapgit_ajson_error.
|
||||
METHODS mapper_test FOR TESTING RAISING zcx_abapgit_ajson_error.
|
||||
METHODS mapper_and_filter FOR TESTING RAISING zcx_abapgit_ajson_error.
|
||||
METHODS opts_copying FOR TESTING RAISING zcx_abapgit_ajson_error.
|
||||
|
||||
ENDCLASS.
|
||||
|
||||
CLASS ltcl_cloning_test IMPLEMENTATION.
|
||||
|
||||
METHOD clone_test.
|
||||
|
||||
DATA li_json TYPE REF TO zif_abapgit_ajson.
|
||||
DATA li_json_new TYPE REF TO zif_abapgit_ajson.
|
||||
DATA lo_nodes_exp TYPE REF TO lcl_nodes_helper.
|
||||
|
||||
li_json = zcl_abapgit_ajson=>create_empty( ).
|
||||
li_json->set(
|
||||
iv_path = '/ab'
|
||||
iv_val = 1 ).
|
||||
li_json->set(
|
||||
iv_path = '/xy'
|
||||
iv_val = 2 ).
|
||||
|
||||
li_json_new = li_json->clone( ).
|
||||
|
||||
CREATE OBJECT lo_nodes_exp.
|
||||
lo_nodes_exp->add( ' | |object | | |2' ).
|
||||
lo_nodes_exp->add( '/ |ab |num |1 | |0' ).
|
||||
lo_nodes_exp->add( '/ |xy |num |2 | |0' ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = li_json->mt_json_tree
|
||||
exp = lo_nodes_exp->sorted( ) ).
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = li_json_new->mt_json_tree
|
||||
exp = lo_nodes_exp->sorted( ) ).
|
||||
|
||||
" ensure disconnection
|
||||
li_json->set(
|
||||
iv_path = '/ab'
|
||||
iv_val = 5 ).
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = li_json->get_integer( '/ab' )
|
||||
exp = 5 ).
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = li_json_new->get_integer( '/ab' )
|
||||
exp = 1 ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD filter_test.
|
||||
|
||||
DATA li_json TYPE REF TO zif_abapgit_ajson.
|
||||
DATA li_json_new TYPE REF TO zif_abapgit_ajson.
|
||||
DATA lo_nodes_exp TYPE REF TO lcl_nodes_helper.
|
||||
|
||||
li_json = zcl_abapgit_ajson=>create_empty( ).
|
||||
li_json->set(
|
||||
iv_path = '/ab'
|
||||
iv_val = 1 ).
|
||||
li_json->set(
|
||||
iv_path = '/xy'
|
||||
iv_val = 2 ).
|
||||
|
||||
li_json_new = li_json->filter( me ).
|
||||
|
||||
CREATE OBJECT lo_nodes_exp.
|
||||
lo_nodes_exp->add( ' | |object | | |1' ).
|
||||
lo_nodes_exp->add( '/ |ab |num |1 | |0' ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = li_json_new->mt_json_tree
|
||||
exp = lo_nodes_exp->sorted( ) ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD mapper_test.
|
||||
|
||||
DATA li_json TYPE REF TO zif_abapgit_ajson.
|
||||
DATA li_json_new TYPE REF TO zif_abapgit_ajson.
|
||||
DATA lo_nodes_exp TYPE REF TO lcl_nodes_helper.
|
||||
|
||||
li_json = zcl_abapgit_ajson=>create_empty( ).
|
||||
li_json->set(
|
||||
iv_path = '/ab'
|
||||
iv_val = 1 ).
|
||||
li_json->set(
|
||||
iv_path = '/xy'
|
||||
iv_val = 2 ).
|
||||
|
||||
li_json_new = li_json->map( me ).
|
||||
|
||||
CREATE OBJECT lo_nodes_exp.
|
||||
lo_nodes_exp->add( ' | |object | | |2' ).
|
||||
lo_nodes_exp->add( '/ |AB |num |1 | |0' ).
|
||||
lo_nodes_exp->add( '/ |xy |num |2 | |0' ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = li_json_new->mt_json_tree
|
||||
exp = lo_nodes_exp->sorted( ) ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD zif_abapgit_ajson_mapping~rename_node.
|
||||
IF cv_name+0(1) = 'a'.
|
||||
cv_name = to_upper( cv_name ).
|
||||
ENDIF.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD zif_abapgit_ajson_mapping~to_abap.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD zif_abapgit_ajson_mapping~to_json.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD zif_abapgit_ajson_filter~keep_node.
|
||||
rv_keep = boolc( is_node-name IS INITIAL OR is_node-name+0(1) <> 'x' ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD mapper_and_filter.
|
||||
|
||||
DATA li_json TYPE REF TO zif_abapgit_ajson.
|
||||
DATA li_json_new TYPE REF TO zif_abapgit_ajson.
|
||||
DATA lo_nodes_exp TYPE REF TO lcl_nodes_helper.
|
||||
|
||||
li_json = zcl_abapgit_ajson=>new( ).
|
||||
li_json->set(
|
||||
iv_path = '/ab'
|
||||
iv_val = 1 ).
|
||||
li_json->set(
|
||||
iv_path = '/bc'
|
||||
iv_val = 2 ).
|
||||
li_json->set(
|
||||
iv_path = '/xy'
|
||||
iv_val = 3 ).
|
||||
|
||||
li_json_new = zcl_abapgit_ajson=>create_from(
|
||||
ii_source_json = li_json
|
||||
ii_filter = me
|
||||
ii_mapper = me ).
|
||||
|
||||
CREATE OBJECT lo_nodes_exp.
|
||||
lo_nodes_exp->add( ' | |object | | |2' ).
|
||||
lo_nodes_exp->add( '/ |AB |num |1 | |0' ).
|
||||
lo_nodes_exp->add( '/ |bc |num |2 | |0' ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = li_json_new->mt_json_tree
|
||||
exp = lo_nodes_exp->sorted( ) ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD opts_copying.
|
||||
|
||||
DATA li_json TYPE REF TO zif_abapgit_ajson.
|
||||
DATA li_json_new TYPE REF TO zif_abapgit_ajson.
|
||||
|
||||
li_json = zcl_abapgit_ajson=>new( )->keep_item_order( ).
|
||||
li_json->set(
|
||||
iv_path = '/ab'
|
||||
iv_val = 1 ).
|
||||
|
||||
li_json_new = li_json->clone( ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = li_json_new->opts( )-keep_item_order
|
||||
exp = abap_true ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
ENDCLASS.
|
||||
|
|
|
@ -4,7 +4,16 @@ CLASS zcl_abapgit_ajson_mapping DEFINITION
|
|||
CREATE PUBLIC.
|
||||
|
||||
PUBLIC SECTION.
|
||||
CLASS-METHODS create_camel_case
|
||||
|
||||
CONSTANTS:
|
||||
BEGIN OF rename_by,
|
||||
attr_name TYPE i VALUE 0,
|
||||
full_path TYPE i VALUE 1,
|
||||
pattern TYPE i VALUE 2,
|
||||
" regex type i value 3, " TODO add if needed in future
|
||||
END OF rename_by.
|
||||
|
||||
CLASS-METHODS create_camel_case " DEPRECATED
|
||||
IMPORTING
|
||||
it_mapping_fields TYPE zif_abapgit_ajson_mapping=>ty_mapping_fields OPTIONAL
|
||||
iv_first_json_upper TYPE abap_bool DEFAULT abap_true
|
||||
|
@ -23,12 +32,38 @@ CLASS zcl_abapgit_ajson_mapping DEFINITION
|
|||
RETURNING
|
||||
VALUE(ri_mapping) TYPE REF TO zif_abapgit_ajson_mapping.
|
||||
|
||||
CLASS-METHODS create_field_mapping
|
||||
CLASS-METHODS create_field_mapping " DEPRECATED
|
||||
IMPORTING
|
||||
it_mapping_fields TYPE zif_abapgit_ajson_mapping=>ty_mapping_fields
|
||||
RETURNING
|
||||
VALUE(ri_mapping) TYPE REF TO zif_abapgit_ajson_mapping.
|
||||
|
||||
CLASS-METHODS create_rename
|
||||
IMPORTING
|
||||
it_rename_map TYPE zif_abapgit_ajson_mapping=>tty_rename_map
|
||||
iv_rename_by TYPE i DEFAULT rename_by-attr_name
|
||||
RETURNING
|
||||
VALUE(ri_mapping) TYPE REF TO zif_abapgit_ajson_mapping.
|
||||
|
||||
CLASS-METHODS create_compound_mapper
|
||||
IMPORTING
|
||||
ii_mapper1 TYPE REF TO zif_abapgit_ajson_mapping OPTIONAL
|
||||
ii_mapper2 TYPE REF TO zif_abapgit_ajson_mapping OPTIONAL
|
||||
ii_mapper3 TYPE REF TO zif_abapgit_ajson_mapping OPTIONAL
|
||||
it_more TYPE zif_abapgit_ajson_mapping=>ty_table_of OPTIONAL
|
||||
RETURNING
|
||||
VALUE(ri_mapping) TYPE REF TO zif_abapgit_ajson_mapping.
|
||||
|
||||
CLASS-METHODS create_to_snake_case
|
||||
RETURNING
|
||||
VALUE(ri_mapping) TYPE REF TO zif_abapgit_ajson_mapping.
|
||||
|
||||
CLASS-METHODS create_to_camel_case
|
||||
IMPORTING
|
||||
iv_first_json_upper TYPE abap_bool DEFAULT abap_false
|
||||
RETURNING
|
||||
VALUE(ri_mapping) TYPE REF TO zif_abapgit_ajson_mapping.
|
||||
|
||||
PROTECTED SECTION.
|
||||
|
||||
PRIVATE SECTION.
|
||||
|
@ -67,6 +102,21 @@ CLASS zcl_abapgit_ajson_mapping IMPLEMENTATION.
|
|||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD create_compound_mapper.
|
||||
|
||||
DATA lt_queue TYPE zif_abapgit_ajson_mapping=>ty_table_of.
|
||||
|
||||
APPEND ii_mapper1 TO lt_queue.
|
||||
APPEND ii_mapper2 TO lt_queue.
|
||||
APPEND ii_mapper3 TO lt_queue.
|
||||
APPEND LINES OF it_more TO lt_queue.
|
||||
DELETE lt_queue WHERE table_line IS INITIAL.
|
||||
|
||||
CREATE OBJECT ri_mapping TYPE lcl_compound_mapper
|
||||
EXPORTING
|
||||
it_queue = lt_queue.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD create_upper_case.
|
||||
|
||||
|
@ -75,4 +125,28 @@ CLASS zcl_abapgit_ajson_mapping IMPLEMENTATION.
|
|||
it_mapping_fields = it_mapping_fields.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD create_rename.
|
||||
|
||||
CREATE OBJECT ri_mapping TYPE lcl_rename
|
||||
EXPORTING
|
||||
it_rename_map = it_rename_map
|
||||
iv_rename_by = iv_rename_by.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD create_to_snake_case.
|
||||
|
||||
CREATE OBJECT ri_mapping TYPE lcl_to_snake.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD create_to_camel_case.
|
||||
|
||||
CREATE OBJECT ri_mapping TYPE lcl_to_camel
|
||||
EXPORTING
|
||||
iv_first_json_upper = iv_first_json_upper.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
ENDCLASS.
|
||||
|
|
|
@ -3,9 +3,6 @@ CLASS lcl_mapping_fields DEFINITION.
|
|||
PUBLIC SECTION.
|
||||
INTERFACES zif_abapgit_ajson_mapping.
|
||||
|
||||
ALIASES to_abap FOR zif_abapgit_ajson_mapping~to_abap.
|
||||
ALIASES to_json FOR zif_abapgit_ajson_mapping~to_json.
|
||||
|
||||
METHODS constructor
|
||||
IMPORTING
|
||||
it_mapping_fields TYPE zif_abapgit_ajson_mapping~ty_mapping_fields OPTIONAL.
|
||||
|
@ -17,6 +14,23 @@ CLASS lcl_mapping_fields DEFINITION.
|
|||
|
||||
ENDCLASS.
|
||||
|
||||
CLASS lcl_rename DEFINITION.
|
||||
|
||||
PUBLIC SECTION.
|
||||
INTERFACES zif_abapgit_ajson_mapping.
|
||||
|
||||
METHODS constructor
|
||||
IMPORTING
|
||||
it_rename_map TYPE zif_abapgit_ajson_mapping~tty_rename_map
|
||||
iv_rename_by TYPE i.
|
||||
|
||||
PROTECTED SECTION.
|
||||
|
||||
PRIVATE SECTION.
|
||||
DATA mt_rename_map TYPE zif_abapgit_ajson_mapping~tty_rename_map.
|
||||
DATA mv_rename_by TYPE i.
|
||||
|
||||
ENDCLASS.
|
||||
|
||||
CLASS lcl_mapping_to_upper DEFINITION.
|
||||
|
||||
|
@ -69,3 +83,34 @@ CLASS lcl_mapping_camel DEFINITION.
|
|||
DATA mi_mapping_fields TYPE REF TO zif_abapgit_ajson_mapping.
|
||||
|
||||
ENDCLASS.
|
||||
|
||||
CLASS lcl_compound_mapper DEFINITION.
|
||||
|
||||
PUBLIC SECTION.
|
||||
INTERFACES zif_abapgit_ajson_mapping.
|
||||
|
||||
METHODS constructor
|
||||
IMPORTING
|
||||
it_queue TYPE zif_abapgit_ajson_mapping=>ty_table_of.
|
||||
|
||||
PROTECTED SECTION.
|
||||
|
||||
PRIVATE SECTION.
|
||||
DATA mt_queue TYPE zif_abapgit_ajson_mapping=>ty_table_of.
|
||||
|
||||
ENDCLASS.
|
||||
|
||||
CLASS lcl_to_snake DEFINITION.
|
||||
PUBLIC SECTION.
|
||||
INTERFACES zif_abapgit_ajson_mapping.
|
||||
ENDCLASS.
|
||||
|
||||
CLASS lcl_to_camel DEFINITION.
|
||||
PUBLIC SECTION.
|
||||
INTERFACES zif_abapgit_ajson_mapping.
|
||||
METHODS constructor
|
||||
IMPORTING
|
||||
iv_first_json_upper TYPE abap_bool.
|
||||
PRIVATE SECTION.
|
||||
DATA mv_first_json_upper TYPE abap_bool.
|
||||
ENDCLASS.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
CLASS lcl_mapping_fields IMPLEMENTATION.
|
||||
CLASS lcl_mapping_fields IMPLEMENTATION. "DEPRECATED
|
||||
|
||||
|
||||
METHOD constructor.
|
||||
|
@ -41,9 +41,58 @@ CLASS lcl_mapping_fields IMPLEMENTATION.
|
|||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD zif_abapgit_ajson_mapping~rename_node.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
ENDCLASS.
|
||||
|
||||
CLASS lcl_rename IMPLEMENTATION.
|
||||
|
||||
METHOD constructor.
|
||||
mt_rename_map = it_rename_map.
|
||||
mv_rename_by = iv_rename_by.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD zif_abapgit_ajson_mapping~to_abap.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD zif_abapgit_ajson_mapping~to_json.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD zif_abapgit_ajson_mapping~rename_node.
|
||||
|
||||
DATA lv_full_path TYPE string.
|
||||
DATA lv_pair_found TYPE abap_bool.
|
||||
FIELD-SYMBOLS <r> LIKE LINE OF mt_rename_map.
|
||||
|
||||
CASE mv_rename_by.
|
||||
WHEN zcl_abapgit_ajson_mapping=>rename_by-attr_name.
|
||||
READ TABLE mt_rename_map ASSIGNING <r> WITH TABLE KEY by_name COMPONENTS from = cv_name.
|
||||
lv_pair_found = boolc( sy-subrc = 0 ).
|
||||
WHEN zcl_abapgit_ajson_mapping=>rename_by-full_path.
|
||||
lv_full_path = is_node-path && cv_name.
|
||||
READ TABLE mt_rename_map ASSIGNING <r> WITH TABLE KEY by_name COMPONENTS from = lv_full_path.
|
||||
lv_pair_found = boolc( sy-subrc = 0 ).
|
||||
WHEN zcl_abapgit_ajson_mapping=>rename_by-pattern.
|
||||
lv_full_path = is_node-path && cv_name.
|
||||
LOOP AT mt_rename_map ASSIGNING <r>.
|
||||
IF lv_full_path CP <r>-from.
|
||||
lv_pair_found = abap_true.
|
||||
EXIT.
|
||||
ENDIF.
|
||||
ENDLOOP.
|
||||
WHEN OTHERS.
|
||||
lv_pair_found = abap_false. " No rename
|
||||
ENDCASE.
|
||||
|
||||
IF lv_pair_found = abap_true.
|
||||
cv_name = <r>-to.
|
||||
ENDIF.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
ENDCLASS.
|
||||
|
||||
CLASS lcl_mapping_to_upper IMPLEMENTATION.
|
||||
|
||||
|
@ -76,6 +125,11 @@ CLASS lcl_mapping_to_upper IMPLEMENTATION.
|
|||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD zif_abapgit_ajson_mapping~rename_node.
|
||||
|
||||
cv_name = to_upper( cv_name ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
ENDCLASS.
|
||||
|
||||
|
@ -111,11 +165,16 @@ CLASS lcl_mapping_to_lower IMPLEMENTATION.
|
|||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD zif_abapgit_ajson_mapping~rename_node.
|
||||
|
||||
cv_name = to_lower( cv_name ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS lcl_mapping_camel IMPLEMENTATION.
|
||||
CLASS lcl_mapping_camel IMPLEMENTATION. "DEPRECATED
|
||||
|
||||
|
||||
METHOD constructor.
|
||||
|
@ -179,5 +238,104 @@ CLASS lcl_mapping_camel IMPLEMENTATION.
|
|||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD zif_abapgit_ajson_mapping~rename_node.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
ENDCLASS.
|
||||
|
||||
CLASS lcl_compound_mapper IMPLEMENTATION.
|
||||
|
||||
METHOD constructor.
|
||||
mt_queue = it_queue.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD zif_abapgit_ajson_mapping~rename_node.
|
||||
|
||||
DATA ls_node LIKE is_node.
|
||||
DATA li_mapper LIKE LINE OF mt_queue.
|
||||
|
||||
ls_node = is_node.
|
||||
|
||||
LOOP AT mt_queue INTO li_mapper.
|
||||
li_mapper->rename_node(
|
||||
EXPORTING
|
||||
is_node = ls_node
|
||||
CHANGING
|
||||
cv_name = cv_name ).
|
||||
ls_node-name = cv_name.
|
||||
ENDLOOP.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD zif_abapgit_ajson_mapping~to_abap.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD zif_abapgit_ajson_mapping~to_json.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
ENDCLASS.
|
||||
|
||||
CLASS lcl_to_snake IMPLEMENTATION.
|
||||
|
||||
METHOD zif_abapgit_ajson_mapping~rename_node.
|
||||
|
||||
REPLACE ALL OCCURRENCES OF REGEX `([a-z])([A-Z])` IN cv_name WITH `$1_$2`.
|
||||
cv_name = to_lower( cv_name ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD zif_abapgit_ajson_mapping~to_abap.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD zif_abapgit_ajson_mapping~to_json.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
ENDCLASS.
|
||||
|
||||
CLASS lcl_to_camel IMPLEMENTATION.
|
||||
|
||||
METHOD constructor.
|
||||
mv_first_json_upper = iv_first_json_upper.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD zif_abapgit_ajson_mapping~rename_node.
|
||||
|
||||
TYPES lty_token TYPE c LENGTH 255.
|
||||
CONSTANTS lc_forced_underscore_marker TYPE c LENGTH 1 VALUE cl_abap_char_utilities=>horizontal_tab.
|
||||
|
||||
DATA lt_tokens TYPE STANDARD TABLE OF lty_token.
|
||||
DATA lv_from TYPE i.
|
||||
FIELD-SYMBOLS <token> LIKE LINE OF lt_tokens.
|
||||
|
||||
IF mv_first_json_upper = abap_true.
|
||||
lv_from = 1.
|
||||
ELSE.
|
||||
lv_from = 2.
|
||||
ENDIF.
|
||||
REPLACE ALL OCCURRENCES OF `__` IN cv_name WITH lc_forced_underscore_marker. " Force underscore
|
||||
|
||||
SPLIT cv_name AT `_` INTO TABLE lt_tokens.
|
||||
DELETE lt_tokens WHERE table_line IS INITIAL.
|
||||
LOOP AT lt_tokens ASSIGNING <token> FROM lv_from.
|
||||
TRANSLATE <token>+0(1) TO UPPER CASE.
|
||||
ENDLOOP.
|
||||
|
||||
CONCATENATE LINES OF lt_tokens INTO cv_name.
|
||||
REPLACE ALL OCCURRENCES OF lc_forced_underscore_marker IN cv_name WITH `_`.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD zif_abapgit_ajson_mapping~to_abap.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD zif_abapgit_ajson_mapping~to_json.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
ENDCLASS.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
CLASS ltcl_camel_case DEFINITION FINAL FOR TESTING
|
||||
CLASS ltcl_test_mappers DEFINITION FINAL FOR TESTING
|
||||
DURATION SHORT
|
||||
RISK LEVEL HARMLESS.
|
||||
|
||||
|
@ -11,10 +11,21 @@ CLASS ltcl_camel_case DEFINITION FINAL FOR TESTING
|
|||
to_json_nested_table FOR TESTING RAISING zcx_abapgit_ajson_error,
|
||||
to_json_first_lower FOR TESTING RAISING zcx_abapgit_ajson_error.
|
||||
|
||||
METHODS:
|
||||
to_snake FOR TESTING RAISING zcx_abapgit_ajson_error,
|
||||
to_camel FOR TESTING RAISING zcx_abapgit_ajson_error,
|
||||
to_camel_1st_upper FOR TESTING RAISING zcx_abapgit_ajson_error,
|
||||
rename_by_attr FOR TESTING RAISING zcx_abapgit_ajson_error,
|
||||
rename_by_path FOR TESTING RAISING zcx_abapgit_ajson_error,
|
||||
rename_by_pattern FOR TESTING RAISING zcx_abapgit_ajson_error,
|
||||
compound_mapper FOR TESTING RAISING zcx_abapgit_ajson_error,
|
||||
test_to_upper FOR TESTING RAISING zcx_abapgit_ajson_error,
|
||||
test_to_lower FOR TESTING RAISING zcx_abapgit_ajson_error.
|
||||
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS ltcl_camel_case IMPLEMENTATION.
|
||||
CLASS ltcl_test_mappers IMPLEMENTATION.
|
||||
|
||||
|
||||
METHOD from_json_to_json.
|
||||
|
@ -175,6 +186,165 @@ CLASS ltcl_camel_case IMPLEMENTATION.
|
|||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD test_to_upper.
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = zcl_abapgit_ajson=>create_from(
|
||||
ii_source_json = zcl_abapgit_ajson=>parse( '{"a":1,"b":{"c":2}}' )
|
||||
ii_mapper = zcl_abapgit_ajson_mapping=>create_upper_case( ) )->stringify( )
|
||||
exp = '{"A":1,"B":{"C":2}}' ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = zcl_abapgit_ajson=>parse( '{"a":1,"b":{"c":2}}'
|
||||
)->map( zcl_abapgit_ajson_mapping=>create_upper_case( )
|
||||
)->stringify( )
|
||||
exp = '{"A":1,"B":{"C":2}}' ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD test_to_lower.
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = zcl_abapgit_ajson=>create_from(
|
||||
ii_source_json = zcl_abapgit_ajson=>parse( '{"A":1,"B":{"C":2}}' )
|
||||
ii_mapper = zcl_abapgit_ajson_mapping=>create_lower_case( ) )->stringify( )
|
||||
exp = '{"a":1,"b":{"c":2}}' ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = zcl_abapgit_ajson=>parse( '{"A":1,"B":{"C":2}}'
|
||||
)->map( zcl_abapgit_ajson_mapping=>create_lower_case( )
|
||||
)->stringify( )
|
||||
exp = '{"a":1,"b":{"c":2}}' ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD rename_by_attr.
|
||||
|
||||
DATA lt_map TYPE zif_abapgit_ajson_mapping=>tty_rename_map.
|
||||
FIELD-SYMBOLS <i> LIKE LINE OF lt_map.
|
||||
|
||||
APPEND INITIAL LINE TO lt_map ASSIGNING <i>.
|
||||
<i>-from = 'a'.
|
||||
<i>-to = 'x'.
|
||||
APPEND INITIAL LINE TO lt_map ASSIGNING <i>.
|
||||
<i>-from = 'c'.
|
||||
<i>-to = 'y'.
|
||||
APPEND INITIAL LINE TO lt_map ASSIGNING <i>.
|
||||
<i>-from = 'd'.
|
||||
<i>-to = 'z'.
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = zcl_abapgit_ajson=>create_from(
|
||||
ii_source_json = zcl_abapgit_ajson=>parse( '{"a":1,"b":{"c":2},"d":{"e":3}}' )
|
||||
ii_mapper = zcl_abapgit_ajson_mapping=>create_rename( lt_map
|
||||
) )->stringify( )
|
||||
exp = '{"b":{"y":2},"x":1,"z":{"e":3}}' ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD rename_by_path.
|
||||
|
||||
DATA lt_map TYPE zif_abapgit_ajson_mapping=>tty_rename_map.
|
||||
FIELD-SYMBOLS <i> LIKE LINE OF lt_map.
|
||||
|
||||
APPEND INITIAL LINE TO lt_map ASSIGNING <i>.
|
||||
<i>-from = '/b/a'.
|
||||
<i>-to = 'x'.
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = zcl_abapgit_ajson=>create_from(
|
||||
ii_source_json = zcl_abapgit_ajson=>parse( '{"a":1,"b":{"a":2},"c":{"a":3}}' )
|
||||
ii_mapper = zcl_abapgit_ajson_mapping=>create_rename(
|
||||
it_rename_map = lt_map
|
||||
iv_rename_by = zcl_abapgit_ajson_mapping=>rename_by-full_path
|
||||
) )->stringify( )
|
||||
exp = '{"a":1,"b":{"x":2},"c":{"a":3}}' ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD rename_by_pattern.
|
||||
|
||||
DATA lt_map TYPE zif_abapgit_ajson_mapping=>tty_rename_map.
|
||||
FIELD-SYMBOLS <i> LIKE LINE OF lt_map.
|
||||
|
||||
APPEND INITIAL LINE TO lt_map ASSIGNING <i>.
|
||||
<i>-from = '/*/this*'.
|
||||
<i>-to = 'x'.
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = zcl_abapgit_ajson=>create_from(
|
||||
ii_source_json = zcl_abapgit_ajson=>parse( '{"andthisnot":1,"b":{"thisone":2},"c":{"a":3}}' )
|
||||
ii_mapper = zcl_abapgit_ajson_mapping=>create_rename(
|
||||
it_rename_map = lt_map
|
||||
iv_rename_by = zcl_abapgit_ajson_mapping=>rename_by-pattern
|
||||
) )->stringify( )
|
||||
exp = '{"andthisnot":1,"b":{"x":2},"c":{"a":3}}' ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD compound_mapper.
|
||||
|
||||
DATA lt_map TYPE zif_abapgit_ajson_mapping=>tty_rename_map.
|
||||
FIELD-SYMBOLS <i> LIKE LINE OF lt_map.
|
||||
|
||||
APPEND INITIAL LINE TO lt_map ASSIGNING <i>.
|
||||
<i>-from = '/b/a'.
|
||||
<i>-to = 'x'.
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = zcl_abapgit_ajson=>create_from(
|
||||
ii_source_json = zcl_abapgit_ajson=>parse( '{"a":1,"b":{"a":2},"c":{"a":3}}' )
|
||||
ii_mapper = zcl_abapgit_ajson_mapping=>create_compound_mapper(
|
||||
ii_mapper1 = zcl_abapgit_ajson_mapping=>create_rename(
|
||||
it_rename_map = lt_map
|
||||
iv_rename_by = zcl_abapgit_ajson_mapping=>rename_by-full_path )
|
||||
ii_mapper2 = zcl_abapgit_ajson_mapping=>create_upper_case( ) )
|
||||
)->stringify( )
|
||||
exp = '{"A":1,"B":{"X":2},"C":{"A":3}}' ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD to_snake.
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = zcl_abapgit_ajson=>create_from(
|
||||
ii_source_json = zcl_abapgit_ajson=>parse( '{"aB":1,"BbC":2,"cD":{"xY":3},"ZZ":4}' )
|
||||
ii_mapper = zcl_abapgit_ajson_mapping=>create_to_snake_case( )
|
||||
)->stringify( )
|
||||
exp = '{"a_b":1,"bb_c":2,"c_d":{"x_y":3},"zz":4}' ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD to_camel.
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = zcl_abapgit_ajson=>create_from(
|
||||
ii_source_json = zcl_abapgit_ajson=>parse( '{"a_b":1,"bb_c":2,"c_d":{"x_y":3},"zz":4}' )
|
||||
ii_mapper = zcl_abapgit_ajson_mapping=>create_to_camel_case( )
|
||||
)->stringify( )
|
||||
exp = '{"aB":1,"bbC":2,"cD":{"xY":3},"zz":4}' ).
|
||||
|
||||
" Forced underscore
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = zcl_abapgit_ajson=>create_from(
|
||||
ii_source_json = zcl_abapgit_ajson=>parse( '{"a__b":1}' )
|
||||
ii_mapper = zcl_abapgit_ajson_mapping=>create_to_camel_case( )
|
||||
)->stringify( )
|
||||
exp = '{"a_b":1}' ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD to_camel_1st_upper.
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
act = zcl_abapgit_ajson=>create_from(
|
||||
ii_source_json = zcl_abapgit_ajson=>parse( '{"aj_bc":1,"bb_c":2,"c_d":{"xq_yq":3},"zz":4}' )
|
||||
ii_mapper = zcl_abapgit_ajson_mapping=>create_to_camel_case( iv_first_json_upper = abap_true )
|
||||
)->stringify( )
|
||||
exp = '{"AjBc":1,"BbC":2,"CD":{"XqYq":3},"Zz":4}' ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
|
|
|
@ -43,11 +43,14 @@ public section.
|
|||
importing
|
||||
!IV_MSG type STRING
|
||||
!IV_LOCATION type STRING optional
|
||||
!IS_NODE type ANY optional
|
||||
raising
|
||||
zcx_abapgit_ajson_error .
|
||||
methods set_location
|
||||
methods SET_LOCATION
|
||||
importing
|
||||
iv_location type string.
|
||||
!IV_LOCATION type STRING optional
|
||||
!IS_NODE type ANY optional
|
||||
preferred parameter IV_LOCATION .
|
||||
protected section.
|
||||
private section.
|
||||
types:
|
||||
|
@ -64,7 +67,7 @@ ENDCLASS.
|
|||
CLASS zcx_abapgit_ajson_error IMPLEMENTATION.
|
||||
|
||||
|
||||
method CONSTRUCTOR.
|
||||
method CONSTRUCTOR.
|
||||
CALL METHOD SUPER->CONSTRUCTOR
|
||||
EXPORTING
|
||||
PREVIOUS = PREVIOUS
|
||||
|
@ -82,51 +85,53 @@ if textid is initial.
|
|||
else.
|
||||
IF_T100_MESSAGE~T100KEY = TEXTID.
|
||||
endif.
|
||||
endmethod.
|
||||
endmethod.
|
||||
|
||||
|
||||
method raise.
|
||||
|
||||
data ls_msg type ty_message_parts.
|
||||
data lv_tmp type string.
|
||||
data lx type ref to zcx_abapgit_ajson_error.
|
||||
|
||||
if iv_location is initial.
|
||||
lv_tmp = iv_msg.
|
||||
else.
|
||||
lv_tmp = iv_msg && | @{ iv_location }|.
|
||||
endif.
|
||||
ls_msg = lv_tmp.
|
||||
|
||||
raise exception type zcx_abapgit_ajson_error
|
||||
exporting
|
||||
textid = zcx_ajson_error
|
||||
message = iv_msg
|
||||
location = iv_location
|
||||
a1 = ls_msg-a1
|
||||
a2 = ls_msg-a2
|
||||
a3 = ls_msg-a3
|
||||
a4 = ls_msg-a4.
|
||||
create object lx exporting message = iv_msg.
|
||||
lx->set_location(
|
||||
iv_location = iv_location
|
||||
is_node = is_node ).
|
||||
raise exception lx.
|
||||
|
||||
endmethod.
|
||||
|
||||
|
||||
method set_location.
|
||||
|
||||
data ls_msg type ty_message_parts.
|
||||
data lv_location type string.
|
||||
data lv_tmp type string.
|
||||
field-symbols <path> type string.
|
||||
field-symbols <name> type string.
|
||||
|
||||
if iv_location is initial.
|
||||
lv_tmp = message.
|
||||
else.
|
||||
lv_tmp = message && | @{ iv_location }|.
|
||||
if iv_location is not initial.
|
||||
lv_location = iv_location.
|
||||
elseif is_node is not initial.
|
||||
assign component 'PATH' of structure is_node to <path>.
|
||||
assign component 'NAME' of structure is_node to <name>.
|
||||
if <path> is assigned and <name> is assigned.
|
||||
lv_location = <path> && <name>.
|
||||
endif.
|
||||
endif.
|
||||
|
||||
if lv_location is not initial.
|
||||
lv_tmp = message && | @{ lv_location }|.
|
||||
else.
|
||||
lv_tmp = message.
|
||||
endif.
|
||||
|
||||
ls_msg = lv_tmp.
|
||||
|
||||
location = iv_location.
|
||||
location = lv_location.
|
||||
a1 = ls_msg-a1.
|
||||
a2 = ls_msg-a2.
|
||||
a3 = ls_msg-a3.
|
||||
a4 = ls_msg-a4.
|
||||
|
||||
endmethod.
|
||||
|
||||
ENDCLASS.
|
||||
|
|
|
@ -8,6 +8,7 @@ class ltcl_error definition
|
|||
|
||||
methods raise for testing.
|
||||
methods raise_w_location for testing.
|
||||
methods raise_w_node for testing.
|
||||
methods set_location for testing.
|
||||
|
||||
endclass.
|
||||
|
@ -50,6 +51,26 @@ class ltcl_error implementation.
|
|||
|
||||
endmethod.
|
||||
|
||||
method raise_w_node.
|
||||
|
||||
data lx type ref to zcx_abapgit_ajson_error.
|
||||
data ls_node type zif_abapgit_ajson=>ty_node.
|
||||
|
||||
ls_node-path = '/x/'.
|
||||
ls_node-name = 'y'.
|
||||
|
||||
try.
|
||||
zcx_abapgit_ajson_error=>raise( iv_msg = 'a'
|
||||
is_node = ls_node ).
|
||||
cl_abap_unit_assert=>fail( ).
|
||||
catch zcx_abapgit_ajson_error into lx.
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = 'a @/x/y'
|
||||
act = lx->get_text( ) ).
|
||||
endtry.
|
||||
|
||||
endmethod.
|
||||
|
||||
method set_location.
|
||||
|
||||
data lx type ref to zcx_abapgit_ajson_error.
|
||||
|
|
|
@ -48,6 +48,27 @@ INTERFACE zif_abapgit_ajson
|
|||
|
||||
DATA mt_json_tree TYPE ty_nodes_ts READ-ONLY.
|
||||
|
||||
" CLONING
|
||||
METHODS clone
|
||||
RETURNING
|
||||
VALUE(ri_json) TYPE REF TO zif_abapgit_ajson
|
||||
RAISING
|
||||
zcx_abapgit_ajson_error.
|
||||
METHODS filter
|
||||
IMPORTING
|
||||
ii_filter TYPE REF TO zif_abapgit_ajson_filter
|
||||
RETURNING
|
||||
VALUE(ri_json) TYPE REF TO zif_abapgit_ajson
|
||||
RAISING
|
||||
zcx_abapgit_ajson_error.
|
||||
METHODS map
|
||||
IMPORTING
|
||||
ii_mapper TYPE REF TO zif_abapgit_ajson_mapping
|
||||
RETURNING
|
||||
VALUE(ri_json) TYPE REF TO zif_abapgit_ajson
|
||||
RAISING
|
||||
zcx_abapgit_ajson_error.
|
||||
|
||||
" METHODS
|
||||
|
||||
METHODS freeze.
|
||||
|
@ -166,6 +187,14 @@ INTERFACE zif_abapgit_ajson
|
|||
RAISING
|
||||
zcx_abapgit_ajson_error.
|
||||
|
||||
METHODS setx
|
||||
IMPORTING
|
||||
iv_param TYPE string
|
||||
RETURNING
|
||||
VALUE(ri_json) TYPE REF TO zif_abapgit_ajson
|
||||
RAISING
|
||||
zcx_abapgit_ajson_error.
|
||||
|
||||
METHODS set_boolean
|
||||
IMPORTING
|
||||
iv_path TYPE string
|
||||
|
|
|
@ -2,7 +2,7 @@ INTERFACE zif_abapgit_ajson_mapping
|
|||
PUBLIC.
|
||||
|
||||
TYPES:
|
||||
BEGIN OF ty_mapping_field,
|
||||
BEGIN OF ty_mapping_field, " deprecated, will be removed
|
||||
abap TYPE string,
|
||||
json TYPE string,
|
||||
END OF ty_mapping_field,
|
||||
|
@ -10,18 +10,35 @@ INTERFACE zif_abapgit_ajson_mapping
|
|||
WITH UNIQUE SORTED KEY abap COMPONENTS abap
|
||||
WITH UNIQUE SORTED KEY json COMPONENTS json.
|
||||
|
||||
METHODS to_abap
|
||||
TYPES:
|
||||
BEGIN OF ty_rename,
|
||||
from TYPE string,
|
||||
to TYPE string,
|
||||
END OF ty_rename,
|
||||
tty_rename_map TYPE STANDARD TABLE OF ty_rename
|
||||
WITH UNIQUE SORTED KEY by_name COMPONENTS from.
|
||||
|
||||
TYPES:
|
||||
ty_table_of TYPE STANDARD TABLE OF REF TO zif_abapgit_ajson_mapping.
|
||||
|
||||
METHODS to_abap " deprecated, will be removed
|
||||
IMPORTING
|
||||
!iv_path TYPE string
|
||||
!iv_name TYPE string
|
||||
RETURNING
|
||||
VALUE(rv_result) TYPE string.
|
||||
|
||||
METHODS to_json
|
||||
METHODS to_json " deprecated, will be removed
|
||||
IMPORTING
|
||||
!iv_path TYPE string
|
||||
!iv_name TYPE string
|
||||
RETURNING
|
||||
VALUE(rv_result) TYPE string.
|
||||
|
||||
METHODS rename_node
|
||||
IMPORTING
|
||||
!is_node TYPE zif_abapgit_ajson=>ty_node
|
||||
CHANGING
|
||||
!cv_name TYPE zif_abapgit_ajson=>ty_node-name.
|
||||
|
||||
ENDINTERFACE.
|
||||
|
|
|
@ -88,7 +88,7 @@ ENDCLASS.
|
|||
|
||||
|
||||
|
||||
CLASS ZCL_ABAPGIT_JSON_HANDLER IMPLEMENTATION.
|
||||
CLASS zcl_abapgit_json_handler IMPLEMENTATION.
|
||||
|
||||
|
||||
METHOD deserialize.
|
||||
|
@ -248,7 +248,7 @@ CLASS ZCL_ABAPGIT_JSON_HANDLER IMPLEMENTATION.
|
|||
|
||||
lo_mapping = zcl_abapgit_ajson_mapping=>create_camel_case( iv_first_json_upper = abap_false ).
|
||||
|
||||
lo_ajson = zcl_abapgit_ajson=>create_empty( lo_mapping ).
|
||||
lo_ajson = zcl_abapgit_ajson=>create_empty( ii_custom_mapping = lo_mapping ).
|
||||
|
||||
lo_ajson->keep_item_order( ).
|
||||
lo_ajson->set(
|
||||
|
|
|
@ -108,6 +108,7 @@
|
|||
{"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_json_to_abap", "method": "to_abap_array_of_arrays", "note": "Expected table to contain 2 rows, got 4"},
|
||||
{"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_writer_test", "method": "set_tab_hashed", "note": "Expected table to contain 4 rows, got 3"},
|
||||
{"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_integrated", "method": "reader", "note": "Path not found @/false, keywords?"},
|
||||
{"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_writer_test", "method": "setx_float", "note": "DecFloat34"},
|
||||
|
||||
{"object": "ZCL_ABAPGIT_REQUIREMENT_HELPER", "class": "ltcl_lower_release", "method": "empty_patch", "note": "Void type: CVERS_SDU"},
|
||||
{"object": "ZCL_ABAPGIT_REQUIREMENT_HELPER", "class": "ltcl_lower_release", "method": "lower_patch", "note": "Void type: CVERS_SDU"},
|
||||
|
|
Loading…
Reference in New Issue
Block a user