jeremydaly / data-api-client

A "DocumentClient" for the Amazon Aurora Serverless Data API
MIT License
439 stars 61 forks source link

Bug regarding dates #66

Open Ricardo1980 opened 3 years ago

Ricardo1980 commented 3 years ago

Hello,

First of all, thanks for this library. It is so annoying having to use AWS SDK for this...

Anyway, I detected what I think is a bug.

My project uses Amplify, AppSync (GraphQL), Lambdas and Aurora Serverless.

One of the types I have in my graphql schema is this one:

type User {
  userId: ID!
  dob: AWSDate!
  ….
}

NOTE: dob is date of birth, so I only care about the date, not about time.

The SQL command I have in my lambda function is something like: SELECT userId, dob …..FROM User WHERE userId='$id'

When using AWS framework var dbResponse = await RDS.executeStatement(params).promise(); I receive something like this:

{
    "numberOfRecordsUpdated": 0,
    "records": [
        [
            {
                "stringValue": "Ricardo"
            },
            {
                "stringValue": "1956-03-12"
            }
        ]
    ]
}

And everything works fine.

However, if I use this library in my lambda function: let dbResponse = await dataApiClient.query('SELECT userId, dob FROM User WHERE userId =:userId;', { userId: userId }); Then I receive this:

{
    "records": [
        {
            "userId": "01B452F74BC941E58642766EE9D2C473",
            "dob": "1977-09-19T00:00:00.000Z",
            ....
        },

And because of that, graphql mapping is failing with this error:

▿ Can't serialize value (/getUsersForGame[0]/user/dob) : Unable to serialize `1977-09-19T00:00:00.000Z` as a valid date.
  ▿ object : 3 elements
    ▿ 0 : 2 elements
      - key : "message"
      - value : Can't serialize value (/getUsersForGame[0]/user/dob) : Unable to serialize `1977-09-19T00:00:00.000Z` as a valid date.
    ▿ 1 : 2 elements
      - key : "path"
      ▿ value : 4 elements
        - 0 : getUsersForGame
        - 1 : 0
        - 2 : user
        - 3 : dob
    ▿ 2 : 2 elements
      - key : "locations"
      - value : <null>

BTW, when I use AWS console and I use the query editor, I also see "1956-03-12", without time.

About my RDS database, the type is this one: dob date NOT NULL

So, for some reason, seems this library is not processing the date type properly. Do you know what's going on? Thanks a lot.

EDIT: I found a workaround. Not ideal, but better than having to use AWS framework: SELECT DATE_FORMAT(dob, GET_FORMAT(DATE,'ISO')) as dob from User;

ffxsam commented 3 years ago

RDS Data API returning a string is correct/expected behavior. I don't think it has anything to do with the data-api-client library. So you'll have to transform dates yourself.

I have the very same problem with Postgres returning dates in useless formats: "2020-11-03 17:30:16.046186+00"

So I wrote a function to transform dates and other stuff that the Data API returns:

const pgDateRx = '^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}\\.\\d+';
const jsonRx = '^\\[?{(?:\\s*"?\\w+":\\s*"?[\\S\\s]+"?,?\\s*)*}\\]?$';

export function transformData(obj, patterns) {
  if (Array.isArray(obj)) {
    return obj.map(o => transformData(o, patterns));
  }

  const newObj = { ...obj };

  for (const key in obj) {
    for (const pat in patterns) {
      if (new RegExp(pat).test(obj[key])) {
        newObj[key] = patterns[pat](obj[key]);
      }
    }
  }

  return newObj;
}

export const standardTransform = obj =>
  transformData(obj, {
    [jsonRx]: value => JSON.parse(value),
    [pgDateRx]: value => new Date(value + 'Z').toISOString(),
  });