GraphQL, фильтрующий родительские данные в дочернем резольвере - PullRequest
0 голосов
/ 20 февраля 2019

Я пытаюсь понять, как реализовать фильтрацию снизу вверх в отношениях родитель-потомок, используя GraphQL.

Рассмотрим следующую иерархию базовых типов, моделирующую парковку и доступные парковочные места:

type ParkingLot {
  id: Int!
  spots: [ParkingSpot]
}

type ParkingSpot {
  id: Int!,
  occupied: Boolean!
}

Я хочу реализовать свои резольверы таким образом, чтобы я мог получить все парковки, которые имеютхотя бы одно бесплатное место для парковки.

query AllParkingLotsWithStatus($status : Boolean = false) {
   ParkingLot {
     id 
     spots(occupied: $status)  {
       id
     }
   }
}

Конкретная реализация GraphQL, которую я использую, основана на PHP и доступна здесь , но любая реализация на основе JS была бы действительно полезна, чтобы указать мне направильное направление.Я знаю, что есть библиотеки, которые поддерживают фильтрацию с использованием параметров «где:», но я должен был бы реализовать этот механизм сам, так как библиотека, которую я использую, не предлагает его из коробки.

Одна из идей, которую я исследовал, заключалась в том, чтобы просто написать оператор JOIN внутри распознавателя для ParkingLot, но я чувствую, что это не в духе GraphQL.

Еще одна идея, о которой я подумал, - переписать запрос так, чтобы он сначала извлекал парковочные места и получал их родителя, только если их статус доступен.Однако это может потребовать значительных вычислительных ресурсов, поскольку парковочных мест будет меньше, чем парковочных мест, поэтому переход между родителем и ребенком будет, вероятно, менее вычислительным.

Какой подход, по вашему мнению, не сводится кдля изменения иерархии типов (я не в состоянии сделать это).Возможно, существует ли способ отклонить родительский узел, как только в распознавателе дочернего объекта возникает какое-то условие, или это будет рассматриваться вне рамок реализации GraphQL и больше похоже на функцию используемой библиотеки?Я полагаю, поскольку некоторые библиотеки там поддерживают фильтрацию с использованием предложений "where:", это должно быть возможно и не должно быть сложным.

1 Ответ

0 голосов
/ 20 февраля 2019

Пара точек.

Предпочтительный способ разработки вашей схемы будет выглядеть примерно так:

type Query {
  parkingLots(where: ParkingLotFilter)
}

input ParkingLotFilter {
  isFull: Boolean
  # other conditions
}

Хотя вы можете добавить аргумент occupied к spots, это оченьнеинтересно, что запрос parkingLots возвращает только места для парковки, на которых есть свободные места, когда указывается этот аргумент.Если я укажу этот аргумент, я ожидаю получить всех парковок с полем spots на каждом, ограниченным местами, которые заняты / не заняты.Другими словами, фильтр для поля должен влиять только на разрешение этого поля, а не на разрешение родительского поля.

Это подводит нас ко второму пункту - ваша проблема может быть просто решена на стороне клиента.Может быть достаточно выставить аргумент occupied на spots и оставить его при этом.Затем клиент получит список парковок, некоторые из которых могут иметь пустой массив для поля spots.Затем клиент может просто отфильтровать список парковок по длине поля spots, чтобы получить список участков, которые заполнены или не заполнены.

Если это неприемлемо, то самый простой способсправиться с этой проблемой, чтобы сделать соединение, как вы предлагаете.В этом нет ничего «не в духе GraphQL» - многие инструменты, такие как join-monster и postgraphile , эффективно используют один и тот же подход.Используя соединение, вы можете получить места для каждой парковки и вернуть их как часть объекта парковки, который возвращается в распознавателе.Пока объект имеет свойство spots, значение этого свойства будет использоваться для разрешения поля spots (при условии, что вы не пишете свой собственный преобразователь).

...