hasura / go-graphql-client

Package graphql provides a GraphQL client implementation.
MIT License
395 stars 91 forks source link

Date/times as variable paramaters to hasura #124

Open Skeletor11 opened 7 months ago

Skeletor11 commented 7 months ago

I am currently trying to pull data through Golang against our harusa implementation. I am able to pull queries just fine until I have a date/time variable. Example:

type queryModel struct { StatusHistory []struct { Id hasura.BigInt graphql:"id" Status string graphql:"status" } graphql:"status_history(where: {ismi: {_eq: $id}, started_at: {_gte: '$ed'}})" }

const iso8601 = "2006-01-02T15:04:05.999999-07:00" var ( statuses = strings.Builder{} q struct{ queryModel } i, = strconv.ParseInt(dd.Id, 10, 64) t, = time.Parse("01-02-2006 15:04:05", "01-23-2024 00:10:17") tt = t.Format(iso8601) filter = map[string]any{ "id": hasura.BigInt(i), "ed": &tt, } )

    if err = d.hasura.Query(ctx, &q, filter); err != nil {
        ctx.Logger().WithError(err).Error("failed to query device data statuses")
        return err
    }

I have tried passing the "ed" variable as a string, time.Time, timestamppb, etc with no luck. I have even tried adding escaped quotes around the "$ed" notation in the query itself bound to the model. Nothing seems to work, every time it returns with an error object (though there are no errors, count == 0) and the model is not populated. However, when I remove the "ed" variable from the filters and the model query, everything works fine. So the code itself seems to be good. Also, I have run the model query directly in hasura (with the $ vars swapped out for actual values) and it all works fine. Is there a special way I should be passing in a date/time variable into the filters for the query?

hgiasac commented 7 months ago

You can use the Graphiql console to autocomplete the full query. The timestamp column of Postgres is usually timestamptz or timestamp if no time zone. For example:

query GetUser($_eq: timestamptz) {
  users(where: {created_at: {_eq: $_eq}}) {
    id
  }
}

That isn't the problem of parsing, but the problem of type reference. You can define the type alias with either string or time.Time

type timestamptz time.Time

type queryModel struct {
  StatusHistory []struct {
    Id hasura.BigInt graphql:"id"
    Status string graphql:"status"
  } graphql:"status_history(where: {ismi: {_eq: $id}, started_at: {_gte: '$ed'}})"
}

variables := map[string]any{
  "id": hasura.BigInt(i),
  "ed": timestamptz(time.Now())
}

Or create a reusable type:

type Timestamptz time.Time

func (t Timestamptz) GetGraphQLType() string { 
  return "timestamptz" 
}

IIRC time.Time can parse Postgres timestamp. If it doesn't work for your use case you can implement the UnmarshalJSON function to decode the value.