0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[LWC] GraphQL Tips

Posted at

GraphQL アダプタの特徴

  • LWCで使用可能
  • Lightning Data Service対応
  • ユーザーの権限(CRUD、FLS、共有)が適用される
  • Apex不要
  • 一回のクエリで複数の検索結果を取得可能
  • クエリと同じ構造でレスポンスが返る

image.png

LWCでGraphQLを使用する

下記はGraphQLをLWCで使用したサンプルです。

FileUploaderSample.js
import { LightningElement, api, wire } from "lwc";
import { gql, graphql, refreshGraphQL } from "lightning/uiGraphQLApi";

const QUERY = gql`
  query GetFiles($recordId: ID!) {
    uiapi {
      query {
        ContentDocumentLink(where: { LinkedEntityId: { eq: $recordId } }) {
          edges {
            node {
              ContentDocument {
                Id
                Title {
                  value
                }
                FileExtension {
                  value
                }
              }
            }
          }
        }
      }
    }
  }
`;

export default class FileUploaderSample extends LightningElement {
  @api recordId;
  files = [];
  wiredData;

  @wire(graphql, {
    query: "$recordQuery",
    variables: "$variables"
  })
  queryGraphql(value) {
    this.wiredData = value;
    const { errors, data } = value;
    if (data) {
      const records = data.uiapi?.query?.ContentDocumentLink?.edges?.map(
        (record) => record.node.ContentDocument
      );
      this.files = records;
    } else if (errors) {
      console.error("GraphQL error", errors);
    }
  }

  get recordQuery() {
    return this.recordId ? QUERY : undefined;
  }

  get variables() {
    return { recordId: this.recordId };
  }

  async handleUploadFinished() {
    await refreshGraphQL(this.wiredData);
    this.reportValidity();
  }

  async handleDelete() {
    await refreshGraphQL(this.wiredData);
    this.reportValidity();
  }
}

サンプルについて説明していきます。
まず、GraphQLのコネクタをインポートする必要があります。

GraphQLコネクタのインポート
import { gql, graphql, refreshGraphQL } from "lightning/uiGraphQLApi";

gqlにテンプレートリテラルを渡してクエリを宣言します。クエリに渡す変数は$varNameの形で宣言します。
なお、長くて邪魔だからと言って、外部のファイルに移すことはできません。ビルド時にテンプレートリテラルを静的に解析するため、コンパイル時にエラーとなってしまいます。

GraphQLのクエリ
const QUERY = gql`
  query GetFiles($recordId: ID!) {
    uiapi {
      query {
        ContentDocumentLink(where: { LinkedEntityId: { eq: $recordId } }) {
          edges {
            node {
              ContentDocument {
                Id
                Title {
                  value
                }
                FileExtension {
                  value
                }
              }
            }
          }
        }
      }
    }
  }
`;

GraphQLはwireアダプタで使用できます。
GraphQLで取得する値は、クエリとおなじ構造でdataの中に含まれます。
map関数やforEatch関数を使ってGraphQLで取得した値を画面表示で使用する形に変換します。
Apexを呼び出す時とは異なり、エラーはerrorsに格納されます(Apexの時はerror)。

  @wire(graphql, {
    query: "$recordQuery",
    variables: "$variables"
  })
  queryGraphql(value) {
    this.wiredData = value;
    const { errors, data } = value;
    if (data) {
      const records = data.uiapi?.query?.ContentDocumentLink?.edges?.map(
        (record) => record.node.ContentDocument
      );
      this.files = records;
    } else if (errors) {
      console.error("GraphQL error", errors);
    }
  }

クエリが実行可能になるまで、Queryにundefinedを渡すことでGraphQLの実行を遅らせることができる。

  get recordQuery() {
    return this.recordId ? QUERY : undefined;
  }

refreshGraphQLを使用することでクエリを再実行し、GraphQLワイヤアダプタでプロビジョニングされたデータを更新できます。

  async handleUploadFinished() {
    await refreshGraphQL(this.wiredData);
    this.reportValidity();
  }

GraphQL API クライアント

GraphQL の検証にはPostmanまたはAltair GraphQLなどが利用可能です。

image.png

一度のクエリで複数の検索を実行する

GraphQL APIでは一回のクエリで10個の検索を実行することができます。
下記の例ではAccountとAccountの集計を同時に行なっています。

query MultiQuerySample {
  uiapi {
    query {
      Account {
        edges {
          node {
            Id
            Name {
              value
            }
          }
        }
      }
    }
    aggregate {
      Account {
        edges {
          node {
            aggregate {
              Id {
                count {
                  value
                }
              }
            }
          }
        }
      }
    }
  }
}

クエリの書き方

基本構造

「edges」はリストを表し、「node」はSObjectのレコードに相当します。

query accounts {
  uiapi {
    query {
      Account {
        edges {
          node {
            Id
            Name {
              value
            }
          }
        }
      }
    }
  }
}

image.png

選択リスト項目のラベル、通貨項目のロケール表示を取得する

value、label、formatが個別フィールドとして返されるため、データ取得後の値変換や追加処理が不要です。

image.png

複合型項目(住所、地理位置情報)を取得する

複合型項目の取得には構成フィールドを使用します。フィルターや集計でも同様です。

image.png

親レコードの項目を取得する

最大55個の子-親リレーションを指定可能です。
最大5階層まで親の項目を取得できます。

query ParentFieldSample {
    uiapi {
      query {
        Contact {
          edges {
            node {
              Name { value }
              AccountId { value }
              Account {
                Name {
                  value
                }
              }
            }
          }
        }
      }
    }
  }

親レコード(多態的リレーション)の項目を取得する

SOQL同様、多態的リレーションで参照先のSObjectTypeごとに取得項目を設定可能です。

image.png

多態的リレーション項目は、GraphQLではUnion型として扱われます。
特定の方のオブジェクトのフィールを参照するときにインライン・フラグメントを使用します。
インライン・フラグメントはOwner、Who、Whatの項目で使用可能です。
(他の多態的リレーションではエラーになったのでおそらく未対応です。)

... on 型名: {
    フィールド名
}

ちなみにSOQLでは以下になります。

soqlの例
SELECT 
    TYPEOF Who
        WHEN Contact THEN Name, Account.Name
        WHEN Lead THEN Name
    END
FROM Task 

子レコードを取得する

最大20個の親-子リレーションを指定可能です。
最大1階層まで親の項目を取得できます。
「edges」はリストを表し、「node」はSObjectのレコードに相当します。

image.png

比較演算子を使用して検索条件を指定する

以下の形でフィルターを行います。

where: { 項目名: { 比較演算子: 値 } }
query OperatorSample {
  uiapi {
    query {
      Contact(where: { Email: { ne: null } }) {
        edges {
          node {
            Id
            Name { value }
            Email { value }
          }
        }
      }
    }
  }
}

使用できる比較演算子は以下の通りです。

image.png

フィルタリングの例です。

image.png

論理演算子を使用して検索条件を組み合わせて使用する

論理演算子はAND、OR、NOTが使用できます。ネストも可能です。

image.png

日付・日時型の比較

日付・日時の比較がSOQLとは異なり、DateInputオブジェクトや日付演算子を使用します。

DateInput

日付・日時・時刻はスカラーではなく、valuerangeliteralのフィールドを持つDateInputオブジェクトと比較します。rangeはDateRange型を、literalはDATE_LITERALを使用します。

image.png

image.png

日付演算子、日時演算子

SOQLの日付関数の代わりに、GraphQLでは日付演算子・日時演算子を使用します。

image.png

image.png

多態的リレーションの絞り込み

通常のリレーションのフィルター同様、多態的なリレーション項目でもフィルターが可能です。

image.png

位置情報による絞り込み

位置情報項目を使用することで、特定の位置から決まった距離以内のレコードを取得するというような、位置情報による絞り込みが可能です。

image.png

SOQLの例
SELECT 
    Id, 
    Name, 
    Location__Latitude__s, 
    Location__Longitude__s 
FROM 
    AccountWHERE 
    DISTANCE(Location__c, GEOLOCATION(:latitude, :longitude), 'km') < 100

WHERE句内でサブクエリを使用する(準結合・反結合)

準結合を使用する場合、inq比較演算子を使用します。
反結合の場合、ninq比較演算子を使用します。

image.png

image.png

並び替えを行う

orderByを使用して並び替えを行うことが可能です。複数キーでの並び替えもできます。
orderは、ASCで昇順、DESCで降順です。nullsは、FIRSTでnull値を先頭に、LASTで最後にします。

image.png

地理位置情報による並び替えを行う

orderByで地理情報を利用することが可能です。

image.png

SOQLの例
SELECT 
    Id, 
    Name, 
    Location__Latitude__s, 
    Location__Longitude__s 
FROM 
    AccountWHERE 
    DISTANCE(Location__c, GEOLOCATION(:latitude, :longitude), 'km') < 100
ORDER BY
    DISTANCE(Location__c, GEOLOCATION(:latitude, :longitude), 'km')

ページング

LIMIT・OFFSETの代わりにGraphQLではfirst/afterをつかって、カーソルベースのページングを行います。
RecordQueryタイプのfirst、after、upperBoundを使用してクエリ結果をページングします。

  • first: 1ページあたりのレコード数を200〜2000の間で指定する
  • after: 2ページ以降のカーソル位置を指定する
  • upperBound: 取得するレコードの上限を指定する

image.png

image.png

endCursorで最後の行のカーソルが取得できます。

image.png

集計結果を取得する

UIAPIタイプにqueryのかわりにaggregateを使用します。

image.png

使用できる集計フィールドは以下になります。

image.png

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?