Могу ли я использовать директиву для фрагмента и условно вызвать его переменную? - PullRequest
0 голосов
/ 05 октября 2019

Я работаю над приложением, которое позволяет пользователям загружать большие наборы данных. Загрузчик имеет «черновую» версию, которую он может редактировать в пользовательском интерфейсе, а затем публикует снимки черновика, которые могут видеть все пользователи. Черновые файлы следует запрашивать только в том случае, если загрузчик вошел в систему.

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

В запросе есть фрагмент для данных "черновиков", включая условно нежелательные файлы. Если я опущу файлы из фрагмента, компонент будет работать для всех пользователей ... но тогда загрузчик не сможет получить свои черновые файлы. Так что, черт побери, если я это сделаю, будь я проклят, если я не буду в затруднительном положении, и мой недостаток опыта работы с graphql и apollo действительно сияет здесь.

Вот запрос и сопровождающий хук:

export const getDatasetPage = gql`
  query dataset($datasetId: ID!) {
    dataset(id: $datasetId) {
      id
      created
      public
      following
      starred
      ...DatasetDraft
      ...DatasetPermissions
      ...DatasetSnapshots
      ...DatasetIssues
      ...DatasetMetadata
      ...DatasetComments
      uploader {
        id
        name
        email
      }
      analytics {
        downloads
        views
      }
      onBrainlife
    }
  }
  ${DatasetQueryFragments.DRAFT_FRAGMENT}
  ${DatasetQueryFragments.PERMISSION_FRAGMENT}
  ${DatasetQueryFragments.DATASET_SNAPSHOTS}
  ${DatasetQueryFragments.DATASET_ISSUES}
  ${DatasetQueryFragments.DATASET_METADATA}
  ${DATASET_COMMENTS}
`

export const DatasetQueryHook = ({ datasetId }) => {
  const {
    data: { dataset },
    loading,
    error,
  } = useQuery(getDatasetPage, {
    variables: { datasetId },
  })
  if (loading) {
    return <Spinner text="Loading Dataset" active />
  } else {
    if (error) Sentry.captureException(error)
    return (
      <ErrorBoundary error={error} subject={'error in dataset page'}>
        <DatasetQueryContext.Provider
          value={{
            datasetId,
          }}>
          <DatasetPage dataset={dataset} />
        </DatasetQueryContext.Provider>
      </ErrorBoundary>
    )
  }
}

И вот фрагмент:

export const DRAFT_FRAGMENT = gql`
  fragment DatasetDraft on Dataset {
    id
    draft {
      id
      modified
      readme
      partial
      description {
        Name
        Authors
        DatasetDOI
        License
        Acknowledgements
        HowToAcknowledge
        Funding
        ReferencesAndLinks
      }
      files {    //when this is removed, it works...except for users with edit privileges
        id
        filename
        size
      }
      summary {
        modalities
        sessions
        subjects
        subjectMetadata {
          participantId
          age
          sex
          group
        }
        tasks
        size
        totalFiles
        dataProcessed
      }
    }
  }
`

Короче говоря: в запросе должны отсутствовать черновики файлов, если у пользователя нет прав на редактирование. Я знаю логику для hasEdit, но я не знаю, как я могу реализовать это с помощью директивы. Могу ли я даже использовать @skip для фрагмента, и даже если да, могу ли я передать его переменную условно? Я не могу найти в документации ничего об этом и не могу найти решение.

1 Ответ

1 голос
/ 05 октября 2019

Да, директивы могут использоваться внутри фрагментов, и да, вы можете использовать переменную для этого.

Вот простой пример с использованием API SWAPI:

query MyQuery ($showDate: Boolean!){
  allFilms {
    films {
      ...FilmFields
    }
  }
}

fragment FilmFields on Film {
  id
  title
  releaseDate @include(if: $showDate)
}

Следует отметить, что переменная все еще определяется как часть операции. Это означает, что если вы помещаете свои фрагменты в отдельные файлы и затем импортируете их в свои запросы, вам необходимо убедиться, что A) операция на самом деле определяет переменную и B) имя переменной правильное.

Bonus

Также стоит отметить, что существует экспериментальная поддержка определения переменных как части фрагментов. Это должно быть явно разрешено на стороне сервера. Если вы используете graphql-tag, он также должен быть явно включен там же . Если вы используете makeExecutableSchema или сервер Apollo, вы можете передать параметр parseOptions, чтобы включить эту функцию на стороне сервера:

makeExecutableSchema({
  typeDefs,
  resolvers,
  parseOptions: {
    experimentalFragmentVariables: true,
  },
})

Затем вы можете создавать фрагменты, такие как:

fragment FilmFields on Film ($showDate: Boolean!) {
  id
  title
  releaseDate @include(if: $showDate)
}
...