Lighthouse / GraphQL - получение `null` для отношения Polymorphi c в схеме GraphQL для программных удалений - PullRequest
0 голосов
/ 18 февраля 2020

У меня есть платформа, которая позволяет пользователям загружать аудиоклипы. Производители аудиоклипов могут видеть свою историю загрузок, но они также могут удалять файлы, которые больше не нужны для загрузки. Каждое событие загрузки имеет запись в БД с отношением polymorphi c к двум различным таблицам, в зависимости от типа аудиоклипа.

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

Laravel Download Модель (каждое событие загрузки создает запись здесь) - это может быть запись BirdSound или HumanSound:

class Download extends BaseModel
{
    protected $types = [
        'bird' => BirdSound::class,
        'human' => HumanSound::class,
    ];

    /**
     * @return MorphTo|EloquentBuilder|QueryBuilder
     */
    public function downloadable() : MorphTo
    {
        return $this->morphTo();
    }
}

Laravel BirdSound Модель (существует эквивалентная модель HumanSound). В этой таблице есть одна запись для каждого файла, доступного для загрузки:

class BirdSounds extends Sounds
{
    use SoftDeletes;

    /**
     * @return MorphMany|EloquentBuilder|QueryBuilder
     */
    public function Download(): MorphMany
    {
        return $this->morphMany(Download::class, 'downloadable');
    }
}

Схема GraphQL:

type Download {
    id: ID!
    name: String!
    email: String!
    downloadable: Downloadable @morphTo
}

interface Downloadable {
    id: ID!
    name: String
    freeDownloads: [Download!] @morphMany
}

type BirdSound implements Downloadable {
    id: ID!
    name: String
    duration: String
    user: User @belongsTo(relation: "user")
    filename: String
    freeDownloads: [Download] @morphMany 
}

type HumanSound implements Downloadable {
    id: ID!
    name: String
    snippet: Int
    user: User @belongsTo(relation: "user")
    artwork_id: Int
    freeDownloads: [Download] @morphMany
}

# Using DownloadCount type to handle the data returned by the laravel function that counts the downloads
type DownloadCount {
    downloadable_id: Int
    downloadable_type: String
    count: Int
    downloadable: MediaInfo
}

# Using MediaInfo instead of the actual `downloadable` object in order to include soft-deleted records, 
# which I can't get working with the polymorphic relationship for lighthouse
type MediaInfo {
    id: ID! # ID of the downloadable record
    name: String # name from the BirdSound or HumanSound
}

extend type Query {
    myTopDownloads(downloaded_at: DateRange)): [DownloadCount]  
        @field(resolver: "App\\GraphQL\\Queries\\FreeDownloads@topDownloads")
}

Laravel Функция, которая получает данные:

public function topDownloads($rootValue, array $args, GraphQLContext $context, ResolveInfo $resolveInfo)
{
    return auth()->guard('graphql')->user()->freeDownloads()
                    ->selectRaw('id, downloadable_id, downloadable_type, count(downloadable_id) as count')
                    ->groupBy('downloadable_id')
                    ->orderBy('count', 'desc')
                    ->with(['downloadable' => function($query){
                        $query->withTrashed();
                    }])
                    ->limit($limit)
                    ->get();
}

Приведенный выше запрос Laravel возвращает как информацию о загрузке, так и связанные загружаемые данные, независимо от того, были ли они удалены или нет, и с помощью схемы graphQL, описанной выше, я могу получить доступ к объекту downloadable через отношение MediaInfo на объекте Download. Однако я не могу понять, как получить фактическое отношение downloadable, как определено в моделях, доступных в graphQL - это отношение всегда показывает null.

Я пробовал следующее:

Изменение типа носителя :

type Media {
    id: Int
    downloadable_id: Int
    name: String
    downloadable_type: String
    count: Int
    downloadable: Downloadable @morphTo @softDeletes
}

Добавление trashed: Trash в запрос (который я предполагаю, является только одномерным, поэтому он не будет работать):

extend type Query {
    myTopDownloads(trashed: Trash, downloaded_at: DateRange)): [Download]  
        @field(resolver: "App\\GraphQL\\Queries\\FreeDownloads@topDownloads")
}

... Я пробовал несколько вариантов вышеупомянутых примеров, каждый из которых приводит к null для объекта downloadable, или я получаю ошибку.

Пример запроса:

{
  myTopDownloads{
    downloadable_id
    downloadable_type
    count
    downloadable(trashed:WITH) {
      __typename
      id
      name
    }
  }
}

"debugMessage": "Использовать @trashed только для классов модели, которые используют черту SoftDeletes.",

Все модели Laravel используют черту SoftDeletes, и я не смог найти документацию по добавлению определенной черты c к типу graphQL (например, в моем типе BirdSound).

Я предположим проблема может заключаться в том, что это полиморфное c отношение, но это мой первый проект с использованием GraphQL, и я все еще пытаюсь обернуть голову вокруг некоторых из деталей ... Любое понимание этого было бы здорово!

1 Ответ

1 голос
/ 16 апреля 2020

Согласно маяку, в полиморфном отношении c вы должны указать союз, указывающий, какие типы он может вернуть.

union Downloadable = HumanSound | BirdSound

https://lighthouse-php.com/master/eloquent/polymorphic-relationships.html#one-ко-многим

Для запроса этих типов используйте нотацию, чтобы указать для данного типа, какие поля возвращать

{
  myTopDownloads{
    downloadable_id
    downloadable_type
    count
    downloadable(trashed:WITH) {
      __typename
      ... on BirdSound {
        id
        name
      }
      ... on HumanSound {
        id
        name
      }
    }
  }
}

https://graphql.org/learn/schema/#union -типы

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

...