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"]),}); });