@@ -2399,29 +2399,6 @@ def wap_publish(self, table_name: TableName, wap_id: str) -> None:
23992399 """
24002400 raise NotImplementedError (f"Engine does not support WAP: { type (self )} " )
24012401
2402- def _get_current_grants_config (self , table : exp .Table ) -> GrantsConfig :
2403- """Returns current grants for a table as a dictionary.
2404-
2405- This method queries the database and returns the current grants/permissions
2406- for the given table, parsed into a dictionary format. The it handles
2407- case-insensitive comparison between these current grants and the desired
2408- grants from model configuration.
2409-
2410- Args:
2411- table: The table/view to query grants for.
2412-
2413- Returns:
2414- Dictionary mapping permissions to lists of grantees. Permission names
2415- should be returned as the database provides them (typically uppercase
2416- for standard SQL permissions, but engine-specific roles may vary).
2417-
2418- Raises:
2419- NotImplementedError: If the engine does not support grants.
2420- """
2421- if not self .SUPPORTS_GRANTS :
2422- raise NotImplementedError (f"Engine does not support grants: { type (self )} " )
2423- raise NotImplementedError ("Subclass must implement get_current_grants" )
2424-
24252402 def sync_grants_config (
24262403 self ,
24272404 table : exp .Table ,
@@ -2449,104 +2426,6 @@ def sync_grants_config(
24492426 if dcl_exprs :
24502427 self .execute (dcl_exprs )
24512428
2452- def _apply_grants_config_expr (
2453- self ,
2454- table : exp .Table ,
2455- grant_config : GrantsConfig ,
2456- table_type : DataObjectType = DataObjectType .TABLE ,
2457- ) -> t .List [exp .Expression ]:
2458- """Returns SQLGlot Grant expressions to apply grants to a table.
2459-
2460- Args:
2461- table: The table/view to grant permissions on.
2462- grant_config: Dictionary mapping permissions to lists of grantees.
2463- table_type: The type of database object (TABLE, VIEW, MATERIALIZED_VIEW).
2464-
2465- Returns:
2466- List of SQLGlot expressions for grant operations.
2467-
2468- Raises:
2469- NotImplementedError: If the engine does not support grants.
2470- """
2471- if not self .SUPPORTS_GRANTS :
2472- raise NotImplementedError (f"Engine does not support grants: { type (self )} " )
2473- raise NotImplementedError ("Subclass must implement _apply_grants_config_expr" )
2474-
2475- def _revoke_grants_config_expr (
2476- self ,
2477- table : exp .Table ,
2478- grant_config : GrantsConfig ,
2479- table_type : DataObjectType = DataObjectType .TABLE ,
2480- ) -> t .List [exp .Expression ]:
2481- """Returns SQLGlot expressions to revoke grants from a table.
2482-
2483- Note: SQLGlot doesn't yet have a Revoke expression type, so implementations
2484- may return other expression types or handle revokes as strings.
2485-
2486- Args:
2487- table: The table/view to revoke permissions from.
2488- grant_config: Dictionary mapping permissions to lists of grantees.
2489- table_type: The type of database object (TABLE, VIEW, MATERIALIZED_VIEW).
2490-
2491- Returns:
2492- List of SQLGlot expressions for revoke operations.
2493-
2494- Raises:
2495- NotImplementedError: If the engine does not support grants.
2496- """
2497- if not self .SUPPORTS_GRANTS :
2498- raise NotImplementedError (f"Engine does not support grants: { type (self )} " )
2499- raise NotImplementedError ("Subclass must implement _revoke_grants_config_expr" )
2500-
2501- @classmethod
2502- def _diff_grants_configs (
2503- cls , new_config : GrantsConfig , old_config : GrantsConfig
2504- ) -> t .Tuple [GrantsConfig , GrantsConfig ]:
2505- """Compute additions and removals between two grants configurations.
2506-
2507- This method compares new (desired) and old (current) GrantsConfigs case-insensitively
2508- for both privilege keys and grantees, while preserving original casing
2509- in the output GrantsConfigs.
2510-
2511- Args:
2512- new_config: Desired grants configuration (specified by the user).
2513- old_config: Current grants configuration (returned by the database).
2514-
2515- Returns:
2516- A tuple of (additions, removals) GrantsConfig where:
2517- - additions contains privileges/grantees present in new_config but not in old_config
2518- - additions uses keys and grantee strings from new_config (user-specified casing)
2519- - removals contains privileges/grantees present in old_config but not in new_config
2520- - removals uses keys and grantee strings from old_config (database-returned casing)
2521-
2522- Notes:
2523- - Comparison is case-insensitive using casefold(); original casing is preserved in results.
2524- - Overlapping grantees (case-insensitive) are excluded from the results.
2525- """
2526-
2527- def _diffs (config1 : GrantsConfig , config2 : GrantsConfig ) -> GrantsConfig :
2528- diffs : GrantsConfig = {}
2529- cf_config2 = {k .casefold (): {g .casefold () for g in v } for k , v in config2 .items ()}
2530- for key , grantees in config1 .items ():
2531- cf_key = key .casefold ()
2532-
2533- # Missing key (add all grantees)
2534- if cf_key not in cf_config2 :
2535- diffs [key ] = grantees .copy ()
2536- continue
2537-
2538- # Include only grantees not in config2
2539- cf_grantees2 = cf_config2 [cf_key ]
2540- diff_grantees = []
2541- for grantee in grantees :
2542- if grantee .casefold () not in cf_grantees2 :
2543- diff_grantees .append (grantee )
2544- if diff_grantees :
2545- diffs [key ] = diff_grantees
2546- return diffs
2547-
2548- return _diffs (new_config , old_config ), _diffs (old_config , new_config )
2549-
25502429 @contextlib .contextmanager
25512430 def transaction (
25522431 self ,
@@ -3075,6 +2954,127 @@ def _check_identifier_length(self, expression: exp.Expression) -> None:
30752954 f"Identifier name '{ name } ' (length { name_length } ) exceeds { self .dialect .capitalize ()} 's max identifier limit of { self .MAX_IDENTIFIER_LENGTH } characters"
30762955 )
30772956
2957+ @classmethod
2958+ def _diff_grants_configs (
2959+ cls , new_config : GrantsConfig , old_config : GrantsConfig
2960+ ) -> t .Tuple [GrantsConfig , GrantsConfig ]:
2961+ """Compute additions and removals between two grants configurations.
2962+
2963+ This method compares new (desired) and old (current) GrantsConfigs case-insensitively
2964+ for both privilege keys and grantees, while preserving original casing
2965+ in the output GrantsConfigs.
2966+
2967+ Args:
2968+ new_config: Desired grants configuration (specified by the user).
2969+ old_config: Current grants configuration (returned by the database).
2970+
2971+ Returns:
2972+ A tuple of (additions, removals) GrantsConfig where:
2973+ - additions contains privileges/grantees present in new_config but not in old_config
2974+ - additions uses keys and grantee strings from new_config (user-specified casing)
2975+ - removals contains privileges/grantees present in old_config but not in new_config
2976+ - removals uses keys and grantee strings from old_config (database-returned casing)
2977+
2978+ Notes:
2979+ - Comparison is case-insensitive using casefold(); original casing is preserved in results.
2980+ - Overlapping grantees (case-insensitive) are excluded from the results.
2981+ """
2982+
2983+ def _diffs (config1 : GrantsConfig , config2 : GrantsConfig ) -> GrantsConfig :
2984+ diffs : GrantsConfig = {}
2985+ cf_config2 = {k .casefold (): {g .casefold () for g in v } for k , v in config2 .items ()}
2986+ for key , grantees in config1 .items ():
2987+ cf_key = key .casefold ()
2988+
2989+ # Missing key (add all grantees)
2990+ if cf_key not in cf_config2 :
2991+ diffs [key ] = grantees .copy ()
2992+ continue
2993+
2994+ # Include only grantees not in config2
2995+ cf_grantees2 = cf_config2 [cf_key ]
2996+ diff_grantees = []
2997+ for grantee in grantees :
2998+ if grantee .casefold () not in cf_grantees2 :
2999+ diff_grantees .append (grantee )
3000+ if diff_grantees :
3001+ diffs [key ] = diff_grantees
3002+ return diffs
3003+
3004+ return _diffs (new_config , old_config ), _diffs (old_config , new_config )
3005+
3006+ def _get_current_grants_config (self , table : exp .Table ) -> GrantsConfig :
3007+ """Returns current grants for a table as a dictionary.
3008+
3009+ This method queries the database and returns the current grants/permissions
3010+ for the given table, parsed into a dictionary format. The it handles
3011+ case-insensitive comparison between these current grants and the desired
3012+ grants from model configuration.
3013+
3014+ Args:
3015+ table: The table/view to query grants for.
3016+
3017+ Returns:
3018+ Dictionary mapping permissions to lists of grantees. Permission names
3019+ should be returned as the database provides them (typically uppercase
3020+ for standard SQL permissions, but engine-specific roles may vary).
3021+
3022+ Raises:
3023+ NotImplementedError: If the engine does not support grants.
3024+ """
3025+ if not self .SUPPORTS_GRANTS :
3026+ raise NotImplementedError (f"Engine does not support grants: { type (self )} " )
3027+ raise NotImplementedError ("Subclass must implement get_current_grants" )
3028+
3029+ def _apply_grants_config_expr (
3030+ self ,
3031+ table : exp .Table ,
3032+ grant_config : GrantsConfig ,
3033+ table_type : DataObjectType = DataObjectType .TABLE ,
3034+ ) -> t .List [exp .Expression ]:
3035+ """Returns SQLGlot Grant expressions to apply grants to a table.
3036+
3037+ Args:
3038+ table: The table/view to grant permissions on.
3039+ grant_config: Dictionary mapping permissions to lists of grantees.
3040+ table_type: The type of database object (TABLE, VIEW, MATERIALIZED_VIEW).
3041+
3042+ Returns:
3043+ List of SQLGlot expressions for grant operations.
3044+
3045+ Raises:
3046+ NotImplementedError: If the engine does not support grants.
3047+ """
3048+ if not self .SUPPORTS_GRANTS :
3049+ raise NotImplementedError (f"Engine does not support grants: { type (self )} " )
3050+ raise NotImplementedError ("Subclass must implement _apply_grants_config_expr" )
3051+
3052+ def _revoke_grants_config_expr (
3053+ self ,
3054+ table : exp .Table ,
3055+ grant_config : GrantsConfig ,
3056+ table_type : DataObjectType = DataObjectType .TABLE ,
3057+ ) -> t .List [exp .Expression ]:
3058+ """Returns SQLGlot expressions to revoke grants from a table.
3059+
3060+ Note: SQLGlot doesn't yet have a Revoke expression type, so implementations
3061+ may return other expression types or handle revokes as strings.
3062+
3063+ Args:
3064+ table: The table/view to revoke permissions from.
3065+ grant_config: Dictionary mapping permissions to lists of grantees.
3066+ table_type: The type of database object (TABLE, VIEW, MATERIALIZED_VIEW).
3067+
3068+ Returns:
3069+ List of SQLGlot expressions for revoke operations.
3070+
3071+ Raises:
3072+ NotImplementedError: If the engine does not support grants.
3073+ """
3074+ if not self .SUPPORTS_GRANTS :
3075+ raise NotImplementedError (f"Engine does not support grants: { type (self )} " )
3076+ raise NotImplementedError ("Subclass must implement _revoke_grants_config_expr" )
3077+
30783078
30793079class EngineAdapterWithIndexSupport (EngineAdapter ):
30803080 SUPPORTS_INDEXES = True
0 commit comments