如何编写突变解析器来更改对象的一个​​或多个特定值?

How to write a mutation resolver to change one or more specific values of an object?

期望一个解析器处理一个或多个对象值的任意组合的输入似乎是合理的。我不应该为 'title'、'published'、'author' 等编写单独的解析器,对吧?

这是我的示例对象:

let books = [
  {
    title: 'Clean Code',
    published: 2008,
    author: 'Robert Martin',
    id: 'afa5b6f4-344d-11e9-a414-719c6709cf8e',
    genres: ['refactoring'],
  },
  {
    title: 'Agile software development',
    published: 2002,
    author: 'Robert Martin',
    id: 'afa5b6f5-344d-11e9-a414-719c6709cf9e',
    genres: ['agile', 'patterns', 'design'],
  },
]

typeDefs:

const typeDefs = gql`
  type Book {
    title: String
    published: Int
    author: String
    id: ID
    genres: [String]
  }

  type Query {
    bookCount: Int!
    allBooks(title: String, author: String, genre: String): [Book]
    findBooks(title: String!): Book
  }

  type Mutation {
    addBook(
      title: String!
      published: Int
      author: String!
      genres: [String]
    ): Book
    editBook(
      id: ID
      title: String
      published: Int
      author: String
      genres: [String]
    ): Book
  }
`

这是我目前拥有的解析器:

 Mutation: {
     editBook: (_, args) => {
      const book = books.find(b => b.id === args.id)
      if (!book) {
        return null
      }
      const updatedBook = {
        ...book,
        title: args.title,
        author: args.author,
        published: args.published,
        genres: [args.genres],
      }
      books = books.map(b => (
        b.id === args.id ? updatedBook : b))
      return updatedBook
    },
    }

这是当前发生的事情。

原始对象:

"allBooks": [
      {
        "id": "afa5b6f4-344d-11e9-a414-719c6709cf8e",
        "title": "Clean Code",
        "author": "Robert Martin",
        "published": 2008,
        "genres": [
          "refactoring"
        ]
      },
{...}
]

突变查询:

mutation {
  editBook(id:"afa5b6f4-344d-11e9-a414-719c6709cf8e", title:"changed"){
    id
    title
    author
    published
    genres
  }
}

Returns这个:

{
  "data": {
    "editBook": {
      "id": "afa5b6f4-344d-11e9-a414-719c6709cf8e",
      "title": "changed",
      "author": null,
      "published": null,
      "genres": [
        null
      ]
    }
  }
}

如何编写解析器来更改对象的一个​​或多个值,而不将未指定的值更改为 'null'?

我承认,我的 javascript 技能相当不稳定,我猜答案在于更多 eloquent 映射函数,但由于代码在 graphql 模式中运行模块,它不处理 console.log 所以故障排除是有问题的。任何解决该问题的建议也将非常有帮助,这样我就可以更好地解决自己的问题。

两点

无需使用地图或重新分配 books。因为 book 变量是对 books 数组中对象的引用,所以您可以改变它(但不能重新分配它)并且您将改变数组中的对象。有关详细信息,请参阅 this question

const book = books.find(b => b.id === args.id)
if (book) {
  // you cannot reassign book and still have the original value change,
  // but you can mutate it
  book.title = args.title
  book.author = args.author
  book.published = args.published
  book.genres = args.genres
}
return book

要仅更改 args 中存在的值,您有一些选择:

如果第一个值是假的,您可以使用逻辑或运算符 (||) 提供另一个要分配的值。此处,book.title 仅在 args.titleundefinednull0NaN""false.

book.title = args.title || book.title

您可以使用 Object.assign,它将属性从一个对象复制到另一个对象。由于 args 将丢失那些未提供的属性,您可以像下面的代码片段那样做。这更加优雅和简洁,但仅当您的参数名称与您的 属性 名称匹配时才有效。

Object.assign(book, args)

您可以遍历 args 对象。如果您有一个或多个参数与 book:

的属性不匹配,这可能更可取
Object.keys(args).forEach(argName => {
  const argValue = args[argName]
  book[argName] = argValue
})

综合起来,我们可能会做:

const book = books.find(b => b.id === args.id)
if (book) {
  Object.assign(book, args)
}
return book