# 0.37.0 - December 2024

This update is significant overhaul for config parsing and validation. Most changes are internal and should have no impact on existing valid YAML configs. But if you use programmatic config to add or change DATABASE, SCHEMA, BUSINESS ROLE, TECHNICAL ROLE objects, please make sure to read this page and update your code accordingly.

### YAML config change: grant of database roles for inbound shares

Previously in order to grant DATABASE ROLE on INBOUND SHARE you had to use parameter `global_roles` or `owner_global_roles` in DATABASE, SCHEMA, BUSINESS\_ROLE object types.

After this update you should use `share_read` or `owner_share_read` parameter. Since native Snowflake DATABASE ROLES are not used for anything but shares in SnowDDL paradigm, it should make config more readable.

If you still need to grant a native Snowflake DATABASE ROLE, you may always do it granting it to global role first and assigning global role to specific objects using `global_roles`.

Before:

```yaml
share_read:
  - snowflake

global_roles:
  - snowflake.object_viewer      # share database roles were in global_roles before
```

After:

```yaml
share_read:
  - snowflake
  - snowflake.object_viewer      # share database roles are now in share_read
```

### Parsing error handling

Property `.errors` and method `.add_error` were moved from `SnowDDLConfig` to individual parsers. Parsers now have their own loggers and print errors. In general, parser errors now operate similar to resolver errors.

If you implemented your own custom parsers, replace `config.add_error()` calls with `self.add_error()` calls.

### Ident patterns

Config method `.get_blueprints_by_type_and_pattern()` was changed. Now it accepts newly introduced object `IdentPattern` as second argument instead of `str`. Pattern format is still the same.

This change helps to make it easier to understand when we expect single identifier and when we expect identifier pattern, which may potentially match a large number of objects.

It also help to keep pattern validation checks inside parsers.

Before:

```
config.get_blueprints_by_type_and_pattern(TableBlueprint, "my_db.my_schema.*")
```

After:

```
config.get_blueprints_by_type_and_pattern(TableBlueprint, IdentPattern("my_db.my_schema.*"))
```

### Blueprint changes, parsers and validators

Several blueprints were significantly reworked, especially blueprints for the following object types:

* DATABASE
* SCHEMA
* BUSINESS ROLE
* TECHNICAL ROLE

Previously all grant-building and most validation was happening in parsers. Now blueprints mostly hold parameters from config, validation is happening later in newly introduced validators, and grant-building is mostly happening in resolvers.

What does it mean in practice?

Previously you had:

```python
SchemaBlueprint(
  full_name=SchemaIdent(self.env_prefix, "my_db", "my_schema"),
  ...
  grants=[Grant(...), Grant(...), Grant(...)],
)
```

Now you have:

```
SchemaBlueprint(
  full_name=SchemaIdent(self.env_prefix, "my_db", "my_schema"),
  owner_schema_read=[IdentPattern(...), IdentPattern(...)],
  owner_warehouse_usage=[AccountObjectIdent(...)],
  owner_account_grants=[AccountGrant("EXECUTE TASK")],
)
```

Now blueprint objects are much closer to what you see in YAML configs.

This change helps to improve user experience with programmatic config. It also helps to perform full validation when YAML config and programmatic config are mixed together. Previously it was not possible, since validation was happening mostly in parsers before programmatic had a chance to run.

Technical roles now use newly introduced objects `GrantPattern`.

Before:

```
TechnicalRoleBlueprint(
  full_name=AccountObjectIdent(self.env_prefix, "my_tech_role"),
  grants=[Grant(privilege="USAGE", on=ObjectType.DATABASE, name=DatabaseIdent(...))],
)
```

After:

```
TechnicalRoleBlueprint(
  full_name=AccountObjectIdent(self.env_prefix, "my_tech_role"),
  grant_patterns=[GrantPattern(privilege="USAGE", on=ObjectType.DATABASE, name=IdentPattern(...))],
)
```

### Stage file blueprints

Stage file blueprints now use `Path` objects instead of `str` for paths. It helps to mitigate various issues related to path handling on Windows OS.

Usually you should be able to safely convert strings into paths using basic `Path(str)`.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.snowddl.com/breaking-changes-log/0.37.0-december-2024.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
