# Resolvers

<mark style="color:green;">**Resolvers**</mark> are used to compare <mark style="color:blue;">**blueprints**</mark> with existing metadata in Snowflake account and generate DDL commands. DDL commands are suggested or immediately applied using <mark style="color:red;">**engine**</mark>, depending on settings. One resolver per object type.

All standard resolvers are located in [`/resolver/`](https://github.com/littleK0i/SnowDDL/tree/master/snowddl/resolver) directory.

### Inheritance

All <mark style="color:green;">**resolvers**</mark> are derived from `AbstractResolver` class.

Resolvers for schema objects (`TABLE`, `VIEW`, etc.) are derived from `AbstractSchemaObjectResolver`, which implements additional logic related to "sandbox" schemas and parallel metadata fetching.

### Resolver workflow

Internally each resolver implements the following workflow:

1. Get object <mark style="color:blue;">**blueprints**</mark> (desired state);
2. Load existing objects from Snowflake metadata (current state);
3. Compare full names of <mark style="color:blue;">**blueprints**</mark> VS full names of existing objects and..
   * "create" new objects;
   * "compare" existing objects;
   * "drop" existing objects without blueprints;
4. Execute "create" / "compare" / "drop" operations in parallel using [ThreadPoolExecutor](https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor).
5. Update caches (if necessary).

### Resolve result

Each object may "resolve" in one of the following ways:

* **CREATE** - object was created, it did not exist before;
* **ALTER** - existing object was updated;
* **DROP** - existing object was dropped;
* **REPLACE** - existing object was replaced entirely;
* **SKIP** - object was not changed, it was skipped;
* **GRANT** - grants were updated (used for various types of ROLES);
* **NOCHANGE** - object was not changed, did not require any change;
* **ERROR** - something went wrong while resolving this object, check logs;
* **UNSUPPORTED** - object should be updated, but it is not possible due to lack of Snowflake support for such operation (e.g. converting TRANSIENT schema to normal schema is not possible without full data rewrite);

Resolve result by object name is available in property `.resolved_objects`.

Intercepted exceptions by object name are available in property `.errors`.

### Methods (base)

* `__init__(engine: SnowDDLEngine)`\
  Initialize resolver with <mark style="color:red;">**engine**</mark>.<br>
* `get_object_type()`\
  Abstract method. Returns object type, which is processed by this resolver.<br>
* `get_blueprints()`\
  Abstract method. Returns <mark style="color:blue;">**blueprints**</mark> to be processed by resolver. Normally it reads blueprints from <mark style="color:purple;">**config**</mark>, but it may also generate blueprints on the fly based on some other blueprints. For example, "schema roles" are generated automatically based on schema blueprints.<br>
* `get_existing_objects()`\
  Abstract method. Returns dict with objects currently existing in Snowflake account. Normally this method calls for `SHOW ...` metadata commands.<br>
* `create_object(self, bp: AbstractBlueprint)`\
  Abstract method. Accepts instance of blueprint. Creates a new object which currently does not exist in Snowflake.<br>
* `compare_object(self, bp: AbstractBlueprint, row: Dict)`\
  Abstract method. Accepts blueprint and metadata of existing object. Compares blueprint with existing object and updates or recreates it. Alternatively, it "does nothing" (skip) if object blueprint matches the existing metadata precisely.<br>
* `drop_object(self, row: Dict)`\
  Abstract method. Accepts metadata of existing object, which does not have a corresponding blueprint. Drops this object.

### Methods (schema objects)

* `get_existing_objects_in_schema(schema: dict)`\
  Abstract method. Use it instead of `get_existing_objects()`. Accepts dict describing schema. Returns dict in the same format as `get_existing_objects()`.

### Properties

* **.resolved\_objects** (dict) - resolve result for processed objects;
  * *{key}* (str) - full name of object;
  * *{value}* (ResolveResult) - enum value;
* **.errors** (dict) - exceptions for processed objects;
  * *{key}* (str) - full name of object;
  * *{value}* (Exception) - exception thrown while processing object;
