change logic to use ast directly, rather than ast -> sql text -> ast again
@@ -29,8 +29,7 @@ if TYPE_CHECKING:
logger = logging.getLogger(__name__)
-def _is_exact_match(sql, sql_dialect=None):
- sql_syntax_tree = sqlglot.parse_one(sql, read=sql_dialect)
+def _is_exact_match(sql_syntax_tree):
signature = sqlglot_tree_signature(sql_syntax_tree)
if signature != "eq column column identifier identifier":
@@ -47,14 +46,13 @@ def _is_exact_match(sql, sql_dialect=None):
return False
-def _exact_match_colname(sql, sql_dialect=None):
+def _exact_match_colname(sql_syntax_tree):
cols = []
- syntax_tree = sqlglot.parse_one(sql.lower(), read=sql_dialect)
- for identifier in syntax_tree.find_all(Identifier):
+ for identifier in sql_syntax_tree.find_all(Identifier):
identifier.args["quoted"] = False
- for tup in syntax_tree.walk():
+ for tup in sql_syntax_tree.walk():
subtree = tup[0]
depth = getattr(subtree, "depth", None)
if depth == 2:
@@ -69,6 +67,12 @@ def _exact_match_colname(sql, sql_dialect=None):
return cols[0]
+def _get_sub_expressions(expr):
+ if isinstance(expr, sqlglot.exp.And):
+ return [*_get_sub_expressions(expr.left), *_get_sub_expressions(expr.right)]
+ return [expr]
+
+
def _default_m_values(num_levels):
proportion_exact_match = 0.95
remainder = 1 - proportion_exact_match
@@ -458,28 +462,32 @@ class ComparisonLevel:
if self._is_else_level:
return False
- sql_syntax_tree = sqlglot.parse_one(self._sql_condition, read=self._sql_dialect)
- # better to use the tree directly, but for now:
- sql_cnf = normalize(sql_syntax_tree).sql()
- sqls = re.split(r" and ", sql_cnf, flags=re.IGNORECASE)
- for sql in sqls:
- if not _is_exact_match(sql, self._sql_dialect):
+ sql_syntax_tree = sqlglot.parse_one(self._sql_condition.lower(), read=self._sql_dialect)
+ sql_cnf = normalize(sql_syntax_tree)
+
+ exprs = _get_sub_expressions(sql_cnf)
+ for expr in exprs:
+ print(f"\tprocessing {expr}")
+ if not _is_exact_match(expr):
return False
return True
@property
def _exact_match_colnames(self):
- sqls = re.split(r" and ", self._sql_condition, flags=re.IGNORECASE)
- for sql in sqls:
- if not _is_exact_match(sql):
+ sql_syntax_tree = sqlglot.parse_one(self._sql_condition.lower(), read=self._sql_dialect)
+ sql_cnf = normalize(sql_syntax_tree)
+
+ exprs = _get_sub_expressions(sql_cnf)
+ for expr in exprs:
+ if not _is_exact_match(expr):
raise ValueError(
"sql_cond not an exact match so can't get exact match column name"
)
cols = []
- for sql in sqls:
- col = _exact_match_colname(sql, sql_dialect=self._sql_dialect)
+ for expr in exprs:
+ col = _exact_match_colname(expr)
cols.append(col)
return cols
