適用於 Node.js 的 Databricks SQL 驅動程式

適用於 Node.js 的 Databricks SQL 驅動程式是一個 Node.js 程式庫,可讓您使用 JavaScript 程式碼,在 Azure Databricks 計算資源上執行 SQL 命令。

需求

  • 執行 Node.js 版本 14 或更高版本的開發機器。 若要列印所安裝的 Node.js 版本,請執行 node -v 命令。 若要安裝和使用不同版本的 Node.js,您可以使用節點版本管理員 (nvm) 之類的工具。

  • 節點套件管理員 (npm)。 更新版本的 Node.js 已包含 npm。 若要檢查是否已安裝 npm,請執行命令 npm -v。 若要視需要安裝 npm,您可以遵循指示,例如下載並安裝 npm 中的指示。

  • @databricks/sql 套件來自npm。 若要在 Node.js 專案中將 @databricks/sql 套件安裝為相依性,請使用 npm 在專案的相同目錄中執行下列指令:

    npm i @databricks/sql
    
  • 若要在 Node.js 專案中安裝和使用 TypeScript 以便用作 devDependencies,請使用 npm 在專案目錄中執行下列指令:

    npm i -D typescript
    npm i -D @types/node
    
  • 現有的叢集或 SQL 倉儲。

  • 現有叢集或 SQL 倉儲的伺服器主機名稱和 HTTP 路徑值。

驗證

適用於 Node.js 的 Databricks SQL 驅動程式支援下列 Azure Databricks 驗證類型:

適用於 Node.js 的 Databricks SQL 驅動程式尚不支援下列 Azure Databricks 驗證類型:

注意

基於安全性最佳做法,您不應該將連線變數值硬式編碼到您的程式碼中。 相反地,您應從安全的位置擷取這些連線變數值。 例如,本文中的程式碼片段和範例會使用環境變數。

Databricks 個人存取憑證驗證

若要搭配驗證使用 Databricks SQL Driver for Node.js,您必須先建立 Azure Databricks 個人存取令牌。 如需此步驟的詳細資訊,請參閱為 工作區使用者建立個人存取權杖。

若要驗證適用於 Node.js 的 Databricks SQL 驅動程式,請使用下列程式碼片段。 此片段假設您已設定下列環境變數:

  • 將 DATABRICKS_SERVER_HOSTNAME 設定為叢集或 SQL 倉儲的 [伺服器主機名稱] 值。
  • DATABRICKS_HTTP_PATH 設定為您的叢集或 SQL 倉儲的 HTTP 路徑 值。
  • DATABRICKS_TOKEN,設定為 Azure Databricks 個人存取權限憑證。

若要設定環境變數,請參閱作業系統的文件。

JavaScript

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);
// ...

TypeScript

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) 驗證

適用於 Node.js 的 Databricks SQL 驅動程式 1.8.0 版和更新版本支援 OAuth 使用者對機器 (U2M) 驗證。

若要使用 OAuth U2M 驗證來驗證適用於 Node.js 的 Databricks SQL 驅動程式,請使用下列程式碼片段。 此片段假設您已設定下列環境變數:

  • 將 DATABRICKS_SERVER_HOSTNAME 設定為叢集或 SQL 倉儲的 [伺服器主機名稱] 值。
  • DATABRICKS_HTTP_PATH 設定為您的叢集或 SQL 倉儲的 HTTP 路徑 值。

若要設定環境變數,請參閱作業系統的文件。

JavaScript

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',
  azureTenantId: '<tenant-id>',
  useDatabricksOAuthInAzure: true,
  host: serverHostname,
  path: httpPath,
};

client.connect(connectOptions);
// ...

TypeScript

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',
  azureTenantId: '<tenant-id>',
  useDatabricksOAuthInAzure: true,
  host: serverHostname,
  path: httpPath,
};

client.connect(connectOptions);
// ...

OAuth 機器對機器 (M2M) 驗證

適用於 Node.js 的 Databricks SQL 驅動程式 1.8.0 版和更新版本支援 OAuth 機器對機器 (U2M) 驗證。

若要使用 OAuth M2M 驗證來驗證適用於 Node.js 的 Databricks SQL 驅動程式,您必須執行下列動作:

  1. 在 Azure Databricks 工作區中建立 Azure Databricks 服務主體,並為該服務主體建立 OAuth 祕密。

    若要建立服務主體及其 OAuth 秘密,請參閱 使用 OAuth 授權服務主體存取 Azure Databricks。 記下服務主體的 UUID 或 應用程式識別碼 值,以及服務主體的 OAuth 秘密值。

  2. 為服務主體提供叢集或倉儲的存取權。 請參閱計算權限或管理 SQL 倉儲。

若要驗證適用於 Node.js 的 Databricks SQL 驅動程式,請使用下列程式碼片段。 此片段假設您已設定下列環境變數:

  • 將 DATABRICKS_SERVER_HOSTNAME 設定為叢集或 SQL 倉儲的 [伺服器主機名稱] 值。
  • DATABRICKS_HTTP_PATH 設定為您的叢集或 SQL 倉儲的 HTTP 路徑 值。
  • DATABRICKS_CLIENT_ID,設定為服務主體的 UUID 或 應用程式識別碼 值。
  • DATABRICKS_CLIENT_SECRET,設定服務主體的 OAuth 憑證為 Secret 值。

若要設定環境變數,請參閱作業系統的文件。

JavaScript

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',
  azureTenantId: '<tenant-id>',
  useDatabricksOAuthInAzure: true,
  host: serverHostname,
  path: httpPath,
  oauthClientId: clientId,
  oauthClientSecret: clientSecret,
};

client.connect(connectOptions);
// ...

TypeScript

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',
  azureTenantId: '<tenant-id>',
  useDatabricksOAuthInAzure: true,
  host: serverHostname,
  path: httpPath,
  oauthClientId: clientId,
  oauthClientSecret: clientSecret,
};

client.connect(connectOptions);
// ...

Microsoft Entra ID 令牌驗證

若要使用適用於 Node.js 的 Databricks SQL 驅動程式搭配 Microsoft Entra ID 權杖驗證,您必須提供適用於 Node.js 的 Databricks SQL 驅動程式和 Microsoft Entra ID 權杖。 若要建立 Microsoft Entra ID 存取權杖,請按照下列步驟操作:

Microsoft Entra ID 權杖的預設有效期間約為 1 小時。 若要建立新的 Microsoft Entra ID 權杖,請重複此程序。

若要驗證適用於 Node.js 的 Databricks SQL 驅動程式,請使用下列程式碼片段。 此片段假設您已設定下列環境變數:

  • 將 DATABRICKS_SERVER_HOSTNAME 設定為叢集或 SQL 倉儲的 [伺服器主機名稱] 值。
  • DATABRICKS_HTTP_PATH 設定為您的叢集或 SQL 倉儲的 HTTP 路徑 值。
  • DATABRICKS_TOKEN,設定為 Microsoft Entra ID 代幣。

若要設定環境變數,請參閱作業系統的文件。

JavaScript

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 ' +
      '<ms-entra-id> 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);
// ...

TypeScript

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 ' +
      '<ms-entra-id> 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);
// ...

設定 User-Agent

下列程式代碼範例示範如何設定 User-Agent 應用程式 product_name 以進行使用追蹤。

JavaScript

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

const client = new DBSQLClient();
client.connect({
  host: process.env.DATABRICKS_SERVER_HOSTNAME,
  path: process.env.DATABRICKS_HTTP_PATH,
  token: process.env.DATABRICKS_TOKEN,
  userAgentEntry: 'product_name',
});

查詢資料

下列程式碼範例示範如何呼叫適用於 Node.js 的 Databricks SQL 驅動程式,在 Azure Databricks 計算資源上執行基本 SQL 查詢。 此命令會從trips目錄的samples架構中傳回nyctaxi數據表的前兩列。

注意

下列程式碼範例示範如何使用 Azure Databricks 個人存取權杖進行驗證。 若要改用其他可用的 Azure Databricks 驗證類型,請參閱驗證。

此程式碼範例會從一組 Azure Databricks 環境變數擷取 token、server_hostname 和 http_path 連線變數值。 這些環境變數具有下列環境變數名稱:

  • DATABRICKS_TOKEN,代表需求中指定的 Azure Databricks 個人存取權杖。
  • DATABRICKS_SERVER_HOSTNAME,代表來自需求的 [伺服器主機名稱] 值。
  • DATABRICKS_HTTP_PATH,代表來自需求的 [HTTP 路徑] 值。

您可使用其他方法來擷取這些連線變數值。 使用環境變數只是眾多方法之一。

下列程式碼範例示範如何呼叫適用於 Node.js 的 Databricks SQL 驅動程式,在叢集或 SQL 倉儲上執行基本 SQL 命令。 此命令會從 trips 資料表傳回前兩個資料列。

JavaScript

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 ?', {
      runAsync: true,
      maxRows: 10000, // This option enables the direct results feature.
      ordinalParameters: [2],
    });

    const result = await queryOperation.fetchAll();

    await queryOperation.close();

    console.table(result);

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

TypeScript

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 ?', {
      runAsync: true,
      maxRows: 10000, // This option enables the direct results feature.
      ordinalParameters: [2],
    });

    const result = await queryOperation.fetchAll();

    await queryOperation.close();

    console.table(result);

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

查詢標籤範例

查詢標籤是鍵值對,可以附加到 SQL 查詢以用於追蹤和分析目的。 設定後,它們會出現在表格中 system.query.history ,可讓您分析查詢模式和使用情況。

將查詢標籤定義為逗號分隔的索引鍵值組,其中每個索引鍵和值都以冒號分隔,例如 key1:value1,key2:value2。

下列範例示範如何搭配工作階段組態使用查詢標籤:

JavaScript

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

const client = new DBSQLClient();

// Open session with query tags configuration
const session = await client.openSession({
  configuration: {
    query_tags: 'team:engineering,test:query-tags,driver:node',
  },
});

const queryOperation = await session.executeStatement('SELECT 1');
const result = await queryOperation.fetchAll();
console.log(result);

await queryOperation.close();
await session.close();

TypeScript

import { DBSQLClient } from '@databricks/sql';

const client: DBSQLClient = new DBSQLClient();

// Open session with query tags configuration
const session = await client.openSession({
  configuration: {
    query_tags: 'team:engineering,test:query-tags,driver:node',
  },
});

const queryOperation = await session.executeStatement('SELECT 1');
const result = await queryOperation.fetchAll();
console.log(result);

await queryOperation.close();
await session.close();

會議

在 IDBSQLSession 中,所有返回 IOperation 物件的 方法都有以下會影響其行為的常見參數:

  • 將 runAsync 設定為 true 啟動異步模式。 IDBSQLSession 方法會將作業放入佇列中,並儘快傳回。 傳回 IOperation 物件的目前狀態可能會有所不同,而且用戶端會負責檢查其狀態,再使用傳回的 IOperation。 請參閱作業。 將 runAsync 設定為 false,表示 IDBSQLSession 方法會等候作業完成。 Databricks 建議一律將 runAsync 設定為 true。
  • 將 maxRows 設定為非 Null 值會啟用直接結果。 透過直接結果,伺服器會嘗試等候作業完成,然後擷取部分資料。 根據伺服器能夠在定義的時間內完成多少工作,IOperation 物件會以某些中繼狀態傳回,而不是在某些擱置狀態中傳回。 所有中繼資料和查詢結果通常會在單一要求內傳回給伺服器。 伺服器會使用 maxRows 來判斷可以立即傳回的記錄數量。 不過,實際區塊的大小可能不同;請參閱 IDBSQLSession.fetchChunk。 預設狀態會啟用直接結果功能。 Databricks 建議禁止停用直接結果。

會話設定

您可以在configuration方法中使用openSession物件,開啟工作階段時傳遞工作階段配置參數。 這些參數會影響該工作階段內所有作業的行為。

常見的工作階段配置參數包括:

  • query_tags:將鍵值標籤附加至 SQL 查詢以進行追蹤和分析。 如需詳細資訊,請參閱 查詢標籤範例。
  • ansi_mode:控制 ANSI SQL 合規性模式 ('true' 或 'false')
  • timezone:設定工作階段時區(例如, 'UTC', 'America/New_York')

營運

如工作階段中所述,IOperation中的 IDBSQLSession 工作階段方法所傳回的物件不會完全填滿。 相關的伺服器作業可能仍在進行中,例如等候 Databricks SQL 倉儲啟動、執行查詢或擷取資料。 IOperation 類別會向使用者隱藏這些詳細資料。 例如,fetchAll、fetchChunk 和 getSchema 等方法會在內部等候作業完成,然後傳回結果。 您可使用 IOperation.finished() 方法來明確等候作業完成。 這些方法會接受一個在等待作業完成時定期被呼叫的回呼函數。 設定 progress 選項為 true,以嘗試向伺服器要求額外的進度資料,並將其傳遞至該回呼。

可以隨時呼叫 close 和 cancel 方法。 呼叫時,它們會立即使 IOperation 物件失效;所有擱置的呼叫,例如 fetchAll、fetchChunk 和 getSchema 都會立即取消,並傳回錯誤。 在某些情況下,伺服器作業可能已經完成,並且 cancel 方法只會影響用戶端。

fetchAll 方法會在內部呼叫 fetchChunk,並將所有資料收集到陣列中。 雖然這樣做很方便,但在對大型資料集進行操作時,可能會造成記憶體不足錯誤。 fetchAll 選項通常會傳遞至 fetchChunk。

擷取資料區塊

擷取資料區塊會使用下列程式碼模式:

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

fetchChunk 方法在 API 參考 中會處理小部分的資料,以減少記憶體使用量。 如果作業尚未完成,fetchChunk 先等候作業完成,然後在等候週期內呼叫回呼,然後擷取下一個資料區塊。

您可以使用 maxRows 選項來指定所需區塊大小。 不過,傳回的區塊可能會有不同的大小,較小,有時甚至更大。 fetchChunk 不會嘗試在內部預先擷取資料來將其分割成所需的部分。 它會將 maxRows 選項傳送至伺服器,並傳回伺服器所傳回的內容。 請勿將此 maxRows 選項與 IDBSQLSession 中的選項混淆。 傳遞至 maxRows 的 fetchChunk 定義每個區塊的大小,且不會執行任何其他動作。

管理 Unity 目錄磁碟區中的檔案

Databricks SQL 驅動程式可讓您將本機檔案寫入 Unity 目錄磁碟區、從磁碟區下載檔案,以及從磁碟區刪除檔案,如下列範例所示:

JavaScript

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);
  });

TypeScript

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 物件在實例化時都會附帶一個記錄器,將資訊輸出到主控台,但您可以使用自訂記錄器,將此資訊傳送到檔案。 下列範例示範如何設定記錄器並變更其層級。

JavaScript

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);

TypeScript

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 存放庫中的範例資料夾。

使用陳述式執行 API

Databricks SQL Node.js 驅動程式可透過 Statement Execution API 連接,該 API 基於 REST 的執行路徑,取代預設的 Thrift 協定。 你必須使用這條路徑才能連接到 Lakehouse Real-Time 運算。

連接器會預先為共用平台提供原生二進位檔。 npm install 自動為你的平台選擇合適的方案:

npm install @databricks/sql

當您連線時,請傳入 useKernel: true:

const { DBSQLClient } = require('@databricks/sql');
const client = new DBSQLClient();
await client.connect({ host, path, token, useKernel: true });
const session = await client.openSession();
const operation = await session.executeStatement('SELECT 1');
console.log(await operation.fetchAll());

注意

此執行路徑僅在設定 useKernel: true時使用。 否則,驅動程式的行為與先前版本相同。 部分操作尚未支援此路徑,會顯示「不支援」錯誤。

測試

若要測試程式碼,您可以使用 JavaScript 測試架構,例如 Jest。 若要在模擬條件下測試程序代碼,而不呼叫 Azure Databricks REST API 端點,或變更 Azure Databricks 帳戶或工作區的狀態,您可以使用 Jest 的內建模擬架構。

例如,假設下列名為 helpers.js 的檔案,其中包含使用 getDBSQLClientWithPAT Azure Databricks 個人存取令牌傳回 Azure Databricks 工作區連線的函式、getAllColumnsFromTable使用連線從指定數據表取得指定數據列數目的函式(例如trips目錄架構中的samplesnyctaxi數據表),以及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();
    // Note: Table names cannot be parameterized; validate tableSpec against allowed values
    queryOperation = await session.executeStatement(`SELECT * FROM ${tableSpec} LIMIT ?`, {
      runAsync: true,
      maxRows: 10000, // This option enables the direct results feature.
      ordinalParameters: [rowCount],
    });
  } 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,
};

並假設下列名為 main.js 的檔案,該檔案會呼叫 getDBSQLClientWithPAT、getAllColumnsFromTable 和 printResults 函式:

// 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 物件,而不是建立與目標工作區的實際連線。 測試也會模擬一些符合實際資料中結構描述和值的資料。 測試會透過模擬連接傳回仿真的數據,然後檢查其中一個仿真的數據列值是否符合預期的值。

// helpers.test.js

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

jest.mock('@databricks/sql', () => {
  return {
    DBSQLClient: jest.fn(() => {
      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 (英文)
用來連線到資料庫的一組選項。
必須填入 host、path 和其他必要欄位。 請參閱驗證。
欄位 userAgentEntry 可讓您提供 User-Agent,並包含在 HTTP 要求標頭中以進行使用追蹤。 請參閱 設定使用者代理程式。

傳回:Promise<IDBSQLClient>

openSession 方法

開啟 DBSQLClient 與資料庫之間的會話。

參數
請求
類型:OpenSessionRequest (英文)
指定初始結構描述和初始目錄的一組選擇性參數
範例:
const session = await client.openSession({ initialCatalog: 'catalog' });

傳回:Promise<IDBSQLSession>

getClient 方法

傳回內部的 thrift TCLIService.Client 物件。 必須在 DBSQLClient 連線之後呼叫。

無參數

傳回 TCLIService.Client。

close 方法

關閉資料庫的連線,並釋放伺服器上的所有相關聯資源。 此用戶端的任何其他呼叫都會引發錯誤。

無參數。

沒有傳回值。

DBSQLSession 類別

DBSQLSessions 主要用於對資料庫執行陳述式,以及進行各種中繼資料擷取作業。

方法
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 (英文)
請求參數。 欄位 catalogName 和 schemaName 可用於篩選目的。

傳回:Promise<IOperation>

getTables 方法

取得資料表清單。

參數
請求
類型:TablesRequest (英文)
請求參數。 可用來篩選的欄位為 catalogName、schemaName 和 tableName。

傳回:Promise<IOperation>

getFunctions 方法

取得資料表清單。

參數
請求
類型:FunctionsRequest (英文)
請求參數。 欄位 functionName 必填。

傳回:Promise<IOperation>

getPrimaryKeys 方法

取得主鍵的清單。

參數
請求
類型:PrimaryKeysRequest (英文)
請求參數。 欄位 schemaName 和 tableName 為必填項。

傳回:Promise<IOperation>

getCrossReference 方法

取得兩個資料表之間外來鍵的相關資訊。

參數
請求
類型:CrossReferenceRequest (英文)
請求參數。 兩個資料表都必須指定結構描述、父系和目錄名稱。

傳回:Promise<IOperation>

DBSQLOperation 類別

DBSQLOperations 由 DBSQLSessions 所建立,可用來擷取陳述式的結果,並檢查其執行。 資料透過函式 fetchChunk 和 fetchAll 來擷取。

方法
getId 方法

傳回作業的 GUID。

無參數。

傳回:str

fetchAll 方法

等候作業完成,然後從作業擷取所有資料列。

參數:無

傳回:Promise<Array<object>>

fetchChunk 方法

等候作業完成後,最多擷取指定數目的資料列。

參數
選項
類型:FetchOptions (英文)
用來擷取的選項。 目前,唯一的選項是 maxRows,其對應於任何指定陣列中要傳回的資料物件數目上限。

傳回:Promise<Array<object>>

close 方法

關閉作業,並釋放所有相關聯的資源。 必須在停止操作後完成。

無參數。

沒有傳回值。