# Проверки

Доступно в v2

По мере роста проектов dbt и увеличения числа участников, добавляющих модели, поддерживать единые стандарты становится сложнее: модель выпускается без описания, у публичной модели нет владельца, новая модель не соответствует соглашениям об именовании. Ничто из этого не нарушает работу, поэтому остаётся незамеченным, но качество незаметно снижается.

Проверки — это SQL-запросы, которые проверяют соблюдение правил и стандартов для метаданных вашего проекта. Определите правила (например, у каждой модели должно быть описание, должны быть заданы обязательные теги и так далее), и dbt обеспечит их соблюдение до начала любых операций в хранилище данных.

Пишите проверки на SQL для DuckDB, используя [макрос `{{ info_schema() }}`](https://docs.getdbt.tech/reference/dbt-jinja-functions/info-schema-macro.md) для обращения к [dbt Information Schema](https://docs.getdbt.tech/docs/build/dbt-information-schema.md) в запросе. Проверки выполняются локально в DuckDB, поэтому им не требуется подключение к хранилищу данных. Если проект нарушает правило, `dbt build` останавливается до компиляции или материализации хотя бы одной модели.

Как и [тесты данных](https://docs.getdbt.tech/docs/build/data-tests.md), проверка находит в проекте все случаи, которые не соответствуют вашим ожиданиям. Проверка проходит успешно, если запрос возвращает ноль строк, и завершается неудачей, если он возвращает одну или несколько строк.

Проверки выполняются автоматически при каждом запуске `dbt build`; их можно пропустить с помощью `--skip-checks`. Также их можно запускать по требованию командой `dbt check`.

## Рекомендации по написанию SQL-файлов проверок

В этом разделе описаны правила и ограничения для написания SQL-файлов проверок и настройки их поведения.

* Проверка — это SQL-файл в каталоге `checks/`. При необходимости рядом с ним в том же каталоге можно разместить YAML-файл свойств для его настройки. Чтобы использовать другой каталог, задайте [`check-paths`](https://docs.getdbt.tech/reference/project-configs/check-paths.md) в `dbt_project.yml`.
* Имя файла без расширения `.sql` становится именем проверки (например, `all_models_have_descriptions` — это имя проверки для `checks/all_models_have_descriptions.sql`).
* Jinja в файлах проверок обрабатывается на этапе разбора. Вы можете использовать Jinja, но уже на этом этапе результат должен быть корректным SQL для DuckDB; в отличие от моделей, проверки не проходят отдельный этап компиляции.
* Проверки — это ресурсы dbt; каждая проверка присутствует в `manifest.json`, поддерживает `tags` и `meta` и отображается в выводе `dbt ls`.

### Макрос `info_schema()`

[`{{ info_schema() }}`](https://docs.getdbt.tech/reference/dbt-jinja-functions/info-schema-macro.md) — это поддерживаемый способ обращения к [dbt Information Schema](https://docs.getdbt.tech/docs/build/dbt-information-schema.md) в проверке. Передайте имя таблицы, к которой хотите выполнить запрос (например, `{{ info_schema('models') }}` для моделей или `{{ info_schema('edges') }}` для рёбер DAG). Материализованные файлы [Information Schema](https://docs.getdbt.tech/reference/info-schema.md) не требуются; проверки выполняются на основе промежуточного представления, созданного на этапе разбора.

Полный список доступных представлений и столбцов приведён в разделе [Столбцы, доступные для проверок](https://docs.getdbt.tech/reference/info-schema.md#columns-available-for-checks).

## Создание первой проверки

Следующие шаги помогут вам создать первую проверку.

1. Объявите версию `info_schema` в `dbt_project.yml`:

   Параметр `info_schema.version` фиксирует версию info schema, которую использует [макрос `{{ info_schema() }}`](https://docs.getdbt.tech/reference/dbt-jinja-functions/info-schema-macro.md). В настоящее время доступна только версия `1`.

   dbt\_project.yml

   ```yaml
   info_schema:
     version: 1
   ```

2. Создайте проверку в каталоге `checks/`:

   Используйте [`{{ info_schema() }}`](https://docs.getdbt.tech/reference/dbt-jinja-functions/info-schema-macro.md) для запросов к метаданным проекта. Проверка проходит успешно, если запрос возвращает ноль строк. Доступные представления и столбцы перечислены в разделе [Столбцы, доступные для проверок](https://docs.getdbt.tech/reference/info-schema.md#columns-available-for-checks).

   checks/all\_models\_have\_descriptions.sql

   ```sql
   select unique_id
   from {{ info_schema('models') }}
   where description = ''
   ```

3. Настройте проверку в YAML-файле свойств в каталоге `checks/`.

   checks/\_checks.yml

   ```yaml
   version: 2
   checks:
     - name: all_models_have_descriptions
       description: "Завершается неудачей, если у какой-либо модели отсутствует описание."
       config:
         severity: warn   # по умолчанию используется error; 'warn' регистрирует проблемы, но не прерывает выполнение
   ```

4. Запустите проверки:

   ```shell
   dbt check
   ```

## Примеры проверок

В следующих примерах показаны распространённые правила качества проекта: каждое из них определено как SQL-запрос с использованием макросов `info_schema` и сохранено в файле `.sql` в каталоге `checks/`.

* Требовать наличия описания у всех моделей с доступом `public`:

  checks/public\_models\_have\_descriptions.sql

  ```sql
  select unique_id
  from {{ info_schema('models') }}
  where access = 'public'
    and description = ''
  ```

* Выявлять источники, на которые не ссылаются модели. У такого источника нет зависимых моделей: он либо не используется, либо отсутствует модель, которая должна на него ссылаться:

  checks/unused\_sources.sql

  ```sql
  select s.unique_id, s.name
  from {{ info_schema('sources') }} as s
  left join {{ info_schema('edges') }} as e on e.parent_unique_id = s.unique_id
  where e.child_unique_id is null
  ```

* Выявлять модели с доступом `public`, у группы которых не указан владелец:

  checks/public\_models\_have\_owners.sql

  ```sql
  select m.unique_id
  from {{ info_schema('models') }} as m
  left join {{ info_schema('groups') }} as g on g.name = m."group"
  where m.access = 'public'
    and (
      g.unique_id is null
      or (
        (g.owner_name is null or trim(g.owner_name) = '')
        and (g.owner_email is null or trim(g.owner_email) = '')
      )
    )
  ```

## Команды

Проверки запускаются командами `dbt check` и `dbt build`.

| Команда                       | Поведение                                                                                                                                                                                                                                                          |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `dbt check`                   | Запускает все проверки.                                                                                                                                                                                                                                            |
| `dbt check <name1> <name2> …` | Запускает только указанные проверки. Неизвестное имя проверки вызывает ошибку; имя отключённой проверки принимается, но сама проверка пропускается.                                                                                                                |
| `dbt build`                   | Запускает все включённые проверки до компиляции моделей. Неудачная проверка останавливает запуск до компиляции или выполнения любой модели. Нарушения с уровнем warn выводятся в отчёте, и сборка продолжается. Для пропуска проверок используйте `--skip-checks`. |

## Пропуск проверок при сборке

Чтобы пропустить все проверки, передайте команде `dbt build` [флаг `--skip-checks`](https://docs.getdbt.tech/reference/commands/build.md?version=2#the---skip-checks-flag).

```shell
dbt build --skip-checks
```

Чтобы пропустить определённую проверку, задайте `enabled: false` в её блоке config в YAML-файле. Проверка по-прежнему будет присутствовать в манифесте, но не будет выполняться.

```yaml
checks:
  - name: all_models_have_descriptions
    config:
      enabled: false
```

Отключение на уровне проекта

Настройка `+enabled: false` в `dbt_project.yml` отключает проверку без уведомления — в выводе ничто не указывает на то, что проверки были пропущены. Успешное выполнение `dbt build` в CI не позволяет определить, отсутствуют ли проверки в проекте или все они отключены. Запуск `dbt check <name>` для отключённой проверки также завершается успешно, не выполняя проверку и не возвращая ошибку.

## Использование селекторов с проверками

При работе с проверками [`--select` и другие методы выбора](https://docs.getdbt.tech/reference/node-selection/syntax.md) определяют, какие ресурсы проекта проверять, а не какие проверки запускать.

Почему проверки работают именно так:

* Как правило, нет необходимости исключать проверки или запускать только часть из них. Проверки выполняются быстро. Проверки с уровнем error должны блокировать выполнение при нарушении правила; если правило носит информационный характер, задайте для него `warn`. Если проверка больше не актуальна, отключите или удалите её.

* Вам может потребоваться ограничить набор проверяемых ресурсов. Это позволяет постепенно внедрять проверки в существующий проект. Во время разработки запускайте `dbt build --select <the part of your DAG you're working on>`, чтобы проверять только соответствующие ресурсы. В CI проверки выполняются только для изменённых ресурсов.

* При разработке новой проверки можно запускать по одной проверке за раз и при необходимости выбирать ресурсы:

  * `dbt check name_of_check`
  * `dbt check name_of_check --select <resources to check>`

Также можно напрямую просмотреть результат любого запроса к `info_schema`: `dbt show --inline "select * from {{ info_schema('...') }}"`. Например, чтобы изучить метаданные самих проверок, выполните `dbt show --inline "select * from {{ info_schema('checks') }}"`.

### Как работает `selection_filter_on`

По умолчанию dbt фильтрует результаты проверок по выбранным ресурсам, сопоставляя значения столбца `unique_id` в выводе. Если проверка не возвращает столбец `unique_id`, она выполняется для всего проекта.

Используйте [`selection_filter_on`](https://docs.getdbt.tech/reference/resource-configs/selection-filter-on.md), если проверка возвращает строки с другими столбцами идентификаторов, по которым требуется фильтрация. Параметр принимает следующие значения:

* **По умолчанию (не задано):** Если запрос возвращает `unique_id`, dbt сохраняет только строки, у которых `unique_id` входит в выборку. Если запрос не возвращает `unique_id`, проверка выполняется для всего проекта. Это полезно для агрегатных проверок, например «в проекте есть хотя бы одна модель».
* **`none`:** Проверка всегда выполняется для всего проекта, игнорируя любые селекторы. Используйте это значение, чтобы явно задать проверку всего проекта.
* **Имя столбца или список имён столбцов:** dbt сохраняет строку, если идентификатор хотя бы в одном из указанных столбцов входит в выборку. Каждый указанный столбец должен присутствовать в результате, иначе проверка завершится с ошибкой. Используйте этот вариант для проверок, которые возвращают связи между ресурсами (рёбра).

Например, следующая проверка возвращает `child_unique_id` вместо `unique_id`, поэтому необходимо задать `selection_filter_on`:

checks/multiple\_sources\_joined.sql

```sql
select child_unique_id, count(*) as source_parents
from {{ info_schema('edges') }}
where parent_unique_id like 'source.%'
group by child_unique_id
having count(*) > 1
```

checks/\_checks.yml

```yaml
checks:
  - name: multiple_sources_joined
    description: "Завершается неудачей, если какая-либо модель читает данные напрямую из нескольких источников."
    config:
      selection_filter_on: child_unique_id
```

## Связанная документация

* [Свойства проверок](https://docs.getdbt.tech/reference/check-properties.md)
* [Конфигурации проверок](https://docs.getdbt.tech/reference/check-configs.md)
* [Команда `dbt check`](https://docs.getdbt.tech/reference/commands/check.md)
* [`info_schema`](https://docs.getdbt.tech/reference/dbt-jinja-functions/info-schema-macro.md)
* [Настройка проекта `check-paths`](https://docs.getdbt.tech/reference/project-configs/check-paths.md)
