Closed7

Remix+CloudflareでWebサイトを作る 36(複数のユニーク制約があるときのエラーハンドリング、fakerのslug、オートスケーリング、日付と時間選択フォーム)

saneatsusaneatsu

【2024-10-14】テーブルに複数ユニーク制約がある場合のエラーハンドリング

背景

こんなモデルがPrismaで定義されているとする。

schema.prisma
model Sample {
  id           Int           @id @unique @default(autoincrement())
  name         String        @unique
  url          String        @unique
  createdAt    DateTime      @default(now())
  updatedAt    DateTime      @updatedAt
}

nameurl で、それぞれ重複している場合のエラーメッセージを変えたい。

export async function createSample(
  client: PrismaClient,
  sample: Pick<Sample, "name" | "url">
): Promise<void> {
  try {
    await client.sample.create({
      data: {
        name: sample.name,
        url: sample.url,        
      },
    });
  } catch (e: any) {
    if (
      e instanceof Prisma.PrismaClientKnownRequestError &&
      e.code === "P2002"
    ) {
      // ここで、URLが重複している場合はエラーメッセージを変えたい
      throw new Error(`名前が重複しています`);
    }

    throw new Error(e);
  }
}

AIに聞いてみる

e.meta?.target の中身でハンドリングする方法を提示されるがこれはうまくいかない。
というのもe.meta?.targetには [ 'UNIQUE constraint failed' ]という値が入っているだけでカラム名は入っていない...。

export async function createSample(
  client: PrismaClient,
  sample: Pick<Sample, "name" | "url">
): Promise<void> {
  try {
    await client.sample.create({
      data: {
        name: sample.name,
        url: sample.url,        
      },
    });
  } catch (e: any) {
    // PrismaClientKnownRequestErrorでユニーク制約違反をキャッチ
    if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === 'P2002') {
      const targetField = e.meta?.target as string[]; // 重複したフィールド名を取得

      if (targetField?.includes('name')) {
        throw new Error('名前が重複しています');
      }

      if (targetField?.includes('url')) {
        throw new Error('URLが重複しています');
      }
    }

    throw new Error(e);
  }
}

なんでだ?

複数のカラムにユニーク制約があるとこうなるっぽい。

ではどうするのかAIに聞いてみる

AIにはfindUniqueを用いてカラムごとに重複チェックを行う方法を教えられた。
これだとカラム名分だけリクエストが発生しちゃうのが気になる。

あと、これそもそも新規作成のときなら良いかもだけど、更新のときに同じ様な書き方をするとバグる。
具体的には、同じ sample.name を入力して更新ボタンを押すとエラーになってしまう。

もっとスマートな方法探さねば。

export async function createSample(
  client: PrismaClient,
  sample: Pick<Sample, "name" | "url">
): Promise<void> {
  try {
    // nameが重複しているかをチェック
    const existingName = await client.sample.findUnique({
      where: { name: sample.name },
    });
    if (existingName) {
      throw new Error('名前が重複しています');
    }

    // url重複しているかをチェック
    const existingLink = await client.sample.findUnique({
      where: { link: sample.link },
    });
    if (existingLink) {
      throw new Error('URLが重複しています');
    }

    await client.sample.create({
      data: {
        name: sample.name,
        url: sample.url,        
      },
    });
  } catch (e: any) {
    throw new Error(e.message || 'Sampleの作成に失敗しました');
  }
}
saneatsusaneatsu

【2024-10-14】エラー:Failed to publish your Function. Got error: Unknown internal error occurred.

GitHub Actionsでデプロイするときにたま〜〜〜〜に(1ヶ月に1回くらい?)発生するこのエラー何。

もう1回実行したら成功する場合もあれば、何回やっても無理で翌日に再実行したらうまくいった時もある。

  ✨ Compiled Worker successfully
  Uploading... (78/112)
  Uploading... (90/112)
  Uploading... (101/112)
  Uploading... (112/112)
  ✨ Success! Uploaded 34 files (78 already uploaded) (1.42 sec)
  
  ✨ Uploading Functions bundle
  🌎 Deploying...
  
  ✘ [ERROR] Deployment failed!
  
    Failed to publish your Function. Got error: Unknown internal error occurred.  
saneatsusaneatsu

【2024-10-17】faker.lorem.slug()fakerJAでは使えない

背景

https://fakerjs.dev/api/lorem.html#slug

slugを作成するためにfaker.lorem.slug({ min: 5, max: 10 }) というコードを書いたら-------みたいなハイフン繋ぎの文字列が作成された。

原因・解決方法

fakerJA を使っていたのが原因だった。
fakerJA.lorem.lines()では日本語で作成できるけど、slugは英語でしか作成できないゆえに起きていることなのかな?
別に日本語でほげほげ-ふがふがというの作成されても良い気がするけどそれはslugではないということなのか。

- import { fakerJA as faker } from "@faker-js/faker";
+ import { fakerJA as faker, fakerEN } from "@faker-js/faker";

- faker.lorem.slug({ min: 5, max: 10 })
+ fakerEN.lorem.slug({ min: 5, max: 10 })
saneatsusaneatsu

【2024-10-17】Cloudflareにおけるオートスケーリングとかロードバランシングとか

背景

https://x.com/integrated1453/status/1846796166744199482
このツイートを見て「大量にリクエストきたときのオートスケーリングとかってCloudflareどうなってるんだっけ?」と思ったので調べてみる。

なんかよしなにやってくれてんの?

https://qiita.com/khayama/items/3f3ca63d5748949632e0#product-and-feature-announcements
https://x.com/kyhayama/status/1592191997661827072

2022年の記事。つまりどういうことだ。
参照記事をAIに要約させよう。

この記事は、Cloudflareが紹介する「Supercloud」と呼ばれる新しいクラウドコンセプトについて説明しています。Supercloudは、従来の仮想マシン(VM)に依存するクラウドコンピューティングから進化し、コードの実行やデータの位置などの複雑な処理を自動化・効率化します。これにより、開発者はスケーリングや仮想マシンの管理を考えることなく、アプリケーションをインターネット規模で動作させることができます。

CloudflareのSupercloudは、効率的なリソース使用とコスト削減を実現し、パフォーマンス、スケーラビリティ、プライバシー、コスト効率が大幅に向上します。例えば、アプリケーションの実行は、必要なときに必要なだけ行われ、無駄なリソースの支払いを避けることができます。また、Supercloudはデータの流動性を高め、必要に応じてコードやデータがユーザーの近くで実行され、最適なパフォーマンスを提供します。

どうやらスケーリングや場所など細かいことは気にせず〜ってことが書かれているっぽいけどほんと?

自分がほしい答えをくれるとそれはそれで不安になる。
調べてちゃんと理解せねば。。

Cloudflare のLoad Balancer with EC2

https://zenn.dev/kameoncloud/articles/aaca06bb775144

Load Balancerの機能自体は別途あって、この記事ではEC2使ってやってる。

saneatsusaneatsu

【2024-10-18】shadcnで日付と時間を選択するフォームが欲しい

公式では

https://ui.shadcn.com/docs/components/date-picker

これは日付を選択できるだけで、時間は選択できない。
調べよう。

shadcn/ui expansions

https://shadcnui-expansions.typeart.cc/docs/datetime-picker
ここを参考にすればできそう。

https://zenn.dev/link/comments/0b9cd05d274297

MultiSelectorのときにも参考にしたところだけどまた助けてくれた...!ありがとう。。

saneatsusaneatsu

選択肢のDropdown(上の画像でいうと「October」のところ)をクリックするとPopoverごと閉じられてしまう挙動になっているので直したい。
あと、UIもちょくちょくpadidngが足りてないところがあるので修正する。

修正したら以下のStackBllitzにコンポーネント作って、以下みたいに記事書く。

https://zenn.dev/saneatsu/articles/shadcn-creatable-combobox

このスクラップは1ヶ月前にクローズされました