|
1 | 1 | import functools |
| 2 | +from dataclasses import field |
2 | 3 | from datetime import datetime |
3 | 4 | import math |
4 | 5 | import sys |
|
15 | 16 | from runtype import dataclass |
16 | 17 | from typing_extensions import Self |
17 | 18 |
|
18 | | -from data_diff.queries.compiler import CompileError |
| 19 | +from data_diff.abcs.compiler import AbstractCompiler |
19 | 20 | from data_diff.queries.extras import ApplyFuncAndNormalizeAsString, Checksum, NormalizeAsString |
20 | 21 | from data_diff.utils import ArithString, is_uuid, join_iter, safezip |
21 | | -from data_diff.queries.api import Expr, Compiler, table, Select, SKIP, Explain, Code, this |
| 22 | +from data_diff.queries.api import Expr, table, Select, SKIP, Explain, Code, this |
22 | 23 | from data_diff.queries.ast_classes import Alias, BinOp, CaseWhen, Cast, Column, Commit, Concat, ConstantTable, Count, \ |
23 | 24 | CreateTable, Cte, \ |
24 | 25 | CurrentTimestamp, DropTable, Func, \ |
|
64 | 65 | cv_params = contextvars.ContextVar("params") |
65 | 66 |
|
66 | 67 |
|
| 68 | +class CompileError(Exception): |
| 69 | + pass |
| 70 | + |
| 71 | + |
| 72 | +# TODO: LATER: Resolve the circular imports of databases-compiler-dialects: |
| 73 | +# A database uses a compiler to render the SQL query. |
| 74 | +# The compiler delegates to a dialect. |
| 75 | +# The dialect renders the SQL. |
| 76 | +# AS IS: The dialect requires the db to normalize table paths — leading to the back-dependency. |
| 77 | +# TO BE: All the tables paths must be pre-normalized before SQL rendering. |
| 78 | +# Also: c.database.is_autocommit in render_commit(). |
| 79 | +# After this, the Compiler can cease referring Database/Dialect at all, |
| 80 | +# and be used only as a CompilingContext (a counter/data-bearing class). |
| 81 | +# As a result, it becomes low-level util, and the circular dependency auto-resolves. |
| 82 | +# Meanwhile, the easy fix is to simply move the Compiler here. |
| 83 | +@dataclass |
| 84 | +class Compiler(AbstractCompiler): |
| 85 | + """ |
| 86 | + Compiler bears the context for a single compilation. |
| 87 | +
|
| 88 | + There can be multiple compilation per app run. |
| 89 | + There can be multiple compilers in one compilation (with varying contexts). |
| 90 | + """ |
| 91 | + |
| 92 | + # Database is needed to normalize tables. Dialect is needed for recursive compilations. |
| 93 | + # In theory, it is many-to-many relations: e.g. a generic ODBC driver with multiple dialects. |
| 94 | + # In practice, we currently bind the dialects to the specific database classes. |
| 95 | + database: AbstractDatabase |
| 96 | + |
| 97 | + in_select: bool = False # Compilation runtime flag |
| 98 | + in_join: bool = False # Compilation runtime flag |
| 99 | + |
| 100 | + _table_context: List = field(default_factory=list) # List[ITable] |
| 101 | + _subqueries: Dict[str, Any] = field(default_factory=dict) # XXX not thread-safe |
| 102 | + root: bool = True |
| 103 | + |
| 104 | + _counter: List = field(default_factory=lambda: [0]) |
| 105 | + |
| 106 | + @property |
| 107 | + def dialect(self) -> AbstractDialect: |
| 108 | + return self.database.dialect |
| 109 | + |
| 110 | + # TODO: DEPRECATED: Remove once the dialect is used directly in all places. |
| 111 | + def compile(self, elem, params=None) -> str: |
| 112 | + return self.dialect.compile(self, elem, params) |
| 113 | + |
| 114 | + def new_unique_name(self, prefix="tmp"): |
| 115 | + self._counter[0] += 1 |
| 116 | + return f"{prefix}{self._counter[0]}" |
| 117 | + |
| 118 | + def new_unique_table_name(self, prefix="tmp") -> DbPath: |
| 119 | + self._counter[0] += 1 |
| 120 | + table_name = f"{prefix}{self._counter[0]}_{'%x'%random.randrange(2**32)}" |
| 121 | + return self.database.dialect.parse_table_name(table_name) |
| 122 | + |
| 123 | + def add_table_context(self, *tables: Sequence, **kw) -> Self: |
| 124 | + return self.replace(_table_context=self._table_context + list(tables), **kw) |
| 125 | + |
| 126 | + |
67 | 127 | def parse_table_name(t): |
68 | 128 | return tuple(t.split(".")) |
69 | 129 |
|
|
0 commit comments