• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

georgia-tech-db / eva / #754

04 Sep 2023 09:54PM UTC coverage: 74.807% (-5.5%) from 80.336%
#754

push

circle-ci

jiashenC
update case

8727 of 11666 relevant lines covered (74.81%)

0.75 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.32
/evadb/parser/lark_visitor/_table_sources.py
1
# coding=utf-8
2
# Copyright 2018-2023 EvaDB
3
#
4
# Licensed under the Apache License, Version 2.0 (the "License");
5
# you may not use this file except in compliance with the License.
6
# You may obtain a copy of the License at
7
#
8
#     http://www.apache.org/licenses/LICENSE-2.0
9
#
10
# Unless required by applicable law or agreed to in writing, software
11
# distributed under the License is distributed on an "AS IS" BASIS,
12
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
# See the License for the specific language governing permissions and
14
# limitations under the License.
15

16
from lark import Token, Tree
1✔
17

18
from evadb.expression.tuple_value_expression import TupleValueExpression
1✔
19
from evadb.parser.select_statement import SelectStatement
1✔
20
from evadb.parser.table_ref import Alias, JoinNode, TableRef, TableValuedExpression
1✔
21
from evadb.parser.types import JoinType
1✔
22
from evadb.utils.logging_manager import logger
1✔
23

24
##################################################################
25
# TABLE SOURCES
26
##################################################################
27

28

29
class TableSources:
1✔
30
    def select_elements(self, tree):
1✔
31
        kind = tree.children[0]
1✔
32
        if kind == "*":
1✔
33
            select_list = [TupleValueExpression(name="*")]
1✔
34
        else:
35
            select_list = []
1✔
36
            for child in tree.children:
1✔
37
                element = self.visit(child)
1✔
38
                select_list.append(element)
1✔
39
        return select_list
1✔
40

41
    def table_sources(self, tree):
1✔
42
        return self.visit(tree.children[0])
1✔
43

44
    def table_source(self, tree):
1✔
45
        left_node = None
1✔
46
        join_nodes = []
1✔
47

48
        for child in tree.children:
1✔
49
            if isinstance(child, Tree):
1✔
50
                if child.data == "table_source_item_with_param":
1✔
51
                    left_node = self.visit(child)
1✔
52
                    join_nodes = [left_node]
1✔
53
                elif child.data.endswith("join"):
1✔
54
                    table = self.visit(child)
1✔
55
                    join_nodes.append(table)
1✔
56

57
        num_table_joins = len(join_nodes)
1✔
58

59
        # Join Nodes
60
        if num_table_joins > 1:
1✔
61
            # Add Join nodes -> left deep tree
62
            # t1, t2, t3 -> j2 ( j1 ( t1, t2 ), t3 )
63
            for i in range(num_table_joins - 1):
1✔
64
                join_nodes[i + 1].join_node.left = join_nodes[i]
1✔
65

66
            return join_nodes[-1]
1✔
67
        else:
68
            return join_nodes[0]
1✔
69

70
    def table_source_item_with_param(self, tree):
1✔
71
        sample_freq = None
1✔
72
        sample_type = None
1✔
73
        alias = None
1✔
74
        table = None
1✔
75
        chunk_params = {}
1✔
76

77
        for child in tree.children:
1✔
78
            if isinstance(child, Tree):
1✔
79
                if child.data == "table_source_item":
1✔
80
                    table = self.visit(child)
1✔
81
                elif child.data == "sample_params":
1✔
82
                    sample_type, sample_freq = self.visit(child)
1✔
83
                elif child.data == "chunk_params":
1✔
84
                    chunk_params = self.visit(child)
×
85
                elif child.data == "alias_clause":
1✔
86
                    alias = self.visit(child)
1✔
87

88
        return TableRef(
1✔
89
            table=table,
90
            alias=alias,
91
            sample_freq=sample_freq,
92
            sample_type=sample_type,
93
            chunk_params=chunk_params,
94
        )
95

96
    def table_source_item(self, tree):
1✔
97
        return self.visit(tree.children[0])
1✔
98

99
    def query_specification(self, tree):
1✔
100
        target_list = None
1✔
101
        from_clause = None
1✔
102
        where_clause = None
1✔
103
        groupby_clause = None
1✔
104
        orderby_clause = None
1✔
105
        limit_count = None
1✔
106

107
        # first child is a SELECT terminal token
108
        for child in tree.children[1:]:
1✔
109
            try:
1✔
110
                if child.data == "select_elements":
1✔
111
                    target_list = self.visit(child)
1✔
112
                elif child.data == "from_clause":
1✔
113
                    clause = self.visit(child)
1✔
114
                    from_clause = clause.get("from", None)
1✔
115
                    where_clause = clause.get("where", None)
1✔
116
                    groupby_clause = clause.get("groupby", None)
1✔
117
                elif child.data == "order_by_clause":
1✔
118
                    orderby_clause = self.visit(child)
1✔
119
                elif child.data == "limit_clause":
1✔
120
                    limit_count = self.visit(child)
1✔
121

122
            except BaseException as e:
123
                # stop parsing something bad happened
124
                logger.error(
125
                    "Error while parsing \
126
                                QuerySpecification"
127
                )
128
                raise e
129

130
        select_stmt = SelectStatement(
1✔
131
            target_list,
132
            from_clause,
133
            where_clause,
134
            groupby_clause=groupby_clause,
135
            orderby_list=orderby_clause,
136
            limit_count=limit_count,
137
        )
138

139
        return select_stmt
1✔
140

141
    # TODO ACTION
142
    def from_clause(self, tree):
1✔
143
        from_table = None
1✔
144
        where_clause = None
1✔
145
        groupby_clause = None
1✔
146
        # TODO ACTION Group By
147

148
        for child in tree.children:
1✔
149
            if isinstance(child, Tree):
1✔
150
                if child.data == "table_sources":
1✔
151
                    from_table = self.visit(child)
1✔
152
                elif child.data == "where_expr":
1✔
153
                    where_clause = self.visit(child)
1✔
154
                elif child.data == "group_by_item":
1✔
155
                    groupby_item = self.visit(child)
1✔
156
                    # TODO: Support multiple group by columns
157
                    groupby_clause = groupby_item
1✔
158

159
        return {"from": from_table, "where": where_clause, "groupby": groupby_clause}
1✔
160

161
    # Join
162
    def inner_join(self, tree):
1✔
163
        table = None
1✔
164
        join_predicate = None
1✔
165

166
        for child in tree.children:
1✔
167
            if isinstance(child, Tree):
1✔
168
                if child.data == "table_source_item_with_param":
1✔
169
                    table = self.visit(child)
1✔
170
                elif child.data.endswith("expression"):
1✔
171
                    join_predicate = self.visit(child)
1✔
172

173
        return TableRef(
1✔
174
            JoinNode(
175
                None,
176
                table,
177
                predicate=join_predicate,
178
                join_type=JoinType.INNER_JOIN,
179
            )
180
        )
181

182
    def lateral_join(self, tree):
1✔
183
        tve = None
1✔
184
        alias = None
1✔
185

186
        for child in tree.children:
1✔
187
            # Rules
188
            if isinstance(child, Tree):
1✔
189
                if child.data == "table_valued_function":
1✔
190
                    tve = self.visit(child)
1✔
191
                elif child.data == "alias_clause":
1✔
192
                    alias = self.visit(child)
1✔
193

194
        if alias is None:
1✔
195
            err_msg = f"TableValuedFunction {tve.func_expr.name} should have alias."
×
196
            logger.error(err_msg)
×
197
            raise SyntaxError(err_msg)
198

199
        join_type = JoinType.LATERAL_JOIN
1✔
200
        return TableRef(JoinNode(None, TableRef(tve, alias=alias), join_type=join_type))
1✔
201

202
    def table_valued_function(self, tree):
1✔
203
        func_expr = None
1✔
204
        has_unnest = False
1✔
205

206
        for child in tree.children:
1✔
207
            if isinstance(child, Tree):
1✔
208
                if child.data.endswith("function_call"):
1✔
209
                    func_expr = self.visit(child)
1✔
210
            elif child.lower() == "unnest":
×
211
                has_unnest = True
×
212

213
        return TableValuedExpression(func_expr, do_unnest=has_unnest)
1✔
214

215
    def subquery_table_source_item(self, tree):
1✔
216
        subquery_table_source_item = None
1✔
217
        for child in tree.children:
1✔
218
            if isinstance(child, Tree):
1✔
219
                if child.data == "simple_select":
1✔
220
                    subquery_table_source_item = self.visit(child)
1✔
221

222
        return subquery_table_source_item
1✔
223

224
    def union_select(self, tree):
1✔
225
        right_select_statement = None
1✔
226
        union_all = False
1✔
227

228
        statement_id = 0
1✔
229
        for child in tree.children:
1✔
230
            if isinstance(child, Tree):
1✔
231
                if child.data.endswith("select"):
1✔
232
                    if statement_id == 0:
1✔
233
                        left_select_statement = self.visit(child)
1✔
234
                    elif statement_id == 1:
1✔
235
                        right_select_statement = self.visit(child)
1✔
236
                    statement_id += 1
1✔
237
            # Token
238
            elif isinstance(child, Token):
1✔
239
                if child.value == "ALL":
1✔
240
                    union_all = True
1✔
241

242
        # FIX: Complex logic
243
        if left_select_statement is not None:
1✔
244
            assert (
1✔
245
                left_select_statement.union_link is None
246
            ), "Checking for the correctness of the operator"
247

248
            # We need to check the correctness for union operator.
249
            # Here when parsing or later operator, plan?
250
            left_select_statement.union_link = right_select_statement
1✔
251

252
            if union_all is False:
1✔
253
                left_select_statement.union_all = False
1✔
254
            else:
255
                left_select_statement.union_all = True
1✔
256

257
        return left_select_statement
1✔
258

259
    def group_by_item(self, tree):
1✔
260
        expr = None
1✔
261

262
        for child in tree.children:
1✔
263
            if isinstance(child, Tree):
1✔
264
                if child.data.endswith("expression"):
1✔
265
                    expr = self.visit(child)
1✔
266

267
        return expr
1✔
268

269
    def alias_clause(self, tree):
1✔
270
        alias_name = None
1✔
271
        column_list = []
1✔
272

273
        for child in tree.children:
1✔
274
            if isinstance(child, Tree):
1✔
275
                if child.data == "uid":
1✔
276
                    alias_name = self.visit(child)
1✔
277
                elif child.data == "uid_list":
×
278
                    column_list = self.visit(child)
×
279
                    column_list = [col.name for col in column_list]
×
280

281
        return Alias(alias_name, column_list)
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc