Amplify Gen2で設定したa.date()に対して「日時」データがうまく保存できてなかった - 葛葉アプスとちらし寿司

Amplify Gen2で設定したa.date()に対して「日時」データがうまく保存できてなかった

version情報

    "aws-amplify": "^6.3.4",

起こったこと(長い前置き)

以下のようなamplify/date/resource.tsがあるとする。

EventテーブルのstartDateについて、a.date()という型があるのでDate型を挿入できるのかと思っていた。

import { type ClientSchema, a, defineData } from "@aws-amplify/backend";

const schema = a.schema({
  //....
  Event: a
    .model({
      id: a.id().required(),
      startDate: a.date(),
    //....
    })
    .authorization((allow) => [
    //....
    ])
    .identifier(["id"]),});
});

export type Schema = ClientSchema<typeof schema>;

export const data = defineData({
  schema,
  authorizationModes: {
    defaultAuthorizationMode: "iam",
    apiKeyAuthorizationMode: {
      description: "Event",
    },
  },
});

このEventテーブルに対してLambdaからデータを挿入する処理を書く。

どうもDynamoDBでは日時データを保存するときは、「文字列でISO 8601形式」か「数値でUnix時間」で格納する必要があるらしい。

export const handler: Handler = async (
  event,
  context,
  callback
): Promise<void> => {
  const dynamoDB = new AWS.DynamoDB.DocumentClient({
    region: "ap-northeast-1",
  });

  const videos = []; //適当なデータ 
  if (!videos.length) {
    console.log("not live data.");
    return;
  }
  const PutRequests = videos.map((video) => {
    return {
      PutRequest: {
        Item: {
          id: video.id?.videoId,
          // ...
          startDate: new Date(
            video.snippet?.publishedAt as string
          ).toISOString(),
          // ...
        },
      },
    };
  });
  await dynamoDB
    .batchWrite({
      RequestItems: {
        [EventTableName]: PutRequests,
      },
    })
    .promise();
}

これを格納し終え、さらにこれをフロントで表現しようとする。

"use client";

import { generateClient } from "aws-amplify/api";
import output from "@/amplify_outputs.json";
import type { Schema } from "@/amplify/data/resource";
import { useEffect, useState } from "react";
import Event from "./Event";

const Events = () => {
  const [events, setEvents] = useState<Schema["Event"]["type"][]>([]);
  useEffect(() => {
    const client = generateClient<Schema>({
      //...
    });
    const sub = client.models.Event.observeQuery().subscribe({
      next: ({ items: events, isSynced }) => {
        setEvents([...events]);
      },
    });
    return () => {
      sub.unsubscribe();
    };
  }, []);
  return (
    <div>
      {events.map((event) => (
        <Event key={event.id} data={event}></Event>
      ))}
    </div>
  );
};

export default Events;

コンソールでこんなエラーが出る

// ...
to serialize "******Z" as a valid date.

やりたいことはa.date()じゃなくてa.datetime()かも

ModelField.d.tsを見に行くとこんな記述。

なお、これは本日(2024/6/5)時点のversion 6.3.4の記述なので未来の人がこれを見たときはきちんとバージョン確認すること。。。

// version 6.3.4
// node_modules/@aws-amplify/data-schema/dist/esm/ModelField.d.tsから抜粋
/**
 * A date scalar type that is represented server-side as an extended ISO 8601 date string in the format `YYYY-MM-DD`.
 * @returns date field definition
 */
export declare function date(): ModelField<Nullable<string>>;
/**
 * A time scalar type that is represented server-side as an extended ISO 8601 time string in the format `hh:mm:ss.sss`.
 * @returns time field definition
 */
export declare function time(): ModelField<Nullable<string>>;
/**
 * A date time scalar type that is represented server-side as an extended ISO 8601 date and time string in the format `YYYY-MM-DDThh:mm:ss.sssZ`.
 * @returns datetime field definition
 */
export declare function datetime(): ModelField<Nullable<string>>;
/**
 * A timestamp scalar type that is represented by an integer value of the number of seconds before or after `1970-01-01-T00:00Z`.
 * @returns timestamp field definition
 */
export declare function timestamp(): ModelField<Nullable<number>>;

要するにdate,time,datetime,timestampの4つがあるらしい。今回は日時データを格納したかったのでdateではなく、datetimeを選択するのが正しいらしい。

以下の処理でデータが正しく格納された。

ただし、フロントエンドから受け取るのは格納した値だと思う。そのため、そのプロパティに対してnew Date()を行う必要があるようだ。

 const schema = a.schema({
   //....
   Event: a
     .model({
       id: a.id().required(),
-      startDate: a.date(),
+      startDate: a.datetime(),
     //....
     })
     .authorization((allow) => [
    //....
    ])
    .identifier(["id"]),});
});