23
23
from sqlmesh .core .metric import Metric , MetricMeta , expand_metrics , load_metric_ddl
24
24
from sqlmesh .core .model import (
25
25
Model ,
26
- ExternalModel ,
27
26
ModelCache ,
28
27
SeedModel ,
29
28
create_external_model ,
@@ -59,6 +58,14 @@ class LoadedProject:
59
58
user_rules : RuleSet
60
59
61
60
61
+ class CacheBase (abc .ABC ):
62
+ @abc .abstractmethod
63
+ def get_or_load_models (
64
+ self , target_path : Path , loader : t .Callable [[], t .List [Model ]]
65
+ ) -> t .List [Model ]:
66
+ """Get or load all models from cache."""
67
+
68
+
62
69
class Loader (abc .ABC ):
63
70
"""Abstract base class to load macros and models for a context"""
64
71
@@ -69,6 +76,10 @@ def __init__(self, context: GenericContext, path: Path) -> None:
69
76
self .config = self .context .configs [self .config_path ]
70
77
self ._variables_by_gateway : t .Dict [str , t .Dict [str , t .Any ]] = {}
71
78
79
+ @abc .abstractmethod
80
+ def _cache (self , ** kwargs : t .Any ) -> CacheBase :
81
+ """Returns an instance of a CacheBase."""
82
+
72
83
def load (self ) -> LoadedProject :
73
84
"""
74
85
Loads all macros and models in the context's path.
@@ -208,32 +219,41 @@ def _load_external_models(
208
219
if external_models_path .exists () and external_models_path .is_dir ():
209
220
paths_to_load .extend (self ._glob_paths (external_models_path , extension = ".yaml" ))
210
221
222
+ def _load () -> t .List [Model ]:
223
+ try :
224
+ with open (path , "r" , encoding = "utf-8" ) as file :
225
+ return [
226
+ create_external_model (
227
+ defaults = self .config .model_defaults .dict (),
228
+ path = path ,
229
+ project = self .config .project ,
230
+ audit_definitions = audits ,
231
+ ** {
232
+ "dialect" : self .config .model_defaults .dialect ,
233
+ "default_catalog" : self .context .default_catalog ,
234
+ ** row ,
235
+ },
236
+ )
237
+ for row in YAML ().load (file .read ())
238
+ ]
239
+ except Exception as ex :
240
+ raise ConfigError (f"Failed to load model definition at '{ path } '.\n { ex } " )
241
+
242
+ cache = self ._cache ()
243
+
211
244
for path in paths_to_load :
212
245
self ._track_file (path )
213
246
214
- with open (path , "r" , encoding = "utf-8" ) as file :
215
- external_models : t .List [ExternalModel ] = []
216
- for row in YAML ().load (file .read ()):
217
- model = create_external_model (
218
- defaults = self .config .model_defaults .dict (),
219
- path = path ,
220
- project = self .config .project ,
221
- audit_definitions = audits ,
222
- ** {
223
- "dialect" : self .config .model_defaults .dialect ,
224
- "default_catalog" : self .context .default_catalog ,
225
- ** row ,
226
- },
227
- )
228
- external_models .append (model )
229
-
230
- # external models with no explicit gateway defined form the base set
231
- for model in (e for e in external_models if e .gateway is None ):
247
+ external_models = cache .get_or_load_models (path , _load )
248
+ # external models with no explicit gateway defined form the base set
249
+ for model in external_models :
250
+ if model .gateway is None :
232
251
models [model .fqn ] = model
233
252
234
- # however, if there is a gateway defined, gateway-specific models take precedence
235
- if gateway :
236
- for model in (e for e in external_models if e .gateway == gateway ):
253
+ # however, if there is a gateway defined, gateway-specific models take precedence
254
+ if gateway :
255
+ for model in external_models :
256
+ if model .gateway == gateway :
237
257
models .update ({model .fqn : model })
238
258
239
259
return models
@@ -339,6 +359,9 @@ def _get_variables(self, gateway_name: t.Optional[str] = None) -> t.Dict[str, t.
339
359
class SqlMeshLoader (Loader ):
340
360
"""Loads macros and models for a context using the SQLMesh file formats"""
341
361
362
+ def _cache (self , ** kwargs : t .Any ) -> CacheBase :
363
+ return SqlMeshLoader ._Cache (self , self .config_path )
364
+
342
365
def _load_scripts (self ) -> t .Tuple [MacroRegistry , JinjaMacroRegistry ]:
343
366
"""Loads all user defined macros."""
344
367
# Store a copy of the macro registry
@@ -416,7 +439,8 @@ def _load_sql_models(
416
439
) -> UniqueKeyDict [str , Model ]:
417
440
"""Loads the sql models into a Dict"""
418
441
models : UniqueKeyDict [str , Model ] = UniqueKeyDict ("models" )
419
- cache = SqlMeshLoader ._Cache (self , self .config_path )
442
+
443
+ cache = self ._cache ()
420
444
421
445
for path in self ._glob_paths (
422
446
self .config_path / c .MODELS ,
@@ -662,7 +686,7 @@ def _load_linting_rules(self) -> RuleSet:
662
686
663
687
return RuleSet (user_rules .values ())
664
688
665
- class _Cache :
689
+ class _Cache ( CacheBase ) :
666
690
def __init__ (self , loader : SqlMeshLoader , config_path : Path ):
667
691
self ._loader = loader
668
692
self .config_path = config_path
0 commit comments