Skip to content

Commit 3b8fab0

Browse files
committed
feat: cache external models and others for faster loading
1 parent 775936b commit 3b8fab0

File tree

2 files changed

+55
-45
lines changed

2 files changed

+55
-45
lines changed

sqlmesh/core/loader.py

+54-44
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
from sqlmesh.core.metric import Metric, MetricMeta, expand_metrics, load_metric_ddl
2424
from sqlmesh.core.model import (
2525
Model,
26-
ExternalModel,
2726
ModelCache,
2827
SeedModel,
2928
create_external_model,
@@ -194,49 +193,7 @@ def _load_external_models(
194193
audits: UniqueKeyDict[str, ModelAudit],
195194
gateway: t.Optional[str] = None,
196195
) -> UniqueKeyDict[str, Model]:
197-
models: UniqueKeyDict[str, Model] = UniqueKeyDict("models")
198-
external_models_yaml = Path(self.config_path / c.EXTERNAL_MODELS_YAML)
199-
deprecated_yaml = Path(self.config_path / c.EXTERNAL_MODELS_DEPRECATED_YAML)
200-
external_models_path = self.config_path / c.EXTERNAL_MODELS
201-
202-
paths_to_load = []
203-
if external_models_yaml.exists():
204-
paths_to_load.append(external_models_yaml)
205-
elif deprecated_yaml.exists():
206-
paths_to_load.append(deprecated_yaml)
207-
208-
if external_models_path.exists() and external_models_path.is_dir():
209-
paths_to_load.extend(self._glob_paths(external_models_path, extension=".yaml"))
210-
211-
for path in paths_to_load:
212-
self._track_file(path)
213-
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):
232-
models[model.fqn] = model
233-
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):
237-
models.update({model.fqn: model})
238-
239-
return models
196+
return UniqueKeyDict("external_models")
240197

241198
def _load_requirements(self) -> t.Tuple[t.Dict[str, str], t.Set[str]]:
242199
"""Loads Python dependencies from the lock file.
@@ -620,6 +577,59 @@ def _load_metrics(self) -> UniqueKeyDict[str, MetricMeta]:
620577

621578
return metrics
622579

580+
def _load_external_models(
581+
self,
582+
audits: UniqueKeyDict[str, ModelAudit],
583+
gateway: t.Optional[str] = None,
584+
) -> UniqueKeyDict[str, Model]:
585+
models: UniqueKeyDict[str, Model] = UniqueKeyDict("models")
586+
external_models_yaml = Path(self.config_path / c.EXTERNAL_MODELS_YAML)
587+
deprecated_yaml = Path(self.config_path / c.EXTERNAL_MODELS_DEPRECATED_YAML)
588+
external_models_path = self.config_path / c.EXTERNAL_MODELS
589+
590+
paths_to_load = []
591+
if external_models_yaml.exists():
592+
paths_to_load.append(external_models_yaml)
593+
elif deprecated_yaml.exists():
594+
paths_to_load.append(deprecated_yaml)
595+
596+
if external_models_path.exists() and external_models_path.is_dir():
597+
paths_to_load.extend(self._glob_paths(external_models_path, extension=".yaml"))
598+
599+
cache = SqlMeshLoader._Cache(self, self.config_path)
600+
601+
def _load() -> t.List[Model]:
602+
try:
603+
with open(path, "r", encoding="utf-8") as file:
604+
return [
605+
create_external_model(
606+
defaults=self.config.model_defaults.dict(),
607+
path=path,
608+
project=self.config.project,
609+
audit_definitions=audits,
610+
**{
611+
"dialect": self.config.model_defaults.dialect,
612+
"default_catalog": self.context.default_catalog,
613+
**row,
614+
},
615+
)
616+
for row in YAML().load(file.read())
617+
]
618+
except Exception as ex:
619+
raise ConfigError(f"Failed to load model definition at '{path}'.\n{ex}")
620+
621+
for path in paths_to_load:
622+
self._track_file(path)
623+
624+
for model in cache.get_or_load_models(path, _load):
625+
if model.gateway == gateway:
626+
models.update({model.fqn: model})
627+
# external models with no explicit gateway defined form the base set
628+
elif gateway and model.gateway is None and model.fqn not in models:
629+
models[model.fqn] = model
630+
631+
return models
632+
623633
def _load_environment_statements(self, macros: MacroRegistry) -> EnvironmentStatements | None:
624634
"""Loads environment statements."""
625635

sqlmesh/core/model/cache.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def get_or_load(
5959
return cache_entry
6060

6161
models = loader()
62-
if isinstance(models, list) and isinstance(seq_get(models, 0), SqlModel):
62+
if isinstance(models, list):
6363
# make sure we preload full_depends_on
6464
for model in models:
6565
model.full_depends_on

0 commit comments

Comments
 (0)