Compartilhar via


Driver do Databricks SQL para Node.js

O Driver do Databricks SQL para Node.js é uma biblioteca Node.js que permite usar o código JavaScript para executar comandos SQL em recursos de computação do Azure Databricks.

Requisitos

  • Um computador de desenvolvimento executando o Node.js 14 ou superior. Para imprimir a versão instalada do Node.js, execute o comando node -v. Para instalar e usar diferentes versões do Node.js, você pode usar ferramentas como o Gerenciador de Versões do Node (nvm).

  • Gerenciador de pacotes do Node (npm). Versões posteriores do Node.js já incluem npm. Para verificar se npm está instalado, execute o comando npm -v. Para instalar npm, se necessário, você pode seguir instruções como aquelas em Baixar e instalar o npm.

  • O pacote @databricks/sql do npm. Para instalar o pacote @databricks/sql em seu projeto do Node.js como uma dependência, use npm para executar o seguinte comando no mesmo diretório que seu projeto:

    npm i @databricks/sql
    
  • Se desejar instalar e usar o TypeScript em seu projeto Node.js como devDependencies, use npm para executar os seguintes comandos do mesmo diretório que seu projeto:

    npm i -D typescript
    npm i -D @types/node
    
  • Um cluster ou SQL warehouse existente.

  • O valor do Nome do host do servidor e do Caminho HTTP para o cluster ou o SQL warehouse existente.

Autenticação

O Driver SQL do Databricks para Node.js dá suporte para os seguintes tipos de autenticação do Azure Databricks:

O Driver SQL do Databricks para Node.js ainda não dá suporte para os seguintes tipos de autenticação do Azure Databricks:

Observação

Como melhor prática de segurança, você não deve codificar os valores das variáveis de conexão diretamente no seu código. Em vez disso, você deve recuperar esses valores de variável de conexão de um local seguro. Por exemplo, os trechos de código e os exemplos deste artigo usam variáveis de ambiente.

Autenticação de token de acesso pessoal do Databricks

Para usar o Driver SQL do Databricks para Node.js com autenticação, primeiro você deve criar um token de acesso pessoal do Azure Databricks. Para obter detalhes sobre esta etapa, consulte Tokens de acesso pessoal do Azure Databricks para usuários do workspace.

Para autenticar o Driver SQL do Databricks para Node.js, use o seguinte trecho de código. Esse snippet de código pressupõe que você tenha definido as seguintes variáveis de ambiente:

  • DATABRICKS_SERVER_HOSTNAMEdefinido como o valor Nome do Host do Servidor do seu cluster ou SQL Warehouse.
  • DATABRICKS_HTTP_PATH, definido para o valor do Caminho HTTP para seu cluster ou SQL Warehouse.
  • DATABRICKS_TOKEN, definido como o token de acesso pessoal do Azure Databricks.

Para definir variáveis de ambiente, confira a documentação do sistema operacional.

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

Autenticação U2M (usuário para computador) do OAuth

O Driver SQL do Databricks para Node.js, versões 1.8.0 e posteriores, dá suporte à autenticação U2M (usuário para computador) do OAuth.

Para autenticar o Driver SQL do Databricks para Node.js com a autenticação U2M do OAuth, use o trecho de código a seguir. Esse snippet de código pressupõe que você tenha definido as seguintes variáveis de ambiente:

  • DATABRICKS_SERVER_HOSTNAMEdefinido como o valor Nome do Host do Servidor do seu cluster ou SQL Warehouse.
  • DATABRICKS_HTTP_PATH, definido para o valor do Caminho HTTP para seu cluster ou SQL Warehouse.

Para definir variáveis de ambiente, confira a documentação do sistema operacional.

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",
    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",
    useDatabricksOAuthInAzure: true,
    host:                      serverHostname,
    path:                      httpPath
  };

  client.connect(connectOptions)
  // ...

Autenticação M2M (de computador para computador) do OAuth

O Driver SQL do Databricks para Node.js, versões 1.8.0 e posteriores, dá suporte à autenticação M2M (computador para computador) do OAuth.

Para usar o Driver SQL do Databricks para Node.js com a autenticação OAuth M2M, você precisa fazer o seguinte:

  1. Crie uma entidade de serviço do Azure Databricks em seu workspace do Azure Databricks e crie um segredo OAuth para essa entidade de serviço.

    Para criar a entidade de serviço e seu segredo OAuth, consulte Autenticar o acesso ao Azure Databricks com uma entidade de serviço usando OAuth (OAuth M2M). Anote o valor do UUID ou da ID do aplicativo da entidade de serviço e o valor do Segredo do segredo OAuth da entidade de serviço.

  2. Conceda à entidade de serviço acesso ao cluster ou ao warehouse. Consulte Permissões de computação ou Gerenciar um SQL warehouse.

Para autenticar o Driver SQL do Databricks para Node.js, use o seguinte trecho de código. Esse snippet de código pressupõe que você tenha definido as seguintes variáveis de ambiente:

  • DATABRICKS_SERVER_HOSTNAMEdefinido como o valor Nome do Host do Servidor do seu cluster ou SQL Warehouse.
  • DATABRICKS_HTTP_PATH, definido para o valor do Caminho HTTP para seu cluster ou SQL Warehouse.
  • DATABRICKS_CLIENT_ID, definido como o valor do UUID ou da ID do aplicativo da entidade de serviço.
  • DATABRICKS_CLIENT_SECRET, definido como o valor do Segredo para o segredo OAuth da entidade de serviço.

Para definir variáveis de ambiente, confira a documentação do sistema operacional.

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

  client.connect(connectOptions)
  // ...

Autenticação de token do Microsoft Entra ID

Para usar o Driver SQL do Databricks para Node.js com autenticação de token do Microsoft Entra ID, você deve fornecer o Driver SQL do Databricks para Node.js com o token do Microsoft Entra ID. Para criar um token de acesso do Microsoft Entra ID, faça o seguinte:

Os tokens do Microsoft Entra ID têm um tempo de vida padrão de cerca de 1 hora. Para criar um novo token do Microsoft Entra ID, repita esse processo.

Para autenticar o Driver SQL do Databricks para Node.js, use o seguinte trecho de código. Esse snippet de código pressupõe que você tenha definido as seguintes variáveis de ambiente:

  • DATABRICKS_SERVER_HOSTNAMEdefinido como o valor Nome do Host do Servidor do seu cluster ou SQL Warehouse.
  • DATABRICKS_HTTP_PATH, definido para o valor do Caminho HTTP para seu cluster ou SQL Warehouse.
  • DATABRICKS_TOKEN, definido como o token do Microsoft Entra ID.

Para definir variáveis de ambiente, confira a documentação do sistema operacional.

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

Consultar dados

O exemplo de código a seguir demonstra como chamar o Driver de SQL do Databricks para Node.js para executar uma consulta SQL básica em um recurso de computação do Azure Databricks. Esse comando retorna as duas primeiras linhas da tabela trips no esquema nyctaxi do catálogo samples.

Observação

O exemplo de código a seguir demonstra como usar um token de acesso pessoal do Azure Databricks para autenticação. Para usar outros tipos de autenticação disponíveis do Azure Databricks, confira Autenticação.

Este exemplo de código recupera os valores de variáveis de conexão token, server_hostname e http_path de um conjunto de variáveis de ambiente do Azure Databricks. Essas variáveis de ambiente têm os seguintes nomes de variáveis de ambiente:

  • DATABRICKS_TOKEN, que representa o token de acesso pessoal do Azure Databricks dos requisitos.
  • DATABRICKS_SERVER_HOSTNAME, que representa o valor do Nome do host do servidor nos requisitos.
  • DATABRICKS_HTTP_PATH, que representa o valor do Caminho HTTP obtido nos requisitos.

Você pode usar outras abordagens para recuperar os valores dessa variável de conexão. Usar variáveis de ambiente é apenas uma abordagem entre muitas.

O exemplo de código a seguir demonstra como chamar o conector do Databricks SQL para Node.js a fim de executar um comando SQL básico em um cluster ou warehouse SQL. Esse comando retorna as duas primeiras linhas da tabela 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 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);
});

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

Saída:

┌─────────┬─────┬────────┬───────────┬───────┬─────────┬────────┬───────┬───────┬────────┬────────┬────────┐
│ (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' │
└─────────┴─────┴────────┴───────────┴───────┴─────────┴────────┴───────┴───────┴────────┴────────┴────────┘

Sessões

Todos os IDBSQLSession métodos que retornam IOperation objetos na Referência de API têm os seguintes parâmetros comuns que afetam seu comportamento:

  • A configuração runAsync para true inicia o modo assíncrono. IDBSQLSession os métodos colocam operações na fila e retornam o mais rápido possível. O estado atual do objeto retornado IOperation pode variar e o cliente é responsável por verificar seus status antes de usar o retornadoIOperation. Consulte Operações. Definir runAsync como false significa que IDBSQLSession os métodos aguardam a conclusão das operações. O Databricks recomenda que você sempre defina runAsync como true.
  • A configuração maxRows para um valor não nulo permite resultados diretos. Com os resultados diretos, o servidor tenta aguardar a conclusão das operações e, em seguida, busca uma parte dos dados. Dependendo de quanto trabalho o servidor foi capaz de concluir dentro do tempo definido, IOperation os objetos retornam em algum estado intermediário em vez de em algum estado pendente. Muitas vezes, todos os metadados e os resultados da consulta são retornados em uma única solicitação para o servidor. O servidor usa maxRows para determinar quantos registros ele pode retornar imediatamente. No entanto, a parte real pode ser de um tamanho diferente; consulte IDBSQLSession.fetchChunk. Os resultados diretos são ativados por padrão. O Databricks recomenda não desabilitar resultados diretos.

Operações

Conforme descrito em Sessões, IOperation os objetos retornados pelos IDBSQLSession métodos de sessão na Referência de API não são totalmente preenchidos. A operação de servidor relacionada ainda pode estar em andamento, como aguardar o Databricks SQL warehouse iniciar, executar a consulta ou buscar os dados. A classe IOperation oculta esses detalhes dos usuários. Por exemplo, métodos como fetchAll, fetchChunk e getSchema esperam internamente que as operações sejam concluídas e, em seguida, retornem resultados. Você pode usar o método IOperation.finished() para aguardar explicitamente a conclusão das operações. Esses métodos recebem um retorno de chamada que é chamado periodicamente enquanto aguarda a conclusão das operações. Definir a opção progress para true tentar solicitar dados de progresso extra do servidor e passá-los para esse retorno de chamada.

Os métodos close e cancel podem ser chamados a qualquer momento. Quando chamados, eles invalidam imediatamente o objeto IOperation; todas as chamadas pendentes, como fetchAll, fetchChunk e getSchema são imediatamente canceladas e um erro é retornado. Em alguns casos, a operação do servidor pode já ter sido concluída e o método cancel afeta apenas o cliente.

O método fetchAll chama fetchChunk internamente e coleta todos os dados em uma matriz. Embora isso seja conveniente, isso pode causar erros de memória insuficiente quando usado em grandes conjuntos de dados. fetchAll as opções normalmente são passadas para fetchChunk.

Buscar partes de dados

Buscar partes de dados usa o seguinte padrão de código:

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

O método fetchChunk na Referência de API processa dados em pequenas partes para reduzir o consumo de memória. fetchChunk primeiro aguarda a conclusão das operações se elas ainda não foram concluídas, chama um retorno de chamada durante o ciclo de espera e busca a próxima parte de dados.

Você pode usar a opção maxRows para especificar o tamanho da parte desejada. No entanto, a parte retornada pode ter um tamanho diferente, menor ou até mesmo às vezes maior. fetchChunk não tenta pré-buscar dados internamente, a fim de segmentá-los nas partes solicitadas. Ele envia a opção maxRows para o servidor e retorna o que o servidor retorna. Não confunda essa maxRows opção com a de IDBSQLSession. maxRows passado para fetchChunk define o tamanho de cada parte e não faz mais nada.

Gerenciar arquivos em volumes do Catálogo do Unity

O driver do Databricks SQL permite gravar arquivos locais em volumes do Catálogo do Unity, baixar arquivos de volumes e excluir arquivos de volumes, conforme mostrado no seguinte exemplo:

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

Configurar o registro em log

O agente fornece informações para depurar problemas com o conector. Todos os objetos DBSQLClient são instanciados com um agente que imprime no console, mas ao transmitir um agente personalizado, é possível enviar essas informações para um arquivo. O exemplo a seguir mostra como configurar um agente e alterar seu nível.

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

Para obter exemplos adicionais, consulte a pasta de exemplos no repositório databricks/databricks-sql-nodejs no GitHub.

Testando

Para testar o seu código, você pode usar estruturas de teste do JavaScript, como Jest. Para testar o seu código em condições simuladas sem chamar pontos de extremidade da API REST do Azure Databricks ou alterar o estado de suas contas ou workspaces do Azure Databricks, você pode usar as estruturas de simulação internas do Jest.

Por exemplo, dado o seguinte arquivo nomeado helpers.js contendo uma função getDBSQLClientWithPAT que usa um token de acesso pessoal do Azure Databricks para retornar uma conexão a um workspace do Azure Databricks, uma função getAllColumnsFromTable que usa a conexão para obter o número especificado de linhas de dados da tabela especificada (por exemplo, a tabela trips no esquema nyctaxi do catálogo samples) e uma função printResults para imprimir o conteúdo das linhas de dados:

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

E dado o seguinte arquivo chamado main.js que chama as funções getDBSQLClientWithPAT, getAllColumnsFromTable e 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);
  });

O arquivo nomeado helpers.test.js a seguir testa se a função getAllColumnsFromTable retorna a resposta esperada. Em vez de criar uma conexão real com o workspace de destino, esse teste simula um objeto DBSQLClient. O teste também simula alguns dados que estão em conformidade com o esquema e os valores que estão nos dados reais. O teste retorna os dados simulados por meio da conexão simulada e verifica se um dos valores das linhas de dados simuladas corresponde ao valor esperado.

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

Para TypeScript, o código anterior é semelhante. Para testes Jest com TypeScript, use ts-jest.

Recursos adicionais

Referência de API

Classes

Classe DBSQLClient

Ponto de entrada principal para interagir com um banco de dados.

Métodos
método connect

Abre uma conexão com o banco de dados.

Parâmetros
options

Digite: ConnectionOptions

O conjunto de opções usado para se conectar ao banco de dados.

Os campos host, path e outros campos obrigatórios devem ser preenchidos. Consulte Autenticação.

Exemplo:


const client: DBSQLClient = new DBSQLClient();

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

Retorna: Promise<IDBSQLClient>

método openSession

Abre a sessão entre o DBSQLClient e o banco de dados.

Parâmetros
solicitação

Digite: OpenSessionRequest

Um conjunto de parâmetros opcionais para especificar o esquema inicial e o catálogo inicial

Exemplo:


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

Retorna: Promise<IDBSQLSession>

método getClient

Retorna o objeto interno thrift TCLIService.Client. Deve ser chamado após a conexão de DBSQLClient.

Sem parâmetros

Retorna TCLIService.Client

método close

Fecha a conexão com o banco de dados e libera todos os recursos associados no servidor. Quaisquer chamadas adicionais para este cliente gerarão um erro.

Sem parâmetros.

Sem valor de retorno.

Classe DBSQLSession

DBSQLSessions são usadas principalmente para a execução de instruções no banco de dados, bem como diversas operações de busca de metadados.

Métodos
método executeStatement

Executa uma instrução com as opções fornecidas.

Parâmetros
instrução

Digite: str

A instrução a ser executada.
options

Digite: ExecuteStatementOptions

Um conjunto de parâmetros opcionais para determinar o tempo limite da consulta, as linhas máximas para resultados diretos e se a consulta deve ser executada de maneira assíncrona. Por padrão, maxRows é definido como 10000. Se maxRows for definido como nulo, a operação será executada com o recurso de resultados diretos desabilitado.

Exemplo:


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

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

Retorna: Promise<IOperation>

método close

Fecha a sessão. Deve ser feito após o uso da sessão.

Sem parâmetros.

Nenhum valor retornado.

método getId

Retorna o GUID da sessão.

Sem parâmetros.

Retorna: str

método getTypeInfo

Retorna informações sobre os tipos de dados compatíveis.

Parâmetros
solicitação

Digite: TypeInfoRequest

Solicita os parâmetros.

Retorna: Promise<IOperation>

método getCatalogs

Obtém a lista de catálogos.

Parâmetros
solicitação

Digite: CatalogsRequest

Solicita os parâmetros.

Retorna: Promise<IOperation>

método getSchemas

Obtém a lista de esquemas.

Parâmetros
solicitação

Digite: SchemasRequest

Solicita os parâmetros. Os campos catalogName e schemaName podem ser usados para fins de filtragem.

Retorna: Promise<IOperation>

método getTables

Obtém a lista de tabelas.

Parâmetros
solicitação

Digite: TablesRequest

Solicita os parâmetros. Campos catalogName, schemaName e
tableName podem ser usados para filtragem.

Retorna: Promise<IOperation>

método getFunctions

Obtém a lista de tabelas.

Parâmetros
solicitação

Digite: FunctionsRequest

Solicita os parâmetros. O campo functionName é obrigatório.

Retorna: Promise<IOperation>

método getPrimaryKeys

Obtém a lista de chaves primárias.

Parâmetros
solicitação

Digite: PrimaryKeysRequest

Solicita os parâmetros. Os campos schemaName e tableName são obrigatórios.

Retorna: Promise<IOperation>

método getCrossReference

Obtém informações sobre chaves estrangeiras entre duas tabelas.

Parâmetros
solicitação

Digite: CrossReferenceRequest

Solicita os parâmetros. Os nomes do esquema, do pai e do catálogo devem ser especificados para ambas as tabelas.

Retorna: Promise<IOperation>

Classe DBSQLOperation

DBSQLOperations são criadas por DBSQLSessions e podem ser usadas para buscar os resultados das instruções e verificar sua execução. Os dados são buscados por meio das funções fetchChunk e fetchAll.

Métodos
método getId

Retorna o GUID da operação.

Sem parâmetros.

Retorna: str

método fetchAll

Aguarda a conclusão da operação e, em seguida, busca todas as linhas dela.

Parâmetros: nenhum

Retorna: Promise<Array<object>>

método fetchChunk

Aguarda a conclusão da operação e, em seguida, busca até um número especificado de linhas dela.

Parâmetros
options

Digite: FetchOptions

Opções usadas para buscar. Atualmente, a única opção é maxRows, que corresponde ao número máximo de objetos de dados a serem retornados em qualquer matriz.

Retorna: Promise<Array<object>>

método close

Encerra a operação e libera todos os recursos associados. Deve ser feito depois de não usar mais a operação.

Sem parâmetros.

Sem valor de retorno.