Миграция с Hasura DDN (v3) на Provisa¶
Предварительные требования¶
- Проект Hasura DDN с файлами HML (расширение
.hml). Проекты DDN обычно имеют структуру каталогов вида:
my-ddn-project/
app/
subgraph1/
models/
MyModel.hml
commands/
MyCommand.hml
subgraph2/
...
globals/
...
- Python 3.11+ с установленным пакетом
provisa.
Использование CLI¶
Аргументы¶
| Аргумент | Обязателен | Описание |
|---|---|---|
hml_dir |
Да | Путь к каталогу проекта DDN HML (рекурсивно сканируется на предмет файлов .hml) |
Опции¶
| Опция | По умолчанию | Описание |
|---|---|---|
-o, --output FILE |
stdout | Путь к выходному файлу YAML |
--source-overrides FILE |
None | Файл YAML с переопределениями подключения по источникам |
--domain-map KEY=VAL ... |
None | Отображения подграф-в-домен (например, app=core analytics=reporting) |
--dry-run |
off | Разбор и валидация без записи вывода |
Файл переопределений источников¶
Файл YAML, ключами которого являются имена коннекторов (после санитизации ID: пробелы, точки, слэши становятся подчёркиваниями), со свойствами подключения:
my_pg_connector:
host: prod-db.example.com
port: 5432
database: chinook
username: provisa_user
password: "${env:PROD_DB_PASSWORD}"
Матрица паритета функций¶
| Тип DDN | Эквивалент Provisa | Примечания |
|---|---|---|
| DataConnectorLink | sources[] |
Тип источника выводится из URL коннектора (postgres, mysql, mssql, mongo, clickhouse, snowflake, bigquery). Детали подключения по умолчанию — заполнители; используйте --source-overrides для задания фактических значений. |
| ObjectType | Определения столбцов на tables[] |
Поля становятся столбцами. dataConnectorTypeMapping.fieldMapping разрешает имена полей GraphQL в имена физических столбцов. |
| Model | tables[] |
Каждая Model производит одну таблицу. source_id из коннектора, table_name из коллекции. graphql_type_name становится alias. Подграф (и, следовательно, domain_id) выводится из каталога файла: первый компонент каталога под корнем проекта. |
| Relationship | relationships[] |
Тип object -> many-to-one, тип array -> one-to-many. Отображение полей разрешается через поиск физических столбцов. |
| TypePermissions | columns[].visible_to[] |
allowedFields определяет, какие роли могут видеть каждый столбец. |
| ModelPermissions | rls_rules[] |
Предикаты фильтра преобразуются в предложения SQL WHERE. Поддерживаются _eq, _neq, _gt, _lt, _gte, _lte, _in, _nin, _like, _is_null, _and, _or, _not. Ссылки на переменные сессии сохраняются как ${x-hasura-...}. |
| Command | functions[] |
Отображаются как функции, так и процедуры. Аргументы, тип возврата и имя корневого поля GraphQL сохраняются. domain_id устанавливается из подграфа. |
| AggregateExpression | Побочный файл provisa-aggregates.yaml |
Count, count_distinct и агрегатные функции по полям сохраняются в побочном файле и преобразуются в конфигурацию агрегатов Provisa. |
| BooleanExpressionType | Пропускается (молча) | Используется внутри DDN для фильтрации; прямого эквивалента в Provisa не требуется. |
| AuthConfig | Пропускается (молча) | Конфигурация авторизации DDN не отображается; настройте авторизацию Provisa отдельно. |
| ScalarType | Пропускается | Выдаётся предупреждение со счётчиком. |
| GraphqlConfig | Пропускается | Выдаётся предупреждение со счётчиком. |
| CompatibilityConfig | Пропускается | Выдаётся предупреждение со счётчиком. |
| Прочие нераспознанные типы (Kinds) | Пропускаются | Выдаётся предупреждение со счётчиком по каждому типу. |
Ключевая концепция: разрешение поля GraphQL в физический столбец¶
DDN отделяет схему GraphQL (имена полей) от физической схемы базы данных
(имена столбцов) через dataConnectorTypeMapping на ObjectTypes. Конвертер:
- Читает записи
fieldMappingиз отображений типов каждого ObjectType. - Строит справочник:
{graphql_field_name -> physical_column_name}. - Для полей без явного отображения предполагает, что имя поля равно имени столбца.
- Использует этот справочник при построении столбцов, связей и выражений фильтра RLS.
Это означает, что выходной provisa.yaml использует имена физических столбцов для columns[].name
и устанавливает columns[].alias в имя поля GraphQL, когда они отличаются.
Шаги после конвертации¶
- Проверьте выходной YAML. Проверьте источники, таблицы и отображения столбцов.
- Настройте подключения источников. Коннекторы предоставляют только подсказку URL для определения
типа. Фактические хост/порт/база данных/учётные данные должны быть заданы через
--source-overridesили путём редактирования вывода. - Проверьте назначения доменов. Имена подграфов выводятся из структуры каталогов
(первый компонент каталога под корнем проекта). Без
--domain-mapкаждое имя подграфа напрямую становится ID домена. Используйте--domain-mapдля их переименования. - Проверьте правила RLS. Предикаты фильтра DDN преобразуются в SQL-приближения.
Вложенная булева логика (
_and/_or/_not) поддерживается, но сложные фильтры, проходящие через связи, могут потребовать ручной проверки. - Проверьте конфигурацию агрегатов. Агрегатные выражения записываются в побочный файл
provisa-aggregates.yamlи преобразуются в конфигурацию агрегатов Provisa. - Просмотрите предупреждения. Конвертер выводит сводку в stderr, перечисляя пропущенные типы (Kinds) DDN и любые модели, ссылающиеся на неизвестные ObjectTypes.
- Протестируйте. Запустите сервер Provisa и проверьте запросы к вашим источникам данных.
Распространённые проблемы и устранение неполадок¶
Определение типа источника не удаётся¶
URL коннектора используется эвристически (проверка на ключевые слова вроде «postgres»,
«mysql», «mongo»). Если URL не содержит распознаваемого ключевого слова, источник
по умолчанию становится postgresql. Переопределите через --source-overrides.
Отсутствует ObjectType для Model¶
Если Model ссылается на имя ObjectType, которое не найдено ни в одном файле .hml,
таблица пропускается и выдаётся предупреждение. Убедитесь, что все файлы HML включены
в сканируемый каталог.
Обнаружение подграфов¶
Подграфы выводятся из структуры каталогов: первый компонент каталога
под корнем проекта берётся как имя подграфа. Поле subgraph внутри
документов HML не используется. Файлы в каталоге globals/ присваиваются
подграфу globals и исключаются из обнаружения доменов.
Разрешение источника связи¶
Связи ссылаются на source_type (имя ObjectType) и target_model (имя
Model). Если ни одна Model не использует данный ObjectType, связь молча пропускается.
Алиасы столбцов повсюду¶
Если ваш проект DDN широко использует fieldMapping, ожидайте, что у большинства столбцов будет
alias в выводе. Это корректное поведение — name является физическим столбцом,
alias — это имя GraphQL, которое использовало ваше приложение.
Агрегатные выражения¶
Агрегатные выражения сохраняются в побочном файле provisa-aggregates.yaml, записываемом
рядом с выводом, и преобразуются в конфигурацию агрегатов Provisa. Они не хранятся в
description таблицы.
Пример: конвертация проекта DDN Chinook¶
# Convert the DDN project
python -m provisa.ddn ./chinook-ddn/ \
-o provisa.yaml \
--domain-map app=music \
--source-overrides overrides.yaml
# Dry run to check warnings first
python -m provisa.ddn ./chinook-ddn/ --dry-run
Структура вывода:
sources:
- id: chinook_pg
type: postgresql
host: prod-db.example.com
port: 5432
database: chinook
...
domains:
- id: music
tables:
- source_id: chinook_pg
domain_id: music
schema_name: public
table_name: Album
columns:
- name: AlbumId
visible_to: [admin, user]
- name: Title
visible_to: [admin, user]
- name: ArtistId
visible_to: [admin, user]
alias: Albums
- source_id: chinook_pg
domain_id: music
schema_name: public
table_name: Artist
columns:
- name: artist_id
visible_to: [admin, user]
alias: ArtistId
- name: artist_name
visible_to: [admin, user]
alias: Name
alias: Artists
roles:
- id: admin
capabilities: [read]
domain_access: ["*"]
- id: user
capabilities: [read]
domain_access: ["*"]
relationships:
- id: chinook_pg.public.Album.Artist
source_table_id: chinook_pg.public.Album
target_table_id: chinook_pg.public.Artist
source_column: ArtistId
target_column: artist_id
cardinality: many-to-one
functions:
- name: GetTopTracks
source_id: chinook_pg
schema_name: public
function_name: get_top_tracks
returns: Track
domain_id: music
description: "DDN function"