1- from dataclasses import dataclass , field
2- from typing import (
3- Union ,
4- Iterable ,
5- Dict ,
6- Mapping ,
7- Set ,
8- Any ,
9- Optional ,
10- )
1+ import typing as t
112import logging
123
13- import sqlglot
14- from sqlglot import exp
15- from sqlmesh .core .context import Context
16- from sqlmesh .core .console import Console
17- from sqlmesh .core .model import Model
184from dagster import (
19- AssetDep ,
205 multi_asset ,
21- AssetCheckResult ,
22- AssetMaterialization ,
23- AssetOut ,
24- AssetKey ,
256 RetryPolicy ,
267)
27- from dagster ._core .definitions .asset_dep import CoercibleToAssetDep
8+
9+ from dagster_sqlmesh .controller .dagster import DagsterSQLMeshController
10+ from dagster_sqlmesh .translator import SQLMeshDagsterTranslator
2811
2912from .config import SQLMeshContextConfig
30- from .console import EventConsole , ConsoleEventHandler , DebugEventConsole
31- from .utils import sqlmesh_model_name_to_key
32- from .context import DagsterSQLMeshContext
3313
3414logger = logging .getLogger (__name__ )
3515
3616
37- MultiAssetResponse = Iterable [Union [AssetCheckResult , AssetMaterialization ]]
38-
39-
40- @dataclass (kw_only = True )
41- class SQLMeshParsedFQN :
42- catalog : str
43- schema : str
44- view_name : str
45-
46-
47- def parse_fqn (fqn : str ):
48- split_fqn = fqn .split ("." )
49-
50- # Remove any quotes
51- split_fqn = list (map (lambda a : a .strip ("'\" " ), split_fqn ))
52- return SQLMeshParsedFQN (
53- catalog = split_fqn [0 ], schema = split_fqn [1 ], view_name = split_fqn [2 ]
54- )
55-
56-
57- @dataclass (kw_only = True )
58- class SQLMeshModelDep :
59- fqn : str
60- model : Optional [Model ] = None
61-
62- def parse_fqn (self ):
63- return parse_fqn (self .fqn )
64-
65-
66- @dataclass (kw_only = True )
67- class SQLMeshMultiAssetOptions :
68- outs : Dict [str , AssetOut ] = field (default_factory = lambda : {})
69- deps : Iterable [CoercibleToAssetDep ] = field (default_factory = lambda : {})
70- internal_asset_deps : Dict [str , Set [AssetKey ]] = field (default_factory = lambda : {})
71-
72-
73- class SQLMeshDagsterTranslator :
74- def get_asset_key_from_model (self , context : Context , model : Model ) -> AssetKey :
75- return AssetKey (model .view_name )
76-
77- def get_asset_key_fqn (self , context : Context , fqn : str ) -> AssetKey :
78- table = self .get_fqn_to_table (context , fqn )
79- return AssetKey (table .name )
80-
81- def get_fqn_to_table (self , context : Context , fqn : str ) -> exp .Table :
82- dialect = self .get_context_dialect (context )
83- return sqlglot .to_table (fqn , dialect = dialect )
84-
85- def get_context_dialect (self , context : Context ) -> str :
86- return context .engine_adapter .dialect
87-
88- # def get_asset_deps(
89- # self, context: Context, model: Model, deps: List[SQLMeshModelDep]
90- # ) -> List[AssetKey]:
91- # asset_keys: List[AssetKey] = []
92- # for dep in deps:
93- # if dep.model:
94- # asset_keys.append(AssetKey(dep.model.view_name))
95- # else:
96- # parsed_fqn = dep.parse_fqn()
97- # asset_keys.append(AssetKey([parsed_fqn.view_name]))
98- # return asset_keys
99-
100-
10117# Define a SQLMesh Asset
10218def sqlmesh_assets (
10319 * ,
10420 config : SQLMeshContextConfig ,
105- name : Optional [str ] = None ,
106- dagster_sqlmesh_translator : Optional [SQLMeshDagsterTranslator ] = None ,
21+ name : t . Optional [str ] = None ,
22+ dagster_sqlmesh_translator : t . Optional [SQLMeshDagsterTranslator ] = None ,
10723 compute_kind : str = "sqlmesh" ,
108- op_tags : Optional [Mapping [str , Any ]] = None ,
109- required_resource_keys : Optional [Set [str ]] = None ,
110- retry_policy : Optional [RetryPolicy ] = None ,
24+ op_tags : t . Optional [t . Mapping [str , t . Any ]] = None ,
25+ required_resource_keys : t . Optional [t . Set [str ]] = None ,
26+ retry_policy : t . Optional [RetryPolicy ] = None ,
11127):
112- controller = setup_sqlmesh_controller (config )
28+ controller = DagsterSQLMeshController . setup (config )
11329 if not dagster_sqlmesh_translator :
11430 dagster_sqlmesh_translator = SQLMeshDagsterTranslator ()
11531 conversion = controller .to_asset_outs (dagster_sqlmesh_translator )
@@ -123,79 +39,4 @@ def sqlmesh_assets(
12339 compute_kind = compute_kind ,
12440 retry_policy = retry_policy ,
12541 required_resource_keys = required_resource_keys ,
126- # can_subset=True,
127- )
128-
129-
130- @dataclass
131- class SQLMeshController :
132- console : EventConsole
133- context : DagsterSQLMeshContext
134-
135- def add_event_handler (self , handler : ConsoleEventHandler ):
136- return self .console .add_handler (handler )
137-
138- def remove_event_handler (self , handler_id : str ):
139- return self .console .remove_handler (handler_id )
140-
141- def to_asset_outs (
142- self , translator : SQLMeshDagsterTranslator
143- ) -> SQLMeshMultiAssetOptions :
144- context = self .context
145- dag = context .dag
146- output = SQLMeshMultiAssetOptions ()
147- depsMap : Dict [str , CoercibleToAssetDep ] = {}
148-
149- for model_fqn , deps in dag .graph .items ():
150- logger .debug (f"model found: { model_fqn } " )
151- model = context .get_model (model_fqn )
152- if not model :
153- # If no model is returned this seems to be an asset dependency
154- continue
155- asset_out = translator .get_asset_key_from_model (
156- context ,
157- model ,
158- )
159- model_deps = [
160- SQLMeshModelDep (fqn = dep , model = context .get_model (dep )) for dep in deps
161- ]
162- internal_asset_deps : Set [AssetKey ] = set ()
163- for dep in model_deps :
164- if dep .model :
165- internal_asset_deps .add (
166- translator .get_asset_key_from_model (context , dep .model )
167- )
168- else :
169- table = translator .get_fqn_to_table (context , dep .fqn )
170- key = translator .get_asset_key_fqn (context , dep .fqn )
171- internal_asset_deps .add (key )
172- # create an external dep
173- depsMap [table .name ] = AssetDep (key )
174- model_key = sqlmesh_model_name_to_key (model .name )
175- output .outs [model_key ] = AssetOut (key = asset_out , is_required = False )
176- output .internal_asset_deps [model_key ] = internal_asset_deps
177-
178- output .deps = list (depsMap .values ())
179- return output
180-
181-
182- def setup_sqlmesh_controller (
183- config : SQLMeshContextConfig ,
184- debug_console : Optional [Console ] = None ,
185- log_override : Optional [logging .Logger ] = None ,
186- ):
187- console = EventConsole (log_override = log_override )
188- if debug_console :
189- console = DebugEventConsole (debug_console )
190- options : Dict [str , Any ] = dict (
191- paths = config .path ,
192- gateway = config .gateway ,
193- console = console ,
194- )
195- if config .sqlmesh_config :
196- options ["config" ] = config .sqlmesh_config
197- context = DagsterSQLMeshContext (** options )
198- return SQLMeshController (
199- console = console ,
200- context = context ,
20142 )
0 commit comments