javascript - Cum să proiectez următorul resolver pentru serverul GraphQL?


Folosesc react-apollo pe Meteor cu MySQL și Sequelize, sunt încă începător în JS. Să presupunem că am următoarea funcție resolver pe apollo-server-ul meu:

 export default resolvers = {
     Query: {
         posts(_, args){
             return Post.findAndCountAll({ where: args   });
         },
         numberOfPosts(){
             return /// the number of selected posts
         }
     }

Aș dori să selectez unele date din baza de date unde sunt îndeplinite anumite condiții și apoi să număr numărul de rânduri selectate și să le returnez în câmpul "numberOfPosts". findAndCountAll() returnează un obiect, care conține rândurile selectate și numărul acestora. Aș dori ca post() să returneze doar rândurile selectate, iar numberOfPosts() să returneze doar numărul postărilor selectate. În prezent, ambele sunt returnate de posts().

Schema mea este:

 type Post {
  id: Int
  date: Float
  text: String
}

 type NumberOfPosts{
  total: Int
  filtered: Int
}

type Query {
  posts(
   id: Ind,
   offset: Int,
   limit: Int,
   filter: String): [Post]
  numberOfPosts:[NumberOfPosts] 
}

schema {
  query: Query
}

Scopul este de a primi date în următorul format:

{
  "data": {
    "numberOfPosts": [
      {
        "total": 1000,
        "filtered": 21
      }
    ],
    "posts": [
      {
        "id": 4,
        "date": 5105626122,
        "text": "jzybiwutudi"
      },
      ...
    ]
  }
}

Munca mea până acum: Încercarea 1:

  let selectedCount;
export default resolvers = {
    Query: {
        posts(_, args){
            return Post.findAndCountAll({where: args}).then(
                function (results) {
                    selectedCount = results.count;
                    return results.rows
                });
        },
        numberOfPosts(){
            return selectedCount
        }
    }}

Deci definesc o variabilă de ajutor în afara rezolvatoarelor și o setez la numărul de rânduri selectate, apoi numărul este returnat în numberOfPosts(), ceea ce funcționează, dar problema este că return results.rows cauzează o eroare și nu înțeleg de ce.

O altă problemă este că selectedCount este întotdeauna numărul anterior de rânduri

Încercarea 2

O altă soluție care pare să funcționeze este să treci argumentele de două ori în interogarea GraphQL, astfel:

{
  numberOfPosts(filter: "example") {
    total
    filtered
  }
  posts(filter: "example") {
    id
    date
    text
  }
}

Atunci ambele funcții resolver cunosc aceleași argumente, așa că pot selecta și număra aceleași postări. Dar asta nu mi se pare corect, deoarece trebuie să trec aceleași argumente de două ori, ele vor fi transmise și de două ori...

Răspuns #1

Ar trebui să te gândești mai mult la design și la ceea ce ar trebui să facă fiecare dintre aceste interogări. Aceste interogări nu ar trebui să modifice baza de date sau starea globală.

Cel mai bine pe care îl poți face este să definești pur și simplu un nou tip care să includă total și filtered, așa cum ai făcut ca NumberOfPosts în prima ta încercare, și de asemenea lista de postări.

Deci, schema ta ar fi așa:

type Post {
  id: Int
  date: Float
  text: String
}

type PostList {
  total: Int
  filtered: Int
  posts: [Post]
}

type Query {
  posts(
    id: Ind,
    offset: Int,
    limit: Int,
    filter: String): PostList
}

schema {
  query: Query
}

Și rezolvi posts astfel:

posts(_, args) {
  return Post.findAndCountAll({ where: args }).then(result => {
    return {
      total: 1000,
      filtered: result.count,
      posts: result.rows
    }
  })
}

Observă cum am pus doar 1000 pentru numărul total. Nu poți obține numărul total de rânduri cu findAndCountAll. Dacă ai nevoie de asta, poți rula două interogări diferite în paralel și folosi Promise.all pentru a aștepta să fie rezolvate.

posts(_, args) {
  return Promise.all([
    Post.count(),
    Post.findAndCountAll({ where: args })
  ]).then(data => {
    return {
      total: data[0],
      filtered: data[1].count,
      posts: data[1].rows
    }
  })
}

Codul de mai sus ar putea beneficia și de destructurarea din ES6:

posts(_, args) {
  return Promise.all([
    Post.count(),
    Post.findAndCountAll({ where: args })
  ]).then(([totalCount, filteredData]) => {
    return {
      total: totalCount,
      filtered: filteredData.count,
      posts: filteredData.rows
    }
  })
}

Acum poți rula:

query {
  posts(filter:"example") {
    total
    filtered
    posts {
      id
      date
      text
    }
  }
}

și obține:

{
  "data": {
    "posts": {
      "total": 1000,
      "filtered": 21,
      "posts": [
        {
          "id": 4,
          "date": 5105626122,
          "text": "jzybiwutudi"
        },
        ...
      ]
    }
  }
}