TheoG
TheoG

Reputation: 1558

HowTo: Increment the value of an integer based field in GraphQL

So, I wish to create a GraphQL mutation, in GraphCool, that increments the existing value of an integer field by a predetermined amount, passed in as a variable. For example:

mutation updateLikes ($id: ID!, $count: Int) {
  updatePosts (id: $id, likes: incrementBy $count) {
    id
    likes
  }
}

Query variable

{
  "id" : "cj0qkl04vep8k0177tky596og",
  "count": 1
}

How do I do this?

Also, I am attempting to trigger the above mentioned process from a onClick event, but am getting an 'cannot read property 'props' of null' error message, I suspect on this.props.client.query:

Photo.js

import React from 'react';
import Comments from './Comments';
import CSSTransitionGroup from 'react-addons-css-transition-group';
import { Link } from 'react-router';
import {
  gql,
  graphql,
  withApollo
} from 'react-apollo';
import ApolloClient from 'apollo-client';

class Photo extends React.Component {

  incrementQuery(currentID) {
    console.log("like of id=" + currentID+ " has been incremented by 1");

    this.props.client.query({
      query: gql`
        mutation updatePosts($id: ID!) {
          updatePosts (id: $id, likes: 1) {
            id
            likes
          }
        }  
      `,
      variables: {
        id: currentID,
      },
    });
  }

  render() {
    const { post, i } = this.props;

    return (
      <figure key={i} className="grid-figure">

        <div className='grid-photo-wrap'>
          <Link to={`/view/${post.id}`}>
            <img className='grid-photo' src={post.displaysrc} alt={post.caption} />
          </Link>

          <CSSTransitionGroup transitionName="like" transitionEnterTimeout={500} transitionLeaveTimeout={500}>
            <span key={post.likes} className="likes-heart">{post.likes}</span>
          </CSSTransitionGroup>

        </div>

        <figcaption>
          <p>{post.caption}</p>

          <div className="control-buttons">
            <button onClick={this.incrementQuery.bind(null,i)} className="likes">&hearts; {post.likes}</button>

            <Link to={`/view/${post.id}`} className="button">
              <span className="comment-count">
                <span className="speech-bubble"></span> {(post.comments ? Object.keys(post.comments).length : 0)}
              </span>
            </Link>
          </div>

        </figcaption>

      </figure>
    )
  }
};

Photo.PropTypes = {
  client: React.PropTypes.instanceOf(ApolloClient).isRequired,
  query: React.PropTypes.object,
  variables: React.PropTypes.object,
  data: React.PropTypes.shape({
    loading: React.PropTypes.bool.isRequired,
    error: React.PropTypes.bool.isRequired,
    updatePosts: React.PropTypes.object,
  }).isRequired,
}

const PhotoWithApollo = withApollo(Photo);

export default PhotoWithApollo;

The thrown error is as follows:

Uncaught TypeError: Cannot read property 'props' of null
    at incrementQuery (http://localhost:7770/static/bundle.js:56347:12)
    at proxiedMethod (http://localhost:7770/static/bundle.js:54898:31)
    at HTMLUnknownElement.wrapped (http://localhost:7770/static/bundle.js:47347:30)
    at Object.ReactErrorUtils.invokeGuardedCallback (http://localhost:7770/static/bundle.js:6346:17)
    at executeDispatch (http://localhost:7770/static/bundle.js:6146:22)
    at Object.executeDispatchesInOrder (http://localhost:7770/static/bundle.js:6169:6)
    at executeDispatchesAndRelease (http://localhost:7770/static/bundle.js:5599:23)
    at executeDispatchesAndReleaseTopLevel (http://localhost:7770/static/bundle.js:5610:11)
    at Array.forEach (native)
    at forEachAccumulated (http://localhost:7770/static/bundle.js:6446:10)
    at Object.processEventQueue (http://localhost:7770/static/bundle.js:5815:8)
    at runEventQueueInBatch (http://localhost:7770/static/bundle.js:6475:19)
    at Object.handleTopLevel [as _handleTopLevel] (http://localhost:7770/static/bundle.js:6491:6)
    at handleTopLevelWithoutPath (http://localhost:7770/static/bundle.js:16697:25)
    at handleTopLevelImpl (http://localhost:7770/static/bundle.js:16677:4)
    at ReactDefaultBatchingStrategyTransaction.perform (http://localhost:7770/static/bundle.js:8643:21)
    at Object.batchedUpdates (http://localhost:7770/static/bundle.js:12680:20)
    at Object.batchedUpdates (http://localhost:7770/static/bundle.js:8148:21)
    at dispatchEvent (http://localhost:7770/static/bundle.js:16808:21)
    at HTMLDocument.wrapped (http://localhost:7770/static/bundle.js:47347:30)

Upvotes: 2

Views: 5894

Answers (3)

vince
vince

Reputation: 1

For the AWS users, I personnaly had the same issue, for an accounting system. The risk with reading and then updating the value is that if several users call your script, some issues of concurrencies might happen. (A user can read the curent value just before it's being updated by another user, so he will arase this other user incrementation). What I did is :

  1. Create a queue request table where I explicitly write that I want to increment my variable.
  2. Create a lambda that is triggered on that table events (this lambda will fire anytime something happens in this table)
  3. Limit this lambda concurrency to 1 to avoid reading a value that is being changed
  4. Read the value from the request queue table, increment my final element and remove the request queue from the queue table. All this has to be done in the unique concurrency lambda that you just created.

Upvotes: 0

Zhang Yung
Zhang Yung

Reputation: 44

Yes. This is a very interesting question. Actually, Apollo client use same method to handle pagination. you must be get current page,when you go to bottom of page, (prev page+1)=>(next page) be a new page variable to get next page content ,then concat to prev page 。 dislike/like,the same way , only difference does't need to concat to prev dike/like. replace it.

Upvotes: -1

marktani
marktani

Reputation: 7808

Currently you need to first query the value:

query Post($id: ID!) {
  Post (id: $id) {
    id
    likes
  }
}

Then increment the likes client-side and update the post with the new value for likes:

mutation updateLikes ($id: ID!, $likes: Int!) {
  updatePost (id: $id, likes: $likes) {
    id
    likes
  }
}

Incrementing the likes by a special number is a great use case for a custom mutation, which we are already working on.

Upvotes: 3

Related Questions