From 9d2bb4da0b54cd451c340e141825ba4f5b26df66 Mon Sep 17 00:00:00 2001 From: Marius Raht <99023738+mraht@users.noreply.github.com> Date: Wed, 2 Aug 2023 06:35:20 +0200 Subject: [PATCH] TABU: Update entries with same key but different component values (#6380) Co-authored-by: Lars Hvam --- .../zcl_abapgit_data_deserializer.clas.abap | 60 ++++-- ...it_data_deserializer.clas.testclasses.abap | 198 ++++++++++++++++++ 2 files changed, 237 insertions(+), 21 deletions(-) diff --git a/src/data/zcl_abapgit_data_deserializer.clas.abap b/src/data/zcl_abapgit_data_deserializer.clas.abap index c093a9224..391b1a735 100644 --- a/src/data/zcl_abapgit_data_deserializer.clas.abap +++ b/src/data/zcl_abapgit_data_deserializer.clas.abap @@ -21,7 +21,8 @@ CLASS zcl_abapgit_data_deserializer DEFINITION IMPORTING !iv_name TYPE tadir-obj_name !it_where TYPE string_table - !ir_data TYPE REF TO data + !ir_lc_data TYPE REF TO data + !ir_db_data TYPE REF TO data RETURNING VALUE(rs_result) TYPE zif_abapgit_data_deserializer=>ty_result RAISING @@ -31,6 +32,7 @@ CLASS zcl_abapgit_data_deserializer DEFINITION !iv_name TYPE tadir-obj_name !ir_del TYPE REF TO data !ir_ins TYPE REF TO data + !ir_upd TYPE REF TO data RAISING zcx_abapgit_exception . METHODS read_database_table @@ -112,23 +114,18 @@ CLASS zcl_abapgit_data_deserializer IMPLEMENTATION. METHOD preview_database_changes. * method currently distinguishes between records be deleted and inserted (comparison of complete record) -* to-do: compare records based on database key of table to determine updates to existing records - - DATA lr_data TYPE REF TO data. FIELD-SYMBOLS TYPE ANY TABLE. FIELD-SYMBOLS TYPE ANY TABLE. FIELD-SYMBOLS TYPE any. FIELD-SYMBOLS TYPE any. + FIELD-SYMBOLS TYPE any. FIELD-SYMBOLS TYPE ANY TABLE. FIELD-SYMBOLS TYPE ANY TABLE. + FIELD-SYMBOLS TYPE ANY TABLE. - lr_data = read_database_table( - iv_name = iv_name - it_where = it_where ). - - ASSIGN lr_data->* TO . - ASSIGN ir_data->* TO . + ASSIGN ir_db_data->* TO . + ASSIGN ir_lc_data->* TO . rs_result-type = zif_abapgit_data_config=>c_data_type-tabu. rs_result-name = iv_name. @@ -137,6 +134,7 @@ CLASS zcl_abapgit_data_deserializer IMPLEMENTATION. rs_result-updates = zcl_abapgit_data_utils=>build_table_itab( iv_name ). ASSIGN rs_result-deletes->* TO . ASSIGN rs_result-inserts->* TO . + ASSIGN rs_result-updates->* TO . = . = . @@ -145,6 +143,10 @@ CLASS zcl_abapgit_data_deserializer IMPLEMENTATION. LOOP AT ASSIGNING . READ TABLE ASSIGNING FROM . IF sy-subrc = 0. + IF <> . + " Identical key but not identical component values + INSERT INTO TABLE . + ENDIF. DELETE TABLE FROM . DELETE TABLE FROM . ENDIF. @@ -176,6 +178,7 @@ CLASS zcl_abapgit_data_deserializer IMPLEMENTATION. FIELD-SYMBOLS TYPE ANY TABLE. FIELD-SYMBOLS TYPE ANY TABLE. + FIELD-SYMBOLS TYPE ANY TABLE. IF zcl_abapgit_data_utils=>does_table_exist( iv_name ) = abap_false. zcx_abapgit_exception=>raise( |Table { iv_name } not found for data deserialization| ). @@ -183,6 +186,7 @@ CLASS zcl_abapgit_data_deserializer IMPLEMENTATION. ASSIGN ir_del->* TO . ASSIGN ir_ins->* TO . + ASSIGN ir_upd->* TO . IF lines( ) > 0. DELETE (iv_name) FROM TABLE . @@ -198,6 +202,13 @@ CLASS zcl_abapgit_data_deserializer IMPLEMENTATION. ENDIF. ENDIF. + IF lines( ) > 0. + UPDATE (iv_name) FROM TABLE . + IF sy-subrc <> 0. + zcx_abapgit_exception=>raise( |Error updating { lines( ) } records into table { iv_name }| ). + ENDIF. + ENDIF. + ENDMETHOD. @@ -236,11 +247,12 @@ CLASS zcl_abapgit_data_deserializer IMPLEMENTATION. write_database_table( iv_name = ls_result-name ir_del = ls_result-deletes - ir_ins = ls_result-inserts ). + ir_ins = ls_result-inserts + ir_upd = ls_result-updates ). ASSIGN ls_result-inserts->* TO . ASSIGN ls_result-deletes->* TO . - ASSIGN ls_result-updates->* TO . " not used + ASSIGN ls_result-updates->* TO . IF zcl_abapgit_data_utils=>is_customizing_table( ls_result-name ) = abap_true. IF li_cts_api IS INITIAL. @@ -267,10 +279,11 @@ CLASS zcl_abapgit_data_deserializer IMPLEMENTATION. * this method does not persist any changes to the database DATA lt_configs TYPE zif_abapgit_data_config=>ty_config_tt. - DATA ls_config LIKE LINE OF lt_configs. - DATA lr_data TYPE REF TO data. - DATA ls_file LIKE LINE OF it_files. - DATA ls_result LIKE LINE OF rt_result. + DATA ls_config LIKE LINE OF lt_configs. + DATA lr_lc_data TYPE REF TO data. + DATA lr_db_data TYPE REF TO data. + DATA ls_file LIKE LINE OF it_files. + DATA ls_result LIKE LINE OF rt_result. lt_configs = ii_config->get_configs( ). @@ -278,7 +291,7 @@ CLASS zcl_abapgit_data_deserializer IMPLEMENTATION. ASSERT ls_config-type = zif_abapgit_data_config=>c_data_type-tabu. " todo ASSERT ls_config-name IS NOT INITIAL. - lr_data = zcl_abapgit_data_utils=>build_table_itab( ls_config-name ). + lr_lc_data = zcl_abapgit_data_utils=>build_table_itab( ls_config-name ). READ TABLE it_files INTO ls_file WITH KEY file_path @@ -286,13 +299,18 @@ CLASS zcl_abapgit_data_deserializer IMPLEMENTATION. filename = zcl_abapgit_data_utils=>build_data_filename( ls_config ). IF sy-subrc = 0. convert_json_to_itab( - ir_data = lr_data + ir_data = lr_lc_data is_file = ls_file ). - ls_result = preview_database_changes( + lr_db_data = read_database_table( iv_name = ls_config-name - it_where = ls_config-where - ir_data = lr_data ). + it_where = ls_config-where ). + + ls_result = preview_database_changes( + iv_name = ls_config-name + it_where = ls_config-where + ir_lc_data = lr_lc_data + ir_db_data = lr_db_data ). MOVE-CORRESPONDING ls_file TO ls_result-file. " data file diff --git a/src/data/zcl_abapgit_data_deserializer.clas.testclasses.abap b/src/data/zcl_abapgit_data_deserializer.clas.testclasses.abap index ff5bcb206..d36d44cf5 100644 --- a/src/data/zcl_abapgit_data_deserializer.clas.testclasses.abap +++ b/src/data/zcl_abapgit_data_deserializer.clas.testclasses.abap @@ -5,6 +5,9 @@ CLASS ltcl_test DEFINITION FOR TESTING DURATION SHORT RISK LEVEL HARMLESS FINAL. PRIVATE SECTION. METHODS test1 FOR TESTING RAISING cx_static_check. + METHODS preview_database_changes_ins FOR TESTING RAISING cx_static_check. + METHODS preview_database_changes_upd FOR TESTING RAISING cx_static_check. + METHODS preview_database_changes_del FOR TESTING RAISING cx_static_check. ENDCLASS. @@ -33,4 +36,199 @@ CLASS ltcl_test IMPLEMENTATION. ENDMETHOD. + + METHOD preview_database_changes_ins. + + CONSTANTS: lc_msgnr TYPE c LENGTH 3 VALUE '999'. + + DATA: li_cut TYPE REF TO zcl_abapgit_data_deserializer, + ls_config TYPE zif_abapgit_data_config=>ty_config, + lr_db_data TYPE REF TO data, + lr_lc_data TYPE REF TO data, + ls_t100 TYPE t100, + ls_result TYPE zif_abapgit_data_deserializer=>ty_result. + + FIELD-SYMBOLS: TYPE ANY TABLE, + TYPE ANY TABLE, + TYPE ANY TABLE, + TYPE t100, + TYPE ANY TABLE, + TYPE ANY TABLE. + + ls_config-type = zif_abapgit_data_config=>c_data_type-tabu. + ls_config-name = 'T100'. + + lr_db_data = zcl_abapgit_data_utils=>build_table_itab( ls_config-name ). + ASSIGN lr_db_data->* TO . + lr_lc_data = zcl_abapgit_data_utils=>build_table_itab( ls_config-name ). + ASSIGN lr_lc_data->* TO . + + " Create test data for INSERT + ls_t100-sprsl = sy-langu. + ls_t100-arbgb = 'AUNIT_ABAPGIT'. + ls_t100-msgnr = lc_msgnr. + ls_t100-text = |abapGit aunit test|. + INSERT ls_t100 INTO TABLE . + + CREATE OBJECT li_cut TYPE zcl_abapgit_data_deserializer. + ls_result = li_cut->preview_database_changes( + iv_name = ls_config-name + it_where = ls_config-where + ir_db_data = lr_db_data + ir_lc_data = lr_lc_data ). + + ASSIGN ls_result-inserts->* TO . + ASSIGN ls_result-updates->* TO . + ASSIGN ls_result-deletes->* TO . + + cl_abap_unit_assert=>assert_equals( + exp = 1 + act = lines( ) ). + cl_abap_unit_assert=>assert_equals( + exp = 0 + act = lines( ) ). + cl_abap_unit_assert=>assert_equals( + exp = 0 + act = lines( ) ). + + LOOP AT ASSIGNING . + cl_abap_unit_assert=>assert_equals( + exp = lc_msgnr + act = -msgnr ). + ENDLOOP. + + ENDMETHOD. + + + METHOD preview_database_changes_upd. + + CONSTANTS: lc_msgnr TYPE c LENGTH 3 VALUE '999'. + + DATA: li_cut TYPE REF TO zcl_abapgit_data_deserializer, + ls_config TYPE zif_abapgit_data_config=>ty_config, + lr_db_data TYPE REF TO data, + lr_lc_data TYPE REF TO data, + ls_t100 TYPE t100, + ls_result TYPE zif_abapgit_data_deserializer=>ty_result. + + FIELD-SYMBOLS: TYPE ANY TABLE, + TYPE ANY TABLE, + TYPE ANY TABLE, + TYPE ANY TABLE, + TYPE t100, + TYPE ANY TABLE. + + ls_config-type = zif_abapgit_data_config=>c_data_type-tabu. + ls_config-name = 'T100'. + + lr_db_data = zcl_abapgit_data_utils=>build_table_itab( ls_config-name ). + ASSIGN lr_db_data->* TO . + lr_lc_data = zcl_abapgit_data_utils=>build_table_itab( ls_config-name ). + ASSIGN lr_lc_data->* TO . + + " Create test data for UPDATE + ls_t100-sprsl = sy-langu. + ls_t100-arbgb = |AUNIT_ABAPGIT|. + ls_t100-msgnr = lc_msgnr. + ls_t100-text = |abapGit aunit test|. + INSERT ls_t100 INTO TABLE . + + ls_t100-sprsl = sy-langu. + ls_t100-arbgb = 'AUNIT_ABAPGIT'. + ls_t100-msgnr = lc_msgnr. + ls_t100-text = |abapGit aunit test UPDATE|. + INSERT ls_t100 INTO TABLE . + + CREATE OBJECT li_cut TYPE zcl_abapgit_data_deserializer. + ls_result = li_cut->preview_database_changes( + iv_name = ls_config-name + it_where = ls_config-where + ir_db_data = lr_db_data + ir_lc_data = lr_lc_data ). + + ASSIGN ls_result-inserts->* TO . + ASSIGN ls_result-updates->* TO . + ASSIGN ls_result-deletes->* TO . + + cl_abap_unit_assert=>assert_equals( + exp = 0 + act = lines( ) ). + cl_abap_unit_assert=>assert_equals( + exp = 1 + act = lines( ) ). + cl_abap_unit_assert=>assert_equals( + exp = 0 + act = lines( ) ). + + LOOP AT ASSIGNING . + cl_abap_unit_assert=>assert_equals( + exp = lc_msgnr + act = -msgnr ). + ENDLOOP. + + ENDMETHOD. + + + METHOD preview_database_changes_del. + + CONSTANTS: lc_msgnr TYPE c LENGTH 3 VALUE '999'. + + DATA: li_cut TYPE REF TO zcl_abapgit_data_deserializer, + ls_config TYPE zif_abapgit_data_config=>ty_config, + lr_db_data TYPE REF TO data, + lr_lc_data TYPE REF TO data, + ls_t100 TYPE t100, + ls_result TYPE zif_abapgit_data_deserializer=>ty_result. + + FIELD-SYMBOLS: TYPE ANY TABLE, + TYPE ANY TABLE, + TYPE ANY TABLE, + TYPE ANY TABLE, + TYPE ANY TABLE, + TYPE t100. + + ls_config-type = zif_abapgit_data_config=>c_data_type-tabu. + ls_config-name = 'T100'. + + lr_db_data = zcl_abapgit_data_utils=>build_table_itab( ls_config-name ). + ASSIGN lr_db_data->* TO . + lr_lc_data = zcl_abapgit_data_utils=>build_table_itab( ls_config-name ). + ASSIGN lr_lc_data->* TO . + + " Create test data for DELETE + ls_t100-sprsl = sy-langu. + ls_t100-arbgb = 'AUNIT_ABAPGIT'. + ls_t100-msgnr = lc_msgnr. + ls_t100-text = |abapGit aunit test DELETE|. + INSERT ls_t100 INTO TABLE . + + CREATE OBJECT li_cut TYPE zcl_abapgit_data_deserializer. + ls_result = li_cut->preview_database_changes( + iv_name = ls_config-name + it_where = ls_config-where + ir_db_data = lr_db_data + ir_lc_data = lr_lc_data ). + + ASSIGN ls_result-inserts->* TO . + ASSIGN ls_result-updates->* TO . + ASSIGN ls_result-deletes->* TO . + + cl_abap_unit_assert=>assert_equals( + exp = 0 + act = lines( ) ). + cl_abap_unit_assert=>assert_equals( + exp = 0 + act = lines( ) ). + cl_abap_unit_assert=>assert_equals( + exp = 1 + act = lines( ) ). + + LOOP AT ASSIGNING . + cl_abap_unit_assert=>assert_equals( + exp = lc_msgnr + act = -msgnr ). + ENDLOOP. + + ENDMETHOD. + ENDCLASS.