WWDC Quick Look 💓 By SwiftGGTeam
Meet CKTool JS

Meet CKTool JS

元の動画を見る

ハイライト

このセッションでは、Node.js に基づく CloudKit コマンド ライン ツールである CKTool JS を紹介します。その位置付けは、CloudKit の日常的な管理操作を、Xcode や Web コンソールに依存するのではなく、スクリプトを通じて自動化できるようにすることです。

主要内容

CloudKit アプリケーション データは iCloud コンテナに配置されます。開発中、開発者はスキーマの変更、レコードの確認、テスト データの書き込みを繰り返し行う必要があります。これまで、Apple プラットフォーム アプリは CloudKit フレームワークを使用でき、Web ページは CloudKit JS を使用でき、自動化スクリプトは主に Xcode 13 で導入された macOS コマンド ライン ツールに依存していました。cktool

(00:57) CKTool JS は、このワークフローを JavaScript にもたらします。これは、スクリプトが CloudKit 管理 API とデータベース API を直接呼び出すことを可能にする一連の npm パッケージを提供します。セッションは、サポートしていると明示的に述べています。cktoolコマンドライン ツールと同じ操作タイプは、レコード タイプの追加やレコードのクエリなどの機能を実装するために CloudKit コンソールでも使用されます。

これはツールチェーンの問題を解決します。すでに Node.js ビルド スクリプト、CI スクリプト、データ準備スクリプトを持っているチームは、CloudKit スキーマと記録操作のために別のツールに切り替える必要はありません。スキーマはから取得できます.ckdbファイルのインポート、レコードは JavaScript を使用してクエリ、作成、更新、削除できます。

(01:43) CKTool JS には TypeScript の型定義も付属しています。間違ったメソッド呼び出しがコンパイル時に公開される可能性があり、IDE が API を完成させることもできます。時間の経過とともに維持される自動スクリプトの場合、これは、一連の裸の JSON リクエストよりもレビューが簡単です。

詳細

CKTool JS を構成する

(02:38) CKTool JS は複数の要素で構成されています@appleスコープ内の npm パッケージで構成されます。主なパッケージは、@apple/cktool.database。 Node.js で実行している場合は、次のものも必要です@apple/cktool.target.nodejs; ブラウザで実行する場合は、次を使用します。@apple/cktool.target.browser

(03:10) CKTool JS は iCloud に直接アクセスするため、スクリプトにはトークンが必要です。スキーマのインポート、エクスポート、検証、運用環境へのリセットなどの管理操作では、管理トークンが使用されます。ユーザーのプライベート データにアクセスするには、ユーザー トークンが必要です。どちらのタイプのトークンも CloudKit コンソールから取得します。

// Create security object and setup default args

const { CKEnvironment } = require("@apple/cktool.database");

const security = {
    "ManagementTokenAuth": "<YOUR_MANAGEMENT_TOKEN>",
    "UserTokenAuth": "<YOUR_USER_TOKEN>"
};

const defaultArgs = {
    "teamId": "<YOUR_TEAM_ID>",
    "containerId": "<YOUR_CONTAINER_ID>",
    "environment": CKEnvironment.DEVELOPMENT
};

キーポイント:

  • 3 行目は次から始まります@apple/cktool.databaseテイクアウトCKEnvironment
  • 5行目から8行目は認証情報を保持します。管理トークンはスキーマなどの管理操作に使用され、ユーザー トークンはユーザー データにアクセスするために使用されます。
  • 行 10 ~ 14 は、各呼び出しで使用されるパラメーター (チーム、コンテナー、環境) を保存します。 -CKEnvironment.DEVELOPMENT開発環境に対応。 Session では、運用データへの影響を避けるために、開発環境でスキーマの変更をテストすることをお勧めします。

(07:17) 認証とデフォルトのパラメータを設定したら、プラットフォーム構成と API オブジェクトを作成する必要があります。createConfigurationターゲット パッケージから取得されるため、Node.js とブラウザーは異なる基礎となる構成を使用します。

// Create configuration and API objects

const { createConfiguration } = require("@apple/cktool.target.nodejs");
const { PromisesApi } = require("@apple/cktool.database");

const configuration = createConfiguration();
const api = new PromisesApi({
    "configuration": configuration,
    "security": security
});

キーポイント:

  • 行 3 は、提供された Node.js ターゲット パッケージを使用しますcreateConfiguration
  • 4行目で導入PromisesApiこれには、iCloud にアクセスするための非同期メソッドが含まれています。
  • 6 行目は、プラットフォームに依存する構成を作成します。
  • 7行目から10行目で設定とトークンを渡します。PromisesApi、後続のスキーマとレコードの操作は から始まります。api開始する。

### 使用.ckdbファイル管理スキーマ

(08:40) セッションでは例としてコイン収集アプリを使用します。このアプリには、CountriesCoinsComponentsなどのレコードタイプ。スキーマは CloudKit スキーマ言語テキスト ファイルとして記述することができ、合意された拡張子は次のとおりです。.ckdb

(09:05) 通常、新しいスキーマを適用する前に、開発環境は運用環境の状態にリセットされます。 CKTool JS が提供するresetToProduction。次に、使用しますimportSchemaローカルに置く.ckdbファイルがコンテナにアップロードされます。

// Create a function to apply a schema

const { File } = require("@apple/cktool.target.nodejs");
const fs = require("fs/promises");
const path = require("path");

const importMySchema = async () => {
    const schemaPath = "<YOUR_SCHEMA_FILE>.ckdb";
    const buffer = await fs.readFile(schemaPath);
    const file = new File([buffer], schemaPath);
    await api.importSchema({ ...defaultArgs, "file": file });
}

// Chain the calls
api.resetToProduction(defaultArgs)
  .then(() => importMySchema());

キーポイント:

  • 3行目ではCKTool JSを導入しています。File、アップロード ファイルの構築に使用されます。
  • 4 行目は、Node.js のファイル システム API の Promise バージョンを使用してスキーマ ファイルを読み取ります。
  • 8行目で指定.ckdbスキーマファイルのパス。
  • 9 行目でファイルを読み込みます。Buffer
  • 10行目BufferCKTool JS にパッケージ化されており、アップロード可能File
  • ライン 11 の通話api.importSchema、展開構文を通じて再利用されます。defaultArgs
  • 15行目から16行目が最初に実行されますresetToProduction、成功後にスキーマをインポートして、2 つの非同期ステップが順番に実行されることを確認します。

この処理はCIに組み込むのに適しています。スキーマ ファイルはバージョン管理に入ります。スクリプトは、毎回最初に開発環境を運用状態に復元し、次に現在のブランチのスキーマを適用します。テストは予測可能なコンテナー状態で実行できます。

クエリレコード

(10:52) スキーマに加えて、CKTool JS はデータの読み取りと書き込みもできます。セッションは、レコードのフィールド値がクライアント側でタイプと範囲がチェックされることを思い出させます。大きな整数などの JavaScript ネイティブ型は、値を直接表すのには適していないため、CKTool JS の型変換またはフィールド値ファクトリ関数を使用する必要があります。

(12:02) レコードにアクセスする前に、まずデータベースのパラメータを整理します。ここでプライベート データベースとデフォルト ゾーンを選択します。

// Create a database arguments object.

const {
    CKDatabaseType, CKEnvironment
} = require("@apple/cktool.database");

const databaseArgs = {
    "containerID": "<YOUR_CONTAINER_ID>",
    "environment": CKEnvironment.DEVELOPMENT,
    "databaseType": CKDatabaseType.PRIVATE,
    "zoneName": "_defaultZone"
};

キーポイント:

  • 3 行目から 5 行目では、データベースの種類と環境定数を紹介します。
  • 8行目は対象コンテナを指定します。
  • Line 9 は開発環境を使用し続けます。
  • 10 行目はプライベート データベースへの操作を制限します。
  • 11行目はデフォルトゾーンを指定します。後続のクエリ、作成、更新、および削除では、このオブジェクトが再利用されます。

(12:16) クエリの使用法queryRecords。 3 桁の ISO コードに基づいて国を検索する例Countries record。

// Define helper function for querying records

const { CKDBQueryFilterType } = require("@apple/cktool.database");
const countryQueryRecordForCountryCode3 = async (countryCode3) => {
    const response = await api.queryRecords({
        ...databaseArgs,
        "body": {
            "query": {
                "recordType": "Countries",
                "filters": [{
                    "fieldName": "isoCode3",
                    "fieldValue": makeRecordFieldValue.string(countryCode3),
                    "type": CKDBQueryFilterType.EQUALS
                }]
            }
        }
    });
    return response.result.records[0];
}

キーポイント:

  • 行 3 では、クエリ フィルター タイプを紹介します。
  • 行 4 は非同期ヘルパーを定義しており、入力は 3 桁の国コードです。
  • 6行目を展開しますdatabaseArgs、コンテナー、環境、データベース、ゾーンを毎回繰り返し渡すことを避けるため。
  • 8行目から15行目はCloudKitのクエリ本体を記述します。
  • クエリ行 9Countriesレコードタイプ。
  • 11行目から13行目までを使用makeRecordFieldValue.string(countryCode3)文字列フィールド値を構築して使用します。EQUALS等価フィルタリングを実行します。
  • 18行目からresponse.result.records最初に一致したレコードを取得します。

レコードを作成する

(12:58) レコードを作成する前に、通常の JavaScript 値を CloudKit レコードのフィールド値に変換する必要があります。この例では、コインの国フィールドは参照、発行年は Int64、額面は Double です。

// Define a helper function for creating field values

const {
    makeRecordFieldValue, CKDBRecordReferenceAction
} = require("@apple/cktool.database");

const makeCoinFieldValues = ({ countryRecordName, issueYear, nominalValue }) => ({
    "country": makeRecordFieldValue.reference({
        recordName: countryRecordName,
        action: CKDBRecordReferenceAction.DELETE_SELF
    }),
    "issueYear": makeRecordFieldValue.int64(issueYear),
    "nominalValue": makeRecordFieldValue.double(nominalValue)
});

キーポイント:

  • 行 3 ~ 5 では、フィールド値ファクトリーと参照アクション定数を導入しています。
  • 7 行目は、生のコイン データを CloudKit フィールド値辞書に変換するヘルパーを定義します。
  • 8行目から11行目は、国レコード名を参照フィールド値に変換します。
  • 10行目の用途DELETE_SELF、参照されたレコードが削除されると、この参照が存在するレコードもこのアクションに従って処理されることを示します。
  • 12 行目は、発行年を Int64 フィールド値に変換します。
  • 13 行目は、額面値を Double フィールド値に変換します。

(13:26) 実際にデータを作成するときは、createRecord、リクエスト本文にレコードタイプとフィールドを入力します。

// Define helper method for creating coins

const coinCreateRecord = async (fields) => {
    const response = await api.createRecord({
        ...databaseArgs,
        "body": {
            "recordType": "Coins",
            "fields": fields
        },
    });
    return response.result.record;
}

キーポイント:

  • 行 3 は、コイン レコードを作成する非同期ヘルパーを定義します。
  • ライン 5 は再利用を継続しますdatabaseArgs
  • 7 行目では、レコード タイプを次のように指定します。Coins
  • 8 行目は、前のヘルパーによって生成されたフィールド値辞書を CloudKit に渡します。
  • 行 11 は、サーバー作成後のレコードを返します。

(13:48) コインを作成する前に、スクリプトはまず国のレコードをクエリし、次に国のレコードを追加します。recordName参照を書き込みます。

// Call coin creation method with field values

const countryRecord = await countryQueryRecordForCountryCode3("USA");

const coinRecord1 = await coinCreateRecord(
    makeCoinFieldValues({
        "countryRecordName": countryRecord.recordName,
        "issueYear": 2007,
        "nominalValue": 0.10
    })
);

キーポイント:

  • 行 3 は ISO コードを次のようにクエリします。USA国の記録。
  • 5 行目は、レコードを作成するヘルパーを呼び出します。
  • 7行目は国を記録しますrecordName参照フィールドに渡されます。
  • 8行目はコインの発行年を設定します。
  • 9行目はコインの価値を設定します。
  • 5行目から11行目は新しく作成されたものを返します。coinRecord1、その後の更新または削除でも引き続き使用されます。

レコードの更新と削除

(14:16) を使用してレコードを更新しますupdateRecord。セッションは特別にマークされており、更新時に渡す必要があります。recordChangeTag

// Define helper method for updating coins.
// Note that recordChangeTag is required

const coinUpdate =
    async (recordName, recordChangeTag, fields) => {
        const response = await api.updateRecord({
            ...databaseArgs,
            "recordName": recordName,
            "body": {
                "recordType": "Coins",
                "recordChangeTag": recordChangeTag,
                "fields": fields
            }
        });
        return response.result.record;
    }

キーポイント:

  • 5 行目のヘルパーは、レコード名、レコード変更タグ、および新しいフィールドを受け取ります。
  • 7 行目はデータベースパラメータを再利用します。
  • 8行目は更新するレコードを指定します。
  • 10行目はレコードタイプを指定します。
  • 11行目は通過しましたrecordChangeTag、CloudKit レコードを更新するために使用されます。
  • 行 12 は、新しいフィールド値辞書をコミットします。
  • 15 行目は更新されたレコードを返します。

(14:57) レコードの削除はより簡単で、データベース パラメータとレコード名を渡すだけです。

// Deleting a record

await api.deleteRecord({
    ...databaseArgs,
   "recordName": coinRecord1.recordName
});

キーポイント:

  • 3 行目は、非同期削除メソッドを呼び出します。
  • 4 行目では、コンテナー、環境、データベース、ゾーンのパラメーターを再利用します。
  • 5行目は削除するレコード名を指定します。
  • セッションサンプルは開発環境で動作します。運用環境スクリプトは、ターゲット レコードを削除する前に、まずターゲット レコードをクエリして確認する必要があります。

重要ポイント

1. CloudKit スキーマの PR レベルの検証を実行します。

  • 何をすべきか:.ckdbスキーマ ファイルはウェアハウスに置かれ、CKTool JS スクリプトが PR ごとに 1 回実行されます。
  • 実行する価値がある理由: セッション ショーresetToProductionそしてimportSchemaこの組み合わせにより、開発環境を運用状態に復元し、現在のスキーマを適用できます。
  • 開始方法: 管理トークンを準備し、CIで実行しますapi.resetToProduction(defaultArgs).then(() => importMySchema())、失敗時のマージを防ぎます。

2. テスト用に再現可能なデータセットを準備する

  • 内容: 固定セットを作成します。CountriesCoinsまたは業務記録。テスト後に削除します。
  • 実行する価値がある理由: CKTool JS は、JavaScript を使用してレコードのクエリ、作成、更新、削除を行うことができ、既存の Node.js テスト ツール チェーンへの接続に適しています。
  • 開始方法: 最初に使用しますqueryRecords依存関係レコードを見つけて使用するmakeRecordFieldValueフィールドを構築し、最後に呼び出しますcreateRecordテストデータを書き込みます。

3. スキーマのインポート前にローカルチェックツールを作成する

  • 対処方法: 送信する前にスキーマを確認してください.ckdbファイルが存在するかどうか、読み取り可能かどうか、ターゲット環境が開発環境であるかどうか。
  • 実行する価値がある理由: セッションのインポート例では、ローカル ファイルを読み取り、それらをパッケージ化する必要があります。File、 電話importSchema。これらの手順は、スクリプト内で事前に検証するのに適しています。
  • 開始方法: 再利用fs.readFileおよびCKTool JSFileインポートプロセスは実際に呼び出されますapi.importSchemaチーム、コンテナ、環境を印刷する前に。

4. 運用チームまたはサポート チーム向けに制限付きデータ修復スクリプトを作成する

  • 作業内容: 一意のフィールドによるレコードのクエリや特定のフィールドの修正など、一般的な修復アクションをパラメータ化されたスクリプトにカプセル化します。
  • 実行する価値がある理由: セッションにボタンが表示されますisoCode3レコードのクエリ、使用recordChangeTagレコードのフルパスを更新します。
  • 開始方法: クエリ条件を一意のフィールドに制限し、更新時に現在のレコードを渡しますrecordNameそしてrecordChangeTag、開発者によって明示的にリストされたレコード タイプでのみスクリプトの操作が許可されます。

関連セッション

コメント

GitHub Issues · utterances