原文

What are computed fields?

Computed fields は動的に演算された擬似的な値 = virtual value、もしくは擬似的なオブジェクト virtual object です。Computed fields はリクエストが発行された際に custom SQL function を用いて演算されます。その際の演算には、テーブルのカラムの値を用いることができます。また必要であれば custom input を使用することも可能です。

(訳注:Computed filed が活躍するのは、親テーブルの値を使って演算した値を生成したい場合である。例えば article テーブルの各種の値に加えて、article.category_id を元に、何らかの集計をした値を生成したい場合だ。)

Computed fields are virtual values or objects that are dynamically computed and can be queried along with a table’s columns. Computed fields are computed when requested for via custom SQL functions using other columns of the table and other custom inputs if needed.

Computed fields は GraphQL API からのみアクセスできます。また Computed fields を追加しても database schema に変更は生じません。

Note

Computed fields are only exposed over the GraphQL API and the database schema is not modified on addition of a computed field.

Supported SQL functions

以下の要件を満たした function だけが computed fileld としてテーブルに追加することができます。

Only functions which satisfy the following constraints can be added as a computed field to a table. (terminology from Postgres docs):

  • Function behaviour: STABLE もしくは IMMUTABLE のどちらかであること
  • Argument modes: IN の場合のみ
  • Table Argument: argument の一つは必ず table row type であること
  • Return type: SETOF <table-name> もしくは BASE type であること
  • Function behaviour: ONLY STABLE or IMMUTABLE
  • Argument modes: ONLY IN
  • Table Argument: One input argument with a table row type
  • Return type: Either SETOF <table-name> or BASE type

Computed fileds で functios が使用される場合、その引数は table row を必ずとる必要がありますが、それに加えてそれ以外の引数をとることも可能です。追加の引数は、GraphQL API を使用する際に引数として渡すことで機能します。

Note

Functions used as computed fields can also accept other arguments other than the mandatory table row argument. Values for these extra arguments can be passed as arguments to the computed field in the GraphQL API.

Computed field types

Computed field が返す値の type は、SQL function の return type に定義した type によって、二種類に分類することができます。

Based on the SQL function’s return type, we can define two types of computed fields:

1. Scalar computed fields

SQL function の return type が Integer, Boolean, Geography といった base type の場合、computed field は scalar type の値を返します。

Computed fields whose associated SQL function returns a base type like Integer, Boolean, Geography etc. are scalar computed fields.

例:

author テーブルが first_namelast_name というカラムを持つとします。それぞれ type は text です。

Example:

The author table has two text columns: firstname and lastname.

ではこれらのテーブルに対して author_full_name という名称の SQL function を定義します。

Define an SQL function called authorfullname:

CREATE FUNCTION author_full_name(author_row author)
RETURNS TEXT AS $$
  SELECT author_row.first_name || ' ' || author_row.last_name
$$ LANGUAGE sql STABLE;

今定義した SQL function を使って、full_name という名称の computed filedauthor テーブルに追加しましょう。

Add a computed field called full_name to the author table using the SQL function above.

結果として以下の query でデータを取得することができます。

Query data from the author table:

query {
  author {
    id
    first_name
    last_name
    full_name
  }
}
{
  "data": {
    "author": [
      {
        "id": 1,
        "first_name": "Chris",
        "last_name": "Raichael",
        "full_name": "Chris Raichael"
      }
    ]
  }
}

Screen Shot 2020-08-13 at 15.38.28

2. Table computed fields

SQL function の return type が SETOF <table-name> の場合、computed field は table type の値を返します。ここで返される table は、必ず track されている必要があります。

Computed fields whose associated SQL function returns SETOF <table-name> are table computed fields. The return table must be tracked to define such a computed field.

単純に author とそれが所持する article を取得するだけであれば、table relationship を定義するだけで実現可能です。

Example:

In a simple author <-> article schema, we can define a table relationship on the author table to fetch authors along with their articles.

ですが、サーチパラメーターを元に author の article を取得したい場合には、computed field を使用する必要があります。

We can make use of computed fields to fetch the author’s articles with a search parameter.

filter_author_articles という名称の SQL function を定義しましょう。

Define an SQL function called filterauthorarticles:

CREATE FUNCTION filter_author_articles(author_row author, search text)
RETURNS SETOF article AS $$
  SELECT *
  FROM article
  WHERE
    ( title ilike ('%' || search || '%')
      OR content ilike ('%' || search || '%')
    ) AND author_id = author_row.id
$$ LANGUAGE sql STABLE;

今定義した SQL function を使って、filtered_articles という名称の computed filedauthor テーブルに追加しましょう。

Add a computed field called filtered_articles to the author table using the SQL function above.

結果として以下の query でデータを取得することができます。

Query data from the author table:

query {
  author {
    id
    first_name
    last_name
    filtered_articles(args: {search: "Hasura"}){
      id
      title
      content
    }
  }
}
{
  "data": {
    "author": [
      {
        "id": 1,
        "first_name": "Chris",
        "last_name": "Raichael",
        "filtered_articles": [
          {
            "id": 1,
            "title": "Computed fields in Hasura",
            "content": "lorem ipsum dolor sit amet"
          }
        ]
      }
    ]
  }
}

Screen Shot 2020-08-13 at 15.52.48

Adding a computed field to a table

該当テーブルの Modify テーブルに移動し、Computed fieldsAdd ボタンを押します。

Head to the Modify tab of the table and click on the Add button in the Computed fields section:

Screen Shot 2020-08-13 at 15.53.58

Console からの設定は v1.1.0 以上から可能になりました。

Supported from

Console support is available in v1.1.0 and above

Computed fields permissions

Computed field へのアクセスコントロールの管理方法は computed field の type によって二通りにわかれます。

Access control to computed fields depends on the type of computed field.

  • Scalar computed field の場合は、通常のカラムと同様 の方法で管理されます。
  • Table computed field の場合は、return type として設定された table に対するパーミンションコントロールが、そのまま適用されます。
  • For scalar computed fields, permissions are managed similar to the columns permissions of the table.
  • For table computed fields, the permissions set on the return table are respected.

Accessing Hasura session variables in computed fields

訳注: ほぼ Extend schema with SQL functions に同じ項目がありますのでそちらを参照ください。

It can be useful to have access to the session variable from the SQL function defining a computed field. For instance, suppose we want to record which users have liked which articles. We can do so using a table article_likes that specifies a many-to-many relationship between article and user. In such a case it can be useful to know if the current user has liked a specific article, and this information can be exposed as a Boolean computed field on article.

Create a function with an argument for session variables and add it with the addcomputedfield API with the session_argument key set. The session argument is a JSON object where keys are session variable names (in lower case) and values are strings. Use the ->> JSON operator to fetch the value of a session variable as shown in the following example.

-- 'hasura_session' will be the session argument
CREATE OR REPLACE FUNCTION article_liked_by_user(article_row article, hasura_session json)
RETURNS boolean AS $$
SELECT EXISTS (
    SELECT 1
    FROM article_likes A
    WHERE A.user_id = hasura_session ->> 'x-hasura-user-id' AND A.article_id = article_row.id
);
$$ LANGUAGE sql STABLE;
POST /v1/query HTTP/1.1
Content-Type: application/json
X-Hasura-Role: admin

{
    "type":"add_computed_field",
    "args":{
        "table":{
            "name":"article",
            "schema":"public"
        },
        "name":"liked_by_user",
        "definition":{
            "function":{
                "name":"article_liked_by_user",
                "schema":"public"
            },
            "table_argument":"article_row",
            "session_argument":"hasura_session"
        }
    }
}

Note

The specified session argument is not included in the argument options of the computed field in the GraphQL schema.

Supported from

This feature is available in v1.3.0-beta.1 and above

Computed fields vs. Postgres generated columns

訳注:実際に Posgres の Generated Columns を使ったことがないため、正確な翻訳ができないのですが、Hasura としては Computed fields の方が拡張性が高く、制限がない、さらに素直な実装になるということなので、こちらをおすすめしているようです。

Postgres, from version 12, is introducing Generated Columns. The value of generated columns is also computed from other columns of a table. Postgres’ generated columns come with their own limitations. Hasura’s computed fields are defined via an SQL function, which allows users to define any complex business logic in a function. Generated columns will go together with computed fields where Hasura treats generated columns as normal Postgres columns.