-
Notifications
You must be signed in to change notification settings - Fork 141
Expand file tree
/
Copy pathsql_parser.py
More file actions
107 lines (84 loc) · 3.58 KB
/
Copy pathsql_parser.py
File metadata and controls
107 lines (84 loc) · 3.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
"""
Abstract SQL parser for the Feldera dbt adapter.
"""
from __future__ import annotations
from abc import ABC, abstractmethod
from enum import Enum
from typing import List, Set
class SqlIntent(Enum):
"""
How a SQL statement should be routed inside the Feldera dbt adapter,
via the ad-hoc DataFusion query endpoint, the pipeline API.
Members
-------
ADHOC_QUERY
``SELECT``, ``WITH``, ``UNION``, set operations, and anything
the parser does not recognise. Routed to Feldera's ad-hoc query
endpoint (DataFusion-backed) - the pipeline endpoint does not support
these statements.
PIPELINE_DDL
``CREATE``, ``DROP`` — structural changes collected by
the pipeline state manager and compiled as a single program.
DATA_INGRESS
``INSERT`` — row-level writes pushed via HTTP ingress. Both the ad-hoc
engine and the ingress API support ``INSERT``.
METADATA
Reserved for future catalog / ``INFORMATION_SCHEMA`` queries.
The Feldera Python SDK's Pipeline object exposes table and view
metadata (via ``tables()`` and ``views()``) which could serve as
a catalog source. See
https://docs.feldera.com/python/feldera.rest.html#module-feldera.rest.sql_table
NO_OP
Empty input, whitespace-only, or comment-only SQL.
"""
ADHOC_QUERY = "adhoc_query"
PIPELINE_DDL = "pipeline_ddl"
DATA_INGRESS = "data_ingress"
METADATA = "metadata"
NO_OP = "no_op"
class SqlParser(ABC):
"""Interface that every SQL parser backend must satisfy.
The adapter code programs against this ABC so that the concrete
parser (currently sqlglot) can be swapped without touching any
call-sites.
"""
@abstractmethod
def classify(self, sql: str) -> SqlIntent:
"""Classify *sql* and return its execution intent.
Must handle leading comments, empty strings, and whitespace
gracefully.
:param sql: Raw SQL text.
:return: The classified :class:`SqlIntent`.
"""
@abstractmethod
def extract_table_ddls(self, sql: str) -> List[str]:
"""Extract ``CREATE TABLE`` statements from a pipeline SQL program.
Must preserve the original SQL text verbatim (including any
dialect-specific extensions such as Feldera ``WITH`` clauses).
Returns each DDL as a string with a trailing semicolon.
:param sql: A full pipeline SQL program.
:return: A list of ``CREATE TABLE`` DDL strings.
"""
@abstractmethod
def extract_table_names(self, table_ddls: List[str]) -> Set[str]:
"""Return lowercase table names from a list of ``CREATE TABLE`` DDLs.
:param table_ddls: DDL strings, e.g. ``CREATE TABLE "foo" (…);``.
:return: A set of lowercase table names.
"""
@abstractmethod
def rename_in_ddl(self, ddl: str, old_name: str, new_name: str) -> str:
"""Rename the primary table/view identifier in a DDL statement.
Must preserve the original SQL text (no regeneration) to avoid
mangling dialect-specific syntax.
:param ddl: The full DDL statement string.
:param old_name: The current table/view name.
:param new_name: The desired new name.
:return: The rewritten DDL string.
"""
@abstractmethod
def sql_type_base_name(self, sql_type: str) -> str:
"""Return the uppercase base type name from a SQL type string.
For example ``"DECIMAL(10,2)"`` → ``"DECIMAL"``.
:param sql_type: A SQL data-type string.
:return: The uppercase base type name.
"""