@@ -2364,29 +2364,6 @@ def wap_publish(self, table_name: TableName, wap_id: str) -> None:
23642364 """
23652365 raise NotImplementedError (f"Engine does not support WAP: { type (self )} " )
23662366
2367- def _get_current_grants_config (self , table : exp .Table ) -> GrantsConfig :
2368- """Returns current grants for a table as a dictionary.
2369-
2370- This method queries the database and returns the current grants/permissions
2371- for the given table, parsed into a dictionary format. The it handles
2372- case-insensitive comparison between these current grants and the desired
2373- grants from model configuration.
2374-
2375- Args:
2376- table: The table/view to query grants for.
2377-
2378- Returns:
2379- Dictionary mapping permissions to lists of grantees. Permission names
2380- should be returned as the database provides them (typically uppercase
2381- for standard SQL permissions, but engine-specific roles may vary).
2382-
2383- Raises:
2384- NotImplementedError: If the engine does not support grants.
2385- """
2386- if not self .SUPPORTS_GRANTS :
2387- raise NotImplementedError (f"Engine does not support grants: { type (self )} " )
2388- raise NotImplementedError ("Subclass must implement get_current_grants" )
2389-
23902367 def sync_grants_config (
23912368 self ,
23922369 table : exp .Table ,
@@ -2414,104 +2391,6 @@ def sync_grants_config(
24142391 if dcl_exprs :
24152392 self .execute (dcl_exprs )
24162393
2417- def _apply_grants_config_expr (
2418- self ,
2419- table : exp .Table ,
2420- grant_config : GrantsConfig ,
2421- table_type : DataObjectType = DataObjectType .TABLE ,
2422- ) -> t .List [exp .Expression ]:
2423- """Returns SQLGlot Grant expressions to apply grants to a table.
2424-
2425- Args:
2426- table: The table/view to grant permissions on.
2427- grant_config: Dictionary mapping permissions to lists of grantees.
2428- table_type: The type of database object (TABLE, VIEW, MATERIALIZED_VIEW).
2429-
2430- Returns:
2431- List of SQLGlot expressions for grant operations.
2432-
2433- Raises:
2434- NotImplementedError: If the engine does not support grants.
2435- """
2436- if not self .SUPPORTS_GRANTS :
2437- raise NotImplementedError (f"Engine does not support grants: { type (self )} " )
2438- raise NotImplementedError ("Subclass must implement _apply_grants_config_expr" )
2439-
2440- def _revoke_grants_config_expr (
2441- self ,
2442- table : exp .Table ,
2443- grant_config : GrantsConfig ,
2444- table_type : DataObjectType = DataObjectType .TABLE ,
2445- ) -> t .List [exp .Expression ]:
2446- """Returns SQLGlot expressions to revoke grants from a table.
2447-
2448- Note: SQLGlot doesn't yet have a Revoke expression type, so implementations
2449- may return other expression types or handle revokes as strings.
2450-
2451- Args:
2452- table: The table/view to revoke permissions from.
2453- grant_config: Dictionary mapping permissions to lists of grantees.
2454- table_type: The type of database object (TABLE, VIEW, MATERIALIZED_VIEW).
2455-
2456- Returns:
2457- List of SQLGlot expressions for revoke operations.
2458-
2459- Raises:
2460- NotImplementedError: If the engine does not support grants.
2461- """
2462- if not self .SUPPORTS_GRANTS :
2463- raise NotImplementedError (f"Engine does not support grants: { type (self )} " )
2464- raise NotImplementedError ("Subclass must implement _revoke_grants_config_expr" )
2465-
2466- @classmethod
2467- def _diff_grants_configs (
2468- cls , new_config : GrantsConfig , old_config : GrantsConfig
2469- ) -> t .Tuple [GrantsConfig , GrantsConfig ]:
2470- """Compute additions and removals between two grants configurations.
2471-
2472- This method compares new (desired) and old (current) GrantsConfigs case-insensitively
2473- for both privilege keys and grantees, while preserving original casing
2474- in the output GrantsConfigs.
2475-
2476- Args:
2477- new_config: Desired grants configuration (specified by the user).
2478- old_config: Current grants configuration (returned by the database).
2479-
2480- Returns:
2481- A tuple of (additions, removals) GrantsConfig where:
2482- - additions contains privileges/grantees present in new_config but not in old_config
2483- - additions uses keys and grantee strings from new_config (user-specified casing)
2484- - removals contains privileges/grantees present in old_config but not in new_config
2485- - removals uses keys and grantee strings from old_config (database-returned casing)
2486-
2487- Notes:
2488- - Comparison is case-insensitive using casefold(); original casing is preserved in results.
2489- - Overlapping grantees (case-insensitive) are excluded from the results.
2490- """
2491-
2492- def _diffs (config1 : GrantsConfig , config2 : GrantsConfig ) -> GrantsConfig :
2493- diffs : GrantsConfig = {}
2494- cf_config2 = {k .casefold (): {g .casefold () for g in v } for k , v in config2 .items ()}
2495- for key , grantees in config1 .items ():
2496- cf_key = key .casefold ()
2497-
2498- # Missing key (add all grantees)
2499- if cf_key not in cf_config2 :
2500- diffs [key ] = grantees .copy ()
2501- continue
2502-
2503- # Include only grantees not in config2
2504- cf_grantees2 = cf_config2 [cf_key ]
2505- diff_grantees = []
2506- for grantee in grantees :
2507- if grantee .casefold () not in cf_grantees2 :
2508- diff_grantees .append (grantee )
2509- if diff_grantees :
2510- diffs [key ] = diff_grantees
2511- return diffs
2512-
2513- return _diffs (new_config , old_config ), _diffs (old_config , new_config )
2514-
25152394 @contextlib .contextmanager
25162395 def transaction (
25172396 self ,
@@ -3040,6 +2919,127 @@ def _check_identifier_length(self, expression: exp.Expression) -> None:
30402919 f"Identifier name '{ name } ' (length { name_length } ) exceeds { self .dialect .capitalize ()} 's max identifier limit of { self .MAX_IDENTIFIER_LENGTH } characters"
30412920 )
30422921
2922+ @classmethod
2923+ def _diff_grants_configs (
2924+ cls , new_config : GrantsConfig , old_config : GrantsConfig
2925+ ) -> t .Tuple [GrantsConfig , GrantsConfig ]:
2926+ """Compute additions and removals between two grants configurations.
2927+
2928+ This method compares new (desired) and old (current) GrantsConfigs case-insensitively
2929+ for both privilege keys and grantees, while preserving original casing
2930+ in the output GrantsConfigs.
2931+
2932+ Args:
2933+ new_config: Desired grants configuration (specified by the user).
2934+ old_config: Current grants configuration (returned by the database).
2935+
2936+ Returns:
2937+ A tuple of (additions, removals) GrantsConfig where:
2938+ - additions contains privileges/grantees present in new_config but not in old_config
2939+ - additions uses keys and grantee strings from new_config (user-specified casing)
2940+ - removals contains privileges/grantees present in old_config but not in new_config
2941+ - removals uses keys and grantee strings from old_config (database-returned casing)
2942+
2943+ Notes:
2944+ - Comparison is case-insensitive using casefold(); original casing is preserved in results.
2945+ - Overlapping grantees (case-insensitive) are excluded from the results.
2946+ """
2947+
2948+ def _diffs (config1 : GrantsConfig , config2 : GrantsConfig ) -> GrantsConfig :
2949+ diffs : GrantsConfig = {}
2950+ cf_config2 = {k .casefold (): {g .casefold () for g in v } for k , v in config2 .items ()}
2951+ for key , grantees in config1 .items ():
2952+ cf_key = key .casefold ()
2953+
2954+ # Missing key (add all grantees)
2955+ if cf_key not in cf_config2 :
2956+ diffs [key ] = grantees .copy ()
2957+ continue
2958+
2959+ # Include only grantees not in config2
2960+ cf_grantees2 = cf_config2 [cf_key ]
2961+ diff_grantees = []
2962+ for grantee in grantees :
2963+ if grantee .casefold () not in cf_grantees2 :
2964+ diff_grantees .append (grantee )
2965+ if diff_grantees :
2966+ diffs [key ] = diff_grantees
2967+ return diffs
2968+
2969+ return _diffs (new_config , old_config ), _diffs (old_config , new_config )
2970+
2971+ def _get_current_grants_config (self , table : exp .Table ) -> GrantsConfig :
2972+ """Returns current grants for a table as a dictionary.
2973+
2974+ This method queries the database and returns the current grants/permissions
2975+ for the given table, parsed into a dictionary format. The it handles
2976+ case-insensitive comparison between these current grants and the desired
2977+ grants from model configuration.
2978+
2979+ Args:
2980+ table: The table/view to query grants for.
2981+
2982+ Returns:
2983+ Dictionary mapping permissions to lists of grantees. Permission names
2984+ should be returned as the database provides them (typically uppercase
2985+ for standard SQL permissions, but engine-specific roles may vary).
2986+
2987+ Raises:
2988+ NotImplementedError: If the engine does not support grants.
2989+ """
2990+ if not self .SUPPORTS_GRANTS :
2991+ raise NotImplementedError (f"Engine does not support grants: { type (self )} " )
2992+ raise NotImplementedError ("Subclass must implement get_current_grants" )
2993+
2994+ def _apply_grants_config_expr (
2995+ self ,
2996+ table : exp .Table ,
2997+ grant_config : GrantsConfig ,
2998+ table_type : DataObjectType = DataObjectType .TABLE ,
2999+ ) -> t .List [exp .Expression ]:
3000+ """Returns SQLGlot Grant expressions to apply grants to a table.
3001+
3002+ Args:
3003+ table: The table/view to grant permissions on.
3004+ grant_config: Dictionary mapping permissions to lists of grantees.
3005+ table_type: The type of database object (TABLE, VIEW, MATERIALIZED_VIEW).
3006+
3007+ Returns:
3008+ List of SQLGlot expressions for grant operations.
3009+
3010+ Raises:
3011+ NotImplementedError: If the engine does not support grants.
3012+ """
3013+ if not self .SUPPORTS_GRANTS :
3014+ raise NotImplementedError (f"Engine does not support grants: { type (self )} " )
3015+ raise NotImplementedError ("Subclass must implement _apply_grants_config_expr" )
3016+
3017+ def _revoke_grants_config_expr (
3018+ self ,
3019+ table : exp .Table ,
3020+ grant_config : GrantsConfig ,
3021+ table_type : DataObjectType = DataObjectType .TABLE ,
3022+ ) -> t .List [exp .Expression ]:
3023+ """Returns SQLGlot expressions to revoke grants from a table.
3024+
3025+ Note: SQLGlot doesn't yet have a Revoke expression type, so implementations
3026+ may return other expression types or handle revokes as strings.
3027+
3028+ Args:
3029+ table: The table/view to revoke permissions from.
3030+ grant_config: Dictionary mapping permissions to lists of grantees.
3031+ table_type: The type of database object (TABLE, VIEW, MATERIALIZED_VIEW).
3032+
3033+ Returns:
3034+ List of SQLGlot expressions for revoke operations.
3035+
3036+ Raises:
3037+ NotImplementedError: If the engine does not support grants.
3038+ """
3039+ if not self .SUPPORTS_GRANTS :
3040+ raise NotImplementedError (f"Engine does not support grants: { type (self )} " )
3041+ raise NotImplementedError ("Subclass must implement _revoke_grants_config_expr" )
3042+
30433043
30443044class EngineAdapterWithIndexSupport (EngineAdapter ):
30453045 SUPPORTS_INDEXES = True
0 commit comments