5
5
from enum import Enum
6
6
from pathlib import Path
7
7
8
- from dbt .adapters .base import BaseRelation
9
8
from dbt .contracts .relation import RelationType
10
- from jinja2 import nodes
11
- from jinja2 .exceptions import UndefinedError
12
9
from pydantic import Field , validator
13
10
from sqlglot .helper import ensure_list
14
11
15
- from sqlmesh .core import constants as c
16
12
from sqlmesh .core import dialect as d
17
13
from sqlmesh .core .config .base import UpdateStrategy
18
14
from sqlmesh .core .model import Model
19
- from sqlmesh .dbt .adapter import ParsetimeAdapter
20
15
from sqlmesh .dbt .column import (
21
16
ColumnConfig ,
22
17
column_descriptions_to_sqlmesh ,
23
18
column_types_to_sqlmesh ,
24
- yaml_to_columns ,
25
19
)
26
20
from sqlmesh .dbt .common import DbtConfig , GeneralConfig , QuotingConfig , SqlStr
27
- from sqlmesh .dbt .context import DbtContext
28
21
from sqlmesh .utils import AttributeDict
29
22
from sqlmesh .utils .conversions import ensure_bool
30
- from sqlmesh .utils .date import date_dict
31
23
from sqlmesh .utils .errors import ConfigError
32
- from sqlmesh .utils .jinja import MacroReference , extract_macro_references
24
+ from sqlmesh .utils .jinja import MacroReference
33
25
from sqlmesh .utils .pydantic import PydanticModel
34
26
27
+ if t .TYPE_CHECKING :
28
+ from sqlmesh .dbt .context import DbtContext
29
+
30
+
35
31
BMC = t .TypeVar ("BMC" , bound = "BaseModelConfig" )
36
32
37
33
@@ -43,21 +39,17 @@ class Dependencies(PydanticModel):
43
39
macros: The references to macros
44
40
sources: The "source_name.table_name" for source tables used
45
41
refs: The table_name for models used
46
- variables: The names of variables used, mapped to a flag that indicates whether their
47
- definition is optional or not.
48
42
"""
49
43
50
44
macros : t .Set [MacroReference ] = set ()
51
45
sources : t .Set [str ] = set ()
52
46
refs : t .Set [str ] = set ()
53
- variables : t .Set [str ] = set ()
54
47
55
48
def union (self , other : Dependencies ) -> Dependencies :
56
49
dependencies = Dependencies ()
57
50
dependencies .macros = self .macros | other .macros
58
51
dependencies .sources = self .sources | other .sources
59
52
dependencies .refs = self .refs | other .refs
60
- dependencies .variables = self .variables | other .variables
61
53
62
54
return dependencies
63
55
@@ -101,7 +93,6 @@ class BaseModelConfig(GeneralConfig):
101
93
storage_format: The storage format used to store the physical table, only applicable in certain engines.
102
94
(eg. 'parquet')
103
95
path: The file path of the model
104
- target_schema: The schema for the profile target
105
96
dependencies: The macro, source, var, and ref dependencies used to execute the model and its hooks
106
97
database: Database the model is stored in
107
98
schema: Custom schema name added to the model schema name
@@ -119,12 +110,11 @@ class BaseModelConfig(GeneralConfig):
119
110
stamp : t .Optional [str ] = None
120
111
storage_format : t .Optional [str ] = None
121
112
path : Path = Path ()
122
- target_schema : str = ""
123
113
dependencies : Dependencies = Dependencies ()
124
114
125
115
# DBT configuration fields
116
+ schema_ : str = Field ("" , alias = "schema" )
126
117
database : t .Optional [str ] = None
127
- schema_ : t .Optional [str ] = Field (None , alias = "schema" )
128
118
alias : t .Optional [str ] = None
129
119
pre_hook : t .List [Hook ] = Field ([], alias = "pre-hook" )
130
120
post_hook : t .List [Hook ] = Field ([], alias = "post-hook" )
@@ -156,13 +146,6 @@ def _validate_bool(cls, v: str) -> bool:
156
146
def _validate_grants (cls , v : t .Dict [str , str ]) -> t .Dict [str , t .List [str ]]:
157
147
return {key : ensure_list (value ) for key , value in v .items ()}
158
148
159
- @validator ("columns" , pre = True )
160
- def _validate_columns (cls , v : t .Any ) -> t .Dict [str , ColumnConfig ]:
161
- if isinstance (v , dict ) and all (isinstance (col , ColumnConfig ) for col in v .values ()):
162
- return v
163
-
164
- return yaml_to_columns (v )
165
-
166
149
_FIELD_UPDATE_STRATEGY : t .ClassVar [t .Dict [str , UpdateStrategy ]] = {
167
150
** GeneralConfig ._FIELD_UPDATE_STRATEGY ,
168
151
** {
@@ -197,7 +180,7 @@ def table_schema(self) -> str:
197
180
"""
198
181
Get the full schema name
199
182
"""
200
- return "_" . join ( part for part in ( self .target_schema , self . schema_ ) if part )
183
+ return self .schema_
201
184
202
185
@property
203
186
def table_name (self ) -> str :
@@ -293,21 +276,6 @@ def sqlmesh_model_kwargs(self, model_context: DbtContext) -> t.Dict[str, t.Any]:
293
276
** optional_kwargs ,
294
277
}
295
278
296
- def render_config (self : BMC , context : DbtContext ) -> BMC :
297
- rendered = super ().render_config (context )
298
- rendered = ModelSqlRenderer (context , rendered ).enriched_config
299
-
300
- rendered_dependencies = rendered .dependencies
301
- for dependency in rendered_dependencies .refs :
302
- model = context .models .get (dependency )
303
- if model and model .materialized == Materialization .EPHEMERAL :
304
- rendered .dependencies = rendered .dependencies .union (
305
- model .render_config (context ).dependencies
306
- )
307
- rendered .dependencies .refs .discard (dependency )
308
-
309
- return rendered
310
-
311
279
@abstractmethod
312
280
def to_sqlmesh (self , context : DbtContext ) -> Model :
313
281
"""Convert DBT model into sqlmesh Model"""
@@ -338,135 +306,5 @@ def _context_for_dependencies(
338
306
model_context .sources = sources
339
307
model_context .seeds = seeds
340
308
model_context .models = models
341
- model_context .variables = {
342
- name : value
343
- for name , value in context .variables .items ()
344
- if name in dependencies .variables
345
- }
346
309
347
310
return model_context
348
-
349
-
350
- class ModelSqlRenderer (t .Generic [BMC ]):
351
- def __init__ (self , context : DbtContext , config : BMC ):
352
- from sqlmesh .dbt .builtin import create_builtin_globals
353
-
354
- self .context = context
355
- self .config = config
356
-
357
- self ._captured_dependencies : Dependencies = Dependencies ()
358
- self ._rendered_sql : t .Optional [str ] = None
359
- self ._enriched_config : BMC = config .copy ()
360
-
361
- self ._jinja_globals = create_builtin_globals (
362
- jinja_macros = context .jinja_macros ,
363
- jinja_globals = {
364
- ** context .jinja_globals ,
365
- ** date_dict (c .EPOCH , c .EPOCH , c .EPOCH ),
366
- "config" : lambda * args , ** kwargs : "" ,
367
- "ref" : self ._ref ,
368
- "var" : self ._var ,
369
- "source" : self ._source ,
370
- "this" : self .config .relation_info ,
371
- "model" : self .config .model_function (),
372
- "schema" : self .config .table_schema ,
373
- },
374
- engine_adapter = None ,
375
- )
376
-
377
- # Set the adapter separately since it requires jinja globals to passed into it.
378
- self ._jinja_globals ["adapter" ] = ModelSqlRenderer .TrackingAdapter (
379
- self ,
380
- context .jinja_macros ,
381
- jinja_globals = self ._jinja_globals ,
382
- dialect = context .engine_adapter .dialect if context .engine_adapter else "" ,
383
- )
384
-
385
- self .jinja_env = self .context .jinja_macros .build_environment (** self ._jinja_globals )
386
-
387
- @property
388
- def enriched_config (self ) -> BMC :
389
- if self ._rendered_sql is None :
390
- self ._enriched_config = self ._update_with_sql_config (self ._enriched_config )
391
- self ._enriched_config .dependencies = Dependencies (
392
- macros = extract_macro_references (self ._enriched_config .all_sql )
393
- )
394
- self .render ()
395
- self ._enriched_config .dependencies = self ._enriched_config .dependencies .union (
396
- self ._captured_dependencies
397
- )
398
- return self ._enriched_config
399
-
400
- def render (self ) -> str :
401
- if self ._rendered_sql is None :
402
- try :
403
- self ._rendered_sql = self .jinja_env .from_string (
404
- self ._enriched_config .all_sql
405
- ).render ()
406
- except UndefinedError as e :
407
- raise ConfigError (e .message )
408
- return self ._rendered_sql
409
-
410
- def _update_with_sql_config (self , config : BMC ) -> BMC :
411
- def _extract_value (node : t .Any ) -> t .Any :
412
- if not isinstance (node , nodes .Node ):
413
- return node
414
- if isinstance (node , nodes .Const ):
415
- return _extract_value (node .value )
416
- if isinstance (node , nodes .TemplateData ):
417
- return _extract_value (node .data )
418
- if isinstance (node , nodes .List ):
419
- return [_extract_value (val ) for val in node .items ]
420
- if isinstance (node , nodes .Dict ):
421
- return {_extract_value (pair .key ): _extract_value (pair .value ) for pair in node .items }
422
- if isinstance (node , nodes .Tuple ):
423
- return tuple (_extract_value (val ) for val in node .items )
424
-
425
- return self .jinja_env .from_string (nodes .Template ([nodes .Output ([node ])])).render ()
426
-
427
- for call in self .jinja_env .parse (self ._enriched_config .sql_embedded_config ).find_all (
428
- nodes .Call
429
- ):
430
- if not isinstance (call .node , nodes .Name ) or call .node .name != "config" :
431
- continue
432
- config = config .update_with (
433
- {kwarg .key : _extract_value (kwarg .value ) for kwarg in call .kwargs }
434
- )
435
-
436
- return config
437
-
438
- def _ref (self , package_name : str , model_name : t .Optional [str ] = None ) -> BaseRelation :
439
- self ._captured_dependencies .refs .add (package_name )
440
- return BaseRelation .create ()
441
-
442
- def _var (self , name : str , default : t .Optional [str ] = None ) -> t .Any :
443
- if default is None and name not in self .context .variables :
444
- raise ConfigError (
445
- f"Variable '{ name } ' was not found for model '{ self .config .table_name } '."
446
- )
447
- self ._captured_dependencies .variables .add (name )
448
- return self .context .variables .get (name , default )
449
-
450
- def _source (self , source_name : str , table_name : str ) -> BaseRelation :
451
- full_name = "." .join ([source_name , table_name ])
452
- self ._captured_dependencies .sources .add (full_name )
453
- return BaseRelation .create ()
454
-
455
- class TrackingAdapter (ParsetimeAdapter ):
456
- def __init__ (self , outer_self : ModelSqlRenderer , * args : t .Any , ** kwargs : t .Any ):
457
- super ().__init__ (* args , ** kwargs )
458
- self .outer_self = outer_self
459
- self .context = outer_self .context
460
-
461
- def dispatch (self , name : str , package : t .Optional [str ] = None ) -> t .Callable :
462
- macros = (
463
- self .context .jinja_macros .packages .get (package , {})
464
- if package is not None
465
- else self .context .jinja_macros .root_macros
466
- )
467
- for target_name in macros :
468
- if target_name .endswith (f"__{ name } " ):
469
- self .outer_self ._captured_dependencies .macros .add (
470
- MacroReference (package = package , name = target_name )
471
- )
472
- return super ().dispatch (name , package = package )
0 commit comments