diff --git a/schema/src/cwms/cwms_ts_pkg.sql b/schema/src/cwms/cwms_ts_pkg.sql index e5a47a47..f7319326 100644 --- a/schema/src/cwms/cwms_ts_pkg.sql +++ b/schema/src/cwms/cwms_ts_pkg.sql @@ -3092,6 +3092,19 @@ AS p_ts_group_id IN VARCHAR2, p_db_office_id IN VARCHAR2 DEFAULT NULL); + /** + * Deletes a time series group from the database + * + * @param p_ts_category_id The time series category that owns the time series group + * @param p_ts_group_id The time series group identifier + * @param p_cascade A flag ('T' or 'F') that specifies whether to delete all time series assignments to the group before deleting the group itself. + * @param p_db_office_id The office that owns the time series group. If not specified or NULL, the session user's default office is used. + */ + PROCEDURE delete_ts_group (p_ts_category_id IN VARCHAR2, + p_ts_group_id IN VARCHAR2, + p_cascade IN VARCHAR2 DEFAULT 'F', + p_db_office_id IN VARCHAR2 DEFAULT NULL); + /** * Assigns a time series to a time series group * diff --git a/schema/src/cwms/cwms_ts_pkg_body.sql b/schema/src/cwms/cwms_ts_pkg_body.sql index 8e19b801..acb8d120 100644 --- a/schema/src/cwms/cwms_ts_pkg_body.sql +++ b/schema/src/cwms/cwms_ts_pkg_body.sql @@ -10345,47 +10345,16 @@ end retrieve_existing_item_counts; ----------------- IF l_cascade THEN - ---------------------------------------------------------------------------- - -- delete any groups in the category (will fail if there are assignments) -- - ---------------------------------------------------------------------------- - FOR group_rec - IN (SELECT ts_group_code - FROM at_ts_group - WHERE ts_category_code = l_category_rec.ts_category_code) - LOOP - FOR assign_rec - IN (SELECT ts_code - FROM at_ts_group_assignment - WHERE ts_group_code = group_rec.ts_group_code) - LOOP - cwms_err.raise ( - 'ERROR', - 'Cannot delete time series category ' - || p_ts_category_id - || ' because at least one of its groups is not empty.'); - END LOOP; - - ---------------------- - -- delete the group -- - ---------------------- - DELETE FROM at_ts_group - WHERE ts_group_code = group_rec.ts_group_code; - END LOOP; - ELSE - ------------------------------ - -- test for existing groups -- - ------------------------------ - FOR group_rec - IN (SELECT ts_group_code - FROM at_ts_group - WHERE ts_category_code = l_category_rec.ts_category_code) - LOOP - cwms_err.raise ( - 'ERROR', - 'Cannot delete time series category ' - || p_ts_category_id - || ' because it is not empty.'); - END LOOP; + FOR group_rec IN (SELECT ts_group_id + FROM at_ts_group + WHERE ts_category_code = l_category_rec.ts_category_code) + LOOP + delete_ts_group (p_ts_category_id => p_ts_category_id, + p_ts_group_id => group_rec.ts_group_id, + p_cascade => p_cascade, + p_db_office_id => cwms_util.get_db_office_id (l_category_rec.db_office_code) + ); + END LOOP; END IF; ------------------------- @@ -10601,6 +10570,19 @@ end retrieve_existing_item_counts; PROCEDURE delete_ts_group (p_ts_category_id IN VARCHAR2, p_ts_group_id IN VARCHAR2, p_db_office_id IN VARCHAR2 DEFAULT NULL) + IS + BEGIN + delete_ts_group (p_ts_category_id => p_ts_category_id, + p_ts_group_id => p_ts_group_id, + p_cascade => 'F', + p_db_office_id => p_db_office_id + ); + END delete_ts_group; + + PROCEDURE delete_ts_group (p_ts_category_id IN VARCHAR2, + p_ts_group_id IN VARCHAR2, + p_cascade IN VARCHAR2 DEFAULT 'F', + p_db_office_id IN VARCHAR2 DEFAULT NULL) IS l_office_code NUMBER (14); l_rec at_ts_group%ROWTYPE; @@ -10651,18 +10633,24 @@ end retrieve_existing_item_counts; || ' can only be deleted by owner.'); END IF; - FOR rec IN (SELECT ts_code - FROM at_ts_group_assignment - WHERE ts_group_code = l_rec.ts_group_code) - LOOP - cwms_err.raise ( - 'ERROR', - 'Cannot delete time series group ' - || p_ts_category_id - || '/' - || p_ts_group_id - || ' because it is not empty.'); - END LOOP; + IF cwms_util.is_true (p_cascade) + THEN + DELETE FROM at_ts_group_assignment + WHERE ts_group_code = l_rec.ts_group_code; + END IF; + + FOR rec IN (SELECT ts_code + FROM at_ts_group_assignment + WHERE ts_group_code = l_rec.ts_group_code) + LOOP + cwms_err.raise ( + 'ERROR', + 'Cannot delete time series group ' + || p_ts_category_id + || '/' + || p_ts_group_id + || ' because it is not empty.'); + END LOOP; ---------------------- -- delete the group -- diff --git a/schema/src/test/test_cwms_ts.sql b/schema/src/test/test_cwms_ts.sql index 60ba2cb4..5160f319 100644 --- a/schema/src/test/test_cwms_ts.sql +++ b/schema/src/test/test_cwms_ts.sql @@ -134,6 +134,9 @@ procedure test_cwdb_258_report_input_validity_errors_to_user; --%test (GitHub issue 76 RetrieveTS is inconsistent across folded DST transition) procedure test_issue_76_inconsistent_retrieve_ts_across_folded_dst_boundary; +--%test (Test delete_ts_group with cascade parameter) +procedure test_delete_ts_group_cascade; + test_base_location_id VARCHAR2(32) := 'TestLoc1'; test_withsub_location_id VARCHAR2(32) := test_base_location_id||'-withsub'; test_renamed_base_location_id VARCHAR2(32) := 'RenameTestLoc1'; @@ -4479,6 +4482,63 @@ AS end loop; end test_issue_76_inconsistent_retrieve_ts_across_folded_dst_boundary; + --------------------------------------------------------------------------------- + -- procedure test_delete_ts_group_cascade + --------------------------------------------------------------------------------- + procedure test_delete_ts_group_cascade + is + l_count integer; + l_ts_id varchar2(200) := test_base_location_id||'.Flow.Inst.1Hour.0.Test'; + begin + setup; + cwms_ts.create_ts('&&office_id', l_ts_id); + + -- Create a test category and group + cwms_ts.store_ts_category('TestCategory', 'Category for unit tests', '&&office_id'); + cwms_ts.store_ts_group('TestCategory', 'TestGroup', 'Group for unit tests', 'F', 'T', null, null, '&&office_id'); + + -- Assign TS to group + cwms_ts.assign_ts_group('TestCategory', 'TestGroup', l_ts_id, null, null, null, '&&office_id'); + + -- Verify assignment exists + select count(*) into l_count + from at_ts_group_assignment + where ts_group_code = (select ts_group_code + from at_ts_group + where ts_category_code = (select ts_category_code + from at_ts_category + where db_office_id = cwms_util.get_office_code('&&office_id') + and upper(ts_category_id) = 'TESTCATEGORY') + and upper(ts_group_id) = 'TESTGROUP'); + ut.expect(l_count).to_equal(1); + + -- Test non-cascade delete (should fail) + begin + cwms_ts.delete_ts_group('TestCategory', 'TestGroup', 'F', '&&office_id'); + cwms_err.raise('ERROR', 'Expected exception not raised for non-cascade delete of non-empty group.'); + exception + when others then + null; -- expected + end; + + -- Test cascade delete + cwms_ts.delete_ts_group('TestCategory', 'TestGroup', 'T', '&&office_id'); + + -- Verify group is gone + select count(*) into l_count + from at_ts_group + where ts_category_code = (select ts_category_code + from at_ts_category + where db_office_id = cwms_util.get_office_code('&&office_id') + and upper(ts_category_id) = 'TESTCATEGORY') + and upper(ts_group_id) = 'TESTGROUP'; + ut.expect(l_count).to_equal(0); + + -- Cleanup category + cwms_ts.delete_ts_category('TestCategory', '&&office_id'); + teardown; + end test_delete_ts_group_cascade; + END test_cwms_ts; / SHOW ERRORS \ No newline at end of file