Gatsby: [bug] ☂️ problema geral para problemas de personalização de esquema

Criado em 4 mar. 2019  ·  131Comentários  ·  Fonte: gatsbyjs/gatsby

Este é um metaproblema para todos os problemas com 2.2.0, que foram introduzidos pela refatoração do esquema.

O que?

Veja a postagem do

Veja a postagem do blog de lançamento para notas de lançamento e atualizações finais.

Como?

Instale a versão mais recente do Gatsby e tente executar seu site. Esperançosamente, tudo funcionará. Se quiser, você também pode tentar as duas novas APIs ( createTypes e createResolvers ).

yarn add gatsby

Changelog

[email protected]

  • Publicados

[email protected]

  • Movido para diretivas explícitas em vez de addResolver

[email protected]

  • Master back merge, upgrade graphql-compose

[email protected]

  • Veja # 13028

[email protected]

  • :champanhe:

[email protected]

  • Corrigida uma regressão quando strings vazias misturadas com datas fazem com que as coisas não sejam interpretadas como datas

[email protected]

  • mesclar último mestre
  • atualização de documentos

[email protected]

  • mesclar último mestre
  • melhores mensagens de erro de análise SDL

[email protected]

  • corrigir regressão na nomenclatura de conexão em tipos de caso são nomeados em minúsculas

[email protected]

  • Escalares personalizados corrigidos sem filtros
  • Adicionados erros ao tentar substituir a interface do Node ou os tipos de filtro / classificação gerados.

[email protected]

  • Adicionada uma nova API de conveniência modelada após graphql-compose. Veja o exemplo de definição de tipo de uso.
exports.sourceNodes = ({ actions, schema }) => {
  const { createTypes } = actions
  createTypes([
    schema.buildObjectType({
      name: `CommentJson`,
      fields: {
        text: `String!`,
        blog: {
          type: `BlogJson`,
          resolve(parent, args, context) {
            return context.nodeModel.getNodeById({
              id: parent.author,
              type: `BlogJson`,
            })
          },
        },
        author: {
          type: `AuthorJson`,
          resolve(parent, args, context) {
            return context.nodeModel.getNodeById({
              id: parent.author,
              type: `AuthorJson`,
            })
          },
        },
      },
      interfaces: [`Node`],
    }),
  ])
}

[email protected]

  • Regressão corrigida com o campo de id do nó não sendo uma string, como no mestre atual.
  • Atualizado para [email protected]
  • FilterInput tipos agora não são prefixados pelo tipo de saída, reduzindo a proliferação de tipos

[email protected]

  • Corrigido o problema de paginação sobre resultados de consulta nulos
  • @dontInfer(noDefaultResolvers: false) realmente funciona
  • em createResolvers resolvers info.originalResolver está disponível mesmo se não houver um resolvedor no campo original

[email protected]

  • Versão alfa refeita com versão de lançamento adequada
  • Corrija os tipos de nó sem que os nós reais não sejam adicionados

[email protected]

  • Alfa inicial
GraphQL

Comentários muito úteis

Publicado em [email protected] . Obrigado a todos!

Todos 131 comentários

Os filtros para campos de ID agora esperam um ID como entrada onde eles desejavam uma string anteriormente. Isso quebra certas consultas, por exemplo:

export const query = graphql`
  query BlogPostTemplateQuery($id: String!) {
    post: sanityPost(id: { eq: $id }) {
      id
      title
    }
  }
`

Irá relatar:

error GraphQL Error Variable "$id" of type "String!" used in position expecting type "ID".

Embora possa ser mais correto atualizar a consulta para refletir isso, é uma alteração importante, então pensei em relatá-la.

@rexxars Belo achado! Presumo que costumávamos converter filtros de ID em String. Vou restaurar o comportamento antigo.

Lançada nova versão.

Tentando consultar o esquema no resolvedor:

exports.createResolvers = ({ createResolvers, schema }) => {
  createResolvers({
    MenuJson: {
      someResolver: {
        type: `String!`,
        async resolve(source, args, context, info) {
          const foo = await graphql(schema, `
            {
              allPageJson {
                nodes {
                  id
                }
              }
            }
          `, {})

          console.log(foo)

          return 'WIP'
        },
      },
    },
  })
}
TypeError: Cannot read property 'nodeModel' of undefined
         at /private/tmp/test-gatsby/node_modules/gatsby/dist/schema/resolvers.js:22:15
         at /private/tmp/test-gatsby/node_modules/gatsby/dist/schema/resolvers.js:49:44
         at Generator.next (<anonymous>)
[...]

@NicoleEtLui Para consultas no resolvedor de campo, use os métodos fornecidos em context.nodeModel , ou seja, você pode usar context.nodeModel.getAllNodes({ type: 'PageJson' }) ou para consultas mais sofisticadas, você pode usar context.nodeModel.runQuery . Existem alguns exemplos básicos aqui .

Se você precisar acessar o esquema, observe que o argumento schema é apenas uma representação intermediária - no resolvedor, você tem acesso ao esquema final construído em info.schema .

Publicado em [email protected]

@stefanprobst Obrigado pela resposta rápida e por todo o excelente trabalho que você fez!

Oi!
Alguma sugestão para lidar com relacionamentos entre nós?

Por exemplo, os arquivos são armazenados em JSON (sem campo de id, assuma o nome do arquivo como id):
data/comments/some-uuid.json = { "message": "Hello", "postId": "some-post" }
data/posts/some-post.json = { "content": "post" }

Usando os plugins source-filesystem e transformer-json , isso faz com que os nós tenham um ID imprevisível, já que o transformador usa createNodeId() . Torna difícil encontrar post de comment .

Oi !
Tentando iniciar o projeto gatsby com qualquer um desses em gatsby-config.js :

  • gatsby-transformer-sharp
  • gatsby-plugin-sharp
  • gatsby-plugin-manifest

vai jogar:

error Plugin gatsby-transformer-sharp returned an error


  Error: Cannot find module 'gatsby/dist/utils/cpu-core-count'

  - loader.js:581 Function.Module._resolveFilename
    internal/modules/cjs/loader.js:581:15

  - loader.js:507 Function.Module._load
    internal/modules/cjs/loader.js:507:25

  - loader.js:637 Module.require
    internal/modules/cjs/loader.js:637:17

  - v8-compile-cache.js:159 require
    [keemotion-corporate]/[v8-compile-cache]/v8-compile-cache.js:159:20
[...]

@NicoleEtLui Atualize gatsby-plugin-manifest e gatsby-plugin-sharp , isso foi corrigido nesses pacotes com https://github.com/gatsbyjs/gatsby/pull/12332

Publicado em [email protected]

@LoicMahieu você pode fornecer manualmente os ids para os nós, então você pode fazer relacionamentos especificando fieldName___NODE campos.

Publicado em [email protected]

Q: É este o caso de uso adequado para createResolvers ?

Eu estou usando um CMS remoto via gatsby-source-graphql que inclui referências a vários arquivos remotos. Atualmente, estou puxando esses arquivos com createRemoteFileNode . No entanto, as consultas página ficar estranho rapidamente, porque é fácil entrar em situações onde eu preciso do resultado da consulta cms (no gatsby-source-graphql fonte de dados) para descobrir quais arquivos vou precisar de gatsby-source-filesystem .

Idealmente, gostaria de adicionar / link / join (?) Esses nós de arquivo remoto nos nós cms de gatsby-source-graphql . Será esta uma situação que createResolvers possa ajudar?

@skinandbones Se estou entendendo corretamente, a resposta curta é "talvez, mas provavelmente ainda não".

Fazemos apoio estendendo configurações de campo sobre os tipos adicionados a partir de um esquema de terceiros, por isso, é possível adicionar um resolvedor campo para um tipo de seu esquema CMS com createResolvers , e usar createRemoteFileNode no resolver. Por exemplo:
https://github.com/stefanprobst/gatsby/blob/5bbfee29b5ec38f13a3070b13de4877aaddd6483/examples/using-gatsby-source-graphql/gatsby-node.js#L56 -L71

O problema é que createRemoteFileNode acionará onCreateNode chamadas de API, e no resolvedor de campo não temos atualmente nenhuma maneira de saber quando essas chamadas de API subsequentes terminaram e é seguro para o resolvedor retornar. (Uma abordagem para resolver isso poderia ser # 12202.) Portanto, dependendo do que exatamente você pretende fazer com os arquivos remotos, isso pode ou não funcionar.

@LoicMahieu Você tem um projeto de exemplo para o qual pode criar um link?

@stefanprobst Sim, você entendeu corretamente e o problema assíncrono faz sentido. O exemplo que você vinculou é muito semelhante ao que eu esperava, então posso tentar e ver o que acontece. Meu plano é executar esses nós de arquivo por meio de gatsby-transformer-sharp na consulta de página.

Outra abordagem viável é usar createRemoteFileNode por meio da API sourceNodes (como de costume) e vincular esses nós ao esquema de terceiros usando a nova API? Até este ponto, não consegui entrar no esquema de terceiros para fazer isso.

@skinandbones desculpe, eu deveria ter esclarecido: a parte no exemplo que eu não está funcionando, exatamente por causa do problema de que quando o resolvedor de campo retornar, o nó File terá sido criado, mas o ImageSharp node (que é criado na chamada de API onCreateNode acionada) ainda não.

Quanto à segunda abordagem, estou interessado em suas descobertas - deve ser possível consultar os nós File remotos adicionados no resolvedor com context.nodeModel.getAllNodes({ type: 'File' }) ou algo como context.nodeModel.runQuery({ type: 'File', query: { filter: { name: { regex: "/^remote/" } } } })

@stefanprobst
Aqui está um exemplo:

  1. https://github.com/LoicMahieu/test-gatsby-refactor-schema
    Aqui podemos vincular comments a post por meio de uma pesquisa complexa no pai File .
  1. https://github.com/LoicMahieu/test-gatsby-refactor-schema/tree/custom-transformer-json
    Aqui, podemos vinculá-los usando um transformador JSON personalizado, onde poderíamos transformar o objeto e também alterar o id.
    Este método funciona, mas: se a postagem for excluída e a referência ainda existir nos comentários, o gatsby falhará.
    Isso poderia ser corrigido não usando a maneira ___NODE , mas sim a nova createResolvers : demo

Ei, acabei de ler esta postagem do blog sobre personalização de esquema e o exemplo de aniversário meio que me pareceu estranho. No exemplo, você está criando um resolvedor personalizado, que tenta resolver um campo de data em uma data e retorna a um valor falso (01-01-1970) se a data de entrada não for uma data adequada. Se você já teve uma data em um sistema real, nunca iria querer substituir entradas incorretas por dados falsos. Você gostaria de sinalizá-los como desconhecidos / incorretos com algo como valores nulos. O fato de null não ser usado no exemplo me fez pensar: existe algum tipo de limitação no Gatsby / GraphQL wrt. valores nulos?

@baobabKoodaa

existe algum tipo de limitação no Gatsby / GraphQL wrt. valores nulos?

Não. No GraphQL, você pode definir explicitamente se um campo deve ser anulável ou não. Mais informações aqui .

@stefanprobst Eu e funciona com ImageSharp . Muito, muito legal e uma virada de jogo para trabalhar com um esquema de terceiros 🎉 🎉

Quanto à segunda abordagem, estou interessado em suas descobertas - deve ser possível consultar os nós remotos File no resolvedor com context.nodeModel.getAllNodes({ type: 'File' }) ou algo como context.nodeModel.runQuery({ type: 'File', query: { filter: { name: { regex: "/^remote/" } } } })

Aqui está o que eu fiz ...

exports.sourceNodes = async ({ actions, store, cache, createNodeId }) => {
  ... do createRemoteFileNode stuff ...
}

exports.createResolvers = ({ createResolvers, schema }) => {
  createResolvers({
    CMS_Thing: {
      thumbFile: {
        type: 'File!',
        async resolve(source, args, context, info) {
          const data = await context.nodeModel.runQuery({
            type: 'File',
            query: { filter: { fields: { ThingThumb: { eq: 'true' }, thingId: { eq: source.id } } } }
          })
          return data[0];
        }
      }
    }
  });
}

(Isso depende de eu criar os nós de arquivo com alguns campos, obviamente.)

O caminho ideal (para o meu caso de uso) será poder usar createRemoteFileNode em createResolvers portanto, esperançosamente, podemos descobrir isso.

@skinandbones Muito legal! A propósito, você pode usar firstOnly: true em runQuery para obter apenas o primeiro resultado.

Lançado em [email protected] .

A meta provisória é mesclar isso para dominar e liberar na próxima semana. Por favor, comente e experimente :)

Parece que os filtros para campos do tipo resolvidos em um createResolvers() não são gerados.

Exemplo:

  • post.json : { "id": "some-post", "author": "Loic", message: "Hello" }
  • comment.json : { "postId": "some-post", message: "World" }
createResolvers({
  CommentsJson: {
    post: {
      type: `PostsJson`,
      resolve (source, args, context, info) {
        const allNodes = context.nodeModel.getNodeById({ id: source.postId, type: 'PostsJson' })
      }
    }
  }
})

CommentsJsonFilterInput tipo não contém post campo. Portanto, uma consulta como esta não poderia funcionar:

{
  allCommentsJson(filter: {post: {author: {eq: "foo"}}}) {
    nodes {
      id
    }
  }
}

Obrigado

@LoicMahieu Este é o comportamento pretendido (pelo menos por agora): novos campos adicionados em createResolvers não estarão presentes no filtro de entrada, porque createResolvers é executado por último na geração do esquema. A abordagem recomendada aqui é definir um tipo de campo com createTypes action e então estendê-lo em createResolvers - ou usar o auxiliar buildObjectType adicionado recentemente (veja acima).

Lamentamos que isso ainda não esteja melhor documentado - por enquanto, você pode dar uma olhada na documentação da API diretamente no branch: createResolvers e createTypes .

@LoicMahieu isso é intencional, adicionar resolvedores acontece após todo o processamento e é uma ferramenta para fazer ajustes finais no esquema. Você deve adicionar campos em createTypes se quiser que eles apareçam nos filtros. Há uma nova sintaxe abreviada que você pode usar, consulte a postagem principal.

EDITAR: Opa, não vi @stefanprobst respondendo já: D

Obrigado a ambos pelo esclarecimento. createResolvers e createTypes parecem atingir o mesmo objetivo.


Uma coisa que pode ser realmente útil é salvar o esquema gerado. Isso permitiria "fazer um instantâneo" dos tipos e garantir que o esquema permanecerá como esperamos.
Escrevi um POC que parece funcionar bem:

const { printType } = require("graphql")
const fs = require("fs-extra")
const path = require("path")

const schemaFilePath = path.join(__dirname, "./src/schema.gql")

exports.sourceNodes = async ({ actions }) => {
  const { createTypes } = actions

  if (await fs.exists(schemaFilePath)) {
    const typeDefs = (await fs.readFile(schemaFilePath)).toString()
    createTypes(typeDefs)
  }
}

exports.onPostBootstrap = async ({ store }) => {
  const { schema } = store.getState()
  const types = ["CommentsJson", "PostsJson"]
  const typeDefs = types
    .map(type => printType(schema.getType(type)))
    .join("\n\n")
  await fs.writeFile(schemaFilePath, typeDefs + "\n")
}

Com isso podemos até excluir todos os dados e o esquema ainda está como esperamos.
Demonstração: https://github.com/LoicMahieu/test-gatsby-refactor-schema/commit/9696c8e386fd066262164f8e38f5689a14f111e1

@LoicMahieu: +1: Algo como isso é parte do nosso roteiro .

Isso não afeta o encadeamento da construção do esquema, certo?

Referindo-se ao comentário: https://github.com/gatsbyjs/gatsby/issues/7373#issuecomment -413570634

Apenas um processo do Node está funcionando (este screencap _não_ é da versão beta, apenas adicionando-o aqui para ilustrar meu ponto):

Screenshot 2019-01-10 10 14 07

@hilja A nova API de customização de esquema não é sobre a execução de consultas , mas sobre a geração de esquema, portanto, isso ainda não mudou. Há um trabalho experimental em andamento para permitir que os resolvedores de campo transfiram o trabalho para outros processos, mas isso ainda não está pronto.

Lançado em 2.2.0-rc.1 . Em breve.

A classificação da consulta em campos recém-criados parece cheia de erros.

Posso criar um novo campo fazendo:

exports.sourceNodes = ({ actions }) => {
  const { createTypes } = actions
  const typeDefs = `
    type MyNode implements Node {
      copyOfId: ID!
    }
  `
  createTypes(typeDefs)
}

exports.createResolvers = ({ createResolvers }) => {
  createResolvers({
    MyNode: {
      copyOfId: {
        resolve(source, args, context, info) {
          return info.originalResolver(
            {
              ...source,
              copyOfId: source.id,
            },
            args,
            context,
            info,
          )
        },
      },
    },
  })
}

Mas então se eu questionar:

query {
    allMyNode (sort: {fields: [copyOfId]}) {
      nodes {
        copyOfId
    }
  }
}

os resultados não são classificados e aparecem na ordem original.

Se eu classificar em id está tudo bem, é claro.

Eu acho que este é o mesmo problema que @LoicMahieu mencionou anteriormente, mas isso é realmente enganoso. Se não podemos fazer isso, então tem que ser super bem documentado porque parece natural para mim facilitar minha filtragem e classificação criando os campos apropriados com esses novos métodos de API.

PS: esqueci de mencionar ... essa nova API é incrível !! : D Não se deixe enganar pelo meu comentário, pensando que estou pessimista. Só estou tentando ser útil. ;) Obrigado pelo excelente trabalho!

@MarcCoet Obrigado por testar! Este é um problema conhecido - atualmente não chamamos resolvedores de campo para campos de classificação, consulte # 11368. É a próxima coisa que abordaremos quando isso for mesclado!

Oh, desculpe. Não pensei em procurar setFieldsOnGraphQLNodeType questões. Foi mal.
Fico feliz em saber que está sendo trabalhado.

então não há realmente nenhuma maneira de contornar isso com a nova API? Temos que seguir os métodos antigos de createNodeField ?

Tentei com buildObjectType mas o mesmo resultado.

exports.sourceNodes = ({ actions, schema }) => {
  const { createTypes } = actions

  createTypes([
    schema.buildObjectType({
      name: `MyNode`,
      fields: {
        copyOfId: {
          type: `ID!`,
          resolve(parent) {
            return parent.id
          },
        },
      },
      interfaces: [`Node`],
    }),
  ])
}

Qualquer outra forma não documentada de conseguir a classificação em novos campos de nó por acaso?

Além disso, acabei de ter um erro de sintaxe com a diretiva @infer() . Mas eu acho que é o que 'Permitir opções de inferência em tipos não SDL' significa nos problemas conhecidos acima ?!

@MarcCoet

erro de sintaxe com a diretiva @infer()

Isso funciona para você?

createTypes('type MyNode implements Node <strong i="11">@infer</strong> { foo: Boolean }')

Quanto ao problema de classificação: este problema é um pouco ortogonal ao refatorador de customização do esquema. O problema é: quando queremos filtrar ou classificar os campos que não estão no objeto de nó em si, mas adicionados por resolvedores de campo, precisamos chamar esses resolvedores antes, para termos todos os nós disponíveis para filtragem e classificação. Por exemplo, em seu exemplo, o objeto de nó não tem um campo copyOfId - para que ele esteja disponível, precisamos chamar o resolvedor antes de filtrar e classificar. Atualmente, fazemos isso apenas para campos de filtro, mas não para campos de classificação. Como alternativa, você pode tentar adicionar um filtro fictício para copyOfId à sua consulta:

query {
  allMyNode (sort: { fields: [copyOfId] }, filter: { copyOfId: { ne: null } }) {
    nodes {
      copyOfId
    }
  }
}

Veja também este comentário .

Estou tentando definir o esquema para os nós do frontmatter gerados por gatsby-transformador-observação e sempre me deparo com este erro: Error: Schema must contain unique named types but contains multiple types named "MarkdownRemarkFrontmatter".

Meu esquema é assim:

type MarkdownRemarkFrontmatter implements Node {
  title: String
}

@kennedyrose Obrigado por testar! O seguinte funciona para você?

exports.sourceNodes = ({ actions }) => {
  const { createTypes } = actions
  createTypes(`
    type MarkdownRemarkFrontmatter {
      title: String
    }
    type MarkdownRemark implements Node {
      frontmatter: MarkdownRemarkFrontmatter
    }
  `)
}

Apenas tipos de nível superior, ou seja, tipos de nós gerados por plug-ins de origem e de transformador (como MarkdownRemark ou ImageSharp ) devem implementar a interface de Nó, não tipos aninhados como o tipo de frontmatter.
(Embora não parecem ter um erro ao alvejar tipos inferido aninhadas diretamente)

Isso funciona. Obrigado!

Publicado em [email protected] .

Publicado em [email protected] . Obrigado a todos!

@stefanprobst

Isso funciona para você?
createTypes('type MyNode implements Node <strong i="9">@infer</strong> { foo: Boolean }')

É verdade! Então, é apenas o artigo original que é enganoso.

Acho que o nevoeiro vai aumentar com a chegada da documentação adequada. ;)

Sobre a questão da triagem, muito obrigado pelos esclarecimentos. Isso é muito útil.
A solução alternativa parece estar funcionando, então, por enquanto, é perfeita.

Estou muito animado com as novas possibilidades de Gatsby. Muito obrigado pelo trabalho que vocês colocaram em Gatsby.

Deseja postar gatsbyjs / gatsby # 12696, especificamente esta postagem

Parece que a inferência / detecção de arquivos pode ter sido ligeiramente ajustada aqui? A atualização para 2.2.2 quebrou, enquanto ~2.1.0 parece inferir corretamente o nó do arquivo.

Acabei de descobrir isso ao experimentar a criação de interfaces personalizadas usando a API. Usar a função resolveType na interface funciona, mas não usar funções isTypeOf nos objetos que compartilham a interface. Acho que isso se deve ao código abaixo em schema.js, que assume que resolveType deve ser node, quando nenhuma função é declarada. Essa suposição agora está incorreta com os tipos de interface customizada.

if (!typeComposer.getResolveType()) {
      typeComposer.setResolveType(node => node.internal.type);
    }

A propósito, ótimo trabalho, bem a tempo para o meu projeto!

Olá @Wolfsun. Sim, uma vez que não é possível fornecer resolveType via SDL, fornecemos um padrão que deve funcionar na maioria dos casos e permitimos fornecer um personalizado via graphql-js tipos. É verdade que isso não funciona bem com isTypeOf . Por curiosidade: há um motivo para usar isTypeOf vez de resolveType ?

Olá @stefanprobst , obrigado pela explicação. Usar resolveType é perfeitamente viável para mim neste estágio, no entanto, usar com isTypeOf seria um pouco mais limpo, pois tenho uma interface com muitos objetos de implementação. Estou usando uma estrutura de dados para representar layouts baseados em grade bastante complexos, tenho uma interface Card e muitos CardTypes implementando essa interface, que são armazenados na estrutura de dados em relação à sua posição na grade. Como não conheço o CardType de antemão, é necessária uma interface. Potencialmente, isTypeOf pode ser útil se eu quiser usar um sistema de plug-in para placas adicionais, mas ainda não pensei muito nisso e pode até não ser uma boa ideia, sendo um problema para outro dia!

Para facilitar a descoberta, estou vinculando a este exemplo que talvez outros também considerem útil. Espero que esteja tudo bem.

Estou tendo exatamente o mesmo problema que @kennedyrose , mas no meu caso a solução fornecida por @stefanprobst não ajudou muito, embora eu não tenha certeza do que estou fazendo, apenas tentei todas as maneiras possíveis de criar isso esquema, mas sempre retorna um erro em relação a multiple types named... .

Aqui está o código:

exports.sourceNodes = ({ actions }) => {
  const { createTypes } = actions;
  const typeDefs = `
    type Wordpress__PAGEAcfIntro {
      title: String
      content: String
    }
    type Wordpress__PAGEAcfThe_problem {
      title: String
      content: String
    }
    type Wordpress__PAGEAcfThe_solution {
      title: String
      content: String
    }
    type Wordpress__PAGEAcf {
      Intro: Wordpress__PAGEAcfIntro
      The_problem: Wordpress__PAGEAcfThe_problem
      The_solution: Wordpress__PAGEAcfThe_solution
    }
    type Wordpress__PAGE implements Node {
      acf: Wordpress__PAGEAcf
    }
  `;
  createTypes(typeDefs);
};

No início, tentei definir apenas os tipos de que precisava (os 3 primeiros) com seus campos, mas então obtive Error: Schema must contain unique named types but contains multiple types named "Wordpress__PAGEAcfIntro". . Enquanto procurava por uma solução, tentei a solução @stefanprobst (como no meu código, mas não tenho certeza se correta), mas não tive sorte.

Além disso, isso é muito para apenas fazer alguns campos terem valores de string opcionais (a consulta será interrompida se algum dos campos não tiver um título ou conteúdo), e esta é apenas a implementação inicial, provavelmente terei que fazer o mesmo em todo o site para muito mais campos que também podem ser opcionais, então estou com muito medo dessa solução e realmente espero que haja uma maneira melhor de resolvê-la.

Bem, depois de pesquisar mais e tentar coisas sem realmente saber o que estou fazendo, eu vim com este trecho que resolveu o problema:

exports.createResolvers = ({ createResolvers }) => {
  createResolvers({
    Wordpress__PAGEAcfIntro: {
      title: { type: `String` },
      content: { type: `String` },
    },
    Wordpress__PAGEAcfThe_problem: {
      title: { type: `String` },
      content: { type: `String` },
    },
    Wordpress__PAGEAcfThe_solution: {
      title: { type: `String` },
      content: { type: `String` },
    },
  });
};

Embora eu ainda não saiba por que minha primeira solução não funcionou. Isso parece ser muito mais fácil de manter.

As considerações finais são que não tenho certeza se apenas não tenho conhecimento das APIs de Gatsby ou se os documentos são enganosos para esse problema específico. Acho que deveria ser mais fácil encontrar uma solução para a questão how to have optional fields in a graphql query using gatsby , porque é uma coisa extremamente básica quando se trabalha com um CMS como o WordPress, onde você pode ter vários campos personalizados e provavelmente muitos deles vão seja opcional.

Declarar um campo como uma matriz de arquivos não funciona para mim.

exports.sourceNodes = ({ actions }) => { const { createTypes } = actions const typeDefs = ` type MarkdownRemarkFrontmatter implements Node { images: [File] } type MarkdownRemark implements Node { frontmatter: MarkdownRemarkFrontmatter } ` createTypes(typeDefs) }
Provavelmente tem algo a ver com https://github.com/gatsbyjs/gatsby/issues/12696

Estou tendo exatamente o mesmo problema que @kennedyrose , mas no meu caso a solução fornecida por @stefanprobst não ajudou muito, embora eu não tenha certeza do que estou fazendo, apenas tentei todas as maneiras possíveis de criar isso esquema, mas sempre retorna um erro em relação a multiple types named... .

Aqui está o código:

exports.sourceNodes = ({ actions }) => {
  const { createTypes } = actions;
  const typeDefs = `
    type Wordpress__PAGEAcfIntro {
      title: String
      content: String
    }
    type Wordpress__PAGEAcfThe_problem {
      title: String
      content: String
    }
    type Wordpress__PAGEAcfThe_solution {
      title: String
      content: String
    }
    type Wordpress__PAGEAcf {
      Intro: Wordpress__PAGEAcfIntro
      The_problem: Wordpress__PAGEAcfThe_problem
      The_solution: Wordpress__PAGEAcfThe_solution
    }
    type Wordpress__PAGE implements Node {
      acf: Wordpress__PAGEAcf
    }
  `;
  createTypes(typeDefs);
};

No início, tentei definir apenas os tipos de que precisava (os 3 primeiros) com seus campos, mas então obtive Error: Schema must contain unique named types but contains multiple types named "Wordpress__PAGEAcfIntro". . Enquanto procurava por uma solução, tentei a solução @stefanprobst (como no meu código, mas não tenho certeza se correta), mas não tive sorte.

Além disso, isso é muito para apenas fazer alguns campos terem valores de string opcionais (a consulta será interrompida se algum dos campos não tiver um título ou conteúdo), e esta é apenas a implementação inicial, provavelmente terei que fazer o mesmo em todo o site para muito mais campos que também podem ser opcionais, então estou com muito medo dessa solução e realmente espero que haja uma maneira melhor de resolvê-la.

@eddiemf , não tenho certeza, mas acho que o problema que você pode estar tendo é que os tipos que está tentando definir já foram inferidos da fonte de dados do Wordpress. Portanto, na verdade, eles estão sendo definidos duas vezes. Usar createResolvers simplesmente criará novos campos em tipos existentes ou substituirá os campos existentes (?) Pela aparência das coisas.

Muitas pequenas correções em 2.2.10 , incluindo relacionamentos explícitos de Node funcionando corretamente.

@Wolfsun Sim, isso é exatamente o que eu pensei sobre isso, mas eu sinto que os documentos levam você a usar createTypes como uma solução para este problema, quando na verdade você deveria usar createResolvers .

Como eu disse, acho que esse é um problema super comum quando se trata de WordPress, então seria bom ter uma solução bem documentada para isso.

@eddiemf Não estou muito familiarizado com o plugin wordpress, mas estender tipos no exemplo using-wordpress pareceu funcionar como esperado. Se você puder fornecer um link para seu repo, posso dar uma olhada em qual pode ser o problema.

Observe que estamos cientes de que ainda não temos muita documentação. Meu palpite é que o problema tem a ver com quais tipos devem implementar a interface Node - isso é algo que deve ser feito principalmente pelos próprios plug-ins (assim que forem portados para as novas APIs).

A semântica da interface Node é marcar os tipos que são apoiados por nós reais no armazenamento de dados interno de Gatsby, ou seja, os objetos que são criados pela ação createNode por plug-ins e têm um id campo. Isso significa que, embora o tipo Frontmatter esteja lá apenas para definir a forma no campo frontmatter em MarkdownRemark nodes, acho que o plugin wordpress realmente registra muitos top- tipos de nós de nível.

@stefanprobst Eu entendo completamente sobre ser leve na documentação por enquanto, estou apenas tentando ajudar :)

Resumindo, uma página WordPress em meu aplicativo tem uma estrutura parecida com page -> acf -> someGroupOfFields -> actualField . Em uma consulta, eu faria o seguinte como exemplo:

wordpressPage(slug: { eq: "home" }) {
  acf {
    intro {
      title
      content
    }
  }
}

Os tipos são gerados automaticamente para ser algo como WordPress__PAGE -> WordPress__PAGEAcf -> WordPress__PAGEAcfIntro . O problema é que esses campos muitas vezes podem ser apenas campos opcionais ( title e content ), então, se um desses campos não fosse fornecido, minha consulta seria interrompida, pois é gerada automaticamente com base no dados.

Não vejo nenhuma maneira possível para o plug-in criar esses campos automaticamente (como ele saberia?), Mas posso estar errado. Portanto, minha primeira solução foi apenas usar createTypes e criar esse tipo WordPress__PAGEAcfIntro com os campos apropriados, mas recebi o erro mencionado.

Eu diria que há algum conflito entre minha criação de tipo e Gatsby / plugin de origem criando o mesmo tipo depois de buscar os dados, mas realmente não estou na melhor posição para fazer suposições porque não tenho nenhuma experiência com GraphQL ou Gatsby API , então não tenho certeza de como as coisas realmente deveriam funcionar.

Mas, como eu disse, por enquanto, criar os resolvedores como em meu último post funcionou muito bem, então estou basicamente criando tipos para tudo que preciso buscar, já que eles sempre podem ser opcionais no CMS.

Você pode verificar meu gatsby-node.js aqui para ver como eu fiz isso.

@eddiemf Isso é interessante. Você tem um exemplo com o erro "O esquema deve conter tipos nomeados exclusivos, mas contém vários tipos chamados" Wordpress__PAGEAcfIntro ""? Gatsby deve ser capaz de manipular tipos de substituição que são inferidos, então não tenho certeza de por que seu código não funciona.

@freiksenet Recebi este erro ao tentar resolvê-lo assim:

exports.sourceNodes = ({ actions }) => {
  const { createTypes } = actions;
  const typeDefs = `
    type Wordpress__PAGEAcfIntro {
      title: String
      content: String
    }
  `;
  createTypes(typeDefs);
};

O campo title foi definido no CMS, mas content estava vazio, então tentei o trecho acima e obtive este erro de nome exclusivo.

Eu também pensei o mesmo sobre a possibilidade de substituir tipos, porque isso é o que os documentos e o artigo sobre esse novo recurso também dizem, então fiquei surpreso ao ver que não funcionou como esperado.

Acho que é quase o mesmo problema que o seguinte:

Estou tentando definir o esquema para os nós do frontmatter gerados por gatsby-transformador-observação e sempre me deparo com este erro: Error: Schema must contain unique named types but contains multiple types named "MarkdownRemarkFrontmatter".

Meu esquema é assim:

type MarkdownRemarkFrontmatter implements Node {
  title: String
}

Com a diferença de que a solução que funcionou para ele não funcionou de verdade para mim. Mas também parece que a parte implements Node foi usada incorretamente aqui, enquanto no meu caso deveria estar correta.

@eddiemf você precisa usar os tipos não-nós em algum lugar para sobrescrevê-lo. Portanto, MarkdownFrontmatter (sem Nó de implementos) precisa ser usado no nó Markdown e Wordpress__PageAcfIntro deve ser usado no WorpressPage. Adicionaremos um erro melhor, mas fizemos esse comportamento dessa forma para que ninguém substitua acidentalmente um nó embutido.

@freiksenet você quer dizer como eu fiz aqui?

Estou tendo exatamente o mesmo problema que @kennedyrose , mas no meu caso a solução fornecida por @stefanprobst não ajudou muito, embora eu não tenha certeza do que estou fazendo, apenas tentei todas as maneiras possíveis de criar isso esquema, mas sempre retorna um erro em relação a multiple types named... .

Aqui está o código:

exports.sourceNodes = ({ actions }) => {
  const { createTypes } = actions;
  const typeDefs = `
    type Wordpress__PAGEAcfIntro {
      title: String
      content: String
    }
    type Wordpress__PAGEAcfThe_problem {
      title: String
      content: String
    }
    type Wordpress__PAGEAcfThe_solution {
      title: String
      content: String
    }
    type Wordpress__PAGEAcf {
      Intro: Wordpress__PAGEAcfIntro
      The_problem: Wordpress__PAGEAcfThe_problem
      The_solution: Wordpress__PAGEAcfThe_solution
    }
    type Wordpress__PAGE implements Node {
      acf: Wordpress__PAGEAcf
    }
  `;
  createTypes(typeDefs);
};

No início, tentei definir apenas os tipos de que precisava (os 3 primeiros) com seus campos, mas então obtive Error: Schema must contain unique named types but contains multiple types named "Wordpress__PAGEAcfIntro". . Enquanto procurava por uma solução, tentei a solução @stefanprobst (como no meu código, mas não tenho certeza se correta), mas não tive sorte.

Além disso, isso é muito para apenas fazer alguns campos terem valores de string opcionais (a consulta será interrompida se algum dos campos não tiver um título ou conteúdo), e esta é apenas a implementação inicial, provavelmente terei que fazer o mesmo em todo o site para muito mais campos que também podem ser opcionais, então estou com muito medo dessa solução e realmente espero que haja uma maneira melhor de resolvê-la.

Tentei criar, digamos, a "árvore de tipo inteiro" ou "modelo de tipo", definindo todos os campos possíveis e usando-os como no exemplo, mas obtive o mesmo erro (às vezes um erro ligeiramente diferente acusando algum outro tipo de não sendo único).

Embora deva admitir que não tinha ideia do que estava fazendo quando tentei isso, estava apenas tentando todas as combinações possíveis de soluções, mas todas falharam para mim.

@eddiemf Seria possível obter a url do site wordpress que você está usando? Quero testá-lo sozinho para descobrir o que causa o erro.

@freiksenet Claro, o url é https://gatsbyislove.com
Vou deixar o campo title da seção de introdução vazio para que você possa conferir.

Você pode ver em https://gatsbyislove.netlify.com/ que a seção de introdução não tem título, mas está funcionando corretamente por causa dos resolvedores que criei.

@eddiemf Muito obrigado! Recebi o erro, investigarei.

Lol, esse é o erro mais engraçado. Portanto, acidentalmente colocamos os tipos de wordpress em maiúsculas. Todos eles devem começar com wordpress . Em vez disso, mantivemos os Nodes em letras minúsculas, mas os objetos internos em letras maiúsculas. Então, isso teria funcionado:

     type Wordpress__PAGEAcfIntro {
       title: String
       content: String
     }

    type Wordpress__PAGEAcf {
      Intro: Wordpress__PAGEAcfIntro
    }

    type wordpress__PAGE implements Node {
      acf: wordpress__PAGEAcf
    }

Estou tentando corrigir agora, então todos os tipos começariam com w minúscula.

Incrível 😄
Mas agora acho, pelo menos para esta situação específica, que usar os resolvedores pode manter o código melhor organizado, já que não preciso declarar esses campos aninhados até o principal que implementa Node .

É realmente melhor ou não estou vendo nada aqui?

De qualquer forma, vou brincar com diferentes soluções e ver qual se encaixa melhor em mim.

Obrigado pelo grande apoio!

@eddiemf É bom usar createResolvers , mas você não obterá esses campos nos parâmetros filter e sort dos campos raiz deste tipo. Se estiver bom para você, use createResolvers .

Aqui está a correção: https://github.com/gatsbyjs/gatsby/pull/12837/files

Vejo que isso não deve ser um problema na maioria dos casos, já que filter e sort geralmente são feitos em campos que estão sempre preenchidos, mas vou manter isso em mente. Obrigado novamente :)

Edit : Isso não acontece mais, embora eu não atualize nada. Não tenho ideia do que aconteceu ou o que me levou a acreditar que não funcionou; mas funciona agora ... ótimo trabalho pessoal!

Olá pessoal, brinquei com este código:

exports.sourceNodes = ({ actions }) => {
  const { createTypes } = actions
  createTypes(`
    type MarkdownRemarkFrontmatter {
      image: File  // <---- could be a relative path, could be an empty string
    }

    type MarkdownRemark implements Node {
      frontmatter: MarkdownRemarkFrontmatter
    }
  `)
}

Eu esperava obter um nó File ou null ao consultar um nó de observação de redução. Em vez disso, sempre recebo null ... Eu teria que procurar manualmente o arquivo:

createResolvers({
    MarkdownRemarkFrontmatter: {
      image: {
        type: `File`,
        resolve(src, args, context) {
          const filePath = src[info.fieldName]
          // find & return the file node
        }
      }
    }
  })

Existe uma maneira de simplesmente dizer a gatsby, "este será um nó de arquivo, localize-o ou retorne nulo"?

Oi! É possível que warning There are conflicting field types in your data. GraphQL schema will omit those fields apareça mesmo se createTypes estiver configurado, evitando que o GraphQL omita os campos?

Este é o aviso de gatsby develop :

ThumbprintToken.tokens.value.web:
 - type: number
   value: 1025
   source: File "../packages/thumbprint-tokens/src/tokens/breakpoint.json"
 - type: string
   value: '4px'
   source: File "../packages/thumbprint-tokens/src/tokens/border-radius.json"

E este é o uso de createTypes :

exports.sourceNodes = ({ actions }) => {
    const { createTypes } = actions;
    const typeDefs = `
        type ThumbprintToken implements Node {
            tokens: [ThumbprintTokenTokens!]!
        }

        type ThumbprintTokenTokens {
            value: ThumbprintTokenTokensValue!
        }

        type ThumbprintTokenTokensValue {
            web: String
            ios: String
            android: String
        }
    `;
    createTypes(typeDefs);
};

Sem usar createTypes , GraphQL realmente omite os campos. Os dados para esses arquivos JSON vêm de gatsby-source-filesystem e gatsby-transformer-json . Estou usando uma função para a configuração typeName em gatsby-transformer-json .

Fico feliz em fazer uma pequena reprodução se parecer que o aviso não deveria estar aparecendo.

Olá!

Estou recebendo um erro ao usar o tipo JSON embutido.

// gatsby-node.js

export const sourceNodes = ({ actions: { createTypes }, schema }) => {
  createTypes([
    schema.buildObjectType({
      name: 'MyTypeName',
      fields: {
        id: 'ID!',
        json: 'JSON!',
      },
    }),
  ])
}

O seguinte erro é emitido:

success source and transform nodes — 1.550 s
error UNHANDLED REJECTION


  Error: Schema must contain unique named types but contains multiple types named "JSON".

  - Array.reduce

  - SchemaComposer.js:122 SchemaComposer.buildSchema
    [gatsby-ww]/[graphql-compose]/lib/SchemaComposer.js:122:12

  - schema.js:480
    [gatsby-starter-ww]/[gatsby]/dist/schema/schema.js:480:47

  - Generator.next

  - new Promise

  - schema.js:539 addCustomResolveFunctions
    [gatsby-starter-ww]/[gatsby]/dist/schema/schema.js:539:18

  - schema.js:162
    [gatsby-starter-ww]/[gatsby]/dist/schema/schema.js:162:11

  - Generator.next

Isso poderia ser o resultado de graphql-compose fornecer seu próprio tipo JSON vez de usar a versão gatsby/graphql ?



gatsby info output:


  System:
    OS: macOS 10.14.2
    CPU: (4) x64 Intel(R) Core(TM) i5-7600K CPU @ 3.80GHz
    Shell: 5.6.2 - /usr/local/bin/zsh
  Binaries:
    Node: 10.15.3 - /var/folders/3z/fgqk0pmx30l2pc4801884_sm0000gn/T/yarn--1554423671012-0.23391063288947023/node
    Yarn: 1.12.3 - /var/folders/3z/fgqk0pmx30l2pc4801884_sm0000gn/T/yarn--1554423671012-0.23391063288947023/yarn
    npm: 6.4.1 - ~/.n/bin/npm
  Languages:
    Python: 2.7.10 - /usr/bin/python
  Browsers:
    Chrome: 73.0.3683.86
    Firefox: 64.0
    Safari: 12.0.2
  npmPackages:
    gatsby: 2.3.11 => 2.3.11

@angeloashmore Deve ser corrigido com https://github.com/gatsbyjs/gatsby/pull/13028 , farei uma versão de pré-lançamento hoje para que você possa testar.

@danoc Atualmente não há como desativar avisos como esse. Com https://github.com/gatsbyjs/gatsby/pull/13028 se você usar @dontInfer , nenhuma verificação de valor de exemplo deve acontecer e então não haverá um aviso. No entanto, também não haverá qualquer inferência.

@ d4rekanguok Você poderia fornecer uma pequena reprodução para isso? Deve funcionar como você descreveu.

Publicado em [email protected]

@samovertonjr @smurrayatwork Pleae não liberte esse problema. Obrigado!

Não sabia que clicar isso afetaria a todos.

Publicado em 2.4.0-alpha.2 .

@prashant-andani Pleae não liberte esse problema. Obrigado!

Oi, isso foi acidental ... desculpe por isso

Na terça-feira, 30 de abril de 2019 às 18:38, Lennart [email protected] escreveu:

@ prashant-andani https://github.com/prashant-andani Pleae não solte
esse problema. Obrigado!

-
Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/gatsbyjs/gatsby/issues/12272#issuecomment-487944961 ,
ou silenciar o tópico
https://github.com/notifications/unsubscribe-auth/AAGKROYK4RRFYRE3MOQL2NLPTBAE7ANCNFSM4G3OVU5Q
.

>

Cumprimentos
Prashant S Andani

Qual é a ordem de execução do mapeamento? Tenho um conjunto de postagens que estou tentando mapear para categorias como o exemplo post -> authors . Minha fonte bruta tem ids em números, então usei tipos de criação para impor uma suposição de string. Infelizmente, o mapeamento não parece funcionar se eu usar createTypes . Achei que createTypes fosse executado antes de o esquema mestre ser criado.

//gatsby-config.js
  mapping: {
    "MarkdownRemark.frontmatter.speaker": `AuthorsYaml.name`, // works as expected
    "MarkdownRemark.frontmatter.categories": `CategoriesYaml`,
  },
//gatsby-node.js
exports.sourceNodes = ({ actions }) => {
  const { createTypes } = actions
  const typeDefs = `
  type MarkdownRemarkFrontmatter {
    categories: [String]
  }

  type MarkdownRemark implements Node {
    frontmatter: MarkdownRemarkFrontmatter
  }
  `
  createTypes(typeDefs)
}

Consultando ...

{
  allMarkdownRemark {
    nodes {
      frontmatter {
        categories
        speaker {
          name
        }
      }
    }
  }
}

Rendimentos…

    "allMarkdownRemark": {
      "nodes": [
        {
          "frontmatter": {
            "categories": [
              "22"
            ],
            "speaker": {
              "name": "Sean Higgins"
            }
          }
        }
]

Eu encontrei uma solução de trabalho em que digo ao tipo para esperar um tipo CategoryYaml em vez de forçá-lo a uma string e usar um resolvedor personalizado para buscar os dados.

Parece que, com o mecanismo de mapeamento em vigor, provavelmente devo ser capaz de forçar a coerção da string e, em seguida, usar o mapeamento para fazer a conexão para mim.

Talvez eu esteja faltando alguma coisa?

Tipos aninhados:

  • Usando gatsby-source-prismic
  • Isso resulta em tipos complexos com tipos de objetos aninhados dentro de objetos

por exemplo

  PrismicNewsBody
    PrismicNewsBody
      PrismicNewsBodyPrimary
      PrismicNewsBodyItems

Tipos têm a noção de grupos repetíveis (que acabam nos Itens), mas se você não tiver nada no grupo, a consulta falha (porque você está consultando um membro de tipo que não foi inferido).

No entanto, se você definir o tipo de forma que possa declarar items , ele será chamado como uma duplicata assim que você realmente usar o grupo de repetição; deixando você no estado em que possui [0 .. ] dados, mas só pode ter código que suporte 0 ou 1 ..

Então, o código poderia (já existe uma maneira) mesclar tipos que não são implements Node ?


Próximo: o sistema de tipos do Prismic é um PITA real e ao usar fatias, etc, cria tipos com nomes anexados ao nome de seu contêiner. Isso é razoável devido à maneira como se comporta - tem um conceito de "biblioteca de fatias", mas é uma biblioteca de cópia, não uma biblioteca de referência - a definição de tipo é apenas copiada para o tipo def para o tipo de conteúdo.

Os programadores OTOH odeiam duplicação. Portanto, tomei cuidado para garantir que o tipo de fatia de um determinado nome seja o mesmo em todos os lugares, definindo-o em uma página, salvando-o na "biblioteca" e copiando-o para fora - poderíamos (temos?) Ter a capacidade de adicione interfaces, em vez de

query {
  pageOne {
    data {
      body {
        ... on PageOneBodyMyslice {
          primary {
            field
          }
        }
      }
    }
  }
  pageTwo {
    data {
      body {
        ... on PageTwoBodyMyslice {
          primary {
            field
          }
        }
      }
    }
  }
}

... Nós poderíamos fazer

`` `
interface MySlice {
primário {
campo
}
}

de alguma forma, marcamos os tipos de fatia de página como implementando este

consulta {
página um {
dados {
corpo {
... no MySlice {
... MySliceFragment

etc

`` `

@awilkins gatsby-source-prismic autor aqui.

Estamos trabalhando na implementação do carregamento automático de esquema para que Gatsby saiba tudo sobre seus formatos de tipo personalizados. Esperamos publicar um beta esta semana (que também inclui um sistema de visualização!).

Você precisará fornecer seus esquemas para o plug-in no futuro.

Re: sua pergunta sobre interfaces, a ideia é boa, mas não tenho certeza se os tipos estão mesclados. Todas as fatias implementam a interface Node e seguem a convenção de nomenclatura pascalcase(${customType} ${sliceZoneName} ${sliceName}) .

@motleydev Olá! Portanto, createTypes e mapeamentos são executados praticamente ao mesmo tempo. Os tipos definidos pelos usuários sempre têm prioridade sobre os tipos de mapeamento. Você precisa usar o resolvedor personalizado neste caso. Gatsby não pode realmente saber que você deseja um objeto que será serializado como string neste caso, pois String e CategoriesYaml não são tipos compatíveis.

@angeloashmore Obrigado pela resposta! Eu vou esperar por isso; meu cliente sem dúvida vai querer mudanças e isso vai tornar as coisas muito mais fáceis.

interfaces

Tenho certeza de que você notou que, devido à maneira como o Prismic faz as coisas, sua "biblioteca de fatias" apenas permite que você copie as informações do tipo de fatia para o seu tipo personalizado - então, os diferentes nomes de tipo são necessários a partir do POV que você pode realmente ter tipos de fatia radicalmente diferentes com o mesmo nome em diferentes tipos de página.

É um PITA para atualizar os tipos de fatia no CMS porque você tem que fazer isso em um lugar, depois copiar para todos os outros tipos, abrir todo o conteúdo e atualizá-lo (se você introduziu quaisquer alterações incompatíveis).

Mas ... se você se comportar bem e fizer isso de forma consistente (ou apenas tiver um conjunto de fatias bem usado e maduro), os benefícios de ser capaz de declarar um fragmento GraphQL global para cada tipo de fatia ou (talvez? ) mesmo um para todas as fatias seria ótimo - mas os fragmentos só podem ser aplicados a um tipo ou interface, daí o desejo de atribuir interfaces comuns a tipos de fatias diferentes, mas idênticos, com o mesmo nome em páginas diferentes.

Publicado em [email protected] .

Olá pessoal. Eu atualizei para Gatsby 2.5.0 mas parece que tenho o mesmo tipo de conflito que @angeloashmore entre o graphql-compose e o gatsby com o tipo JSON. Existe alguma maneira simples de resolver esse conflito?

Estou atualizando do Gatsby 1.9.x se isso ajudar. Os registros estão abaixo:

`` `
erro REJEIÇÃO NÃO MANIPULADA

Erro: o esquema deve conter tipos nomeados exclusivamente, mas contém vários tipos denominados "JSON".

  • Array.reduce

  • Array.reduce

  • SchemaComposer.js: 130 SchemaComposer.buildSchema
    [blog] / [graphql-compose] /lib/SchemaComposer.js:130:12

  • schema.js: 500
    [blog] / [gatsby] /dist/schema/schema.js:500:47

  • Generator.next

  • debuggability.js: 313 Promise._execute
    [npm] / [gatsby-cli] / [bluebird] /js/release/debuggability.js:313:9

  • promessa.js: 483 Promise._resolveFromExecutor
    [npm] / [gatsby-cli] / [bluebird] /js/release/promise.js:483:18

  • promessa.js: 79 nova promessa
    [npm] / [gatsby-cli] / [bluebird] /js/release/promise.js:79:10

  • schema.js: 559 addCustomResolveFunctions
    [blog] / [gatsby] /dist/schema/schema.js:559:18

  • schema.js: 163
    [blog] / [gatsby] /dist/schema/schema.js:163:11

  • Generator.next

  • util.js: 16 tryCatcher
    [npm] / [gatsby-cli] / [bluebird] /js/release/util.js:16:23

  • promessa.js: 512 Promise._settlePromiseFromHandler
    [npm] / [gatsby-cli] / [bluebird] /js/release/promise.js:512:31

  • promessa.js: 569 Promise._settlePromise
    [npm] / [gatsby-cli] / [bluebird] /js/release/promise.js:569:18

  • promessa.js: 606 Promise._settlePromiseCtx
    [npm] / [gatsby-cli] / [bluebird] /js/release/promise.js:606:10

  • async.js: 142 _drainQueueStep
    [npm] / [gatsby-cli] / [bluebird] /js/release/async.js:142:12
    `` ``

@ Spiderpig86 Você tem esse problema ao atualizar para 2.4? Gostaria de saber se você poderia fornecer um projeto de reprodução (ou código para seu aplicativo).

No final, acabei descartando todas as dependências que tinha e reinstalando completamente. Esta é a configuração que uso agora e funciona muito bem.

Estamos tendo um problema com gatsby-source-prismic v3.0.0-alpha.2 com gatsby-source-filesystem nós de arquivo.

Dizemos a Gatsby que os campos de imagem terão um campo localFile com o tipo File , mas se nenhum nó File for criado em qualquer lugar do site, Gatsby não saberá o que File is.

Error: Type with name "File" does not exists

Desculpe, esta pode ser uma questão de gatsby-source-filesystem mais do que uma questão de personalização de esquema, mas apenas querendo saber se há uma maneira de dizer a Gatsby o que é File forma confiável. gatsby-source-filesystem precisaria exportar uma definição de tipo de arquivo do pacote onde os plug-ins de origem poderiam ser explicitamente fornecidos ao Gatsby?

Problema relacionado: https://github.com/angeloashmore/gatsby-source-prismic/issues/97

@angeloashmore poderíamos fazer gatsby-source-filesystem registrar explicitamente o tipo File (e torná-lo não panic quando o caminho configurado não existir). Desta forma seria possível apenas fornecer gatsby-source-filesystem (sem opções) em gatsby-config e ter o tipo File disponível no esquema. Algo assim funciona no seu caso? Isso ainda exigiria que gatsby-source-filesystem fosse instalado porque ele possui o tipo - mas ainda não há planos concretos para talvez promover File a um tipo de núcleo em algum ponto.

@stefanprobst Sim, algo assim parece que pode funcionar.

Em relação aos autores do plug-in, se o plug-in criar de forma não determinística um nó Arquivo, isso significaria:

  1. Os autores do plug-in devem pedir aos usuários do plug-in que sempre adicionem gatsby-source-filesystem aos seus gatsby-config.js para garantir que Gatsby conheça o tipo File , ou
  2. Os autores do plug-in apenas incluem campos que usam o tipo File nas definições de tipo se o plug-in puder determinar que um nó File será criado. Ou seja, se sabemos que nenhum nó será criado com um campo File , não inclua o campo File no nó que o usa. Isso pode interromper as compilações se as consultas contiverem o campo agora inexistente.

Com a Opção 1, os usuários poderiam ver a mensagem de erro de caminho inexistente em cada develop ou build se eles não fornecerem um caminho. Em alguns projetos, pode não haver necessidade de usar gatsby-source-filesystem exceto para fornecer o tipo File . Talvez pudéssemos alterá-lo para que só verifique se o caminho existe se um caminho for fornecido.

Com a Opção 2, os autores do plug-in precisam lidar com o aumento da complexidade de rastrear File criação de nó. Isso pode ser tão simples quanto atualizar uma variável global, mas ainda é algo a se considerar.

Se gatsby-source-filesystem exportou o tipo File (via objeto GraphQL ou string SDL) e permitiu aos autores do plug-in registrá-lo com createType , os usuários não precisam alterar seus autores de fluxo de trabalho e plug-in não é necessário rastrear o uso de File .

Isso poderia causar problemas no futuro se / quando as alterações de tipo File e os plug-ins usassem gatsby-source-filesystem versões diferentes com definições File incompatíveis. Isso funciona bem agora, pois, pelo que entendi, Gatsby infere a forma agregada.

Para referência, é aqui que definimos um campo usando File : standardTypes.graphql . Isso é passado diretamente para createTypes .

Corrija-me se eu estiver errado @pieh , @stefanprobst , mas acho que fazer File um tipo de núcleo não vai ser uma mudança significativa. Irá quebrar apenas os casos em que costumava falhar porque File não estava lá. Então, proponho que façamos isso.

Peço desculpas por colocar isso aqui, se você puder me orientar na direção certa, vou apresentar um tíquete mais focado.

tl; dr Tipos dirigidos por frontmatter.

Eu venho de uma experiência em CMS, então controlar meus esquemas é atraente. Meu site Gatsby usa o frontmatter Markdown com type: author no YAML para especificar o "tipo", mas como tudo é um tipo de nó MarkdownRemark , não obtenho esquemas reais.

Agora tenho um tipo Author por meio de createTypes . Eu tentei várias maneiras de fazer um nó Author , de preferência como um filho do nó MarkdownRemark (para que seja excluído gratuitamente), mas não consigo encontrar uma maneira de fazer tão. createNode não parece estar disponível em um resolvedor.

@pauleveritt Uma maneira de configurar relações de chave estrangeira entre campos é com a diretiva @link . Para um blog típico (postagens como .md arquivos, informações do autor e tags em .yaml arquivos), pode ter a seguinte aparência:

exports.sourceNodes = ({ actions }) => {
  actions.createTypes(`
    type MarkdownRemark implements Node <strong i="10">@dontInfer</strong> {
      frontmatter: Frontmatter
    }
    type Frontmatter {
      title: String!
      author: AuthorYaml @link(by: "email")
      tags: [TagYaml] @link(by: "slug")
    }
    type AuthorYaml implements Node <strong i="11">@dontInfer</strong> {
      name: String!
      email: String!
      info: String
      posts: [MarkdownRemark] @link(by: "frontmatter.author.email", from: "email")
    }
    type TagYaml implements Node <strong i="12">@dontInfer</strong> {
      slug: String!
      title: String!
      description: String
      posts: [MarkdownRemark] @link(by: "frontmatter.tags.slug", from: "slug")
    }
  `)
}

Eu também juntei isso neste repositório .

Finalmente, também temos um pouco de documentação sobre as APIs de personalização de esquema aqui . Por favor, deixe-nos saber se algo não estiver claro ou faltando.

@freiksenet Eu acho que depende se isso significa mover as definições de tipo de File para o núcleo, ou se (partes de) o que agora é gatsby-source-filesystem deve ser movido com ele também. Mover File sozinho deve estar ok, eu acho.

@stefanprobst Conceito

https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby-transformer-remark/src/on-node-create.js#L45

Não sei como posso obter um nó criado como AuthorYaml base no frontmatter proveniente de gatsby-source-filesystem e gatsby-transformer-remark .

É provável que eu precise parar de pensar em destinos de link como conteúdo de Markdown e usar .yaml gatsby-transformer-yaml, que me permite nomear o tipo de nó.

@pauleveritt

use .yaml gatsby-transformer-yaml

sim, isso é o que faço no exemplo vinculado. Alguma razão para colocar as informações do autor nos arquivos de redução?

@stefanprobst "Alguma razão para colocar as informações do autor nos arquivos markdown?"

Eu quero que tudo - autor, categoria, tag, etc. - seja um "recurso" rico que as pessoas possam editar, adicionar imagens, blocos de código, coisas MDX no Markdown, etc.

Mas não vou conseguir isso facilmente. :) Vou mudar para YAML para eles. Infelizmente, meu "conteúdo regular" (tutoriais, artigos, postagens de blog) também poderia ser tipos com esquemas diferentes, mas vou ficar com o esquema inferido, em vez do novo mundo de tipos / esquemas explícitos promovido desde 2.2.

@pauleveritt sim, gatsby-transformer-remark criará apenas um tipo MarkdownRemark - e usar isso para representar entidades diferentes será problemático. portanto, este não é realmente um problema relacionado ao esquema, mas você precisa de um plug-in de transformador de markdown que possa criar nós makrkdown com nomes diferentes (o que deve ser bastante factível).

Dito isso (apenas como um experimento), é possível fazer isso com MarkdownRemark nodes apenas e usar @link em campos de frontmatter. parece um pouco feio, mas funciona, veja aqui o exemplo.

@stefanprobst Eu entendo seu ponto, mas acho que se o objetivo é fazer menos esquema inferido e mais esquema declarado, o frontmatter Markdown deve estar no escopo. Gatsby com arquivos Markdown é uma combinação popular. eu

Ter diferentes tipos / esquemas no Markdown seria mais fácil se gatsby-transformer-remark não tornasse a área de superfície da bifurcação tão grande. Há muita coisa acontecendo na função de seta que faz a atribuição do tipo de nó.

Vamos encerrar essa conversa. Provavelmente estou em uma minoria daqueles que desejam diferentes tipos de conteúdo no Markdown. Muito obrigado pelo código de amostra, essa é a direção que irei tomar por agora.

Com relação a runQuery e seu parâmetro query ... Tenho filter funcionando corretamente, mas não consigo obter um exemplo de sort funcionando. Os testes que usam classificação parecem usar runQuery de uma string de modelo. Quando tento sort: { order: 'DESC', fields: ['frontmatter___date'] } (ou com 'desc' como string), a resolução falha.

@pauleveritt Funciona com uma matriz em order ?

@stefanprobst Infelizmente, não. Esse:

sort: { order: ['DESC'], fields: ['frontmatter___date'] }

...leva a:

error gatsby-node.js returned an error

  TypeError: Cannot read property 'resolve' of undefined

  - prepare-nodes.js:34 awaitSiftField
    [gatsby-theme-bulmaio]/[gatsby]/dist/redux/prepare-nodes.js:34:13

  - prepare-nodes.js:52 
    [gatsby-theme-bulmaio]/[gatsby]/dist/redux/prepare-nodes.js:52:69

  - Array.map

  - prepare-nodes.js:52 resolveRecursive
    [gatsby-theme-bulmaio]/[gatsby]/dist/redux/prepare-nodes.js:52:44
...

@pauleveritt, infelizmente, não consegui reproduzir com esta configuração básica - você poderia fornecer uma pequena reprodução para que este problema analise? Isso seria muito útil, obrigado!

@stefanprobst Encontrou a causa: é 2.8.x - quer que eu preencha um novo tíquete?

Imagine seu gatsby-blog para o repositório YAML. Adicione isto a gatsby-node.js :

exports.createResolvers = ({ createResolvers, schema }) => {
  createResolvers({
    Query: {
      allResourcesByType: {
        type: ['MarkdownRemark'],
        args: {
          resourceType: 'String'
        },
        resolve(source, args, context, info) {
          return context.nodeModel.runQuery({
            query: {
              filter: {
                frontmatter: {}
              },
              sort: { fields: ["frontmatter___title"], order: ["ASC"] },
            },
            type: `MarkdownRemark`
          })
        }
      }
    }
  })
}

No gatsby 2.7.6 você pode consultar allResourcesByType no explorer. Em 2.8.0-2.8.2, você obtém um erro de resolução.

@stefanprobst Estou tentando converter as tags que especifico como um array de strings no frontmatter das minhas postagens em um tipo Tag com os campos title e slug onde title é apenas a string que escrevi e slug = _.kebabCase(title) . Eu juntei este trecho

exports.sourceNodes = ({ actions, schema }) => {
  actions.createTypes([
    `type MarkdownRemark implements Node {
      frontmatter: MarkdownRemarkFrontmatter
    }`,
    `type Tag { title: String!, slug: String! }`,
    schema.buildObjectType({
      name: `MarkdownRemarkFrontmatter`,
      fields: {
        tags: {
          type: `[Tag!]`,
          resolve(source) {
            if (!source.tags) return null
            return source.tags.map(tag => ({
              title: tag,
              slug: kebabCase(tag),
            }))
          },
        },
      },
    }),
  ])
}

que funciona para adicionar o tipo Tag a MarkdownRemarkFrontmatter.tags . Mas é claro, quando tento agrupar todas as tags com

tags: allMarkdownRemark {
  group(field: frontmatter___tags) {
    title: fieldValue
    count: totalCount
  }
}

Pego apenas a string que escrevi no frontmatter. Tentei escrever um resolvedor para allTags assim

exports.createResolvers = ({ createResolvers }) => {
  const resolvers = {
    Query: {
      allTags: {
        type: [`Tag`],
        resolve(source, args, context) {
          return context.nodeModel.getAllNodes({
            type: `MarkdownRemarkFrontmatterTags`,
          })
        },
      },
    },
  }
  createResolvers(resolvers)
}

mas não consigo fazer funcionar. Algum conselho?

@janosh

  • Ao alterar o tipo de campo de frontmatter.tags de [String] para [Tag] , o argumento field de group também teria que ser ajustado para qualquer um frontmatter___tags___title ou frontmatter___tags___slug . Infelizmente, isso ainda não funciona corretamente, porque não chamamos resolvedores de campo para group campos, apenas para filter e sort campos (consulte # 11368).
  • No momento, você pode contornar isso usando um filtro fictício para acionar o resolvedor de campo:
{
  allMarkdownRemark(filter: {frontmatter: {tags: {elemMatch: {title: {ne: null}}}}}) {
    group(field: frontmatter___tags___title) {
      fieldValue
      totalCount
      nodes {
        frontmatter {
          title
        }
      }
    }
  }
}

Consertar isso está na minha lista de tarefas - vou resolvê-lo o mais rápido possível

  • O problema com seu createResolvers snippet é o seguinte: getAllNodes recuperará nós por tipo, onde "nó" significa objetos com um ID exclusivo criado por plug-ins de origem ou transformador (com o createNode action). Portanto, você teria que recuperar MarkdownRemark nodes e, em seguida, manipular ainda mais os resultados no resolvedor.
  • Dependendo do seu caso de uso, você pode nem precisar usar createTypes , mas pode simplesmente adicionar um campo de consulta raiz personalizado para agrupar postagens por tag e incluir um campo slug:
// gatsby-node.js
const { kebabCase } = require(`lodash`)

exports.createResolvers = ({ createResolvers }) => {
  createResolvers({
    Query: {
      allMarkdownRemarkGroupedByTag: {
        type: [
          `type MarkdownRemarkGroup {
            nodes: [MarkdownRemark]
            count: Int
            tag: String
            slug: String
          }`,
        ],
        resolve(source, args, context, info) {
          const allMarkdownRemarkNodes = context.nodeModel.getAllNodes({
            type: `MarkdownRemark`,
          })

          const groupedByTag = allMarkdownRemarkNodes.reduce((acc, node) => {
            const { tags } = node.frontmatter
            tags.forEach(tag => {
              acc[tag] = (acc[tag] || []).concat(node)
            })
            return acc
          }, {})

          return Object.entries(groupedByTag).map(([tag, nodes]) => {
            return {
              nodes,
              count: nodes.length,
              tag,
              slug: kebabCase(tag),
            }
          })
        },
      },
    },
  })
}

@stefanprobst Obrigado pela resposta rápida!

Portanto, você teria que recuperar os nós MarkdownRemark e, em seguida, manipular ainda mais os resultados no resolvedor.

Pensei em fazer isso, mas suspeitei que estava negligenciando algo e, portanto, abordando isso do ângulo errado. Obrigado por esclarecer isso e por planejar adicionar suporte para resolvedores de campo para group campos!

Talvez outra solução seria deixar Tag implementar Node forma que Gatsby crie uma consulta allTag automaticamente.

type Tag implements Node { title: String!, slug: String! }

Então, tudo que eu teria que fazer seria criar nós do tipo Tag toda vez que encontrar um novo na chamada para schema.buildObjectType para MarkdownRemarkFrontmatter . É possível aplicar efeitos colaterais como esse de dentro dos resolvedores? Ou seja, neste caso, verifique se Tag com o título MyTag existe e se não existe createNode({type: `Tag`, title: `MyTag, slug: `my-tag` }) .

@pauleveritt desculpe pela resposta tardia!

Em seu exemplo, a classificação deve funcionar com isso:

exports.createResolvers = ({ createResolvers }) => {
  createResolvers({
    Query: {
      allResourcesByType: {
        type: ["MarkdownRemark"],
        args: {
          resourceType: "String",
        },
        resolve(source, args, context, info) {
          return context.nodeModel.runQuery({
            query: {
              sort: { fields: ["frontmatter.post_title"], order: ["DESC"] },
            },
            type: "MarkdownRemark",
          })
        },
      },
    },
  })
}

Observe que ambos os tipos fields e order são arrays, e fields usa a notação de ponto em vez de sublinhado triplo para separar os campos. (Temos que documentar isso! EDITAR: # 14681)
Existem duas razões pelas quais isso é diferente em runQuery do que quando se usa uma string de consulta (ou seja, no explorador Graph_i_ql):

  • nos campos da lista, os valores escalares serão automaticamente analisados ​​como uma matriz de item único (é por isso que é possível apenas dizer DESC ). atualmente não fazemos isso com runQuery (provavelmente deveríamos)
  • ambos fields e order são campos GraphQLEnum . Em Graph_i_ql, você usaria as chaves de enum, enquanto runQuery precisa dos valores de enum internos. Por exemplo, o enum fields separa os campos por sublinhado triplo porque o graphql não permite pontos, mas internamente isso se traduz em campos em notação de ponto.

O agrupamento [email protected]

@stefanprobst Uau, isso foi rápido! Obrigado pela atualização.

Existe uma maneira de obter o título e o slug de uma tag em um único agrupamento? Só consigo descobrir como agrupar por um deles e só tenho acesso a um deles.

{
  tags: allMarkdownRemark {
    group(field: frontmatter___tags___(slug|title)) {
     (slug|title): fieldValue
      count: totalCount
    }
  }
}

Se eu tentar agrupar por frontmatter___tags vez disso,

{
  tags: allMarkdownRemark {
    group(field: frontmatter___tags) {
      tag: fieldValue
      count: totalCount

    }
  }
}

Eu consigo apenas um único resultado

{
  "data": {
    "tags": {
      "group": [
        {
          "tag": "[object Object]",
          "count": 52
        }
      ]
    }
  }
}

@janosh você só pode agrupar por um campo (subgrupos hierárquicos não são possíveis). se precisar dos valores de title e slug , você pode agrupar por um e obter o valor do outro a partir dos resultados (talvez eu esteja entendendo mal?):

{
  allMarkdownRemark {
    group(field: frontmatter___tags___title) {
      fieldValue
      totalCount
      nodes {
        frontmatter {
          tags {
            slug
            title
          }
        }
      }
    }
  }
}

@stefanprobst Isso não se encaixa no meu caso de uso, mas é apenas um pequeno inconveniente. Obrigado por todo o trabalho incrível que você está colocando na personalização do esquema!

Tenho tido um problema desde 2.2.0 que parece estar relacionado ao sistema operacional. Eu ficaria grato se outro usuário do Windows 10 examinasse ele para um teste, para que eu pudesse confirmar ou descartar: https://github.com/escaladesports/gatsby-plugin-netlify-cms-paths/issues/10

Obrigado!

@laradevitt No momento não tenho acesso a uma máquina Windows e também não estou familiarizado com gatsby-plugin-netlify-cms-paths - mas funciona se você substituir o caminho em frontmatter.image por um caminho relativo , ou seja, ../static/media/gatsby-astronaut.png ?

@stefanprobst - Obrigado pela sua resposta! Sim, é verdade, mas o objetivo do plug-in é que você não precise usar caminhos relativos:

Um plugin gatsby para alterar os caminhos dos arquivos em seus arquivos markdown para caminhos amigáveis ​​ao Gatsby ao usar o Netlify CMS para editá-los.

Eu criei uma solicitação pull com uma correção que torna a plataforma de caminho relativo retornada agnóstica.

Ainda não sei por que quebrou com o 2.2.0. 🤷‍♀

@laradevitt ah, desculpe, deveria ter verificado o readme.

Ainda não sei por que quebrou com o 2.2.0.

Esta é muito provavelmente uma regressão em Gatsby, já que a inferência de tipo 2.2.0 mudou um pouco - mas normalizar caminhos em gatsby-plugin-netlify-cms-paths definitivamente parece mais correto: +1:

@stefanprobst

Acabei de criar um novo tíquete relacionado à personalização do esquema. Se for melhor para mim fechar isso e colocá-lo neste tópico guarda-chuva, é só me avisar.

https://github.com/gatsbyjs/gatsby/issues/16099

Obrigado!

Descrição

Os argumentos em uma consulta GraphQL não funcionam ao usar a personalização do esquema.

Depois de assistir ao stream de learn with Jason em GraphQL avançado (dividido em várias partes devido a dificuldades técnicas), incorporei muito do que foi falado em meu tema.
No entanto, o uso de argumentos graphQL (como filtro e classificação) que dependem de valores do esquema personalizado não funciona.

Passos para reproduzir

executar este ramo do meu tema localmente.
Abra / ___ graphql e consulte allBlogPosts.
Agora tente consultar allBlogPosts novamente com uma classificação por data decrescente.
RESULTADO: nenhuma alteração na ordem (ASC ou DESC)

Exemplo 2

Consulte todas as postagens e mostre seus títulos.

query MyQuery {
  allBlogPost {
    nodes {
      title
    }
  }
}

RESULTADO: funciona

agora consulte todas as postagens que tenham uma tag com o slug "lorem-ipsum"

query MyQuery {
  allBlogPost(filter: {tags: {elemMatch: {slug: {eq: "lorem-ipsum"}}}}) {
    nodes {
      title
    }
  }
}

RESULTADO: array de nós vazio.

solução temporária, possível motivo pelo qual não funciona?

Tente consultar um único BlogPost (escolhe primeiro um por padrão se nenhum argumento for fornecido).
Agora tente consultar blogPost(slug: {eq: "herp-derpsum"}) .
Acho que isso funciona porque adicionei o slug ao nó MdxBlogPost.
https://github.com/NickyMeuleman/gatsby-theme-nicky-blog/blob/d29c966e639f4733caf9ee43e9f5755df42db71d/theme/gatsby-node.js#L209 -L210

Parece que os argumentos do graphql usam dados do nó MdxBlogPost em vez do resultado eventual após a execução de seus resolvedores. Minha suspeita está próxima?

Ambiente

Sistema:
SO: Linux 4.19 Ubuntu 18.04.2 LTS (Bionic Beaver)
CPU: (4) x64 Intel (R) Core (TM) i5-2500K CPU @ 3,30 GHz
Shell: 4.4.19 - / bin / bash
Binários:
Nó: 12.4.0 - /tmp/yarn--1565124765846-0.45931526383359134/node
Fio: 1.16.0 - /tmp/yarn--1565124765846-0.45931526383359134/yarn
npm: 6.9.0 - ~ / .nvm / versions / node / v12.4.0 / bin / npm
Línguas:
Python: 2.7.15+ - / usr / bin / python

Notas Adicionais

Partes relevantes do código estão em gatsby-node.js no diretório do tema.
especificamente os ciclos de vida createSchemaCustomization e onCreateNode .
Eu tentei muito comentar para mostrar meu processo de pensamento.

@NickyMeuleman, desculpe, não tive tempo ainda para olhar de perto, mas parece que está faltando uma extensão de link na interface do BlogPost.

Você define seu campo MdxBlogPost.tags para vincular por nome:

tags: {
  type: "[Tag]",
  extensions: {
    link: { by: "name" },
  },
},

nos typedefs da interface do BlogPost, você tem:

  interface BlogPost <strong i="12">@nodeInterface</strong> {
    tags: [Tag]
  }

Funciona com

  interface BlogPost <strong i="16">@nodeInterface</strong> {
    tags: [Tag] @link(by: "name")
  }

Relacionado: # 16466

Depois de adicionar sua sugestão, consultar allBlogPost com um filter baseado em uma tag funcionou! 🎉 Obrigado!

No futuro, poderei remover @link da interface, uma vez que as Tags podem ser vinculadas de maneira diferente por tipo que implementa a interface BlogPost? (mesma pergunta para o Autor, a filtragem não funciona, mesmo com @link movido para o nível da interface.

@NickyMeuleman
obrigado por experimentar!
depois de olhar para isso, acho que é algo que precisamos corrigir no núcleo: ambos os problemas têm a ver com o fato de que usamos o resolvedor de interfaces ao preparar manualmente os nós para que possamos executar um filtro neles. em vez disso, devemos executar o resolvedor do tipo que obtemos da interface resolveType , que também é o que acontece quando o graphql processa o conjunto de seleção.

Depois que https://github.com/gatsbyjs/gatsby/pull/17284 foi mesclado, tentei remover a lógica do meu tema para contornar isso.

Versão de Gatsby usada: 2.15.14
Não parece estar funcionando.
https://github.com/NickyMeuleman/gatsby-theme-nicky-blog/blob/bbc782332e6938daaa2fca1b25d6df7e78f19c6c/theme/gatsby-node.js#L278 -L282
Quando você comenta as linhas vinculadas acima, a filtragem em GraphQL nesses campos não é mais possível.

LekoArts sugeriu que eu fizesse essa pergunta mais publicamente do que na discórdia, uma vez que pode ser um bom tópico para documentação.

Como descrevo relacionamentos de muitos para muitos com createSchemaCustomization?

Os casos de uso que tenho são os seguintes:

  1. Eu tenho um produto e uma loja. As lojas podem conter qualquer número de produtos, e os produtos não são exclusivos de nenhuma loja. Qual é a melhor maneira de expressar esses dois tipos de nós?
  2. Estou tentando fazer uma página para um sistema de jogo. Eu expressei cada Habilidade como um Nodo. As habilidades têm qualquer número de pré-requisitos e qualquer número de habilidades dependentes. De preferência, gostaria de fazer um link para essas páginas (pré-requisitos e dependentes) na página da habilidade em si. Como faço para modelar esses relacionamentos em graphQL e, além disso, na API de Gatsby para isso?

@Everspace Tente isso para 1. adicionar a gatsby-node.js . Eu não tentei isso, mas estou fazendo algo semelhante vinculando de um tipo personalizado (usando a interface do nó) a uma imagem e funciona. Ele depende da extensão do link, então você precisará usar os IDs atribuídos por Gatsby. Eu acho que você poderia mapear quaisquer IDs que você está usando em sua fonte de dados para IDs de Gatsby durante createPages ?

exports.createSchemaCustomization = ({ actions }) => {
  const { createTypes } = actions
  const typeDefs = [
    schema.buildObjectType({
      name: 'Store',
      fields: {
        products: {
          type: "[Product]",
          extensions: {
            link: {},
          },
        },
      },
      interfaces: ['Node'],
    }),
    schema.buildObjectType({
      name: 'Product',
      fields: {
        stores: {
          type: "[Store]",
          extensions: {
            link: {},
          },
        },
      },
      interfaces: ['Node'],
    }),
  ]
  createTypes(typeDefs)
}

@NickyMeuleman Quer dizer que você não obtém resultados ou que não vê campos no objeto de entrada?

Quando eu comento a chave date nesse link , classificar por data não tem mais efeito.

query MyQuery {
  allBlogPost(sort: {fields: date, order: DESC}) {
    nodes {
      date(fromNow: true)
    }
  }
}

tem o mesmo resultado (não vazio) que a mesma consulta com o pedido definido como ASC .
Esperava que isso não fosse necessário, pois há um resolvedor de data personalizado

Existem exemplos de como lidar com a personalização do esquema para uma imagem opcional proveniente do Contentful?

Já faz um tempo que a Personalização do esquema foi lançada e as coisas estão estáveis. Acho que é hora de encerrar esse problema 🙂

Trabalho incrível @freiksenet e @stefanoverna ❤️

Pessoal, se você está tendo problemas relacionados à Personalização do Esquema, vamos abrir problemas independentes. Obrigado!

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

magicly picture magicly  ·  3Comentários

mikestopcontinues picture mikestopcontinues  ·  3Comentários

Oppenheimer1 picture Oppenheimer1  ·  3Comentários

KyleAMathews picture KyleAMathews  ·  3Comentários

signalwerk picture signalwerk  ·  3Comentários