0

I am trying to create a very simple 3 page schedule managing app using React and Hasura GraphQL. I display all scheduled meetings one one page, I take the Title of the meeting, Date and number of participants as input from the user and sen the user to the next page to input the start and end time of teh meeting. However, When I try to wrote the inputted values in the database, I get an error saying :

variable startTime of type String! is used in position expecting time

and

variable date of type String! is used in position expecting Date

I am not sure if Date and Time are expected datatyoes in the schema that I can use while writing teh queries. I am also attaching the code of the two input pages to give you an idea of what I am doing incorrectly right now.

Here is my first input page:

import React from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import Form from 'react-bootstrap/Form'
import Button from 'react-bootstrap/Button'; 
import { Link } from "react-router-dom";
import { withRouter } from 'react-router-dom'

class NewSchedulePageFirst extends React.Component {
  constructor(props) {
    super(props);
    this.state= {
      title: "",
      date: "",
      participants: ""
    }

    this.handleChange=this.handleChange.bind(this);

  }

  handleChange(event) {
    const {name, value} = event.target
    this.setState({
        [name]: value
    })
  }

  render() {
    
      return (
        <div className="form">
          <div className="form-title">
            <h2>Enter details for new entry </h2>
          </div>
          <div className="form-fields">
            <Form> 
                <div className="form-title">
                  <Form.Control type="text" placeholder="Title" onChange={this.handleChange} value={this.state.title} name="title" />
                </div>
                <div className="form-date">
                  <Form.Control type="date" onChange={this.handleChange} value={this.state.date} name="date" />
                </div>
                <div className="form-participants">
                  <Form.Control type="number" placeholder="No. of participants" onChange={this.handleChange} value={this.state.participants} name="participants" />
                </div>
            </ Form>
          </div>
          <Link to={{
                pathname: "/NewSchedulePageTwo",
                state : {
                    title: this.state.title,
                    date: this.state.date,
                    participants: this.state.participants
                }
              }}>
            <Button variant="outline-primary"> Next </Button>
          </Link>

        </div>
      );
    }
}

export default withRouter(NewSchedulePageFirst) ;

Here is my second page in which I try to write the data into the database :

import React, { useState } from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import Form from 'react-bootstrap/Form'
import Button from 'react-bootstrap/Button'; 
import { GET_MY_SCHEDULE } from './currentscheduledisplay'
import { Link , withRouter } from "react-router-dom";
import { gql } from "@apollo/client";
import { useMutation } from "@apollo/client";



const ADD_SCHEDULE = gql `
mutation($title: String!, $date: String!, $startTime: String!, $endTime: String!, $participants: Int!) {
    insert_Schedule(objects: {title: $title, date: $date, startTime: $startTime, endTime: $endTime, participants: $participants }) {
      affected_rows
      returning {
        id
        title
        date
        startTime
        endTime
        participants
      }
    }
  }

 `;


function NewSchedulePageSecond(props) {
    // console.log(props.location.state);
    const { title, date, participants } = props.location.state;
      const [ stitle, setStitle ] = useState(title);
      const [ sdate, setSdate ] = useState(date);
      const [ sparticipants, setSparticipants ] = useState(participants);
      const [ startTime, setStartTime ] = useState('');
      const [ endTime, setEndTime ] = useState('');


  // handleChange(event) {
  //   const {name, value} = event.target
  //   this.setState({
  //       [name]: value
  //   })
  // }

  // scheduleInput(event) {
  //   const { value } = event.target;
  //   this.setState({schedule : value});
  // }

  // componentDidMount() {
    
  // }

  const resetInput = () => {
      setStitle(title);
      setSdate(date);
      setSparticipants(participants);
      setStartTime('');
      setEndTime('');
    
  }

    const updateCache = (cache, {data}) => {
      // Fetch the todos from the cache
      const existingSchedule = cache.readQuery({
        query: GET_MY_SCHEDULE
      });
      // Add the new todo to the cache
      const newSchedule = data.insert_todos.returning[0];
      cache.writeQuery({
        query: GET_MY_SCHEDULE,
        data: {schedule: [newSchedule, ...existingSchedule.schedule]}
      });
    };


    const [addSchedule] = useMutation(ADD_SCHEDULE, { update: updateCache, onCompleted: resetInput });

      return (
        <div className="form">
          <div className="form-title">
            <h2>Enter details for new entry </h2>
          </div>
          <div className="form-fields">
            <Form> 
                <div className="form-start-time">
                  <Form.Control type="time" onChange={(e) => setStartTime(e.target.value)} value={startTime} name="startTime" />
                </div>
                <div className="form-end-time">
                  <Form.Control type="time" onChange={(e) => setEndTime(e.target.value)} value={endTime} name="endTime" />
                </div>
            </ Form>
          </div>

          <Link to='/'>
            <Button variant="outline-primary" onClick={() => {addSchedule(
                                  {variables: {title: stitle, 
                                                date: sdate,
                                                participants: sparticipants,
                                                startTime: startTime,
                                                endTime: endTime
                                      }})}}> 
                              Create 
            </Button>
          </Link>

          {/* <p>
            Title: {title}
          </p>
          <p>
            Date: {date}
          </p> */}

        </div>
      );
    
}

export default withRouter(NewSchedulePageSecond);

The schema for my relation is as follows:

id - integer, primary key, unique, default: nextval('"Schedule_id_seq"'::regclass)
title - text, default: 'Meeting'::text
participants - integer, default: 2
startTime - time without time zone
endTime - time without time zone
date - text, default: 'No Date Entered'::text

I am unable to figure out a way to represent Date and Time. i am using GraphQl for the first time so it would be great if you could explain why I am getting this error as well.

EDIT: My mutation is as follows :

mutation($title: String!, $date: String!, $startTime: String!, $endTime: String!, $participants: Int!) {
    insert_Schedule(objects: {title: $title, date: $date, startTime: $startTime, endTime: $endTime, participants: $participants }) {
      affected_rows
      returning {
        id
        title
        date
        startTime
        endTime
        participants
      }
    }
  }
Yash Sethia
  • 55
  • 1
  • 8
  • 'insert_Schedule' mutation **server** signature? argument types? – xadm Nov 03 '20 at 20:53
  • @xadm These are the attributes in my table 'Schedule' :- id - integer, primary key, unique, default: nextval('"Schedule_id_seq"'::regclass) title - text, default: 'Meeting'::text participants - integer, default: 2 startTime - time without time zone endTime - time without time zone date - text, default: 'No Date Entered'::text – Yash Sethia Nov 03 '20 at 21:02
  • I don't care about DB .... test your query in graphiql/playground ... docs explorer shows types defs ... again, how looks this mutation def and argument types - custom date and time scalars ... pass arguments [in format] matching these scalars requirements – xadm Nov 03 '20 at 21:29
  • @xadm That is exactly what I am struggling with, it would be good if you could be a bit more specific as to what I am supposed to do in order to resolve this issue. I am just learning GraohQL so it would be great if you could explain the obvious things as well. – Yash Sethia Nov 03 '20 at 21:32
  • check SERVER mutation specs, your CLIENT mutation must match SERVER defs/arg types ... you can check this in graphiql/playground docs ... or custom type defs and mutation definition input and return types, show this, not how you call this, is was known earlier – xadm Nov 05 '20 at 10:49

1 Answers1

1

You are getting this error because in your GraphQL mutation you are specifying a variable as type String! and then using it where a Date is expected.

For example, suppose you have a mutation called update_event that expects and argument time that is of type Date, your mutation should look like:

mutation ($time: Date) {
    update_event(time: $time) {
        id
    }
}

and not

mutation ($time: String!) {
    update_event(time: $time) {
        id
    }
}

In both mutations, update_event expects argument $time time to be Date. In the first mutation, it is a Date In the second one, it is a String!. The first is correct, the second will fail.


In your case, you have mutation:

mutation($title: String!, $date: String!, $startTime: String!, $endTime: String!, $participants: Int!) {
    insert_Schedule(objects: {title: $title, date: $date, startTime: $startTime, endTime: $endTime, participants: $participants }) {
      affected_rows
      returning {
         # ...
      }
    }
  }

You are specifying all the argument types as String! but, per the error, the endTime and startTime need to be specified as time:

mutation($title: String!, $date: String, $startTime: time, $endTime: time, $participants: Int!) {
    insert_Schedule(objects: {title: $title, date: $date, startTime: $startTime, endTime: $endTime, participants: $participants }) {
      affected_rows
      returning {
         # ...
      }
    }
  }
Dmitry Minkovsky
  • 36,185
  • 26
  • 116
  • 160
  • I have aaded my mutation as a part of my code, but I will add it explicitely as well. When I try to specify the type of my variable as Time (For startTime and endTime) and Date (for date) it throws an error saying ` Unhandled Rejection (Error): no such type exists in the schema: 'Time' ` I am not sure why though. – Yash Sethia Nov 05 '20 at 10:43
  • Yeah I'm sorry I missed it initially. I saw it after a while and modified my answer. Also, I am now seeing that you specified your DB field types. So you have `startTime` is `time without time zone`, `endTime` is `time without time zone` and `date` is `text`. Check out this table https://hasura.io/docs/1.0/graphql/core/api-reference/postgresql-types.html#implicitly-supported-types and use the appropriate corresponding GraphQL tyes. So for the first two, the corresponding type is `Implicit` (not sure why, never used it) and for a DB `text` type the corresponding type is `String` – Dmitry Minkovsky Nov 05 '20 at 10:55
  • Also, I highly suggest using the "GraphiQL` page in Hasura console test your mutation first and make sure it works. It'll help you a lot. Do you know where that is? – Dmitry Minkovsky Nov 05 '20 at 10:56
  • Just tested it in my Hasura and looks like if you have a `time without time zone` field, the corresponding type expected in the mutation is `time`. I updated my answer. It may need to be `time!` is the DB field is non-nullable. – Dmitry Minkovsky Nov 05 '20 at 10:59
  • Also it errors on the `date` field because you specify `String!` as the type, but it's a nullable field, so it needs to be `String`. Updated the answer for that, too. – Dmitry Minkovsky Nov 05 '20 at 11:09