|
22 | 22 | from typing import Callable, Mapping, TypeVar
|
23 | 23 |
|
24 | 24 | from bigframes import dtypes
|
25 |
| -from bigframes.core import expression |
| 25 | +from bigframes.core import expression, window_spec |
26 | 26 | import bigframes.core.identifiers as ids
|
27 | 27 | import bigframes.operations.aggregations as agg_ops
|
28 | 28 |
|
@@ -149,3 +149,68 @@ def replace_args(
|
149 | 149 | self, larg: expression.Expression, rarg: expression.Expression
|
150 | 150 | ) -> BinaryAggregation:
|
151 | 151 | return BinaryAggregation(self.op, larg, rarg)
|
| 152 | + |
| 153 | + |
| 154 | +@dataclasses.dataclass(frozen=True) |
| 155 | +class WindowExpression(expression.Expression): |
| 156 | + analytic_expr: Aggregation |
| 157 | + window: window_spec.WindowSpec |
| 158 | + |
| 159 | + @property |
| 160 | + def column_references(self) -> typing.Tuple[ids.ColumnId, ...]: |
| 161 | + return tuple( |
| 162 | + itertools.chain.from_iterable( |
| 163 | + map(lambda x: x.column_references, self.inputs) |
| 164 | + ) |
| 165 | + ) |
| 166 | + |
| 167 | + @functools.cached_property |
| 168 | + def is_resolved(self) -> bool: |
| 169 | + return all(input.is_resolved for input in self.inputs) |
| 170 | + |
| 171 | + @property |
| 172 | + def output_type(self) -> dtypes.ExpressionType: |
| 173 | + return self.analytic_expr.output_type |
| 174 | + |
| 175 | + @property |
| 176 | + def inputs( |
| 177 | + self, |
| 178 | + ) -> typing.Tuple[expression.Expression, ...]: |
| 179 | + return (self.analytic_expr, *self.window.expressions) |
| 180 | + |
| 181 | + @property |
| 182 | + def free_variables(self) -> typing.Tuple[str, ...]: |
| 183 | + return tuple( |
| 184 | + itertools.chain.from_iterable(map(lambda x: x.free_variables, self.inputs)) |
| 185 | + ) |
| 186 | + |
| 187 | + @property |
| 188 | + def is_const(self) -> bool: |
| 189 | + return all(child.is_const for child in self.inputs) |
| 190 | + |
| 191 | + def transform_children( |
| 192 | + self: WindowExpression, |
| 193 | + t: Callable[[expression.Expression], expression.Expression], |
| 194 | + ) -> WindowExpression: |
| 195 | + return WindowExpression( |
| 196 | + self.analytic_expr.transform_children(t), |
| 197 | + self.window.transform_exprs(t), |
| 198 | + ) |
| 199 | + |
| 200 | + def bind_variables( |
| 201 | + self: WindowExpression, |
| 202 | + bindings: Mapping[str, expression.Expression], |
| 203 | + allow_partial_bindings: bool = False, |
| 204 | + ) -> WindowExpression: |
| 205 | + return self.transform_children( |
| 206 | + lambda x: x.bind_variables(bindings, allow_partial_bindings) |
| 207 | + ) |
| 208 | + |
| 209 | + def bind_refs( |
| 210 | + self: WindowExpression, |
| 211 | + bindings: Mapping[ids.ColumnId, expression.Expression], |
| 212 | + allow_partial_bindings: bool = False, |
| 213 | + ) -> WindowExpression: |
| 214 | + return self.transform_children( |
| 215 | + lambda x: x.bind_refs(bindings, allow_partial_bindings) |
| 216 | + ) |
0 commit comments