@@ -983,6 +983,11 @@ def deploy_all(
983983 is_flag = True ,
984984 help = "Remove from production (use 'carto' schema instead of prefixed schema)" ,
985985)
986+ @click .option (
987+ "--drop-schema" ,
988+ is_flag = True ,
989+ help = "Drop entire schema with CASCADE (faster, removes all objects in schema)" ,
990+ )
986991@click .pass_context
987992def remove_all (
988993 ctx ,
@@ -994,11 +999,15 @@ def remove_all(
994999 functions : Optional [str ],
9951000 dry_run : bool ,
9961001 production : bool ,
1002+ drop_schema : bool ,
9971003):
9981004 """Remove Lambda functions and external functions from Redshift
9991005
10001006 NOTE: This command does NOT delete IAM roles. Roles can be reused across
10011007 deployments and should be managed separately.
1008+
1009+ Use --drop-schema for CI environments to drop the entire schema with CASCADE.
1010+ This is faster and cleaner than dropping individual functions.
10021011 """
10031012 logger .info ("Removing Analytics Toolbox from Redshift" )
10041013
@@ -1079,16 +1088,20 @@ def remove_all(
10791088 lambda_name = f"{ lambda_prefix } { func .name } "
10801089 logger .info (f" - { lambda_name } " )
10811090
1082- # Count external functions
1083- external_count = sum (
1084- 1 for f in to_remove
1085- if f .get_cloud_config (CloudType .REDSHIFT ).external_function_template
1086- )
1087- logger .info (f"\n External functions in { rs_schema } ({ external_count } ):" )
1088- for func in to_remove :
1089- cloud_config = func .get_cloud_config (CloudType .REDSHIFT )
1090- if cloud_config .external_function_template :
1091- logger .info (f" - { rs_schema } .{ func .name .upper ()} " )
1091+ if drop_schema :
1092+ logger .info (f"\n Schema:" )
1093+ logger .info (f" - DROP SCHEMA { rs_schema } CASCADE" )
1094+ else :
1095+ # Count external functions
1096+ external_count = sum (
1097+ 1 for f in to_remove
1098+ if f .get_cloud_config (CloudType .REDSHIFT ).external_function_template
1099+ )
1100+ logger .info (f"\n External functions in { rs_schema } ({ external_count } ):" )
1101+ for func in to_remove :
1102+ cloud_config = func .get_cloud_config (CloudType .REDSHIFT )
1103+ if cloud_config .external_function_template :
1104+ logger .info (f" - { rs_schema } .{ func .name .upper ()} " )
10921105
10931106 logger .info ("\n NOTE: IAM roles will NOT be deleted (they can be reused)" )
10941107 return
@@ -1110,15 +1123,37 @@ def remove_all(
11101123
11111124 # Phase 1: Drop all functions from Redshift
11121125 if rs_host and rs_user and rs_password and rs_database :
1113- logger .info ("\n === Phase 1: Dropping all functions from Redshift ===\n " )
1126+ logger .info ("\n === Phase 1: Dropping from Redshift ===\n " )
11141127
11151128 # Filter functions that have external function templates
11161129 functions_to_drop = [
11171130 f for f in to_remove
11181131 if f .get_cloud_config (CloudType .REDSHIFT ).external_function_template
11191132 ]
11201133
1121- if functions_to_drop :
1134+ if drop_schema :
1135+ # Drop entire schema with CASCADE - faster and cleaner for CI
1136+ try :
1137+ logger .info (f"Dropping schema { rs_schema } with CASCADE..." )
1138+ drop_schema_sql = f"DROP SCHEMA IF EXISTS { rs_schema } CASCADE"
1139+
1140+ with redshift_connector .connect (
1141+ host = rs_host ,
1142+ database = rs_database ,
1143+ user = rs_user ,
1144+ password = rs_password ,
1145+ timeout = 300 ,
1146+ ) as conn :
1147+ conn .autocommit = True
1148+ with conn .cursor () as cursor :
1149+ cursor .execute (drop_schema_sql )
1150+
1151+ logger .info (f"✓ Dropped schema { rs_schema } (all objects removed)\n " )
1152+ external_success = len (functions_to_drop )
1153+ except Exception as e :
1154+ logger .error (f"✗ Failed to drop schema: { e } \n " )
1155+ # Continue with Lambda deletion even if schema drop fails
1156+ elif functions_to_drop :
11221157 try :
11231158 # Drop ALL external functions (Lambda-backed) in the schema
11241159 # Gateway only deploys external functions, so this is safe
0 commit comments