原文

Introduction

テーブル間の「一対一 = one to one」の関係性は、unique foreign key 制限 = unique foreign key constraint を用いて実装することができます。

A one-to-one relationship between two tables can be established via a unique foreign key constraint.

以下のスキーマを持つ二つのテーブルあるとしましょう。

Say we have the following two tables in our database schema:

author (
  id SERIAL PRIMARY KEY,
  name TEXT
)

passport_info (
  id SERIAL PRIMARY KEY,
  owner_id INT NOT NULL
  passport_number TEXT
  ...
)

この二つのテーブルは one-to-one relationship によって関連づけられています。つまり次のような特徴を持ちます。

  • author は一つの passport_info を持つ(訳注:正確には 0 もしくは 1)
  • passport_info は一つの owner を持つ(訳注:こちらは 0 には絶対にならない)

These two tables are related via a one-to-one relationship. i.e.:

an author can have one passportinfo a passportinfo has one owner

Step 1: Set up a table relationship in the database

one-to-one relationship を作るためには dabase に対して以下の操作を加えます。

This one-to-one relationship can be established in the database by:

  • foreign key constraint 機能を用いて、passport_info テーブルと author テーブルを紐付けます。passport_info.owner_id から author.id に対して制限を設けます。

  • passport_infoowner_id に対して unique constraint を設けます。

  • Adding a foreign key constraint from the passportinfo table to the author table using the ownerid and id columns of the tables respectively

  • Adding a unique constraint to the ownerid column for the passportinfo table

これらの操作によって、passport_info テーブルの owner_id を持つ author が必ず存在することが保証されます。(訳注:FK によって)また passport_info テーブルの owner_id が特定の値を持つカラムは、必ず一つであることが保証されます。(訳注:unique constraint によって)

This will ensure that the value of the ownerid column in passportinfo table is present in the id column of the author table and there will be only one row with a particular owner_id.

Step 2: Set up GraphQL relationships

GraphQL API を使って nested objects query にアクセスできるようにするためには、以下の操作をとおして relationships を定義します。

To access the nested objects via the GraphQL API, create the following relationships:

  • 一つめの Object relationship を作成します。author テーブル から passport_info にアクセスできるようにするために、author テーブルRelationships 設定画面から次のように設定します。id -> passport_info :: owner_id

  • 二つめの Object relationship を作成します。passport_info テーブル から owner にアクセスできるようにするために、passport_info テーブルRelationships 設定画面から次のように設定します。owner_id -> author :: id

  • Object relationship, passportinfo from the author table using id -> passportinfo :: owner_id

  • Object relationship, owner from the passportinfo table using ownerid -> author :: id

Step 3: Query using relationships

設定が完了しましたので、passport_info をともなった author リストのフェッチをおこなってみましょう。

We can now:

fetch a list of authors with their passport_info:

Screen Shot 2020-08-12 at 12.13.02

owner 情報をともなった passport_info リストのフェッチをおこなってみましょう。

fetch a list of passport_infos with their owner:

Screen Shot 2020-08-12 at 12.13.07

Current limitations with nested mutations

one-to-one relationships において現状、nested mutations は一方向にしか正常に動作しません。

With one-to-one relationships, currently nested mutations will work only in one of the two directions.

今回の例でいうと、passport_info に対する mutation を発行し、nest された owner を伴って passport_info を追加することは可能なのですが、反対に author に対する mutation を発行し、nest された passport_info を伴って author を追加しようとすると constraint violation error が発生してしまいます。

In our example, inserting a passportinfo with their nested owner will work seamlessly but trying to insert an author with their nested passportinfo will throw a constraint violation error.

これは Hasura GraphQL が nested mutation を扱う方法が原因です。(これについては この記事 が詳細を説明しています。)nested object は親よりも先に inert されます。つまり上記のエラーが起きる例では passport_info の方が先に insert されるので、その時点では owner が存在しないため owner_id が null になってしまいます。結果として passport_info.owner_idNot-NULL 制限をかけているのであればこの時点でエラーが発生します。(訳注:passport_info に対する mutation を発行する方法もどうやるのかよくわからない。わかる人がいれば訳者まで是非連絡を)

This is due to the way Hasura GraphQL engine currently handles nested mutations (described in detail here). As nested object relations are inserted before the parent, the passportinfo will be attempted to be inserted first and the value of its ownerid will be attempted to be set as the id of the author. Due to this, based on whether the ownerid of passportinfo is nullable or not, a Not-NULL violation error will be thrown either for the ownerid field of passportinfo or the id field of author.