Converts a query that contains references to nested types, to an equivalent query for for a flattened dataset. This class depends on the dataset flattener implementation.
| 36 | LOG = getLogger(__name__) |
| 37 | |
| 38 | class QueryFlattener(object): |
| 39 | '''Converts a query that contains references to nested types, to an equivalent query for |
| 40 | for a flattened dataset. This class depends on the dataset flattener implementation. |
| 41 | ''' |
| 42 | |
| 43 | def __init__(self): |
| 44 | self.clear_state() |
| 45 | |
| 46 | def clear_state(self): |
| 47 | self.tmp_alias = 0 |
| 48 | # Elements such as join clauses or columns that are not present in the original query. |
| 49 | self.for_flattening = set() |
| 50 | |
| 51 | def contains_jump(self, table_expr): |
| 52 | '''If some ancestor CollectionColumn or Table has an alias, but there is a closer |
| 53 | ancestor CollectionColumn without an alias, then this function will return True. |
| 54 | For example, suppose we have customer t1 and t1.orders.lineitems t2. If we call |
| 55 | this function with t2 CollectionColumn as parameter, it will return True. |
| 56 | ''' |
| 57 | result = False |
| 58 | while True: |
| 59 | if table_expr.owner.alias: |
| 60 | return result |
| 61 | if isinstance(table_expr.owner, Table): |
| 62 | # We reached the root and did not encounter an ancestor with an alias |
| 63 | return False |
| 64 | if isinstance(table_expr.owner, CollectionColumn): |
| 65 | # We encountered a CollectionColumn with no alias |
| 66 | result = True |
| 67 | table_expr = table_expr.owner |
| 68 | |
| 69 | def get_first_aliased_ancestor(self, table_expr): |
| 70 | '''Finds the first ancestor that is not a struct. It is returned if it has an alias, |
| 71 | otherwise, None is returned. |
| 72 | ''' |
| 73 | while True: |
| 74 | if table_expr.owner.alias: |
| 75 | return table_expr.owner |
| 76 | elif isinstance(table_expr.owner, StructColumn): |
| 77 | table_expr = table_expr.owner |
| 78 | else: |
| 79 | return None |
| 80 | |
| 81 | def flatten_join_clause(self, join_clause, query): |
| 82 | |
| 83 | if join_clause.is_lateral_join: |
| 84 | if isinstance(join_clause.table_expr, CollectionColumn): |
| 85 | # All laterally joined Collecitons are converted to an inline view. |
| 86 | join_clause.table_expr = self.convert_correlated_collection_to_inline_view( |
| 87 | join_clause.table_expr) |
| 88 | self.flatten(join_clause.table_expr.query, inner=True) |
| 89 | join_clause.boolean_expr = join_clause.boolean_expr or Boolean(True) |
| 90 | elif join_clause not in self.for_flattening: |
| 91 | if isinstance(join_clause.table_expr, CollectionColumn) and \ |
| 92 | self.contains_jump(join_clause.table_expr): |
| 93 | join_clause.table_expr = self.convert_correlated_collection_to_inline_view( |
| 94 | join_clause.table_expr) |
| 95 | if isinstance(join_clause.table_expr, CollectionColumn): |