ajson, Automatic Update (#5036)

* [create-pull-request] automated change

* upd

* fix

Co-authored-by: larshp <larshp@users.noreply.github.com>
Co-authored-by: Marc Bernard <59966492+mbtools@users.noreply.github.com>
Co-authored-by: Lars Hvam <larshp@hotmail.com>
This commit is contained in:
github-actions[bot] 2021-10-20 17:50:51 +02:00 committed by GitHub
parent e85e2f51d3
commit 27eca9b766
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 880 additions and 112 deletions

View File

@ -18,9 +18,9 @@
"url": "git+https://github.com/abapGit/abapGit.git"
},
"devDependencies": {
"@abaplint/cli": "^2.79.30",
"@abaplint/transpiler-cli": "^1.6.50",
"@abaplint/runtime": "^1.6.50",
"@abaplint/cli": "^2.79.32",
"@abaplint/transpiler-cli": "^1.6.53",
"@abaplint/runtime": "^1.6.53",
"abapmerge": "^0.14.3",
"eslint": "^8.0.1"
}

View File

@ -55,6 +55,16 @@ CLASS zcl_abapgit_ajson DEFINITION
RETURNING
VALUE(ro_instance) TYPE REF TO zcl_abapgit_ajson.
" Experimental ! May change
CLASS-METHODS create_from
IMPORTING
!ii_source_json TYPE REF TO zif_abapgit_ajson
!ii_filter TYPE REF TO zif_abapgit_ajson_filter OPTIONAL
RETURNING
VALUE(ro_instance) TYPE REF TO zcl_abapgit_ajson
RAISING
zcx_abapgit_ajson_error .
PROTECTED SECTION.
PRIVATE SECTION.
@ -84,7 +94,6 @@ CLASS zcl_abapgit_ajson DEFINITION
iv_name TYPE string
RETURNING
VALUE(rv_deleted) TYPE abap_bool.
ENDCLASS.
@ -98,6 +107,32 @@ CLASS zcl_abapgit_ajson IMPLEMENTATION.
ENDMETHOD.
METHOD create_from.
DATA lo_filter_runner TYPE REF TO lcl_filter_runner.
IF ii_source_json IS NOT BOUND.
zcx_abapgit_ajson_error=>raise( 'Source not bound' ).
ENDIF.
CREATE OBJECT ro_instance.
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.
ro_instance->mt_json_tree = ii_source_json->mt_json_tree.
" Copy keep order and custom mapping ???
ENDIF.
ENDMETHOD.
METHOD delete_subtree.
DATA lv_parent_path TYPE string.
@ -453,9 +488,11 @@ CLASS zcl_abapgit_ajson IMPLEMENTATION.
DATA lt_new_nodes TYPE zif_abapgit_ajson=>ty_nodes_tt.
DATA ls_new_path TYPE zif_abapgit_ajson=>ty_path_name.
DATA lv_new_index TYPE i.
lv_new_index = lr_parent->children + 1.
ls_new_path-path = lcl_utils=>normalize_path( iv_path ).
ls_new_path-name = |{ lr_parent->children + 1 }|.
ls_new_path-name = |{ lv_new_index }|.
lt_new_nodes = lcl_abap_to_json=>convert(
iv_keep_item_order = mv_keep_item_order
@ -463,10 +500,10 @@ CLASS zcl_abapgit_ajson IMPLEMENTATION.
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 !
ASSERT sy-subrc = 0.
lr_new_node->index = lr_parent->children + 1.
lr_new_node->index = lv_new_index.
" update data
lr_parent->children = lr_parent->children + 1.
lr_parent->children = lv_new_index.
INSERT LINES OF lt_new_nodes INTO TABLE mt_json_tree.
ri_json = me.
@ -553,8 +590,10 @@ CLASS zcl_abapgit_ajson IMPLEMENTATION.
ENDIF.
" update data
lr_parent->children = lr_parent->children + 1.
INSERT LINES OF lt_new_nodes INTO TABLE mt_json_tree.
IF lines( lt_new_nodes ) > 0.
lr_parent->children = lr_parent->children + 1.
INSERT LINES OF lt_new_nodes INTO TABLE mt_json_tree.
ENDIF.
ENDMETHOD.

View File

@ -776,7 +776,7 @@ CLASS lcl_json_to_abap IMPLEMENTATION.
DATA lv_date TYPE d.
DATA lv_time TYPE t.
DATA lv_seconds_conv TYPE i.
DATA lv_timestamp TYPE timestamp.
DATA lv_timestamp TYPE timestampl.
FIND FIRST OCCURRENCE OF REGEX lc_regex_ts_with_hour
IN is_path-value SUBMATCHES ls_timestamp-year ls_timestamp-month ls_timestamp-day ls_timestamp-t
@ -823,7 +823,8 @@ CLASS lcl_json_to_abap IMPLEMENTATION.
iv_location = is_path-path && is_path-name ).
ENDTRY.
rv_result = lv_timestamp.
cl_abap_tstmp=>move( EXPORTING tstmp_src = lv_timestamp
IMPORTING tstmp_tgt = rv_result ).
ENDMETHOD.
@ -887,7 +888,9 @@ CLASS lcl_abap_to_json DEFINITION FINAL.
is_prefix TYPE zif_abapgit_ajson=>ty_path_name
iv_index TYPE i DEFAULT 0
CHANGING
ct_nodes TYPE zif_abapgit_ajson=>ty_nodes_tt.
ct_nodes TYPE zif_abapgit_ajson=>ty_nodes_tt
RAISING
zcx_abapgit_ajson_error.
METHODS convert_value
IMPORTING
@ -971,7 +974,7 @@ CLASS lcl_abap_to_json IMPLEMENTATION.
lo_type = cl_abap_typedescr=>describe_by_data( iv_data ).
CREATE OBJECT lo_converter.
lo_converter->mi_custom_mapping = ii_custom_mapping.
lo_converter->mi_custom_mapping = ii_custom_mapping.
lo_converter->mv_keep_item_order = iv_keep_item_order.
lo_converter->convert_any(
@ -1053,17 +1056,22 @@ CLASS lcl_abap_to_json IMPLEMENTATION.
METHOD convert_ajson.
FIELD-SYMBOLS <n> LIKE LINE OF ct_nodes.
FIELD-SYMBOLS <src> LIKE LINE OF ct_nodes.
FIELD-SYMBOLS <dst> LIKE LINE OF ct_nodes.
ct_nodes = io_json->mt_json_tree.
IF io_json IS NOT BOUND.
RETURN.
ENDIF.
LOOP AT ct_nodes ASSIGNING <n>.
IF <n>-path IS INITIAL AND <n>-name IS INITIAL. " root node
<n>-path = is_prefix-path.
<n>-name = is_prefix-name.
<n>-index = iv_index.
LOOP AT io_json->mt_json_tree ASSIGNING <src>.
APPEND <src> TO ct_nodes ASSIGNING <dst>.
IF <dst>-path IS INITIAL AND <dst>-name IS INITIAL. " root node
<dst>-path = is_prefix-path.
<dst>-name = is_prefix-name.
<dst>-index = iv_index.
ELSE.
<n>-path = is_prefix-path && is_prefix-name && <n>-path.
<dst>-path = is_prefix-path && is_prefix-name && <dst>-path.
ENDIF.
ENDLOOP.
@ -1071,22 +1079,21 @@ CLASS lcl_abap_to_json IMPLEMENTATION.
METHOD convert_value.
FIELD-SYMBOLS <n> LIKE LINE OF ct_nodes.
DATA ls_node LIKE LINE OF ct_nodes.
APPEND INITIAL LINE TO ct_nodes ASSIGNING <n>.
<n>-path = is_prefix-path.
<n>-name = is_prefix-name.
<n>-index = iv_index.
<n>-order = iv_item_order.
ls_node-path = is_prefix-path.
ls_node-name = is_prefix-name.
ls_node-index = iv_index.
ls_node-order = iv_item_order.
IF mi_custom_mapping IS BOUND.
<n>-name = mi_custom_mapping->to_json( iv_path = is_prefix-path
iv_name = is_prefix-name ).
ls_node-name = mi_custom_mapping->to_json(
iv_path = is_prefix-path
iv_name = is_prefix-name ).
ENDIF.
IF <n>-name IS INITIAL.
<n>-name = is_prefix-name.
IF ls_node-name IS INITIAL.
ls_node-name = is_prefix-name.
ENDIF.
IF io_type->absolute_name = '\TYPE-POOL=ABAP\TYPE=ABAP_BOOL'
@ -1094,53 +1101,56 @@ CLASS lcl_abap_to_json IMPLEMENTATION.
OR io_type->absolute_name = '\TYPE=XSDBOOLEAN'
OR io_type->absolute_name = '\TYPE=FLAG'
OR io_type->absolute_name = '\TYPE=XFELD'.
<n>-type = zif_abapgit_ajson=>node_type-boolean.
ls_node-type = zif_abapgit_ajson=>node_type-boolean.
IF iv_data IS NOT INITIAL.
<n>-value = 'true'.
ls_node-value = 'true'.
ELSE.
<n>-value = 'false'.
ls_node-value = 'false'.
ENDIF.
ELSEIF io_type->type_kind CO 'CNgXyDT'. " Char like, date/time, xstring
<n>-type = zif_abapgit_ajson=>node_type-string.
<n>-value = |{ iv_data }|.
ls_node-type = zif_abapgit_ajson=>node_type-string.
ls_node-value = |{ iv_data }|.
ELSEIF io_type->type_kind CO 'bsI8PaeF'. " Numeric
<n>-type = zif_abapgit_ajson=>node_type-number.
<n>-value = |{ iv_data }|.
ls_node-type = zif_abapgit_ajson=>node_type-number.
ls_node-value = |{ iv_data }|.
ELSE.
zcx_abapgit_ajson_error=>raise( |Unexpected elementary type [{
io_type->type_kind }] @{ is_prefix-path && is_prefix-name }| ).
ENDIF.
APPEND ls_node TO ct_nodes.
ENDMETHOD.
METHOD convert_ref.
FIELD-SYMBOLS <n> LIKE LINE OF ct_nodes.
DATA ls_node LIKE LINE OF ct_nodes.
APPEND INITIAL LINE TO ct_nodes ASSIGNING <n>.
<n>-path = is_prefix-path.
<n>-name = is_prefix-name.
<n>-index = iv_index.
<n>-order = iv_item_order.
ls_node-path = is_prefix-path.
ls_node-name = is_prefix-name.
ls_node-index = iv_index.
ls_node-order = iv_item_order.
IF mi_custom_mapping IS BOUND.
<n>-name = mi_custom_mapping->to_json( iv_path = is_prefix-path
iv_name = is_prefix-name ).
ls_node-name = mi_custom_mapping->to_json(
iv_path = is_prefix-path
iv_name = is_prefix-name ).
ENDIF.
IF <n>-name IS INITIAL.
<n>-name = is_prefix-name.
IF ls_node-name IS INITIAL.
ls_node-name = is_prefix-name.
ENDIF.
IF iv_data IS INITIAL.
<n>-type = zif_abapgit_ajson=>node_type-null.
<n>-value = 'null'.
ls_node-type = zif_abapgit_ajson=>node_type-null.
ls_node-value = 'null'.
ELSE.
" TODO support data references
zcx_abapgit_ajson_error=>raise( |Unexpected reference @{ is_prefix-path && is_prefix-name }| ).
ENDIF.
APPEND ls_node TO ct_nodes.
ENDMETHOD.
METHOD convert_struc.
@ -1149,11 +1159,40 @@ CLASS lcl_abap_to_json IMPLEMENTATION.
DATA lt_comps TYPE cl_abap_structdescr=>component_table.
DATA ls_next_prefix LIKE is_prefix.
DATA lv_item_order TYPE i.
DATA ls_root LIKE LINE OF ct_nodes.
FIELD-SYMBOLS <root> LIKE LINE OF ct_nodes.
FIELD-SYMBOLS <root> LIKE ls_root.
FIELD-SYMBOLS <c> LIKE LINE OF lt_comps.
FIELD-SYMBOLS <val> TYPE any.
" Object root
IF cs_root IS SUPPLIED. " call for include structure
ASSIGN cs_root TO <root>.
ELSE. " First call
ls_root-path = is_prefix-path.
ls_root-name = is_prefix-name.
ls_root-type = zif_abapgit_ajson=>node_type-object.
ls_root-index = iv_index.
IF mi_custom_mapping IS BOUND.
ls_root-name = mi_custom_mapping->to_json(
iv_path = is_prefix-path
iv_name = is_prefix-name ).
ENDIF.
IF ls_root-name IS INITIAL.
ls_root-name = is_prefix-name.
ENDIF.
ls_root-order = iv_item_order.
APPEND ls_root TO ct_nodes ASSIGNING <root>.
ENDIF.
" Object attributes
lo_struc ?= io_type.
lt_comps = lo_struc->get_components( ).
" get_components is potentially much slower than lo_struc->components
@ -1161,27 +1200,6 @@ CLASS lcl_abap_to_json IMPLEMENTATION.
" and rtti seems to cache type descriptions really well (https://github.com/sbcgua/benchmarks.git)
" the structures will be repeated in real life
IF cs_root IS SUPPLIED. " call for include structure
ASSIGN cs_root TO <root>.
ELSE. " First call
APPEND INITIAL LINE TO ct_nodes ASSIGNING <root>.
<root>-path = is_prefix-path.
<root>-name = is_prefix-name.
<root>-type = zif_abapgit_ajson=>node_type-object.
<root>-index = iv_index.
IF mi_custom_mapping IS BOUND.
<root>-name = mi_custom_mapping->to_json( iv_path = is_prefix-path
iv_name = is_prefix-name ).
ENDIF.
IF <root>-name IS INITIAL.
<root>-name = is_prefix-name.
ENDIF.
<root>-order = iv_item_order.
ENDIF.
ls_next_prefix-path = is_prefix-path && is_prefix-name && '/'.
LOOP AT lt_comps ASSIGNING <c>.
@ -1229,30 +1247,37 @@ CLASS lcl_abap_to_json IMPLEMENTATION.
DATA lo_ltype TYPE REF TO cl_abap_typedescr.
DATA ls_next_prefix LIKE is_prefix.
DATA lv_tabix TYPE sy-tabix.
DATA ls_root LIKE LINE OF ct_nodes.
FIELD-SYMBOLS <root> LIKE LINE OF ct_nodes.
FIELD-SYMBOLS <root> LIKE ls_root.
FIELD-SYMBOLS <tab> TYPE ANY TABLE.
FIELD-SYMBOLS <val> TYPE any.
lo_table ?= io_type.
lo_ltype = lo_table->get_table_line_type( ).
" Array root
APPEND INITIAL LINE TO ct_nodes ASSIGNING <root>.
<root>-path = is_prefix-path.
<root>-name = is_prefix-name.
<root>-type = zif_abapgit_ajson=>node_type-array.
<root>-index = iv_index.
<root>-order = iv_item_order.
ls_root-path = is_prefix-path.
ls_root-name = is_prefix-name.
ls_root-type = zif_abapgit_ajson=>node_type-array.
ls_root-index = iv_index.
ls_root-order = iv_item_order.
IF mi_custom_mapping IS BOUND.
<root>-name = mi_custom_mapping->to_json( iv_path = is_prefix-path
iv_name = is_prefix-name ).
ls_root-name = mi_custom_mapping->to_json(
iv_path = is_prefix-path
iv_name = is_prefix-name ).
ENDIF.
IF <root>-name IS INITIAL.
<root>-name = is_prefix-name.
IF ls_root-name IS INITIAL.
ls_root-name = is_prefix-name.
ENDIF.
APPEND ls_root TO ct_nodes ASSIGNING <root>.
" Array items
lo_table ?= io_type.
lo_ltype = lo_table->get_table_line_type( ).
ls_next_prefix-path = is_prefix-path && is_prefix-name && '/'.
ASSIGN iv_data TO <tab>.
@ -1283,7 +1308,7 @@ CLASS lcl_abap_to_json IMPLEMENTATION.
lo_type = cl_abap_typedescr=>describe_by_data( iv_data ).
CREATE OBJECT lo_converter.
lo_converter->mi_custom_mapping = ii_custom_mapping.
lo_converter->mi_custom_mapping = ii_custom_mapping.
lo_converter->mv_keep_item_order = iv_keep_item_order.
lo_converter->insert_value_with_type(
@ -1301,8 +1326,7 @@ CLASS lcl_abap_to_json IMPLEMENTATION.
METHOD insert_value_with_type.
DATA lv_prefix TYPE string.
FIELD-SYMBOLS <n> LIKE LINE OF ct_nodes.
DATA ls_node LIKE LINE OF ct_nodes.
lv_prefix = is_prefix-path && is_prefix-name.
IF io_type->type_kind CO 'CNgXyDT'. " Char like, date/time, xstring
@ -1324,24 +1348,125 @@ CLASS lcl_abap_to_json IMPLEMENTATION.
zcx_abapgit_ajson_error=>raise( |Unexpected type [{ io_type->type_kind }] @{ lv_prefix }| ).
ENDIF.
APPEND INITIAL LINE TO ct_nodes ASSIGNING <n>.
<n>-path = is_prefix-path.
<n>-name = is_prefix-name.
<n>-index = iv_index.
<n>-value = iv_data.
<n>-type = iv_type.
<n>-order = iv_item_order.
ls_node-path = is_prefix-path.
ls_node-name = is_prefix-name.
ls_node-index = iv_index.
ls_node-value = iv_data.
ls_node-type = iv_type.
ls_node-order = iv_item_order.
IF mi_custom_mapping IS BOUND.
<n>-name = mi_custom_mapping->to_json( iv_path = is_prefix-path
iv_name = is_prefix-name ).
ls_node-name = mi_custom_mapping->to_json(
iv_path = is_prefix-path
iv_name = is_prefix-name ).
ENDIF.
IF <n>-name IS INITIAL.
<n>-name = is_prefix-name.
IF ls_node-name IS INITIAL.
ls_node-name = is_prefix-name.
ENDIF.
APPEND ls_node TO ct_nodes.
ENDMETHOD.
ENDCLASS.
**********************************************************************
* FILTER RUNNER
**********************************************************************
CLASS lcl_filter_runner DEFINITION FINAL.
PUBLIC SECTION.
METHODS run
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.
PRIVATE SECTION.
DATA mi_filter TYPE REF TO zif_abapgit_ajson_filter.
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 walk
IMPORTING
iv_path TYPE string
CHANGING
cs_parent TYPE zif_abapgit_ajson=>ty_node OPTIONAL
RAISING
zcx_abapgit_ajson_error.
ENDCLASS.
CLASS lcl_filter_runner IMPLEMENTATION.
METHOD run.
ASSERT ii_filter IS BOUND.
mi_filter = ii_filter.
CLEAR ct_dest_tree.
GET REFERENCE OF it_source_tree INTO mr_source_tree.
GET REFERENCE OF ct_dest_tree INTO mr_dest_tree.
walk( iv_path = '' ).
ENDMETHOD.
METHOD walk.
DATA ls_node TYPE zif_abapgit_ajson=>ty_node.
LOOP AT mr_source_tree->* INTO ls_node WHERE path = iv_path.
CASE ls_node-type.
WHEN zif_abapgit_ajson=>node_type-boolean OR zif_abapgit_ajson=>node_type-null
OR zif_abapgit_ajson=>node_type-number OR zif_abapgit_ajson=>node_type-string.
IF mi_filter->keep_node( ls_node ) = abap_false.
CONTINUE.
ENDIF.
WHEN zif_abapgit_ajson=>node_type-array OR zif_abapgit_ajson=>node_type-object.
IF mi_filter->keep_node(
is_node = ls_node
iv_visit = zif_abapgit_ajson_filter=>visit_type-open ) = abap_false.
CONTINUE.
ENDIF.
" Intentionally clear AFTER "open"
CLEAR ls_node-children.
walk(
EXPORTING
iv_path = iv_path && ls_node-name && `/`
CHANGING
cs_parent = ls_node ).
IF mi_filter->keep_node(
is_node = ls_node
iv_visit = zif_abapgit_ajson_filter=>visit_type-close ) = abap_false.
CONTINUE.
ENDIF.
WHEN OTHERS.
zcx_abapgit_ajson_error=>raise( |Unexpected node type { ls_node-type }| ).
ENDCASE.
IF cs_parent IS SUPPLIED.
cs_parent-children = cs_parent-children + 1.
IF cs_parent-type = zif_abapgit_ajson=>node_type-array.
ls_node-name = |{ cs_parent-children }|.
ls_node-index = cs_parent-children.
ENDIF.
ENDIF.
INSERT ls_node INTO TABLE mr_dest_tree->*.
ENDLOOP.
ENDMETHOD.
ENDCLASS.

View File

@ -1695,6 +1695,7 @@ CLASS ltcl_writer_test DEFINITION FINAL
METHODS read_only FOR TESTING RAISING zcx_abapgit_ajson_error.
METHODS set_array_obj FOR TESTING RAISING zcx_abapgit_ajson_error.
METHODS set_with_type FOR TESTING RAISING zcx_abapgit_ajson_error.
METHODS set_with_type_slice
IMPORTING
io_json_in TYPE REF TO zcl_abapgit_ajson
@ -1920,24 +1921,22 @@ CLASS ltcl_writer_test IMPLEMENTATION.
METHOD ignore_empty.
DATA lo_nodes TYPE REF TO lcl_nodes_helper.
DATA lo_cut TYPE REF TO zcl_abapgit_ajson.
DATA li_writer TYPE REF TO zif_abapgit_ajson.
DATA li_cut TYPE REF TO zif_abapgit_ajson.
lo_cut = zcl_abapgit_ajson=>create_empty( ).
li_writer = lo_cut.
li_cut = zcl_abapgit_ajson=>create_empty( ).
CREATE OBJECT lo_nodes.
lo_nodes->add( ' | |object | ||1' ).
lo_nodes->add( '/ |a |num |1 ||0' ).
li_writer->set(
li_cut->set(
iv_path = '/a'
iv_val = 1 ).
li_writer->set( " ignore empty
li_cut->set( " ignore empty
iv_path = '/b'
iv_val = 0 ).
cl_abap_unit_assert=>assert_equals(
act = lo_cut->mt_json_tree
act = li_cut->mt_json_tree
exp = lo_nodes->sorted( ) ).
CREATE OBJECT lo_nodes.
@ -1945,12 +1944,12 @@ CLASS ltcl_writer_test IMPLEMENTATION.
lo_nodes->add( '/ |a |num |1 ||0' ).
lo_nodes->add( '/ |b |num |0 ||0' ).
li_writer->set(
li_cut->set(
iv_ignore_empty = abap_false
iv_path = '/b'
iv_val = 0 ).
cl_abap_unit_assert=>assert_equals(
act = lo_cut->mt_json_tree
act = li_cut->mt_json_tree
exp = lo_nodes->sorted( ) ).
ENDMETHOD.
@ -2610,6 +2609,7 @@ CLASS ltcl_writer_test IMPLEMENTATION.
ENDLOOP.
ENDMETHOD.
ENDCLASS.
@ -3243,3 +3243,174 @@ CLASS ltcl_abap_to_json IMPLEMENTATION.
ENDMETHOD.
ENDCLASS.
**********************************************************************
* FILTER TEST
**********************************************************************
CLASS ltcl_filter_test DEFINITION FINAL
FOR TESTING
DURATION SHORT
RISK LEVEL HARMLESS.
PUBLIC SECTION.
INTERFACES zif_abapgit_ajson_filter.
PRIVATE SECTION.
TYPES:
BEGIN OF ty_visit_history,
path TYPE string,
type TYPE zif_abapgit_ajson_filter=>ty_visit_type,
END OF ty_visit_history.
DATA mt_visit_history TYPE TABLE OF ty_visit_history.
METHODS simple_test FOR TESTING RAISING zcx_abapgit_ajson_error.
METHODS array_test FOR TESTING RAISING zcx_abapgit_ajson_error.
METHODS visit_types FOR TESTING RAISING zcx_abapgit_ajson_error.
ENDCLASS.
CLASS ltcl_filter_test IMPLEMENTATION.
METHOD zif_abapgit_ajson_filter~keep_node.
DATA ls_visit_history LIKE LINE OF mt_visit_history.
IF iv_visit > 0.
ls_visit_history-type = iv_visit.
ls_visit_history-path = is_node-path && is_node-name && '/'.
APPEND ls_visit_history TO mt_visit_history.
ENDIF.
rv_keep = boolc( NOT is_node-name CA 'xX' AND NOT is_node-value CA 'xX' ).
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 = '/a'
iv_val = 1 ).
lo_json->set(
iv_path = '/b'
iv_val = 1 ).
lo_json->set(
iv_path = '/x'
iv_val = 1 ).
lo_json->set(
iv_path = '/c/x'
iv_val = 1 ).
lo_json->set(
iv_path = '/c/y'
iv_val = 1 ).
lo_json_filtered = zcl_abapgit_ajson=>create_from(
ii_source_json = lo_json
ii_filter = me ).
CREATE OBJECT lo_nodes_exp.
lo_nodes_exp->add( ' | |object | | |3' ).
lo_nodes_exp->add( '/ |a |num |1 | |0' ).
lo_nodes_exp->add( '/ |b |num |1 | |0' ).
lo_nodes_exp->add( '/ |c |object | | |1' ).
lo_nodes_exp->add( '/c/ |y |num |1 | |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( '/' ).
lo_json->push(
iv_path = '/'
iv_val = 'a' ).
lo_json->push(
iv_path = '/'
iv_val = 'x' ).
lo_json->push(
iv_path = '/'
iv_val = 'b' ).
lo_json_filtered = zcl_abapgit_ajson=>create_from(
ii_source_json = lo_json
ii_filter = me ).
CREATE OBJECT lo_nodes_exp.
lo_nodes_exp->add( ' | |array | | |2' ).
lo_nodes_exp->add( '/ |1 |str |a |1|0' ).
lo_nodes_exp->add( '/ |2 |str |b |2|0' ).
cl_abap_unit_assert=>assert_equals(
act = lo_json_filtered->mt_json_tree
exp = lo_nodes_exp->sorted( ) ).
ENDMETHOD.
METHOD visit_types.
DATA lo_json TYPE REF TO zcl_abapgit_ajson.
DATA lo_json_filtered TYPE REF TO zcl_abapgit_ajson.
DATA lt_visits_exp LIKE mt_visit_history.
FIELD-SYMBOLS <v> LIKE LINE OF lt_visits_exp.
DATA:
BEGIN OF ls_dummy,
d TYPE i VALUE 10,
e TYPE i VALUE 20,
END OF ls_dummy.
CLEAR mt_visit_history.
lo_json = zcl_abapgit_ajson=>create_empty( ).
lo_json->touch_array( '/' ).
lo_json->push(
iv_path = '/'
iv_val = 'a' ).
lo_json->push(
iv_path = '/'
iv_val = 'b' ).
lo_json->push(
iv_path = '/'
iv_val = ls_dummy ).
lo_json_filtered = zcl_abapgit_ajson=>create_from(
ii_source_json = lo_json
ii_filter = me ).
APPEND INITIAL LINE TO lt_visits_exp ASSIGNING <v>.
<v>-path = '/'.
<v>-type = zif_abapgit_ajson_filter=>visit_type-open.
APPEND INITIAL LINE TO lt_visits_exp ASSIGNING <v>.
<v>-path = '/3/'.
<v>-type = zif_abapgit_ajson_filter=>visit_type-open.
APPEND INITIAL LINE TO lt_visits_exp ASSIGNING <v>.
<v>-path = '/3/'.
<v>-type = zif_abapgit_ajson_filter=>visit_type-close.
APPEND INITIAL LINE TO lt_visits_exp ASSIGNING <v>.
<v>-path = '/'.
<v>-type = zif_abapgit_ajson_filter=>visit_type-close.
cl_abap_unit_assert=>assert_equals(
act = mt_visit_history
exp = lt_visits_exp ).
ENDMETHOD.
ENDCLASS.

View File

@ -0,0 +1,56 @@
CLASS zcl_abapgit_ajson_filter_lib DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
CLASS-METHODS create_empty_filter
RETURNING
VALUE(ri_filter) TYPE REF TO zif_abapgit_ajson_filter
RAISING
zcx_abapgit_ajson_error .
CLASS-METHODS create_path_filter
IMPORTING
!it_skip_paths TYPE string_table OPTIONAL
!iv_skip_paths TYPE string OPTIONAL
RETURNING
VALUE(ri_filter) TYPE REF TO zif_abapgit_ajson_filter
RAISING
zcx_abapgit_ajson_error .
CLASS-METHODS create_and_filter
IMPORTING
!it_filters TYPE zif_abapgit_ajson_filter=>ty_filter_tab
RETURNING
VALUE(ri_filter) TYPE REF TO zif_abapgit_ajson_filter
RAISING
zcx_abapgit_ajson_error .
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_abapgit_ajson_filter_lib IMPLEMENTATION.
METHOD create_and_filter.
CREATE OBJECT ri_filter TYPE lcl_and_filter
EXPORTING
it_filters = it_filters.
ENDMETHOD.
METHOD create_empty_filter.
CREATE OBJECT ri_filter TYPE lcl_empty_filter.
ENDMETHOD.
METHOD create_path_filter.
CREATE OBJECT ri_filter TYPE lcl_paths_filter
EXPORTING
it_skip_paths = it_skip_paths
iv_skip_paths = iv_skip_paths.
ENDMETHOD.
ENDCLASS.

View File

@ -0,0 +1,129 @@
**********************************************************************
* FILTER EMPTY VALUES
**********************************************************************
CLASS lcl_empty_filter DEFINITION FINAL.
PUBLIC SECTION.
INTERFACES zif_abapgit_ajson_filter.
ENDCLASS.
CLASS lcl_empty_filter IMPLEMENTATION.
METHOD zif_abapgit_ajson_filter~keep_node.
rv_keep = boolc(
( iv_visit = zif_abapgit_ajson_filter=>visit_type-value AND is_node-value IS NOT INITIAL ) OR
( iv_visit <> zif_abapgit_ajson_filter=>visit_type-value AND is_node-children > 0 ) ).
" children = 0 on open for initially empty nodes and on close for filtered ones
ENDMETHOD.
ENDCLASS.
**********************************************************************
* FILTER PREDEFINED PATHS
**********************************************************************
CLASS lcl_paths_filter DEFINITION FINAL.
PUBLIC SECTION.
INTERFACES zif_abapgit_ajson_filter.
METHODS constructor
IMPORTING
it_skip_paths TYPE string_table OPTIONAL
iv_skip_paths TYPE string OPTIONAL
RAISING
zcx_abapgit_ajson_error.
PRIVATE SECTION.
DATA mt_skip_paths TYPE HASHED TABLE OF string WITH UNIQUE KEY table_line.
ENDCLASS.
CLASS lcl_paths_filter IMPLEMENTATION.
METHOD zif_abapgit_ajson_filter~keep_node.
DATA lv_path TYPE string.
lv_path = is_node-path && is_node-name.
READ TABLE mt_skip_paths WITH KEY table_line = lv_path TRANSPORTING NO FIELDS.
rv_keep = boolc( sy-subrc <> 0 ).
ENDMETHOD.
METHOD constructor.
DATA lv_s TYPE string.
DATA lt_tab TYPE string_table.
FIELD-SYMBOLS <s> TYPE string.
IF boolc( iv_skip_paths IS INITIAL ) = boolc( it_skip_paths IS INITIAL ). " XOR
zcx_abapgit_ajson_error=>raise( 'no filter path specified' ).
ENDIF.
LOOP AT it_skip_paths INTO lv_s.
lv_s = to_lower( lv_s ).
APPEND lv_s TO lt_tab.
ENDLOOP.
IF iv_skip_paths IS NOT INITIAL.
SPLIT iv_skip_paths AT ',' INTO TABLE lt_tab.
LOOP AT lt_tab ASSIGNING <s>.
IF <s> IS INITIAL.
DELETE lt_tab INDEX sy-tabix.
CONTINUE.
ENDIF.
<s> = condense( to_lower( <s> ) ).
ENDLOOP.
ENDIF.
SORT lt_tab BY table_line.
DELETE ADJACENT DUPLICATES FROM lt_tab.
mt_skip_paths = lt_tab.
ENDMETHOD.
ENDCLASS.
**********************************************************************
* MULTI FILTER
**********************************************************************
CLASS lcl_and_filter DEFINITION FINAL.
PUBLIC SECTION.
INTERFACES zif_abapgit_ajson_filter.
METHODS constructor
IMPORTING
it_filters TYPE zif_abapgit_ajson_filter=>ty_filter_tab
RAISING
zcx_abapgit_ajson_error.
PRIVATE SECTION.
DATA mt_filters TYPE zif_abapgit_ajson_filter=>ty_filter_tab.
ENDCLASS.
CLASS lcl_and_filter IMPLEMENTATION.
METHOD zif_abapgit_ajson_filter~keep_node.
DATA li_filter LIKE LINE OF mt_filters.
rv_keep = abap_true.
LOOP AT mt_filters INTO li_filter.
rv_keep = li_filter->keep_node(
is_node = is_node
iv_visit = iv_visit ).
IF rv_keep = abap_false.
RETURN.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD constructor.
DATA li_filter LIKE LINE OF it_filters.
LOOP AT it_filters INTO li_filter WHERE table_line IS BOUND.
APPEND li_filter TO mt_filters.
ENDLOOP.
ENDMETHOD.
ENDCLASS.

View File

@ -0,0 +1,168 @@
CLASS ltcl_filters_test DEFINITION FINAL
FOR TESTING
RISK LEVEL HARMLESS
DURATION SHORT.
PRIVATE SECTION.
METHODS empty_filter_simple FOR TESTING RAISING zcx_abapgit_ajson_error.
METHODS empty_filter_deep FOR TESTING RAISING zcx_abapgit_ajson_error.
METHODS path_filter FOR TESTING RAISING zcx_abapgit_ajson_error.
METHODS path_filter_deep FOR TESTING RAISING zcx_abapgit_ajson_error.
METHODS and_filter FOR TESTING RAISING zcx_abapgit_ajson_error.
ENDCLASS.
CLASS ltcl_filters_test IMPLEMENTATION.
METHOD empty_filter_simple.
DATA li_json TYPE REF TO zif_abapgit_ajson.
DATA li_json_filtered TYPE REF TO zif_abapgit_ajson.
li_json = zcl_abapgit_ajson=>create_empty( ).
li_json->set(
iv_path = '/a'
iv_val = '1' ).
li_json->set(
iv_path = '/b'
iv_val = '' ).
li_json->set(
iv_path = '/c'
iv_val = '3' ).
li_json->set(
iv_path = '/d'
iv_val = 0 ).
li_json_filtered = zcl_abapgit_ajson=>create_from(
ii_source_json = li_json
ii_filter = zcl_abapgit_ajson_filter_lib=>create_empty_filter( ) ).
cl_abap_unit_assert=>assert_equals(
act = li_json_filtered->stringify( )
exp = '{"a":"1","c":"3"}' ).
ENDMETHOD.
METHOD empty_filter_deep.
DATA li_json TYPE REF TO zif_abapgit_ajson.
DATA li_json_filtered TYPE REF TO zif_abapgit_ajson.
li_json = zcl_abapgit_ajson=>create_empty( ).
li_json->set(
iv_path = '/a'
iv_val = '1' ).
li_json->set(
iv_path = '/b/c'
iv_val = '' ).
li_json->set(
iv_path = '/b/d'
iv_val = 0 ).
li_json->set(
iv_path = '/d/e'
iv_val = 0 ).
li_json_filtered = zcl_abapgit_ajson=>create_from(
ii_source_json = li_json
ii_filter = zcl_abapgit_ajson_filter_lib=>create_empty_filter( ) ).
cl_abap_unit_assert=>assert_equals(
act = li_json_filtered->stringify( )
exp = '{"a":"1"}' ).
ENDMETHOD.
METHOD path_filter.
DATA li_json TYPE REF TO zif_abapgit_ajson.
DATA li_json_filtered TYPE REF TO zif_abapgit_ajson.
DATA lt_paths TYPE string_table.
APPEND '/b/c' TO lt_paths.
li_json = zcl_abapgit_ajson=>create_empty( ).
li_json->set(
iv_path = '/a'
iv_val = '1' ).
li_json->set(
iv_path = '/b/c'
iv_val = '2' ).
li_json->set(
iv_path = '/c/d'
iv_val = '3' ).
li_json_filtered = zcl_abapgit_ajson=>create_from(
ii_source_json = li_json
ii_filter = zcl_abapgit_ajson_filter_lib=>create_path_filter( it_skip_paths = lt_paths ) ).
cl_abap_unit_assert=>assert_equals(
act = li_json_filtered->stringify( )
exp = '{"a":"1","b":{},"c":{"d":"3"}}' ).
ENDMETHOD.
METHOD path_filter_deep.
DATA li_json TYPE REF TO zif_abapgit_ajson.
DATA li_json_filtered TYPE REF TO zif_abapgit_ajson.
DATA lt_paths TYPE string_table.
APPEND '/b' TO lt_paths.
li_json = zcl_abapgit_ajson=>create_empty( ).
li_json->set(
iv_path = '/a'
iv_val = '1' ).
li_json->set(
iv_path = '/b/c'
iv_val = '2' ).
li_json->set(
iv_path = '/b/d'
iv_val = 'x' ).
li_json->set(
iv_path = '/c/d'
iv_val = '3' ).
li_json_filtered = zcl_abapgit_ajson=>create_from(
ii_source_json = li_json
ii_filter = zcl_abapgit_ajson_filter_lib=>create_path_filter( it_skip_paths = lt_paths ) ).
cl_abap_unit_assert=>assert_equals(
act = li_json_filtered->stringify( )
exp = '{"a":"1","c":{"d":"3"}}' ).
ENDMETHOD.
METHOD and_filter.
DATA li_json TYPE REF TO zif_abapgit_ajson.
DATA li_json_filtered TYPE REF TO zif_abapgit_ajson.
DATA lt_filters TYPE zif_abapgit_ajson_filter=>ty_filter_tab.
APPEND zcl_abapgit_ajson_filter_lib=>create_empty_filter( ) TO lt_filters.
APPEND zcl_abapgit_ajson_filter_lib=>create_path_filter( iv_skip_paths = '/c' ) TO lt_filters.
li_json = zcl_abapgit_ajson=>create_empty( ).
li_json->set(
iv_path = '/a'
iv_val = '1' ).
li_json->set(
iv_path = '/b'
iv_val = '' ).
li_json->set(
iv_path = '/c'
iv_val = '3' ).
li_json->set(
iv_path = '/d'
iv_val = 0 ).
li_json_filtered = zcl_abapgit_ajson=>create_from(
ii_source_json = li_json
ii_filter = zcl_abapgit_ajson_filter_lib=>create_and_filter( lt_filters ) ).
cl_abap_unit_assert=>assert_equals(
act = li_json_filtered->stringify( )
exp = '{"a":"1"}' ).
ENDMETHOD.
ENDCLASS.

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<abapGit version="v1.0.0" serializer="LCL_OBJECT_CLAS" serializer_version="v1.0.0">
<asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
<asx:values>
<VSEOCLASS>
<CLSNAME>ZCL_ABAPGIT_AJSON_FILTER_LIB</CLSNAME>
<LANGU>E</LANGU>
<DESCRIPT>AJson common typical filters</DESCRIPT>
<STATE>1</STATE>
<CLSCCINCL>X</CLSCCINCL>
<FIXPT>X</FIXPT>
<UNICODE>X</UNICODE>
<WITH_UNIT_TESTS>X</WITH_UNIT_TESTS>
</VSEOCLASS>
</asx:values>
</asx:abap>
</abapGit>

View File

@ -1,7 +1,7 @@
INTERFACE zif_abapgit_ajson
PUBLIC.
CONSTANTS version TYPE string VALUE 'v1.1.0'. "#EC NOTEXT
CONSTANTS version TYPE string VALUE 'v1.1.1-beta'. "#EC NOTEXT
CONSTANTS origin TYPE string VALUE 'https://github.com/sbcgua/ajson'. "#EC NOTEXT
CONSTANTS license TYPE string VALUE 'MIT'. "#EC NOTEXT

View File

@ -0,0 +1,23 @@
INTERFACE zif_abapgit_ajson_filter
PUBLIC.
TYPES ty_filter_tab TYPE STANDARD TABLE OF REF TO zif_abapgit_ajson_filter WITH DEFAULT KEY.
TYPES ty_visit_type TYPE i.
CONSTANTS:
BEGIN OF visit_type,
value TYPE ty_visit_type VALUE 0,
open TYPE ty_visit_type VALUE 1,
close TYPE ty_visit_type VALUE 2,
END OF visit_type.
METHODS keep_node
IMPORTING
is_node TYPE zif_abapgit_ajson=>ty_node
iv_visit TYPE ty_visit_type DEFAULT visit_type-value
RETURNING
VALUE(rv_keep) TYPE abap_bool
RAISING
zcx_abapgit_ajson_error.
ENDINTERFACE.

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<abapGit version="v1.0.0" serializer="LCL_OBJECT_INTF" serializer_version="v1.0.0">
<asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
<asx:values>
<VSEOINTERF>
<CLSNAME>ZIF_ABAPGIT_AJSON_FILTER</CLSNAME>
<LANGU>E</LANGU>
<DESCRIPT>AJSON filter interface</DESCRIPT>
<EXPOSURE>2</EXPOSURE>
<STATE>1</STATE>
<UNICODE>X</UNICODE>
</VSEOINTERF>
</asx:values>
</asx:abap>
</abapGit>

View File

@ -162,11 +162,15 @@
{"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_json_to_abap", "method": "find_loc", "note": "assert failed"},
{"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_json_to_abap", "method": "to_abap_negative"},
{"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_json_to_abap", "method": "to_abap", "note": "Void type: TIMESTAMPL"},
{"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_writer_test", "method": "set_obj"},
{"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_writer_test", "method": "set_ajson"},
{"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_writer_test", "method": "set_tab"},
{"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_writer_test", "method": "set_tab_hashed", "note": "runtime error, SortByLengthZero"},
{"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_writer_test", "method": "arrays"},
{"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_writer_test", "method": "root_assignment"},
{"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_reader_test", "method": "get_timestamp", "note": "Void type: TIMESTAMPL"},
{"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_parser_test", "method": "parse_error"},
@ -174,8 +178,29 @@
{"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_integrated", "method": "array_index", "note": "Index not found in table @/10"},
{"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_integrated", "method": "array_simple", "note": "Index not found in table @/10"},
{"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_integrated", "method": "item_order_integrated"},
{"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_integrated", "method": "stringify"},
{"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_abap_to_json", "method": "set_obj"},
{"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_abap_to_json", "method": "set_array"},
{"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_abap_to_json", "method": "set_complex_obj"},
{"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_filter_test", "method": "simple_test"},
{"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_filter_test", "method": "array_test"},
{"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_filter_test", "method": "visit_types"},
{"object": "ZCL_ABAPGIT_AJSON_FILTER_LIB", "class": "ltcl_filters_test", "method": "empty_filter_simple"},
{"object": "ZCL_ABAPGIT_AJSON_FILTER_LIB", "class": "ltcl_filters_test", "method": "empty_filter_deep"},
{"object": "ZCL_ABAPGIT_AJSON_FILTER_LIB", "class": "ltcl_filters_test", "method": "path_filter"},
{"object": "ZCL_ABAPGIT_AJSON_FILTER_LIB", "class": "ltcl_filters_test", "method": "path_filter_deep"},
{"object": "ZCL_ABAPGIT_AJSON_FILTER_LIB", "class": "ltcl_filters_test", "method": "and_filter"},
{"object": "ZCL_ABAPGIT_AJSON_MAPPING", "class": "ltcl_camel_case", "method": "to_abap", "note": "secondary key fields? READ WITH KEY, Path not found @/FieldData"},
{"object": "ZCL_ABAPGIT_AJSON_MAPPING", "class": "ltcl_camel_case", "method": "to_json"},
{"object": "ZCL_ABAPGIT_AJSON_MAPPING", "class": "ltcl_camel_case", "method": "to_json_first_lower"},
{"object": "ZCL_ABAPGIT_AJSON_MAPPING", "class": "ltcl_fields", "method": "to_json"},
{"object": "ZCL_ABAPGIT_AJSON_MAPPING", "class": "ltcl_to_lower", "method": "to_json"},
{"object": "ZCL_ABAPGIT_AJSON_MAPPING", "class": "ltcl_to_upper", "method": "to_json"},
{"object": "ZCL_ABAPGIT_GUI_UTILS", "class": "ltcl_gui_utils", "method": "is_renderable", "note": "casting, https://github.com/abaplint/transpiler/issues/465"},
{"object": "ZCL_ABAPGIT_GUI_UTILS", "class": "ltcl_gui_utils", "method": "is_event_handler", "note": "casting, https://github.com/abaplint/transpiler/issues/465"},