#graphql #hasura
#graphql ( графический sql ) #hasura #graphql
Вопрос:
Я создаю API поверх моей базы данных PostgreSQL, используя Hasura и GraphQL в качестве среднего уровня.
Я управляю сервисным бизнесом, где клиенты могут подписаться на такие услуги, как «еженедельная чистка кофемашины» или «пополнение буфета для мохито». Клиент может подписаться на одну и ту же услугу только один раз.
Мы являемся организацией, ориентированной на продажи, поэтому у нас есть разные приложения, в которые люди могут добавлять (customer, subscription)
комбинации. Нам нужна конечная точка, которая принимает эту (customer, subscription)
комбинацию и заботится о таких деталях, как вставка, customer
если она не существует.
Сначала мы попытались использовать следующую мутацию против Hasura:
mutation InsertOrders {
insert_orders(objects: [
{
customer: {data: {name: "GE"}},
subscription: {data: {name: "Coffee Refill"}}
}
])
{
affected_rows
}
}
Эта операция выполняется успешно, только если "GE"
не является существующим клиентом и "Coffee Refill"
не является существующей подпиской.
Затем мы попытались использовать "on_conflict"
функциональность в Hasura:
mutation InsertOrders {
insert_orders(objects: [
{
customer: {data: {name: "GE"},
on_conflict: { constraint:customers_name_unique , update_columns:[name] }
},
subscription: {data: {name: "Coffee Refill"},
on_conflict: { constraint:subscriptions_name_unique , update_columns:[name] }
}
}
])
{
affected_rows
}
}
Такой способ работает, но у него есть несколько недостатков:
- Он обновляет строку клиента (или подписки), если клиент существует, фактически обновление без операции. Это также обновляет потенциальный
updated_at
столбец. - Это неэффективно (см. 1.). У нас крошечная база данных (сотни строк), и время ожидания нашей попытки вставить около 50
(customer, subscription)
комбинаций в один запрос истекло.
Определение базы данных здесь:
CREATE TABLE customer (
id UUID PRIMARY KEY,
name VARCHAR(50) UNIQUE
);
CREATE TABLE subscription (
id UUID PRIMARY KEY,
name VARCHAR(50) UNIQUE
);
CREATE TABLE orders (
customer UUID REFERENCES customer (id),
subscription UUID REFERENCES subscription (id),
PRIMARY KEY (customer, subscription)
)
Комментарии:
1. Чтобы проигнорировать обновление, вы должны оставить update_columns пустым. Что-то вроде { on_conflict: { constraint:products_name_unique , update_columns:[] } }
2. @LeonardoAlves Спасибо вам за ваш вклад. Я пробовал это, но получаю ошибку
cannot proceed to insert object relation "subscription" since insert to table "subscription" affects zero rows
. Это упоминается в разделе «Вложенные предупреждения о вводе» в документации Hasura3. простота использования приложения не должна приводить к плохому дизайну БД… одно действие в приложении может привести к нескольким последовательным действиям под капотом (обновить / обновить клиента, создать продукт, использовать результаты для вставки заказа — для накладной скопируйте данные пользователя / продукта, а не только свяжите их) … заказ [строка] не должен содержать прямого отношения к продукту (нет согласованности — изменение продукта влияет на более ранние отношения)