@@ -65,21 +65,26 @@ def create(
6565 from sqlmesh .core .console import set_console
6666 from sqlmesh_dbt .console import DbtCliConsole
6767 from sqlmesh .utils .errors import SQLMeshError
68+ from sqlmesh .core .config import ModelDefaultsConfig
6869
6970 configure_logging (force_debug = debug )
7071 set_console (DbtCliConsole ())
7172
7273 progress .update (load_task_id , description = "Loading project" , total = None )
7374
74- # inject default start date if one is not specified to prevent the user from having to do anything
75- _inject_default_start_date (project_dir )
75+ cli_config = get_or_create_sqlmesh_config (project_dir )
76+ # todo: we will need to build this out when we start storing more than model_defaults
77+ model_defaults = (
78+ ModelDefaultsConfig .model_validate (cli_config ["model_defaults" ])
79+ if "model_defaults" in cli_config
80+ else None
81+ )
7682
7783 config = sqlmesh_config (
7884 project_root = project_dir ,
79- # do we want to use a local duckdb for state?
80- # warehouse state has a bunch of overhead to initialize, is slow for ongoing operations and will create tables that perhaps the user was not expecting
81- # on the other hand, local state is not portable
85+ # This triggers warehouse state. Users will probably find this very slow
8286 state_connection = None ,
87+ model_defaults = model_defaults ,
8388 )
8489
8590 sqlmesh_context = Context (
@@ -109,25 +114,27 @@ def create(
109114 return DbtOperations (sqlmesh_context , dbt_project )
110115
111116
112- def _inject_default_start_date (project_dir : t .Optional [Path ] = None ) -> None :
117+ def get_or_create_sqlmesh_config (project_dir : t .Optional [Path ] = None ) -> t . Dict [ str , t . Any ] :
113118 """
114- SQLMesh needs a start date to as the starting point for calculating intervals on incremental models
119+ SQLMesh needs a start date to as the starting point for calculating intervals on incremental models, amongst other things
115120
116121 Rather than forcing the user to update their config manually or having a default that is not saved between runs,
117- we can inject it automatically to the dbt_project.yml file
122+ we can store sqlmesh-specific things in a `sqlmesh.yaml` file. This is preferable to trying to inject config into `dbt_project.yml`
123+ because it means we have full control over the file and dont need to worry about accidentally reformatting it or accidentally
124+ clobbering other config
118125 """
119- from sqlmesh .dbt .project import PROJECT_FILENAME , load_yaml
120- from sqlmesh .utils .yaml import dump
126+ import sqlmesh .utils .yaml as yaml
121127 from sqlmesh .utils .date import yesterday_ds
128+ from sqlmesh .core .config import ModelDefaultsConfig
129+
130+ potential_filenames = [
131+ (project_dir or Path .cwd ()) / f"sqlmesh.{ ext } " for ext in ("yaml" , "yml" )
132+ ]
133+
134+ sqlmesh_yaml_file = next ((f for f in potential_filenames if f .exists ()), potential_filenames [0 ])
135+
136+ if not sqlmesh_yaml_file .exists ():
137+ with sqlmesh_yaml_file .open ("w" ) as f :
138+ yaml .dump ({"model_defaults" : ModelDefaultsConfig (start = yesterday_ds ()).dict ()}, f )
122139
123- project_yaml_path = (project_dir or Path .cwd ()) / PROJECT_FILENAME
124- if project_yaml_path .exists ():
125- loaded_project_file = load_yaml (project_yaml_path )
126- start_date_keys = ("start" , "+start" )
127- if "models" in loaded_project_file and all (
128- k not in loaded_project_file ["models" ] for k in start_date_keys
129- ):
130- loaded_project_file ["models" ]["+start" ] = yesterday_ds ()
131- # todo: this may format the file differently, is that acceptable?
132- with project_yaml_path .open ("w" ) as f :
133- dump (loaded_project_file , f )
140+ return yaml .load (sqlmesh_yaml_file , render_jinja = False )
0 commit comments