PromiseベースのTable Storage SDK
Node SDK v12
azure-sdk-for-jsのモジュールとしてAzure Table Storageを操作するための新しいSDKが公開されています。
We are excited to introduce new #Azure #Data Table Libraries! Check out this blog to learn how to get started using the new libraries. https://t.co/XUcu5TEaYh
— Azure SDK (@AzureSDK) June 16, 2021
このモジュールはNode.js、ブラウザの両方で動作します。
yarn add @azure/data-tables
テーブル上のエンティティの操作
操作クライアントの作成
テーブル上のエンティティを操作するにはTableClient
オブジェクトが必要になります。接続文字列から作成する方法と、Storageアカウント名とキーから作成する方法があります。
const connectionString = ''
const tableName = ''
const tableClient = TableClient.fromConnectionString(connectionString, tableName)
const account = ''
const accountKey = ''
const tableName = ''
const credential = new AzureNamedKeyCredential(account, accountKey)
const tableClient = new TableClient(
`https://${account}.table.core.windows.net`,
tableName,
credential
)
エンティティの取得
TableClient
クラスのgetEntity
メソッドから取得できる。getEntity
のシグネチャは以下のようになっています。
getEntity<T extends object = Record<string, unknown>>(
partitionKey: string,
rowKey: string,
options?: GetTableEntityOptions
): Promise<GetTableEntityResponse<TableEntityResult<T>>>;
TableStorageのレコードはPartitionKey
とRowKey
が複合主キーとなるため、その2つを指定すれば一意なエンティティを取得できます。
型パラメータにPartitionKey
とRowKey
を除いたエンティティの型情報を渡すことによって、クエリの結果が片付けされて扱うことができます。
export declare type TableEntityResult<T> = T & {
etag: string;
partitionKey?: string;
rowKey?: string;
timestamp?: string;
};
クエリ
なにかしらの条件にもとづいてエンティティを取得する場合はTableClient
クラスのlistEntities
メソッドを使用する。listEntities
のシグネチャは以下のようになっています。
listEntities<T extends object = Record<string, unknown>>(
options?: ListTableEntitiesOptions
): PagedAsyncIterableIterator<TableEntityResult<T>, TableEntityResult<T>[]>;
引数に渡すListTableEntitiesOptions
型は以下のように定義されています。
export declare type ListTableEntitiesOptions = OperationOptions & {
queryOptions?: TableEntityQueryOptions;
disableTypeConversion?: boolean;
};
TableEntityQueryOptions
にてWHERE句に相当する条件とSLELECT句に相当する条件を指定します。
export declare interface TableEntityQueryOptions {
filter?: string;
select?: string[];
}
select
については必要なカラム名だけを指定すればよいのですが、filter
についてはOData filter形式で記述する必要があります。odata
関数という[[Tagged Template Literals]]を利用した関数が用意されているため、そちらを使ってクエリを記述するのがオススメです。
const pk1 = 'pk-A'
const pk2 = 'pk-B'
const query = odata`PartitionKey eq ${pk1} or PartitionKey eq ${pk2}`
// queryは「PartitionKey eq 'pk-A' or PartitionKey eq 'pk-B'」
なお、もう一つのオプションであるdisableTypeConversion
プロパティについてですが、こちらをtrue
に設定すると、プロパティはJavaScript組み見込み型に型変換されず、文字列形式の値と型タイプのRecordの状態でオブジェクトが返されます。
例えば、あるカラムがInt32の値であった場合、{value: "123", type: Int32"}
となります。このオプションはデフォルトではfalse
となっています。
戻り値はPagedAsyncIterableIterator
型であり、これはAsyncIterableなオブジェクトである。したがってfor await
を使うことによって、取得できたエンティティを列挙することができます。
export interface PagedAsyncIterableIterator<T, PageT = T[], PageSettingsT = PageSettings> {
next(): Promise<IteratorResult<T, T>>;
[Symbol.asyncIterator](): PagedAsyncIterableIterator<T, PageT, PageSettingsT>;
byPage: (settings?: PageSettingsT) => AsyncIterableIterator<PageT>;
}
また、このAsyncIterableなオブジェクトは遅延評価がなされるため、実際に値の取り出しが評価されるまでTableStorageへのHTTPリクエストは送信されません。
TableStorageはエンティティのリストを取得する場合、1回のHTTPリクエストで最大1000件までしか取得できない制約がある。1000件を超える場合はページングされるため、レスポンスヘッダを確認して再度HTTPリクエストを送信して後続のエンティティを取得する必要がある。このSDKでは1000件を超えるエンティティを取得しようとしたとき、AsyncIteratorから1001件目のエンティティを取り出そうとしたタイミングでHTTPリクエストが送信されるよう設計されています。
旧来のazure-storageの場合は、Continuation Tokenを使って自分で後続ページを取得する必要があったが、本SDKではlistEntities
を使うことによってページングについては透過的に扱うことができます。
また、前述のように1件ずつIteratorResultを得る以外にもPagedAsyncIterableIterator
オブジェクトのbyPage
メソッドを使えば、ページ単位でのIteratorResultを取得することもできます。
挿入
TableClient
クラスのcreateEntity
メソッドを使うことによってエンティティの挿入ができます。
createEntity<T extends object>(
entity: TableEntity<T>,
options?: OperationOptions
): Promise<CreateTableEntityResponse>;
挿入するエンティティはTableEntity<T>
型となっており、その定義は以下のようになっています。
export declare type TableEntity<T extends object = Record<string, unknown>> = T & {
partitionKey: string;
rowKey: string;
};
旧来のazure-storageでは、ヘルパーメソッドを使ってエンティティのプロパティをそれぞれ専用の型に変換する必要がありましたが、本SDKでは組み込み型をそのまま使うことができます。数値型だけ注意する必要があって、Int32として扱う場合はnumber
型として、Int64として扱う場合はBigInt
型として数値を設定する必要があります。
なお、createEntity
メソッドでは、エンティティに設定したpartitionKeyとrowKeyの組が既にテーブルに存在する場合は例外がスローされます。
更新
TableClient
クラスのupdateEntity
メソッドを使うことによってエンティティの更新ができます。
updateEntity<T extends object>(
entity: TableEntity<T>,
mode?: UpdateMode,
options?: UpdateTableEntityOptions
): Promise<UpdateEntityResponse>;
使い方はcreateEntity
メソッドとほぼ同様ですが、特徴的なのは第二引数のUpdateMode
です。TableStorageはエンティティの更新方法としてMerge
とReplace
の二つを用意しています。Merge
の場合は引数に与えられたエンティティ内に存在するプロパティだけが更新されます。引数に与えられたエンティティ内に存在しないプロパティについては、更新前の値そのままとなります。一方Replace
はその名の通り置き換えとなります。引数に与えられたエンティティ内に存在しないプロパティについては、置き換え後はそのカラムはnullとして記録されます。
updateEntity
の類似メソッドとしてupsertEntity
が存在するが、こちらは該当するエンティティが存在しない場合は挿入操作を行うメソッドとなります。(updateEntity
メソッドは該当するエンティティが存在しない場合は例外をスローする)
削除
TableClient
クラスのdeleteEntity
メソッドを使います。主キーであるPartitionKeyとRowKeyを指定して使用します。該当するエンティティが存在しない場合は例外をスローします。
deleteEntity(
partitionKey: string,
rowKey: string,
options?: DeleteTableEntityOptions
): Promise<DeleteTableEntityResponse>;
エンティティグループトランザクション
Table Storageには、同一パーティションにあるエンティティに対してアトミックなトランザクションを実現するエンティティグループトランザクションという機能があります。同一パーティションに存在するエンティティに限る、1回のトランザクションで操作できるエンティティの数は100までといった制限はありますが、APIのコール数1回で処理が完了するため何度もAPIを叩いて複数件のエンティティを処理するよりもはるかに早いです。またアトミック性も保証されているため、要件にマッチするなら積極的に使っていきたい機能です。azure-storageでも利用できた機能ですが、本SDKでもTableClient
クラスのsubmitTransaction
メソッド経由で使うことができます。
submitTransaction(actions: TransactionAction[]): Promise<TableTransactionResponse>;
引数に渡すTransactionAction[]
ですが、どんなオブジェクトになるかは例を見るのが早いです。
const actions: TransactionAction[] = [
["create", {partitionKey: "p1", rowKey: "1", data: "test1"}],
["delete", {partitionKey: "p1", rowKey: "2"}],
["update", {partitionKey: "p1", rowKey: "3", data: "newTest"}, "Merge"]
アクションとして含ませることができるのは、create
、delete
、update
、upsert
の4つです。update
とupsert
についてはMerge
かReplace
かも指定することができます。