76
76
LOG_SQL = False
77
77
78
78
79
- def translate (table : ibis .Table , pipeline : ParsedPipeline ) -> ibis .Table :
79
+ class ResultsProjection :
80
+ """Projection of the results of the pipeline.
81
+
82
+ This class is used to select the columns to be returned
83
+ from the pipeline. It can be used to select specific
84
+ columns or to omit the results of the pipeline.
85
+
86
+ It can also be used to skip the select step of columns
87
+ from the pipeline.
88
+ """
89
+
90
+ RESULTS = object ()
91
+ OMIT = object ()
92
+
93
+ def __init__ (self , select : typing .Optional [list [str ]] = None ) -> None :
94
+ """
95
+ :param select: A list of additional columns to be selected from the pipeline.
96
+ or ResultsProjection.OMIT to skip the selection.
97
+ """
98
+ if select is self .OMIT :
99
+ self ._select = None
100
+ else :
101
+ self ._select = [self .RESULTS ]
102
+ if select :
103
+ self ._select .extend (select )
104
+
105
+ def is_empty (self ) -> bool :
106
+ """Check if the projection step should be skipped."""
107
+ return self ._select is None
108
+
109
+ def _expand (self , results : typing .Iterable [str ]) -> typing .Optional [list [str ]]:
110
+ if self ._select is None :
111
+ return None
112
+
113
+ selected_columns = self ._select
114
+
115
+ def _emit_projection () -> typing .Generator [str , None , None ]:
116
+ for item in selected_columns :
117
+ if item is self .RESULTS :
118
+ yield from results
119
+ elif isinstance (item , str ):
120
+ yield item
121
+
122
+ return list (_emit_projection ())
123
+
124
+
125
+ def translate (
126
+ table : ibis .Table ,
127
+ pipeline : ParsedPipeline ,
128
+ projection : ResultsProjection = ResultsProjection (),
129
+ ) -> ibis .Table :
80
130
"""Translate a pipeline into an Ibis expression.
81
131
82
132
This function takes a pipeline and a table and translates the pipeline
@@ -98,14 +148,18 @@ def translate(table: ibis.Table, pipeline: ParsedPipeline) -> ibis.Table:
98
148
translator .process ()
99
149
table = translator .mutated_table # Translator might return a new table.
100
150
_log_debug_end (translator , variables )
101
- return _projection_results (table , variables )
151
+ return _projection_results (table , variables , projection )
102
152
103
153
104
- def _projection_results (table : ibis .Table , variables : GraphVariables ) -> ibis .Table :
154
+ def _projection_results (
155
+ table : ibis .Table ,
156
+ variables : GraphVariables ,
157
+ projection : ResultsProjection = ResultsProjection (),
158
+ ) -> ibis .Table :
105
159
# As we pop out the variables as we use them
106
160
# the remaining ones are the values resulting from all
107
161
# graph branches.
108
- final_projections = {}
162
+ final_projections : dict [ str , typing . Any ] = {}
109
163
for key , value in variables .remaining ().items ():
110
164
if isinstance (value , dict ):
111
165
for field in value :
@@ -116,7 +170,11 @@ def _projection_results(table: ibis.Table, variables: GraphVariables) -> ibis.Ta
116
170
final_projections [colkey ] = colvalue
117
171
else :
118
172
final_projections [key ] = value
119
- return table .mutate (** final_projections ).select (final_projections .keys ())
173
+ query = table .mutate (** final_projections )
174
+ selection = projection ._expand (final_projections .keys ())
175
+ if selection is not None :
176
+ query = query .select (* selection )
177
+ return query
120
178
121
179
122
180
def _log_debug_start (translator : Translator , variables : GraphVariables ) -> None :
0 commit comments