From 7d7def95a513cda6240fcf8d3d5e1448ac7db253 Mon Sep 17 00:00:00 2001 From: Lars Hvam Date: Tue, 10 Jul 2018 16:39:49 +0200 Subject: [PATCH] Generic object handler + ASFC support #1578 (#1590) * scaffolding #1578 * generic object handler #1578 * fix linter errors --- src/objects/zcl_abapgit_object_asfc.clas.abap | 109 +++ src/objects/zcl_abapgit_object_asfc.clas.xml | 18 + .../zcl_abapgit_objects_generic.clas.abap | 682 ++++++++++++++++++ ...pgit_objects_generic.clas.testclasses.abap | 41 ++ .../zcl_abapgit_objects_generic.clas.xml | 19 + 5 files changed, 869 insertions(+) create mode 100644 src/objects/zcl_abapgit_object_asfc.clas.abap create mode 100644 src/objects/zcl_abapgit_object_asfc.clas.xml create mode 100644 src/objects/zcl_abapgit_objects_generic.clas.abap create mode 100644 src/objects/zcl_abapgit_objects_generic.clas.testclasses.abap create mode 100644 src/objects/zcl_abapgit_objects_generic.clas.xml diff --git a/src/objects/zcl_abapgit_object_asfc.clas.abap b/src/objects/zcl_abapgit_object_asfc.clas.abap new file mode 100644 index 000000000..374865f0f --- /dev/null +++ b/src/objects/zcl_abapgit_object_asfc.clas.abap @@ -0,0 +1,109 @@ +CLASS zcl_abapgit_object_asfc DEFINITION + PUBLIC + INHERITING FROM zcl_abapgit_objects_super + CREATE PUBLIC . + + PUBLIC SECTION. + + INTERFACES zif_abapgit_object . + PROTECTED SECTION. + PRIVATE SECTION. +ENDCLASS. + + + +CLASS ZCL_ABAPGIT_OBJECT_ASFC IMPLEMENTATION. + + + METHOD zif_abapgit_object~changed_by. + rv_user = zcl_abapgit_objects_super=>c_user_unknown. + ENDMETHOD. + + + METHOD zif_abapgit_object~compare_to_remote_version. + CREATE OBJECT ro_comparison_result TYPE zcl_abapgit_comparison_null. + ENDMETHOD. + + + METHOD zif_abapgit_object~delete. + + DATA: lo_generic TYPE REF TO zcl_abapgit_objects_generic. + + CREATE OBJECT lo_generic + EXPORTING + is_item = ms_item. + + lo_generic->delete( ). + + ENDMETHOD. + + + METHOD zif_abapgit_object~deserialize. + + DATA: lo_generic TYPE REF TO zcl_abapgit_objects_generic. + + CREATE OBJECT lo_generic + EXPORTING + is_item = ms_item. + + lo_generic->deserialize( + iv_package = iv_package + io_xml = io_xml ). + + ENDMETHOD. + + + METHOD zif_abapgit_object~exists. + + DATA: lo_generic TYPE REF TO zcl_abapgit_objects_generic. + + CREATE OBJECT lo_generic + EXPORTING + is_item = ms_item. + + rv_bool = lo_generic->exists( ). + + ENDMETHOD. + + + METHOD zif_abapgit_object~get_metadata. + + rs_metadata = get_metadata( ). + rs_metadata-delete_tadir = abap_true. + + ENDMETHOD. + + + METHOD zif_abapgit_object~has_changed_since. + + rv_changed = abap_true. + + ENDMETHOD. + + + METHOD zif_abapgit_object~is_locked. + + rv_is_locked = abap_false. + + ENDMETHOD. + + + METHOD zif_abapgit_object~jump. + + zcx_abapgit_exception=>raise( |TODO: Jump| ). + + ENDMETHOD. + + + METHOD zif_abapgit_object~serialize. + + DATA: lo_generic TYPE REF TO zcl_abapgit_objects_generic. + + CREATE OBJECT lo_generic + EXPORTING + is_item = ms_item. + + lo_generic->serialize( io_xml ). + + ENDMETHOD. +ENDCLASS. diff --git a/src/objects/zcl_abapgit_object_asfc.clas.xml b/src/objects/zcl_abapgit_object_asfc.clas.xml new file mode 100644 index 000000000..1d15f2e46 --- /dev/null +++ b/src/objects/zcl_abapgit_object_asfc.clas.xml @@ -0,0 +1,18 @@ + + + + + + ZCL_ABAPGIT_OBJECT_ASFC + 1 + E + ASFC + 2 + 1 + X + X + X + + + + diff --git a/src/objects/zcl_abapgit_objects_generic.clas.abap b/src/objects/zcl_abapgit_objects_generic.clas.abap new file mode 100644 index 000000000..9f09da2ff --- /dev/null +++ b/src/objects/zcl_abapgit_objects_generic.clas.abap @@ -0,0 +1,682 @@ +CLASS zcl_abapgit_objects_generic DEFINITION + PUBLIC + CREATE PUBLIC . + + PUBLIC SECTION. + + METHODS constructor + IMPORTING + !is_item TYPE zif_abapgit_definitions=>ty_item + RAISING + zcx_abapgit_exception . + METHODS delete + RAISING + zcx_abapgit_exception . + METHODS deserialize + IMPORTING + !iv_package TYPE devclass + !io_xml TYPE REF TO zcl_abapgit_xml_input + RAISING + zcx_abapgit_exception . + METHODS exists + RETURNING + VALUE(rv_bool) TYPE abap_bool + RAISING + zcx_abapgit_exception . + METHODS serialize + IMPORTING + !io_xml TYPE REF TO zcl_abapgit_xml_output + RAISING + zcx_abapgit_exception . + PROTECTED SECTION. + + TYPES: + BEGIN OF ty_s_objkey, + num TYPE numc3, + value TYPE char128, + END OF ty_s_objkey . + TYPES: + ty_t_objkey TYPE SORTED TABLE OF ty_s_objkey WITH UNIQUE KEY num . + + DATA ms_object_header TYPE objh . + DATA: + mt_object_table TYPE STANDARD TABLE OF objsl WITH DEFAULT KEY . + DATA: + mt_object_method TYPE STANDARD TABLE OF objm WITH DEFAULT KEY . + DATA ms_item TYPE zif_abapgit_definitions=>ty_item . + + METHODS after_import . + METHODS before_export . + METHODS corr_insert + IMPORTING + !iv_package TYPE devclass + RAISING + zcx_abapgit_exception . + METHODS deserialize_data + IMPORTING + !io_xml TYPE REF TO zcl_abapgit_xml_input + RAISING + zcx_abapgit_exception . + METHODS distribute_name_to_components + IMPORTING + !it_key_component TYPE ddfields + CHANGING + !ct_objkey TYPE ty_t_objkey + !cs_objkey TYPE ty_s_objkey + !cv_non_value_pos TYPE numc3 . + METHODS get_key_fields + IMPORTING + !iv_table TYPE objsl-tobj_name + RETURNING + VALUE(rt_keys) TYPE ddfields + RAISING + zcx_abapgit_exception . + METHODS get_primary_table + RETURNING + VALUE(rv_table) TYPE objsl-tobj_name + RAISING + zcx_abapgit_exception . + METHODS get_where_clause + IMPORTING + !iv_tobj_name TYPE objsl-tobj_name + RETURNING + VALUE(rv_where) TYPE string + RAISING + zcx_abapgit_exception . + METHODS serialize_data + IMPORTING + !io_xml TYPE REF TO zcl_abapgit_xml_output + RAISING + zcx_abapgit_exception . + METHODS split_value_to_keys + IMPORTING + !it_key_component TYPE ddfields + CHANGING + !ct_objkey TYPE ty_t_objkey + !cs_objkey TYPE ty_s_objkey + !cv_non_value_pos TYPE numc3 . + METHODS validate + IMPORTING + !io_xml TYPE REF TO zcl_abapgit_xml_input + RAISING + zcx_abapgit_exception . + PRIVATE SECTION. +ENDCLASS. + + + +CLASS ZCL_ABAPGIT_OBJECTS_GENERIC IMPLEMENTATION. + + + METHOD after_import. + + DATA: lt_cts_object_entry TYPE STANDARD TABLE OF e071 WITH DEFAULT KEY, + ls_cts_object_entry LIKE LINE OF lt_cts_object_entry, + lt_cts_key TYPE STANDARD TABLE OF e071k WITH DEFAULT KEY. + + FIELD-SYMBOLS LIKE LINE OF mt_object_method. + + + ls_cts_object_entry-pgmid = rs_c_pgmid_r3tr. + ls_cts_object_entry-object = ms_item-obj_type. + ls_cts_object_entry-obj_name = ms_item-obj_name. + INSERT ls_cts_object_entry INTO TABLE lt_cts_object_entry. + + READ TABLE mt_object_method ASSIGNING + WITH KEY + objectname = ms_item-obj_type + objecttype = 'L' + method = 'AFTER_IMP'. + IF sy-subrc = 0. +* client is actually optional for most AIM, but let's supply it and hope +* that those client-independent-ones just ignore it + CALL FUNCTION -methodname + EXPORTING + iv_tarclient = sy-mandt + iv_is_upgrade = abap_false + TABLES + tt_e071 = lt_cts_object_entry + tt_e071k = lt_cts_key. + ENDIF. + + ENDMETHOD. + + + METHOD before_export. + + DATA: lt_cts_object_entry TYPE STANDARD TABLE OF e071 WITH DEFAULT KEY, + ls_cts_object_entry LIKE LINE OF lt_cts_object_entry, + lt_cts_key TYPE STANDARD TABLE OF e071k WITH DEFAULT KEY, + lv_client TYPE trclient. + + FIELD-SYMBOLS LIKE LINE OF mt_object_method. + + + READ TABLE mt_object_method ASSIGNING + WITH KEY + objectname = ms_item-obj_type + objecttype = 'L' + method = 'BEFORE_EXP' ##no_text. + IF sy-subrc = 0. + lv_client = sy-mandt. + + ls_cts_object_entry-pgmid = rs_c_pgmid_r3tr. + ls_cts_object_entry-object = ms_item-obj_type. + ls_cts_object_entry-obj_name = ms_item-obj_name. + INSERT ls_cts_object_entry INTO TABLE lt_cts_object_entry. + + CALL FUNCTION -methodname + EXPORTING + iv_client = lv_client + TABLES + tt_e071 = lt_cts_object_entry + tt_e071k = lt_cts_key. + ENDIF. + + ENDMETHOD. + + + METHOD constructor. + + CONSTANTS lc_logical_transport_object TYPE c LENGTH 1 VALUE 'L'. + + + SELECT SINGLE * FROM objh INTO ms_object_header + WHERE objectname = is_item-obj_type + AND objecttype = lc_logical_transport_object. + IF sy-subrc <> 0. + zcx_abapgit_exception=>raise( 'Not found in OBJH, or not supported' ). + ENDIF. + +* object tables + SELECT * FROM objsl INTO CORRESPONDING FIELDS OF TABLE mt_object_table + WHERE objectname = is_item-obj_type + AND objecttype = lc_logical_transport_object + AND tobject = 'TABU'. + IF mt_object_table IS INITIAL. + zcx_abapgit_exception=>raise( |Obviously corrupted object-type { + is_item-obj_type }: No tables defined| ). + ENDIF. + +* object methods + SELECT * FROM objm INTO TABLE mt_object_method + WHERE objectname = is_item-obj_type + AND objecttype = lc_logical_transport_object. + + ms_item = is_item. + + ENDMETHOD. + + + METHOD corr_insert. + +* this will also insert into TADIR + CALL FUNCTION 'RS_CORR_INSERT' + EXPORTING + object = ms_item-obj_name + object_class = ms_item-obj_type + mode = 'I' + global_lock = abap_true + devclass = iv_package + master_language = sy-langu + EXCEPTIONS + cancelled = 1 + permission_failure = 2 + unknown_objectclass = 3 + OTHERS = 4. + IF sy-subrc <> 0. + zcx_abapgit_exception=>raise( 'error from RS_CORR_INSERT, CMPT' ). + ENDIF. + + ENDMETHOD. + + + METHOD delete. + + DATA: lv_where TYPE string, + lv_primary TYPE objsl-tobj_name. + + FIELD-SYMBOLS LIKE LINE OF mt_object_table. + + + lv_primary = get_primary_table( ). + + LOOP AT mt_object_table ASSIGNING . + lv_where = get_where_clause( -tobj_name ). + ASSERT NOT lv_where IS INITIAL. + + DELETE FROM (-tobj_name) WHERE (lv_where). + + IF -tobj_name = lv_primary. + ASSERT sy-dbcnt <= 1. "Just to be on the very safe side + ENDIF. + ENDLOOP. + + ENDMETHOD. + + + METHOD deserialize. + + validate( io_xml ). + + delete( ). + + deserialize_data( io_xml ). + + after_import( ). + + corr_insert( iv_package ). + + ENDMETHOD. + + + METHOD deserialize_data. + + DATA: lr_ref TYPE REF TO data. + + FIELD-SYMBOLS: TYPE STANDARD TABLE, + LIKE LINE OF mt_object_table. + + + LOOP AT mt_object_table ASSIGNING . + + CREATE DATA lr_ref TYPE STANDARD TABLE OF (-tobj_name). + ASSIGN lr_ref->* TO . + + io_xml->read( + EXPORTING + iv_name = -tobj_name + CHANGING + cg_data = ). + + INSERT (-tobj_name) FROM TABLE . + IF sy-subrc <> 0. + zcx_abapgit_exception=>raise( |Error inserting data, { + -tobj_name }| ). + ENDIF. + + ENDLOOP. + + ENDMETHOD. + + + METHOD distribute_name_to_components. + + DATA: lt_key_component_uncovered LIKE it_key_component, + ls_key_component_uncovered LIKE LINE OF lt_key_component_uncovered, + ls_objkey_sub LIKE cs_objkey, + lv_objkey_sub_pos TYPE i, + lv_remaining_length TYPE i, + lv_count_components_covered LIKE ls_objkey_sub-num. + + DATA lv_len LIKE ls_key_component_uncovered-leng. + + + lt_key_component_uncovered = it_key_component. + ls_objkey_sub-num = cs_objkey-num. + lv_objkey_sub_pos = 0. + +* we want to fill the atribute values which are not covered by explicit key components yet + lv_count_components_covered = ls_objkey_sub-num - 1. + DO lv_count_components_covered TIMES. + DELETE lt_key_component_uncovered INDEX 1. + ENDDO. + + LOOP AT lt_key_component_uncovered INTO ls_key_component_uncovered. + CLEAR ls_objkey_sub-value. + +* Some datatype used in the key might exceed the total remaining characters length (e. g. SICF) + TRY. + lv_remaining_length = strlen( |{ substring( val = cs_objkey-value off = lv_objkey_sub_pos ) }| ). + CATCH cx_sy_range_out_of_bounds. + lv_remaining_length = 0. + RETURN. ">>>>>>>>>>>>>>>>>>>>>>>>>>> + ENDTRY. + IF ls_key_component_uncovered-leng <= lv_remaining_length. + lv_len = ls_key_component_uncovered-leng. + ELSE. + lv_len = lv_remaining_length. + ENDIF. + + ls_objkey_sub-value = |{ substring( val = cs_objkey-value off = lv_objkey_sub_pos len = lv_len ) }|. + ls_objkey_sub-num = cv_non_value_pos. + + INSERT ls_objkey_sub INTO TABLE ct_objkey. + + lv_objkey_sub_pos = lv_objkey_sub_pos + ls_key_component_uncovered-leng. + cv_non_value_pos = cv_non_value_pos + 1. + CLEAR ls_objkey_sub. + + IF lv_objkey_sub_pos = strlen( cs_objkey-value ). + cs_objkey-num = cv_non_value_pos. + EXIT. "end splitting - all characters captured + ENDIF. + ENDLOOP. + + ENDMETHOD. + + + METHOD exists. + + DATA: lv_where_clause TYPE string, + lv_primary TYPE objsl-tobj_name, + lr_table_line TYPE REF TO data. + + FIELD-SYMBOLS: TYPE any. + + + lv_primary = get_primary_table( ). + + lv_where_clause = get_where_clause( lv_primary ). + + CREATE DATA lr_table_line TYPE (lv_primary). + ASSIGN lr_table_line->* TO . + + SELECT SINGLE * FROM (lv_primary) INTO WHERE (lv_where_clause). + rv_bool = boolc( sy-dbcnt > 0 ). + + ENDMETHOD. + + + METHOD get_key_fields. + + DATA: lv_table TYPE ddobjname. + + + lv_table = iv_table. + + CALL FUNCTION 'DDIF_NAMETAB_GET' + EXPORTING + tabname = lv_table + TABLES + dfies_tab = rt_keys + EXCEPTIONS + not_found = 1 + OTHERS = 2. + IF sy-subrc <> 0. + zcx_abapgit_exception=>raise_t100( ). + ENDIF. + + DELETE rt_keys WHERE keyflag = abap_false. + + ENDMETHOD. + + + METHOD get_primary_table. + + DATA: ls_object_table LIKE LINE OF mt_object_table. + + + READ TABLE mt_object_table INTO ls_object_table WITH KEY prim_table = abap_true. + IF sy-subrc <> 0. +* Fallback. For some objects, no primary table is explicitly flagged +* The, the one with only one key field shall be chosen + READ TABLE mt_object_table INTO ls_object_table WITH KEY tobjkey = '/&'. "#EC CI_SUBRC + ENDIF. + IF ls_object_table IS INITIAL. + zcx_abapgit_exception=>raise( |Object { ms_item-obj_type } has got no defined primary table| ). + ENDIF. + + rv_table = ls_object_table-tobj_name. + + ENDMETHOD. + + + METHOD get_where_clause. + + DATA: lv_objkey_pos TYPE i, + lv_next_objkey_pos TYPE i, + lv_value_pos TYPE i, + lv_objkey_length TYPE i, + lt_objkey TYPE ty_t_objkey, + ls_objkey LIKE LINE OF lt_objkey, + lv_non_value_pos TYPE numc3, + lt_key_fields TYPE ddfields. + + DATA: lv_is_asterix TYPE abap_bool, + lv_where_statement TYPE string, + lv_key_pos TYPE i, + lv_value128 TYPE string. + + FIELD-SYMBOLS LIKE LINE OF mt_object_table. + + FIELD-SYMBOLS LIKE LINE OF lt_key_fields. + + + READ TABLE mt_object_table ASSIGNING WITH KEY tobj_name = iv_tobj_name. + ASSERT sy-subrc = 0. + + lt_key_fields = get_key_fields( iv_tobj_name ). + +* analyze the object key and compose the key (table) + CLEAR lt_objkey. + CLEAR ls_objkey. + lv_objkey_pos = 0. + lv_non_value_pos = 1. + lv_value_pos = 0. + lv_objkey_length = strlen( -tobjkey ). + + WHILE lv_objkey_pos <= lv_objkey_length. + ls_objkey-num = lv_non_value_pos. +* command + IF -tobjkey+lv_objkey_pos(1) = '/'. + IF NOT ls_objkey-value IS INITIAL. +* We reached the end of a key-definition. +* this key part may address multiple fields. +* E. g. six characters may address one boolean field and a five-digit version field. +* Thus, we need to analyze the remaining key components which have not been covered yet. + split_value_to_keys( + EXPORTING + it_key_component = lt_key_fields + CHANGING + ct_objkey = lt_objkey + cs_objkey = ls_objkey + cv_non_value_pos = lv_non_value_pos ). + ENDIF. + lv_next_objkey_pos = lv_objkey_pos + 1. +* '*' means all further key values + IF -tobjkey+lv_next_objkey_pos(1) = '*'. + ls_objkey-value = '*'. + INSERT ls_objkey INTO TABLE lt_objkey. + CLEAR ls_objkey. + lv_non_value_pos = lv_non_value_pos + 1. + lv_objkey_pos = lv_objkey_pos + 1. +* object name + ELSEIF -tobjkey+lv_next_objkey_pos(1) = '&'. + "TODO + ls_objkey-value = ms_item-obj_name. +* The object name might comprise multiple key components (e. g. WDCC) +* This string needs to be split + distribute_name_to_components( + EXPORTING + it_key_component = lt_key_fields + CHANGING + ct_objkey = lt_objkey + cs_objkey = ls_objkey + cv_non_value_pos = lv_non_value_pos ). + CLEAR ls_objkey. + lv_objkey_pos = lv_objkey_pos + 1. +* language + ELSEIF -tobjkey+lv_next_objkey_pos(1) = 'L'. + ls_objkey-value = sy-langu. + INSERT ls_objkey INTO TABLE lt_objkey. + CLEAR ls_objkey. + lv_non_value_pos = lv_non_value_pos + 1. + lv_objkey_pos = lv_objkey_pos + 1. +* Client + ELSEIF -tobjkey+lv_next_objkey_pos(1) = 'C'. + ls_objkey-value = sy-mandt. + INSERT ls_objkey INTO TABLE lt_objkey. + CLEAR ls_objkey. + lv_non_value_pos = lv_non_value_pos + 1. + lv_objkey_pos = lv_objkey_pos + 1. + ENDIF. + lv_value_pos = 0. +* value + ELSE. + ls_objkey-value+lv_value_pos(1) = -tobjkey+lv_objkey_pos(1). + lv_value_pos = lv_value_pos + 1. + ENDIF. + + lv_objkey_pos = lv_objkey_pos + 1. + ENDWHILE. + +* Similarly to that, fixed values might be supplied in the object key which actually make up key components + IF NOT ls_objkey-value IS INITIAL. + split_value_to_keys( + EXPORTING + it_key_component = lt_key_fields + CHANGING + ct_objkey = lt_objkey + cs_objkey = ls_objkey + cv_non_value_pos = lv_non_value_pos ). + ENDIF. + +* compose the where clause + lv_is_asterix = abap_false. + lv_key_pos = 1. + + LOOP AT lt_key_fields ASSIGNING . + READ TABLE lt_objkey INTO ls_objkey + WITH TABLE KEY num = lv_key_pos. + IF sy-subrc <> 0 OR -fieldname = 'LANGU'. + CLEAR ls_objkey. + lv_key_pos = lv_key_pos + 1. + CONTINUE. + ENDIF. + IF ls_objkey-value = '*'. + lv_is_asterix = rs_c_true. + ENDIF. + IF lv_is_asterix = rs_c_true. + CONTINUE. + ENDIF. + IF NOT lv_where_statement IS INITIAL. + CONCATENATE lv_where_statement 'AND' INTO lv_where_statement + SEPARATED BY space. + ENDIF. + CONCATENATE '''' ls_objkey-value '''' INTO lv_value128. + CONCATENATE lv_where_statement -fieldname '=' + lv_value128 INTO lv_where_statement SEPARATED BY space. + lv_key_pos = lv_key_pos + 1. + ENDLOOP. + + rv_where = condense( lv_where_statement ). + + ENDMETHOD. + + + METHOD serialize. + + before_export( ). + + serialize_data( io_xml ). + + ENDMETHOD. + + + METHOD serialize_data. + + DATA: lr_ref TYPE REF TO data, + lv_where TYPE string. + + FIELD-SYMBOLS: TYPE STANDARD TABLE, + LIKE LINE OF mt_object_table. + + + LOOP AT mt_object_table ASSIGNING . + + CREATE DATA lr_ref TYPE STANDARD TABLE OF (-tobj_name). + ASSIGN lr_ref->* TO . + + lv_where = get_where_clause( -tobj_name ). + + SELECT * FROM (-tobj_name) + INTO TABLE + WHERE (lv_where). + + io_xml->add( + iv_name = -tobj_name + ig_data = ). + + ENDLOOP. + + ENDMETHOD. + + + METHOD split_value_to_keys. + + DATA: lt_key_component_uncovered LIKE it_key_component, + ls_dummy LIKE LINE OF ct_objkey, + ls_key_component_uncovered LIKE LINE OF lt_key_component_uncovered, + ls_objkey_sub LIKE cs_objkey, + lv_objkey_sub_pos TYPE i. + + + lt_key_component_uncovered = it_key_component. + +* we want to fill the atribute values which are not covered by explicit key components yet + LOOP AT ct_objkey INTO ls_dummy. + DELETE lt_key_component_uncovered INDEX 1. + ENDLOOP. + + ls_objkey_sub-num = cs_objkey-num. + lv_objkey_sub_pos = 0. + LOOP AT lt_key_component_uncovered INTO ls_key_component_uncovered. + CLEAR ls_objkey_sub-value. + ls_objkey_sub-value = cs_objkey-value+lv_objkey_sub_pos(ls_key_component_uncovered-leng). + ls_objkey_sub-num = cv_non_value_pos. + + INSERT ls_objkey_sub INTO TABLE ct_objkey. + + lv_objkey_sub_pos = lv_objkey_sub_pos + ls_key_component_uncovered-leng. + cv_non_value_pos = cv_non_value_pos + 1. + CLEAR ls_objkey_sub. + + IF lv_objkey_sub_pos = strlen( cs_objkey-value ). + cs_objkey-num = cv_non_value_pos. + EXIT. "end splitting - all characters captured + ENDIF. + ENDLOOP. + + ENDMETHOD. + + + METHOD validate. + + DATA: lv_where TYPE string, + lv_primary TYPE objsl-tobj_name, + lr_ref TYPE REF TO data. + + FIELD-SYMBOLS: TYPE STANDARD TABLE. + + + lv_primary = get_primary_table( ). + + CREATE DATA lr_ref TYPE STANDARD TABLE OF (lv_primary). + ASSIGN lr_ref->* TO . + + io_xml->read( + EXPORTING + iv_name = lv_primary + CHANGING + cg_data = ). + + IF lines( ) = 0. + zcx_abapgit_exception=>raise( |Primary table { lv_primary + } not found in imported container | ). + ELSEIF lines( ) <> 1. + zcx_abapgit_exception=>raise( |Primary table { lv_primary + } contains more than one instance! | ). + ENDIF. + + lv_where = get_where_clause( lv_primary ). + +* validate that max one local instance was affected by the import + SELECT COUNT(*) FROM (lv_primary) WHERE (lv_where). + IF sy-dbcnt > 1. + zcx_abapgit_exception=>raise( |More than one instance exists locally in primary table { + lv_primary }| ). + ENDIF. + + ENDMETHOD. +ENDCLASS. diff --git a/src/objects/zcl_abapgit_objects_generic.clas.testclasses.abap b/src/objects/zcl_abapgit_objects_generic.clas.testclasses.abap new file mode 100644 index 000000000..32b8fbb7f --- /dev/null +++ b/src/objects/zcl_abapgit_objects_generic.clas.testclasses.abap @@ -0,0 +1,41 @@ +CLASS ltcl_test DEFINITION FOR TESTING + DURATION SHORT + RISK LEVEL HARMLESS FINAL. + + PRIVATE SECTION. + METHODS: serialize FOR TESTING RAISING zcx_abapgit_exception. + +ENDCLASS. + + +CLASS ltcl_test IMPLEMENTATION. + + METHOD serialize. + + DATA: lo_cut TYPE REF TO zcl_abapgit_objects_generic, + lo_xml TYPE REF TO zcl_abapgit_xml_output, + ls_item TYPE zif_abapgit_definitions=>ty_item. + +* assumption: this object exists in all SAP systems + ls_item-obj_type = 'ASFC'. + ls_item-obj_name = 'SAP_AS_TEST_001'. + + CREATE OBJECT lo_cut + EXPORTING + is_item = ls_item. + + CREATE OBJECT lo_xml. + + lo_cut->serialize( lo_xml ). +* checks that it does not dump + + ENDMETHOD. + +* todo, implement tests for methods: +* DISTRIBUTE_NAME_TO_COMPONENTS +* GET_KEY_FIELDS +* GET_PRIMARY_TABLE +* GET_WHERE_CLAUSE +* SPLIT_VALUE_TO_KEYS + +ENDCLASS. diff --git a/src/objects/zcl_abapgit_objects_generic.clas.xml b/src/objects/zcl_abapgit_objects_generic.clas.xml new file mode 100644 index 000000000..ae3f63e8f --- /dev/null +++ b/src/objects/zcl_abapgit_objects_generic.clas.xml @@ -0,0 +1,19 @@ + + + + + + ZCL_ABAPGIT_OBJECTS_GENERIC + 1 + E + Generic object helper + 2 + 1 + X + X + X + X + + + +