21
21
from data_diff .queries .extras import ApplyFuncAndNormalizeAsString , Checksum , NormalizeAsString
22
22
from data_diff .utils import ArithString , is_uuid , join_iter , safezip
23
23
from data_diff .queries .api import Expr , table , Select , SKIP , Explain , Code , this
24
- from data_diff .queries .ast_classes import Alias , BinOp , CaseWhen , Cast , Column , Commit , Concat , ConstantTable , Count , \
25
- CreateTable , Cte , \
26
- CurrentTimestamp , DropTable , Func , \
27
- GroupBy , \
28
- ITable , In , InsertToTable , IsDistinctFrom , \
29
- Join , \
30
- Param , \
31
- Random , \
32
- Root , TableAlias , TableOp , TablePath , \
33
- TimeTravel , TruncateTable , UnaryOp , WhenThen , _ResolveColumn
24
+ from data_diff .queries .ast_classes import (
25
+ Alias ,
26
+ BinOp ,
27
+ CaseWhen ,
28
+ Cast ,
29
+ Column ,
30
+ Commit ,
31
+ Concat ,
32
+ ConstantTable ,
33
+ Count ,
34
+ CreateTable ,
35
+ Cte ,
36
+ CurrentTimestamp ,
37
+ DropTable ,
38
+ Func ,
39
+ GroupBy ,
40
+ ITable ,
41
+ In ,
42
+ InsertToTable ,
43
+ IsDistinctFrom ,
44
+ Join ,
45
+ Param ,
46
+ Random ,
47
+ Root ,
48
+ TableAlias ,
49
+ TableOp ,
50
+ TablePath ,
51
+ TimeTravel ,
52
+ TruncateTable ,
53
+ UnaryOp ,
54
+ WhenThen ,
55
+ _ResolveColumn ,
56
+ )
34
57
from data_diff .abcs .database_types import (
35
58
Array ,
36
59
Struct ,
@@ -67,17 +90,11 @@ class CompileError(Exception):
67
90
pass
68
91
69
92
70
- # TODO: LATER: Resolve the circular imports of databases-compiler-dialects:
71
- # A database uses a compiler to render the SQL query.
72
- # The compiler delegates to a dialect.
73
- # The dialect renders the SQL.
74
- # AS IS: The dialect requires the db to normalize table paths — leading to the back-dependency.
75
- # TO BE: All the tables paths must be pre-normalized before SQL rendering.
76
- # Also: c.database.is_autocommit in render_commit().
77
- # After this, the Compiler can cease referring Database/Dialect at all,
78
- # and be used only as a CompilingContext (a counter/data-bearing class).
79
- # As a result, it becomes low-level util, and the circular dependency auto-resolves.
80
- # Meanwhile, the easy fix is to simply move the Compiler here.
93
+ # TODO: remove once switched to attrs, where ForwardRef[]/strings are resolved.
94
+ class _RuntypeHackToFixCicularRefrencedDatabase :
95
+ dialect : "BaseDialect"
96
+
97
+
81
98
@dataclass
82
99
class Compiler (AbstractCompiler ):
83
100
"""
@@ -90,7 +107,7 @@ class Compiler(AbstractCompiler):
90
107
# Database is needed to normalize tables. Dialect is needed for recursive compilations.
91
108
# In theory, it is many-to-many relations: e.g. a generic ODBC driver with multiple dialects.
92
109
# In practice, we currently bind the dialects to the specific database classes.
93
- database : "Database"
110
+ database : _RuntypeHackToFixCicularRefrencedDatabase
94
111
95
112
in_select : bool = False # Compilation runtime flag
96
113
in_join : bool = False # Compilation runtime flag
@@ -102,7 +119,7 @@ class Compiler(AbstractCompiler):
102
119
_counter : List = field (default_factory = lambda : [0 ])
103
120
104
121
@property
105
- def dialect (self ) -> "Dialect " :
122
+ def dialect (self ) -> "BaseDialect " :
106
123
return self .database .dialect
107
124
108
125
# TODO: DEPRECATED: Remove once the dialect is used directly in all places.
@@ -223,7 +240,6 @@ class BaseDialect(abc.ABC):
223
240
SUPPORTS_PRIMARY_KEY = False
224
241
SUPPORTS_INDEXES = False
225
242
TYPE_CLASSES : Dict [str , type ] = {}
226
- MIXINS = frozenset ()
227
243
228
244
PLACEHOLDER_TABLE = None # Used for Oracle
229
245
@@ -414,7 +430,9 @@ def render_checksum(self, c: Compiler, elem: Checksum) -> str:
414
430
415
431
def render_concat (self , c : Compiler , elem : Concat ) -> str :
416
432
# We coalesce because on some DBs (e.g. MySQL) concat('a', NULL) is NULL
417
- items = [f"coalesce({ self .compile (c , Code (self .to_string (self .compile (c , expr ))))} , '<null>')" for expr in elem .exprs ]
433
+ items = [
434
+ f"coalesce({ self .compile (c , Code (self .to_string (self .compile (c , expr ))))} , '<null>')" for expr in elem .exprs
435
+ ]
418
436
assert items
419
437
if len (items ) == 1 :
420
438
return items [0 ]
@@ -559,17 +577,15 @@ def render_groupby(self, c: Compiler, elem: GroupBy) -> str:
559
577
columns = columns ,
560
578
group_by_exprs = [Code (k ) for k in keys ],
561
579
having_exprs = elem .having_exprs ,
562
- )
580
+ ),
563
581
)
564
582
565
583
keys_str = ", " .join (keys )
566
584
columns_str = ", " .join (self .compile (c , x ) for x in columns )
567
585
having_str = (
568
586
" HAVING " + " AND " .join (map (compile_fn , elem .having_exprs )) if elem .having_exprs is not None else ""
569
587
)
570
- select = (
571
- f"SELECT { columns_str } FROM { self .compile (c .replace (in_select = True ), elem .table )} GROUP BY { keys_str } { having_str } "
572
- )
588
+ select = f"SELECT { columns_str } FROM { self .compile (c .replace (in_select = True ), elem .table )} GROUP BY { keys_str } { having_str } "
573
589
574
590
if c .in_select :
575
591
select = f"({ select } ) { c .new_unique_name ()} "
@@ -601,7 +617,7 @@ def render_timetravel(self, c: Compiler, elem: TimeTravel) -> str:
601
617
# TODO: why is it c.? why not self? time-trvelling is the dialect's thing, isnt't it?
602
618
c .time_travel (
603
619
elem .table , before = elem .before , timestamp = elem .timestamp , offset = elem .offset , statement = elem .statement
604
- )
620
+ ),
605
621
)
606
622
607
623
def render_createtable (self , c : Compiler , elem : CreateTable ) -> str :
@@ -768,18 +784,6 @@ def _convert_db_precision_to_digits(self, p: int) -> int:
768
784
# See: https://en.wikipedia.org/wiki/Single-precision_floating-point_format
769
785
return math .floor (math .log (2 ** p , 10 ))
770
786
771
- @classmethod
772
- def load_mixins (cls , * abstract_mixins ) -> Self :
773
- "Load a list of mixins that implement the given abstract mixins"
774
- mixins = {m for m in cls .MIXINS if issubclass (m , abstract_mixins )}
775
-
776
- class _DialectWithMixins (cls , * mixins , * abstract_mixins ):
777
- pass
778
-
779
- _DialectWithMixins .__name__ = cls .__name__
780
- return _DialectWithMixins ()
781
-
782
-
783
787
@property
784
788
@abstractmethod
785
789
def name (self ) -> str :
@@ -822,7 +826,7 @@ def __getitem__(self, i):
822
826
return self .rows [i ]
823
827
824
828
825
- class Database (abc .ABC ):
829
+ class Database (abc .ABC , _RuntypeHackToFixCicularRefrencedDatabase ):
826
830
"""Base abstract class for databases.
827
831
828
832
Used for providing connection code and implementation specific SQL utilities.
0 commit comments