1313# limitations under the License.
1414from __future__ import annotations
1515
16- import dataclasses
1716import typing
1817
1918from bigframes .core import identifiers , nodes
2019
2120
22- # TODO: May as well just outright remove selection nodes in this process.
21+ def _create_mapping_operator (
22+ id_def_remapping_by_node : dict [
23+ nodes .BigFrameNode , dict [identifiers .ColumnId , identifiers .ColumnId ]
24+ ],
25+ id_ref_remapping_by_node : dict [
26+ nodes .BigFrameNode , dict [identifiers .ColumnId , identifiers .ColumnId ]
27+ ],
28+ ):
29+ """
30+ Builds a remapping operator that uses predefined local remappings for ids.
31+
32+ Args:
33+ id_remapping_by_node: A mapping from nodes to their local remappings.
34+
35+ Returns:
36+ A remapping operator.
37+ """
38+
39+ def _mapping_operator (node : nodes .BigFrameNode ) -> nodes .BigFrameNode :
40+ # Step 1: Get the local remapping for the current node.
41+ local_def_remaps = id_def_remapping_by_node .get (node , {})
42+ local_ref_remaps = id_ref_remapping_by_node .get (node , {})
43+
44+ node = node .remap_vars (local_def_remaps )
45+ node = node .remap_refs (local_ref_remaps )
46+
47+ return node
48+
49+ return _mapping_operator
50+
51+
2352def remap_variables (
2453 root : nodes .BigFrameNode ,
2554 id_generator : typing .Iterator [identifiers .ColumnId ],
@@ -42,46 +71,29 @@ def remap_variables(
4271 A tuple of the new root node and a mapping from old to new column IDs
4372 visible to the parent node.
4473 """
45- # Step 1: Recursively remap children to get their new nodes and ID mappings.
46- new_child_nodes : list [nodes .BigFrameNode ] = []
47- new_child_mappings : list [dict [identifiers .ColumnId , identifiers .ColumnId ]] = []
48- for child in root .child_nodes :
49- new_child , child_mappings = remap_variables (child , id_generator = id_generator )
50- new_child_nodes .append (new_child )
51- new_child_mappings .append (child_mappings )
52-
53- # Step 2: Transform children to use their new nodes.
54- remapped_children : dict [nodes .BigFrameNode , nodes .BigFrameNode ] = {
55- child : new_child for child , new_child in zip (root .child_nodes , new_child_nodes )
56- }
57- new_root = root .transform_children (lambda node : remapped_children [node ])
58-
59- # Step 3: Transform the current node using the mappings from its children.
60- if isinstance (new_root , nodes .InNode ):
61- new_root = typing .cast (nodes .InNode , new_root )
62- new_root = dataclasses .replace (
63- new_root ,
64- left_col = new_root .left_col .remap_column_refs (
65- new_child_mappings [0 ], allow_partial_bindings = True
66- ),
67- )
68- else :
69- downstream_mappings : dict [identifiers .ColumnId , identifiers .ColumnId ] = {
70- k : v for mapping in new_child_mappings for k , v in mapping .items ()
71- }
72- new_root = new_root .remap_refs (downstream_mappings )
73-
74- # Step 4: Create new IDs for columns defined by the current node.
75- node_defined_mappings = {
76- old_id : next (id_generator ) for old_id in root .node_defined_ids
77- }
78- new_root = new_root .remap_vars (node_defined_mappings )
74+ # step 1: defined remappings for each individual unique node
75+ # step 2: bottom up traversal to apply remappings
7976
80- new_root ._validate ()
77+ id_def_remaps : dict [
78+ nodes .BigFrameNode , dict [identifiers .ColumnId , identifiers .ColumnId ]
79+ ] = {}
80+ id_ref_remaps : dict [
81+ nodes .BigFrameNode , dict [identifiers .ColumnId , identifiers .ColumnId ]
82+ ] = {}
83+ for node in root .iter_nodes_topo (): # bottom_up
84+ local_def_remaps = {
85+ col_id : next (id_generator ) for col_id in node .node_defined_ids
86+ }
87+ id_def_remaps [node ] = local_def_remaps
8188
82- # Step 5: Determine which mappings to propagate up to the parent.
83- propagated_mappings = {
84- old_id : new_id for old_id , new_id in zip (root .ids , new_root .ids )
85- }
89+ local_ref_remaps = {}
90+ for child in node .child_nodes : # inherit ref and def mappings from children
91+ local_ref_remaps .update (id_def_remaps [child ])
92+ if not child .defines_namespace :
93+ local_ref_remaps .update (id_ref_remaps [child ])
94+ id_ref_remaps [node ] = local_ref_remaps
8695
87- return new_root , propagated_mappings
96+ return (
97+ root .top_down (_create_mapping_operator (id_def_remaps , id_ref_remaps )),
98+ id_def_remaps [root ],
99+ )
0 commit comments