diff --git a/README.md b/README.md index 071ee53..b25c57c 100644 --- a/README.md +++ b/README.md @@ -193,6 +193,42 @@ dbt-invoke properties.delete - `` uses the same arguments as for creating/updating property files, except for `--threads`. + +### Applying default properties using `dbt_invoke_template.yml` + +You can pass custom default properties to be added to property files on update. +To do so, add a `dbt_invoke_template.yml` at the root of your dbt project, +using the following convention: + + +``` +model: + meta: + owner: "@default" + columns: + foo: "bar" + +seed: + meta: + owner: "@default" + columns: + foo: "bar" + +snapshot: + meta: + owner: "@default" + columns: + foo: "bar" + +analysis: + meta: + owner: "@default" + columns: + foo: "bar" +``` + +Note: only `model`, `seed`, `snapshot` and `analysis` are supported. + ### Help - To view the list of available commands and their short descriptions, run: diff --git a/dbt_invoke/internal/_utils.py b/dbt_invoke/internal/_utils.py index 7f69a7e..c86cddb 100644 --- a/dbt_invoke/internal/_utils.py +++ b/dbt_invoke/internal/_utils.py @@ -132,6 +132,12 @@ def get_project_info(ctx, project_dir=None): Path(project_path, macro_path) for macro_path in project_yml.get('macro-paths', ['macros']) ] + # retrieves template information if provided + template_path = Path(project_path, 'dbt_invoke_template.yml') + if template_path.exists(): + ctx.config['template_yml'] = parse_yaml(template_path) + else: + ctx.config['template_yml'] = None # Set context config key-value pairs ctx.config['project_path'] = project_path ctx.config['project_name'] = project_name diff --git a/dbt_invoke/properties.py b/dbt_invoke/properties.py index 01412e1..5e77e32 100644 --- a/dbt_invoke/properties.py +++ b/dbt_invoke/properties.py @@ -715,6 +715,7 @@ def _create_property_file( property_path, resource_dict, columns, + ctx.config['template_yml'] ) _utils.write_yaml( property_path, @@ -786,7 +787,12 @@ def _get_columns(ctx, resource_location, resource_dict, **kwargs): return columns -def _structure_property_file_dict(location, resource_dict, columns_list): +def _structure_property_file_dict( + location, + resource_dict, + columns_list, + template_yml +): """ Structure a dictionary that will be used to create a property file @@ -813,6 +819,12 @@ def _structure_property_file_dict(location, resource_dict, columns_list): property_file_dict = _get_property_header(resource_name, resource_type) # Get the sub-dictionaries of each existing column resource_type_plural = _SUPPORTED_RESOURCE_TYPES[resource_type] + # If dbt_invoke_template.yml exists, adds templated properties to header + # when not already present + if template_yml and resource_type in template_yml: + _apply_template( + property_file_dict[resource_type_plural][0], template_yml[resource_type] + ) existing_columns_dict = { item['name']: item for item in property_file_dict[resource_type_plural][0]['columns'] @@ -825,12 +837,33 @@ def _structure_property_file_dict(location, resource_dict, columns_list): column_dict = existing_columns_dict.get( column, _get_property_column(column) ) + # If dbt_invoke_template.yml exists, adds templated properties to column + # when not already present + if template_yml and 'columns' in template_yml.get(resource_type, dict()): + _apply_template( + column_dict, template_yml[resource_type]['columns'] + ) property_file_dict[resource_type_plural][0]['columns'].append( column_dict ) return property_file_dict +def _apply_template(property_dict, template): + """ + Updates a dictionary with template's yml default properties + if said dictionary does not already contain the properties. + + :param property_dict: the dictionary to be updated + :param template: a dictionary representing the templated properties + to be applied on property_dict + :return: None + """ + for key in template: + if key not in property_dict: + property_dict[key] = template[key] + + def _get_property_header(resource, resource_type, properties=None): """ Create a dictionary representing resources properties