ノード用のDatabricks SQL ドライバー.js

ノード. js の Databricks SQL ドライバーは 、JavaScript コードを使用 して Databric ks コンピュート リソースで SQL コマンドを実行できるように する Node.js ライブラリで す。

要件

  • Node.js バージョン 14 以降を実行している開発マシン。 インストールされているバージョンの Node.js を印刷するには、コマンド node -vを実行します。 異なるバージョンの Node.js をインストールして使用するには、 ノード バージョン マネージャー (nvm) などのツールを使用できます。

  • ノード パッケージ マネージャー (npm)。 それ以降のバージョンの Node.js には、すでに npmが含まれています。 npm がインストールされているかどうかを確認するには、コマンドを実行します npm -v。必要に応じて npm をインストールするには、「 npmをダウンロードしてインストールする」などの手順に従います。

  • npm からの @databricks/sql パッケージ。@databricks/sql パッケージを依存関係として Node.js プロジェクトにインストールするには、 npm を使用して、プロジェクトと同じディレクトリ内から次のコマンドを実行します。

    npm i @databricks/sql
    
  • TypeScript を Node.js プロジェクトに devDependenciesとしてインストールして使用する場合は、 npm を使用して、プロジェクトと同じディレクトリ内から次のコマンドを実行します。

    npm i -D typescript
    npm i -D @types/node
    
  • 既存のクラスターまたはSQL ウェアハウス

  • 既存のクラスターまたは SQLウェアハウスの サーバーのホスト名HTTP パス の値。

認証

Node.js 用 Databricks SQL ドライバーでは、次の Databricks 認証の種類がサポートされています。

Node.js 用 Databricks SQL ドライバーは、次の Databricks 認証タイプをまだサポートしていません。

セキュリティのベスト プラクティスとして、接続変数の値をコードにハード コード化しないでください。 代わりに、これらの接続変数値を安全な場所から取得する必要があります。 たとえば、この記事のコード スニペットと例では、環境変数を使用しています。

Databricks個人用アクセストークン認証

Databricks 個人用アクセストークン認証で Databricks SQL Driver for Node.js を使用するには、まず次のように Databricks 個人 用アクセストークンを作成する必要があります。

  1. Databricks ワークスペースで、上部のバーにある Databricks ユーザー名をクリックし、ドロップダウンから[設定]を選択します。

  2. [ 開発者] をクリックします。

  3. [アクセストークン] の横にある [管理] をクリックします。

  4. [ 新しいトークンの生成] をクリックします。

  5. (任意)今後このトークンを識別するのに役立つコメントを入力し、トークンのデフォルトの有効期間である90日を変更します。有効期間のないトークンを作成するには(非推奨)、[有効期間 (日) ] ボックスを空白のままにしてください。

  6. [生成] をクリックします。

  7. 表示されたトークンを安全な場所にコピーし、[完了] をクリックします。

コピーしたトークンは、必ず安全な場所に保存してください。 コピーしたトークンを他のユーザーと共有しないでください。 コピーしたトークンを紛失した場合、まったく同じトークンを再生成することはできません。 代わりに、この手順を繰り返して新しいトークンを作成する必要があります。 コピーしたトークンを紛失した場合、またはトークンが侵害されたと思われる場合は、アクセストークン ページでトークンの横にあるごみ箱 (取り消し) アイコンをクリックして、ワークスペースからそのトークンをすぐに削除することを強くお勧めします。

ワークスペースでトークンを作成または使用できない場合は、ワークスペース管理者がトークンを無効にしたか、トークンを作成または使用する権限を与えていないことが原因である可能性があります。ワークスペース管理者に問い合わせるか、以下をご覧ください。

Databricks SQL Driver for Node.js を認証するには、 次のコード スニペットを使用します。 このスニペットは、次の環境変数が設定されていることを前提としています。

  • DATABRICKS_SERVER_HOSTNAMEをクラスターまたは SQLウェアハウスの [Server Hostname ] の値に設定します。

  • DATABRICKS_HTTP_PATHで、クラスターまたは SQLウェアハウスの HTTP パス 値に設定します。

  • DATABRICKS_TOKENを Databricks personal アクセストークンに設定します。

環境変数を設定するには、ご利用になっているオペレーティングシステムのドキュメントを参照してください。

const { DBSQLClient } = require('@databricks/sql');

const serverHostname = process.env.DATABRICKS_SERVER_HOSTNAME;
const httpPath       = process.env.DATABRICKS_HTTP_PATH;
const token          = process.env.DATABRICKS_TOKEN;

if (!token || !serverHostname || !httpPath) {
    throw new Error("Cannot find Server Hostname, HTTP Path, or " +
                    "personal access token. " +
                    "Check the environment variables DATABRICKS_SERVER_HOSTNAME, " +
                    "DATABRICKS_HTTP_PATH, and DATABRICKS_TOKEN.");
  }

  const client = new DBSQLClient();
  const connectOptions = {
    token: token,
    host:  serverHostname,
    path:  httpPath
  };

  client.connect(connectOptions)
  // ...
import { DBSQLClient } from "@databricks/sql";

const serverHostname: string = process.env.DATABRICKS_SERVER_HOSTNAME || '';
const httpPath: string       = process.env.DATABRICKS_HTTP_PATH || '';
const token: string          = process.env.DATABRICKS_TOKEN || '';

if (token == '' || serverHostname == '' || httpPath == '') {
    throw new Error("Cannot find Server Hostname, HTTP Path, or personal access token. " +
                    "Check the environment variables DATABRICKS_SERVER_HOSTNAME, " +
                    "DATABRICKS_HTTP_PATH, and DATABRICKS_TOKEN.");
  }

  const client: DBSQLClient = new DBSQLClient();
  const connectOptions = {
    token: token,
    host:  serverHostname,
    path:  httpPath
  };

  client.connect(connectOptions)
  // ...

OAuthユーザー対マシン(U2M)認証

Databricks SQL Driver for Node.js バージョン 1.8.0 以降は、OAuth ユーザー対マシン (U2M) 認証をサポートしています。

OAuth U2M 認証を使用して Databricks SQL Driver for Node.js を認証するには、次のコード スニペットを使用します。 このスニペットは、次の環境変数が設定されていることを前提としています。

  • DATABRICKS_SERVER_HOSTNAMEをクラスターまたは SQLウェアハウスの [Server Hostname ] の値に設定します。

  • DATABRICKS_HTTP_PATHで、クラスターまたは SQLウェアハウスの HTTP パス 値に設定します。

環境変数を設定するには、ご利用になっているオペレーティングシステムのドキュメントを参照してください。

const { DBSQLClient } = require('@databricks/sql');

const serverHostname = process.env.DATABRICKS_SERVER_HOSTNAME;
const httpPath       = process.env.DATABRICKS_HTTP_PATH;

if (!serverHostname || !httpPath) {
    throw new Error("Cannot find Server Hostname or HTTP Path. " +
                    "Check the environment variables DATABRICKS_SERVER_HOSTNAME " +
                    "and DATABRICKS_HTTP_PATH.");
  }

  const client = new DBSQLClient();
  const connectOptions = {
    authType: "databricks-oauth",
    host:     serverHostname,
    path:     httpPath
  };

  client.connect(connectOptions)
  // ...
import { DBSQLClient } from "@databricks/sql";

const serverHostname: string = process.env.DATABRICKS_SERVER_HOSTNAME || '';
const httpPath: string       = process.env.DATABRICKS_HTTP_PATH || '';

if (serverHostname == '' || httpPath == '') {
    throw new Error("Cannot find Server Hostname or HTTP Path. " +
                    "Check the environment variables DATABRICKS_SERVER_HOSTNAME " +
                    "and DATABRICKS_HTTP_PATH.");
  }

  const client: DBSQLClient = new DBSQLClient();
  const connectOptions = {
    authType: "databricks-oauth",
    host:     serverHostname,
    path:     httpPath
  };

  client.connect(connectOptions)
  // ...

OAuthマシン間(M2M)認証

Databricks SQL Driver for Node.js バージョン 1.8.0 以降は、OAuth マシン間 (U2M) 認証をサポートしています。

OAuth M2M 認証で Node.js 用 Databricks SQL ドライバーを使用するには、次の操作を行う必要があります。

  1. Databricks ワークスペースに Databricks サービスプリンシパルを作成し、そのサービスプリンシパルの OAuth シークレットを作成します。

    サービスプリンシパルとそのOAuthシークレットを作成するには、 「 サービスプリンシパルを使用してDatabricksで認証する 」を参照してください。 サービスプリンシパルの UUID または アプリケーション ID の 値と、サービスプリンシパルの シークレットの シークレットOAuth 値をメモします。

  2. サービスプリンシパルにクラスターまたはウェアハウスへのアクセスを許可します。 「コンピュート権限」または「SQL ウェアハウスの管理」を参照してください。

Databricks SQL Driver for Node.js を認証するには、 次のコード スニペットを使用します。 このスニペットは、次の環境変数が設定されていることを前提としています。

  • DATABRICKS_SERVER_HOSTNAMEをクラスターまたは SQLウェアハウスの [Server Hostname ] の値に設定します。

  • DATABRICKS_HTTP_PATHで、クラスターまたは SQLウェアハウスの HTTP パス 値に設定します。

  • DATABRICKS_CLIENT_IDは、サービスプリンシパルの UUID または アプリケーション ID の値に設定されます。

  • DATABRICKS_CLIENT_SECRETで、サービスプリンシパルの OAuth シークレットの Secret 値に設定します。

環境変数を設定するには、ご利用になっているオペレーティングシステムのドキュメントを参照してください。

const { DBSQLClient } = require('@databricks/sql');

const serverHostname = process.env.DATABRICKS_SERVER_HOSTNAME;
const httpPath       = process.env.DATABRICKS_HTTP_PATH;
const clientId       = process.env.DATABRICKS_CLIENT_ID;
const clientSecret   = process.env.DATABRICKS_CLIENT_SECRET;

if (!serverHostname || !httpPath || !clientId || !clientSecret) {
    throw new Error("Cannot find Server Hostname, HTTP Path, or " +
                    "service principal ID or secret. " +
                    "Check the environment variables DATABRICKS_SERVER_HOSTNAME, " +
                    "DATABRICKS_HTTP_PATH, DATABRICKS_CLIENT_ID, and " +
                    "DATABRICKS_CLIENT_SECRET.");
  }

  const client = new DBSQLClient();
  const connectOptions = {
    authType:          "databricks-oauth",
    host:              serverHostname,
    path:              httpPath,
    oauthClientId:     clientId,
    oauthClientSecret: clientSecret
  };

  client.connect(connectOptions)
  // ...
import { DBSQLClient } from "@databricks/sql";

const serverHostname: string = process.env.DATABRICKS_SERVER_HOSTNAME || '';
const httpPath: string       = process.env.DATABRICKS_HTTP_PATH || '';
const clientId: string       = process.env.DATABRICKS_CLIENT_ID || '';
const clientSecret: string   = process.env.DATABRICKS_CLIENT_SECRET || '';

if (serverHostname == '' || httpPath == '' || clientId == '' || clientSecret == '') {
    throw new Error("Cannot find Server Hostname, HTTP Path, or " +
                    "service principal ID or secret. " +
                    "Check the environment variables DATABRICKS_SERVER_HOSTNAME, " +
                    "DATABRICKS_HTTP_PATH, DATABRICKS_CLIENT_ID, and " +
                    "DATABRICKS_CLIENT_SECRET.");
  }

  const client: DBSQLClient = new DBSQLClient();
  const connectOptions = {
    authType:          "databricks-oauth",
    host:              serverHostname,
    path:              httpPath,
    oauthClientId:     clientId,
    oauthClientSecret: clientSecret
  };

  client.connect(connectOptions)
  // ...

データのクエリー

次のコード例は、Databricks コンピュート リソースに対して基本的な SQL クエリーを実行するために Node.js 用 Databricks SQL ドライバーを呼び出す方法を示しています。 このコマンドは、samples カタログのnyctaxiスキーマのtripsテーブルから最初の 2 行を返します。

このコード例では、Databricks 環境変数のセットから tokenserver_hostname 、および http_path 接続変数の値を取得します。 これらの環境変数には、次の環境変数名があります。

  • DATABRICKS_TOKENこれは、要件からの Databricks 個人用アクセストークンを表します。

  • DATABRICKS_SERVER_HOSTNAMEこれは、要件の サーバ ホスト名 の値を表します。

  • DATABRICKS_HTTP_PATHこれは、要件からの HTTP パス 値を表します。

これらの接続変数の値を取得するには、他の方法を使用できます。 環境変数の使用は、多くのアプローチの 1 つにすぎません。

次のコード例は、Node.js の Databricks SQL コネクタを呼び出して、クラスターまたは SQLウェアハウスで基本的な SQL コマンドを実行する方法を示しています。 このコマンドは、 trips テーブルから最初の 2 行を返します。

const { DBSQLClient } = require('@databricks/sql');

const token          = process.env.DATABRICKS_TOKEN;
const serverHostname = process.env.DATABRICKS_SERVER_HOSTNAME;
const httpPath       = process.env.DATABRICKS_HTTP_PATH;

if (!token || !serverHostname || !httpPath) {
  throw new Error("Cannot find Server Hostname, HTTP Path, or personal access token. " +
                  "Check the environment variables DATABRICKS_TOKEN, " +
                  "DATABRICKS_SERVER_HOSTNAME, and DATABRICKS_HTTP_PATH.");
}

const client = new DBSQLClient();
const connectOptions = {
  token: token,
  host: serverHostname,
  path: httpPath
};

client.connect(connectOptions)
  .then(async client => {
    const session = await client.openSession();
    const queryOperation = await session.executeStatement(
      'SELECT * FROM samples.nyctaxi.trips LIMIT 2',
      {
        runAsync: true,
        maxRows:  10000 // This option enables the direct results feature.
      }
    );

    const result = await queryOperation.fetchAll();

    await queryOperation.close();

    console.table(result);

    await session.close();
    await client.close();
})
.catch((error) => {
  console.error(error);
});
import { DBSQLClient } from '@databricks/sql';
import IDBSQLSession from '@databricks/sql/dist/contracts/IDBSQLSession';
import IOperation from '@databricks/sql/dist/contracts/IOperation';

const serverHostname: string = process.env.DATABRICKS_SERVER_HOSTNAME || '';
const httpPath: string       = process.env.DATABRICKS_HTTP_PATH || '';
const token: string          = process.env.DATABRICKS_TOKEN || '';

if (serverHostname == '' || httpPath == '' || token == '') {
  throw new Error("Cannot find Server Hostname, HTTP Path, or personal access token. " +
                  "Check the environment variables DATABRICKS_SERVER_HOSTNAME, " +
                  "DATABRICKS_HTTP_PATH, and DATABRICKS_TOKEN.");
}

const client: DBSQLClient = new DBSQLClient();
const connectOptions = {
  host: serverHostname,
  path: httpPath,
  token: token
};

client.connect(connectOptions)
  .then(async client => {
    const session: IDBSQLSession = await client.openSession();

    const queryOperation: IOperation = await session.executeStatement(
      'SELECT * FROM samples.nyctaxi.trips LIMIT 2',
      {
        runAsync: true,
        maxRows: 10000 // This option enables the direct results feature.
      }
    );

    const result = await queryOperation.fetchAll();

    await queryOperation.close();

    console.table(result);

    await session.close();
    client.close();
  })
  .catch((error) => {
    console.error(error);
});

アウトプット:

┌─────────┬─────┬────────┬───────────┬───────┬─────────┬────────┬───────┬───────┬────────┬────────┬────────┐
│ (index) │ _c0 │ carat  │    cut    │ color │ clarity │ depth  │ table │ price │   x    │   y    │   z    │
├─────────┼─────┼────────┼───────────┼───────┼─────────┼────────┼───────┼───────┼────────┼────────┼────────┤
│    0    │ '1' │ '0.23' │  'Ideal'  │  'E'  │  'SI2'  │ '61.5' │ '55'  │ '326' │ '3.95' │ '3.98' │ '2.43' │
│    1    │ '2' │ '0.21' │ 'Premium' │  'E'  │  'SI1'  │ '59.8' │ '61'  │ '326' │ '3.89' │ '3.84' │ '2.31' │
└─────────┴─────┴────────┴───────────┴───────┴─────────┴────────┴───────┴───────┴────────┴────────┴────────┘

セッション

API リファレンスIOperation オブジェクトを返すすべての IDBSQLSession メソッドには、その動作に影響を与える次の共通パラメーターがあります。

  • runAsynctrue に設定すると、非同期モードが開始されます。IDBSQLSession メソッドは、操作をキューに入れ、できるだけ早く戻ります。 返される IOperation オブジェクトの現在の状態は異なる場合があり、クライアントは返された IOperationを使用する前にその状態を確認する必要があります。 「 操作」を参照してください。 runAsyncfalse に設定すると、IDBSQLSessionメソッドは操作の完了を待機します。Databricks では、常に runAsynctrueに設定することをお勧めします。

  • maxRows null 以外の値に設定すると、直接結果が有効になります。直接結果の場合、サーバーは操作が完了するのを待ってから、データの一部をフェッチしようとします。 定義された時間内にサーバーが完了できた作業量に応じて、 IOperation オブジェクトは保留状態ではなく中間状態で返されます。 多くの場合、すべてのメタデータとクエリーの結果は、サーバーへの単一の要求内で返されます。 サーバーは maxRows を使用して、すぐに返すことができるレコードの数を決定します。 ただし、実際のチャンクのサイズは異なる場合があります。 IDBSQLSession.fetchChunkを参照してください。 直接結果はデフォルトで有効になります。 Databricks では、直接結果を無効にしないことをお勧めします。

オペレーションズ

「セッション」で説明されているように、API リファレンスIDBSQLSession セッションメソッドによって返されるIOperationオブジェクトは、完全には設定されません。Databricks SQLウェアハウスの起動の待機、クエリーの実行、データのフェッチなど、関連するサーバー操作がまだ進行中である可能性があります。 IOperation クラスは、これらの詳細をユーザーから隠します。たとえば、 fetchAllfetchChunkgetSchema などのメソッドは、操作の完了を内部的に待機してから結果を返します。 IOperation.finished() メソッドを使用すると、操作が完了するまで明示的に待機できます。これらのメソッドは、操作の完了を待っている間に定期的に呼び出されるコールバックを受け取ります。 progress オプションを true に設定すると、サーバーから追加の進行状況データを要求し、そのコールバックに渡そうとします。

close メソッドと cancel メソッドはいつでも呼び出すことができます。呼び出されると、 IOperation オブジェクトをすぐに無効にします。 fetchAllfetchChunkgetSchema などの保留中の呼び出しはすべて直ちに取り消され、エラーが返されます。 場合によっては、サーバー操作が既に完了していて、 cancel メソッドがクライアントにのみ影響することがあります。

fetchAll メソッドは内部で fetchChunk を呼び出し、すべてのデータを配列に収集します。これは便利ですが、大きなデータセットで使用するとメモリ不足エラーが発生する可能性があります。 fetchAll オプションは、通常、 fetchChunkに渡されます。

データのチャンクをフェッチする

データ チャンクのフェッチでは、次のコード パターンを使用します。

do {
  const chunk = await operation.fetchChunk();
  // Process the data chunk.
} while (await operation.hasMoreRows());

API リファレンスfetchChunk メソッドは、メモリ消費を削減するためにデータを少しずつ処理します。fetchChunk 、操作がまだ完了していない場合は、最初に操作が完了するのを待機し、待機サイクル中にコールバックを呼び出してから、次のデータ チャンクをフェッチします。

maxRows オプションを使用して、目的のチャンク サイズを指定できます。ただし、返されるチャンクのサイズは、小さい場合もあれば大きい場合もあります。 fetchChunk は、要求された部分にスライスするために、データを内部的にプリフェッチしようとはしません。 maxRows オプションをサーバーに送信し、サーバーが返すものを返します。この maxRows オプションを IDBSQLSessionのオプションと混同しないでください。 fetchChunk に渡されるmaxRows 、各チャンクのサイズを定義し、それ以外は何も行いません。

Unity Catalogボリューム内のファイルを管理する

Databricks SQLドライバーを使用すると、次の例に示すように、 Unity Catalogボリュームにローカル ファイルを書き込んだり、ボリュームからファイルをダウンロードしたり、ボリュームからファイルを削除したりできます。

const { DBSQLClient } = require('@databricks/sql');

const serverHostname = process.env.DATABRICKS_SERVER_HOSTNAME;
const httpPath       = process.env.DATABRICKS_HTTP_PATH;
const token          = process.env.DATABRICKS_TOKEN;

if (!token || !serverHostname || !httpPath) {
    throw new Error("Cannot find Server Hostname, HTTP Path, or " +
                    "personal access token. " +
                    "Check the environment variables DATABRICKS_SERVER_HOSTNAME, " +
                    "DATABRICKS_HTTP_PATH, and DATABRICKS_TOKEN.");
}

const client = new DBSQLClient();
const connectOptions = {
  token: token,
  host:  serverHostname,
  path:  httpPath
};

client.connect(connectOptions)
  .then(async client => {
    const session = await client.openSession();

    // Write a local file to a volume in the specified path.
    // For writing local files to volumes, you must first specify the path to the
    // local folder that contains the file to be written.
    // Specify OVERWRITE to overwrite any existing file in that path.
    await session.executeStatement(
      "PUT 'my-data.csv' INTO '/Volumes/main/default/my-volume/my-data.csv' OVERWRITE", {
        stagingAllowedLocalPath: ["/tmp/"]
      }
    );

    // Download a file from a volume in the specified path.
    // For downloading files in volumes, you must first specify the path to the
    // local folder that will contain the downloaded file.
    await session.executeStatement(
      "GET '/Volumes/main/default/my-volume/my-data.csv' TO 'my-downloaded-data.csv'", {
        stagingAllowedLocalPath: ["/Users/paul.cornell/samples/nodejs-sql-driver/"]
      }
    )

      // Delete a file in a volume from the specified path.
      // For deleting files from volumes, you must add stagingAllowedLocalPath,
      // but its value will be ignored. As such, in this example, an empty string is
      // specified.
      await session.executeStatement(
        "REMOVE '/Volumes/main/default/my-volume/my-data.csv'", {
          stagingAllowedLocalPath: [""]
        }
      )

      await session.close();
      await client.close();
  })
  .catch((error) => {
    console.error(error);
  });
import { DBSQLClient } from '@databricks/sql';

const serverHostname: string | undefined = process.env.DATABRICKS_SERVER_HOSTNAME;
const httpPath: string | undefined = process.env.DATABRICKS_HTTP_PATH;
const token: string | undefined = process.env.DATABRICKS_TOKEN;

if (!token || !serverHostname || !httpPath) {
  throw new Error("Cannot find Server Hostname, HTTP Path, or " +
                  "personal access token. " +
                  "Check the environment variables DATABRICKS_SERVER_HOSTNAME, " +
                  "DATABRICKS_HTTP_PATH, and DATABRICKS_TOKEN.");
}

const client: DBSQLClient = new DBSQLClient();
const connectOptions = {
  token: token,
  host: serverHostname,
  path: httpPath
};

client.connect(connectOptions)
  .then(async client => {
    const session = await client.openSession();

    // Write a local file to a volume in the specified path.
    // For writing local files to volumes, you must first specify the path to the
    // local folder that contains the file to be written.
    // Specify OVERWRITE to overwrite any existing file in that path.
    await session.executeStatement(
      "PUT 'my-data.csv' INTO '/Volumes/main/default/my-volume/my-data.csv' OVERWRITE", {
        stagingAllowedLocalPath: ["/tmp/"]
      }
    );

    // Download a file from a volume in the specified path.
    // For downloading files in volumes, you must first specify the path to the
    // local folder that will contain the downloaded file.
    await session.executeStatement(
      "GET '/Volumes/main/default/my-volume/my-data.csv' TO 'my-downloaded-data.csv'", {
        stagingAllowedLocalPath: ["/Users/paul.cornell/samples/nodejs-sql-driver/"]
      }
    )

    // Delete a file in a volume from the specified path.
    // For deleting files from volumes, you must add stagingAllowedLocalPath,
    // but its value will be ignored. As such, in this example, an empty string is
    // specified.
    await session.executeStatement(
      "REMOVE '/Volumes/main/default/my-volume/my-data.csv'", {
        stagingAllowedLocalPath: [""]
      }
    )

    await session.close();
    await client.close();
  })
  .catch((error: any) => {
    console.error(error);
  });

ログの構成

ロガーは、コネクターの問題をデバッグするための情報を提供します。 すべての DBSQLClient オブジェクトは、コンソールに出力するロガーでインスタンス化されますが、カスタム ロガーを渡すことで、この情報をファイルに送信できます。 次の例は、ロガーを構成し、そのレベルを変更する方法を示しています。

const { DBSQLLogger, LogLevel } = require('@databricks/sql');
const logger = new DBSQLLogger({
  filepath: 'log.txt',
  level: LogLevel.info
});

// Set logger to different level.
logger.setLevel(LogLevel.debug);
import { DBSQLLogger, LogLevel } from '@databricks/sql';
const logger = new DBSQLLogger({
  filepath: 'log.txt',
  level: LogLevel.info,
});

// Set logger to different level.
logger.setLevel(LogLevel.debug);

その他の例については、GitHub の databricks/databricks-sql-nodejs リポジトリにある examples フォルダーを参照してください。

テスティング

コードをテストするには、 Jest などの JavaScript テストフレームワークを使用できます。 Databricks REST API エンドポイントを呼び出さずに、または Databricks アカウントやワークスペースの状態を変更せずに、シミュレートされた条件下でコードをテストするには、Jest の組み込みモック フレームワークを使用できます。

たとえば、次の helpers.js という名前のファイルがあるとします。このファイルには、 Databricks個人用アクセストークンを使用してDatabricksワークスペースへの接続を返す getDBSQLClientWithPAT 関数、接続を使用して指定されたテーブル (たとえば、samples カタログの nyctaxi スキーマの trips テーブル) から指定された数のデータ行を取得する getAllColumnsFromTable 関数、およびデータ行のコンテンツを出力する printResults 関数が含まれています。

// helpers.js

const { DBSQLClient } = require('@databricks/sql');

async function getDBSQLClientWithPAT(token, serverHostname, httpPath) {
  const client = new DBSQLClient();
  const connectOptions = {
    token: token,
    host: serverHostname,
    path: httpPath
  };
  try {
    return await client.connect(connectOptions);
  } catch (error) {
    console.error(error);
    throw error;
  }
}

async function getAllColumnsFromTable(client, tableSpec, rowCount) {
  let session;
  let queryOperation;
  try {
    session = await client.openSession();
    queryOperation = await session.executeStatement(
      `SELECT * FROM ${tableSpec} LIMIT ${rowCount}`,
      {
        runAsync: true,
        maxRows: 10000 // This option enables the direct results feature.
      }
    );
  } catch (error) {
    console.error(error);
    throw error;
  }
  let result;
  try {
    result = await queryOperation.fetchAll();
  } catch (error) {
    console.error(error);
    throw error;
  } finally {
    if (queryOperation) {
      await queryOperation.close();
    }
    if (session) {
      await session.close();
    }
  }
  return result;
}

function printResult(result) {
  console.table(result);
}

module.exports = {
  getDBSQLClientWithPAT,
  getAllColumnsFromTable,
  printResult
};

また、getDBSQLClientWithPATgetAllColumnsFromTable、および printResults 関数を呼び出す main.js という名前の次のファイルがあるとします。

// main.js

const { getDBSQLClientWithPAT, getAllColumnsFromTable, printResult } = require('./helpers');

const token          = process.env.DATABRICKS_TOKEN;
const serverHostname = process.env.DATABRICKS_SERVER_HOSTNAME;
const httpPath       = process.env.DATABRICKS_HTTP_PATH;
const tableSpec      = process.env.DATABRICKS_TABLE_SPEC;

if (!token || !serverHostname || !httpPath) {
  throw new Error("Cannot find Server Hostname, HTTP Path, or personal access token. " +
    "Check the environment variables DATABRICKS_TOKEN, " +
    "DATABRICKS_SERVER_HOSTNAME, and DATABRICKS_HTTP_PATH.");
}

if (!tableSpec) {
  throw new Error("Cannot find table spec in the format catalog.schema.table. " +
    "Check the environment variable DATABRICKS_TABLE_SPEC."
  )
}

getDBSQLClientWithPAT(token, serverHostname, httpPath)
  .then(async client => {
    const result = await getAllColumnsFromTable(client, tableSpec, 2);
    printResult(result);
    await client.close();
  })
  .catch((error) => {
    console.error(error);
  });

次の helpers.test.js という名前のファイルは、 getAllColumnsFromTable 関数が予期される応答を返すかどうかをテストします。 このテストは、ターゲットワークスペースへの実際の接続を作成するのではなく、 DBSQLClientオブジェクトをモックします。 また、このテストでは、実際のデータに含まれるスキーマと値に準拠する一部のデータをモックします。 このテストでは、モックされた接続を介してモックされたデータが返され、モックされたデータ行の 1 つの値が期待値と一致するかどうかがチェックされます。

// helpers.test.js

const { getDBSQLClientWithPAT, getAllColumnsFromTable, printResult} = require('./helpers')

jest.mock('@databricks/sql', () => {
  return {
    DBSQLClient: jest.fn().mockImplementation(() => {
      return {
        connect: jest.fn().mockResolvedValue({ mock: 'DBSQLClient'})
      };
    }),
  };
});

test('getDBSQLClientWithPAT returns mocked Promise<DBSQLClient> object', async() => {
  const result = await getDBSQLClientWithPAT(
    token = 'my-token',
    serverHostname = 'mock-server-hostname',
    httpPath = 'mock-http-path'
  );

  expect(result).toEqual({ mock: 'DBSQLClient' });
});

const data = [
  {
    tpep_pickup_datetime: new Date(2016, 1, 13, 15, 51, 12),
    tpep_dropoff_datetime: new Date(2016, 1, 13, 16, 15, 3),
    trip_distance: 4.94,
    fare_amount: 19.0,
    pickup_zip: 10282,
    dropoff_zip: 10171
  },
  {
    tpep_pickup_datetime: new Date(2016, 1, 3, 17, 43, 18),
    tpep_dropoff_datetime: new Date(2016, 1, 3, 17, 45),
    trip_distance: 0.28,
    fare_amount: 3.5,
    pickup_zip: 10110,
    dropoff_zip: 10110
  }
];

const mockDBSQLClientForSession = {
  openSession: jest.fn().mockResolvedValue({
    executeStatement: jest.fn().mockResolvedValue({
      fetchAll: jest.fn().mockResolvedValue(data),
      close: jest.fn().mockResolvedValue(null)
    }),
    close: jest.fn().mockResolvedValue(null)
  })
};

test('getAllColumnsFromTable returns the correct fare_amount for the second mocked data row', async () => {
  const result = await getAllColumnsFromTable(
    client    = mockDBSQLClientForSession,
    tableSpec = 'mock-table-spec',
    rowCount  = 2);
  expect(result[1].fare_amount).toEqual(3.5);
});

global.console.table = jest.fn();

test('printResult mock prints the correct fare_amount for the second mocked data row', () => {
  printResult(data);
  expect(console.table).toHaveBeenCalledWith(data);
  expect(data[1].fare_amount).toBe(3.5);
});

TypeScript の場合、上記のコードは似ています。 TypeScript で Jest をテストするには、 ts-jest を使用します。

関連リソース

API リファレンス

クラス

DBSQLClient クラス

データベースと対話するためのメイン エントリ ポイント。

メソッド
connect 方法

データベースへの接続を開きます。

パラメーター

オプション

種類: ConnectionOptions

データベースへの接続に使用するオプションのセット。

hostpath、およびその他の必須フィールドに入力する必要があります。「 認証」を参照してください。

例:

const client: DBSQLClient = new DBSQLClient();

client.connect(
  {
    host:  serverHostname,
    path:  httpPath,
    // ...
  }
)

収益: Promise<IDBSQLClient>

openSession 方法

DBSQLClient とデータベース間のセッションを開きます。

パラメーター

依頼

種類: OpenSessionRequest

初期スキーマおよび初期カタログを指定するためのオプション・パラメーターのセット

例:

const session = await client.openSession(
  {initialCatalog: 'catalog'}
);

収益: Promise<IDBSQLSession>

getClient 方法

内部倹約 TCLIService.Client オブジェクトを返します。 DBSQLClient が接続した後に呼び出す必要があります。

パラメーターなし

収益 TCLIService.Client

close 方法

データベースへの接続を閉じ、サーバー上のすべての関連リソースを解放します。 このクライアントをさらに呼び出すと、エラーがスローされます。

パラメーターはありません。

戻り値はありません。

DBSQLSession クラス

DBSQLSession は、主にデータベースに対するステートメントの実行や、さまざまなメタデータの取得操作に使用されます。

メソッド
executeStatement 方法

指定されたオプションを使用してステートメントを実行します。

パラメーター

陳述

種類: str

実行するステートメント。

オプション

種類: ExecuteStatementOptions

クエリー タイムアウト、直接結果の最大行数、およびクエリーを非同期的に実行するかどうかを決定するための一連の省略可能なパラメーター。 デフォルトでは、 maxRows は 10000 に設定されています。 maxRows が null に設定されている場合、直接結果機能がオフの状態で操作が実行されます。

例:

const session = await client.openSession(
  {initialCatalog: 'catalog'}
);

queryOperation = await session.executeStatement(
  'SELECT "Hello, World!"', { runAsync: true }
);

収益: Promise<IOperation>

close 方法

セッションを閉じます。 セッションを使用した後に行う必要があります。

パラメーターはありません。

戻り値はありません。

getId 方法

セッションの GUID を返します。

パラメーターはありません。

収益: str

getTypeInfo 方法

サポートされているデータ型に関する情報を返します。

パラメーター

依頼

種類: TypeInfoRequest

要求パラメーター。

収益: Promise<IOperation>

getCatalogs 方法

カタログの一覧を取得します。

パラメーター

依頼

種類: CatalogsRequest

要求パラメーター。

収益: Promise<IOperation>

getSchemas 方法

スキーマのリストを取得します。

パラメーター

依頼

種類: SchemasRequest

要求パラメーター。 フィールド catalogNameschemaName は、フィルター処理の目的で使用できます。

収益: Promise<IOperation>

getTables 方法

テーブルのリストを取得します。

パラメーター

依頼

種類: TablesRequest

要求パラメーター。 フィールド catalogNameschemaName および tableName は、フィルター処理に使用できます。

収益: Promise<IOperation>

getFunctions 方法

テーブルのリストを取得します。

パラメーター

依頼

種類: FunctionsRequest

要求パラメーター。 フィールド functionName は必須です。

収益: Promise<IOperation>

getPrimaryKeys 方法

主キーの一覧を取得します。

パラメーター

依頼

種類: PrimaryKeysRequest

要求パラメーター。 フィールド schemaNametableName は必須です。

収益: Promise<IOperation>

getCrossReference 方法

2 つのテーブル間の外部キーに関する情報を取得します。

パラメーター

依頼

種類: CrossReferenceRequest

要求パラメーター。 両方のテーブルにスキーマ、親、およびカタログ名を指定する必要があります。

収益: Promise<IOperation>

DBSQLOperation クラス

DBSQLOperations は DBSQLSessions によって作成され、ステートメントの結果をフェッチし、その実行をチェックするために使用できます。 データは、関数 fetchChunk および fetchAll を使用してフェッチされます。

メソッド
getId 方法

操作の GUID を返します。

パラメーターはありません。

収益: str

fetchAll 方法

操作の完了を待機してから、操作からすべての行をフェッチします。

パラメーター: None

収益: Promise<Array<object>>

fetchChunk 方法

操作の完了を待機し、操作から指定された行数までフェッチします。

パラメーター

オプション

種類: FetchOptions

フェッチに使用されるオプション。 現在、唯一のオプションは maxRows で、これは特定の配列で返されるデータ オブジェクトの最大数に対応します。

収益: Promise<Array<object>>

close 方法

操作を閉じ、関連付けられているすべてのリソースを解放します。 操作を使用しなくなった後に実行する必要があります。

パラメーターはありません。

戻り値はありません。