Pilote SQL Databricks pour Node.js

Le pilote Databricks SQL pour Node.js est une bibliothèque Node.js permettant d’utiliser du code JavaScript pour exécuter des commandes SQL sur des ressources de calcul Azure Databricks.

Spécifications

  • Machine de développement exécutant Node.js, version 14 ou ultérieure. Pour imprimer la version installée de Node.js, exécutez la commande node -v. Pour installer et utiliser différentes versions de Node.js, vous pouvez utiliser des outils tels que Node Version Manager (nvm).

  • Gestionnaire de package Node (npm). Les versions ultérieures de Node.js incluent déjà npm. Pour vérifier si npm est installé, exécutez la commande npm -v. Pour installer npm si nécessaire, vous pouvez suivre des instructions telles que celles du téléchargement et de l’installation de npm.

  • Le package @databricks/sql venant de npm. Pour installer le package @databricks/sql dans votre projet Node.js comme dépendance, utilisez npm pour exécuter la commande suivante à partir du même répertoire que celui de votre projet :

    npm i @databricks/sql
    
  • Si vous souhaitez installer et utiliser TypeScript dans votre projet Node.js comme devDependencies, utilisez npm pour exécuter les commandes suivantes à partir du même répertoire que celui de votre projet :

    npm i -D typescript
    npm i -D @types/node
    
  • Cluster ou entrepôt SQL existant.

  • Les valeurs Nom d’hôte du serveur et Chemin HTTP pour le cluster ou l’entrepôt SQL existant.

Authentification

Le pilote Databricks SQL pour Node.js prend en charge les types d’authentification Azure Databricks suivants :

Le pilote Databricks SQL pour Node.js ne prend pas encore en charge les types d’authentification Azure Databricks suivants :

Remarque

Une bonne pratique de sécurité est de ne pas coder en dur les valeurs de variable de connexion dans votre code. Au lieu de cela, vous devez récupérer ces valeurs de variable de connexion à partir d’un emplacement sécurisé. Par exemple, les extrait de code et exemples de cet article utilisent des variables d’environnement.

Authentification par jeton d’accès personnel Databricks

Pour utiliser Databricks SQL Driver pour Node.js avec l’authentification, vous devez d’abord créer un jeton d’accès personnel Azure Databricks. Pour plus d’informations sur cette étape, consultez les jetons d’accès personnels Azure Databricks pour les utilisateurs de l’espace de travail.

Pour authentifier le pilote Databricks SQL pour Node.js, utilisez l’extrait de code suivant. Cet extrait suppose que vous avez défini les variables d’environnement suivantes :

  • DATABRICKS_SERVER_HOSTNAME réglé sur la valeur Nom d'hôte de serveur de votre cluster ou entrepôt SQL.
  • DATABRICKS_HTTP_PATH, réglé sur la valeur Chemin HTTP de votre cluster ou entrepôt SQL.
  • DATABRICKS_TOKEN, réglé sur le jeton d’accès personnel Azure Databricks.

Pour définir des variables d’environnement, consultez la documentation de votre système d’exploitation.

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

Authentification utilisateur à machine (U2M) OAuth

Les versions 1.8.0 et ultérieures du pilote Databricks SQL pour Node.js prennent en charge l’authentification utilisateur à machine (U2M) OAuth.

Pour authentifier le pilote Databricks SQL pour Node.js avec l’authentification U2M OAuth, utilisez l’extrait de code suivant. Cet extrait suppose que vous avez défini les variables d’environnement suivantes :

  • DATABRICKS_SERVER_HOSTNAME réglé sur la valeur Nom d'hôte de serveur de votre cluster ou entrepôt SQL.
  • DATABRICKS_HTTP_PATH, réglé sur la valeur Chemin HTTP de votre cluster ou entrepôt SQL.

Pour définir des variables d’environnement, consultez la documentation de votre système d’exploitation.

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

Authentification OAuth machine à machine (M2M)

Les versions 1.8.0 et ultérieures du pilote Databricks SQL pour Node.js prennent en charge l’authentification machine à machine (U2M) OAuth.

Pour utiliser le pilote Databricks SQL pour Node.js avec l’authentification M2M OAuth, vous devez effectuer les opérations suivantes :

  1. Créez un principal de service Azure Databricks dans votre espace de travail Azure Databricks et créez un secret OAuth pour ce principal de service.

    Pour créer le principal de service et son secret OAuth, consultez Authentifier l’accès à Azure Databricks avec un principal de service à l’aide d’OAuth (OAuth M2M). Notez la valeur de l’UUID ou de l’ID de l’application du principal de service, ainsi que la valeur du secret OAuth du principal de service.

  2. Accordez au principal de service l’accès à votre cluster ou entrepôt. Consultez Autorisations de calcul ou Gérer un entrepôt SQL.

Pour authentifier le pilote Databricks SQL pour Node.js, utilisez l’extrait de code suivant. Cet extrait suppose que vous avez défini les variables d’environnement suivantes :

  • DATABRICKS_SERVER_HOSTNAME réglé sur la valeur Nom d'hôte de serveur de votre cluster ou entrepôt SQL.
  • DATABRICKS_HTTP_PATH, réglé sur la valeur Chemin HTTP de votre cluster ou entrepôt SQL.
  • DATABRICKS_CLIENT_ID, est fixé à la valeur de l’UUID ou de l’ID de l’application du principal de service.
  • DATABRICKS_CLIENT_SECRET, définie sur la valeur Secret du secret OAuth du principal de service.

Pour définir des variables d’environnement, consultez la documentation de votre système d’exploitation.

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

Authentification par jeton Microsoft Entra ID

Pour utiliser le pilote Databricks SQL pour Node.js avec l’authentification par jeton Microsoft Entra ID, vous devez fournir le pilote Databricks SQL pour Node.js avec le jeton Microsoft Entra ID. Pour créer un jeton d’accès Microsoft Entra ID, effectuez ce qui suit :

Les jetons Microsoft Entra ID ont une durée de vie par défaut d’environ une heure. Pour créer un jeton Microsoft Entra ID, répétez ce processus.

Pour authentifier le pilote Databricks SQL pour Node.js, utilisez l’extrait de code suivant. Cet extrait suppose que vous avez défini les variables d’environnement suivantes :

  • DATABRICKS_SERVER_HOSTNAME réglé sur la valeur Nom d'hôte de serveur de votre cluster ou entrepôt SQL.
  • DATABRICKS_HTTP_PATH, réglé sur la valeur Chemin HTTP de votre cluster ou entrepôt SQL.
  • DATABRICKS_TOKEN, défini sur le jeton Microsoft Entra ID.

Pour définir des variables d’environnement, consultez la documentation de votre système d’exploitation.

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

Interroger des données

L’exemple de code suivant montre comment appeler le pilote Databricks SQL pour Node.js pour exécuter une requête SQL de base sur une ressource de calcul Azure Databricks. Cette commande retourne les deux premières lignes de la table trips dans le schéma nyctaxi du catalogue samples.

Remarque

L’exemple de code suivant montre comment utiliser un jeton d’accès personnel Azure Databricks pour l’authentification. Pour utiliser plutôt d’autres types d’authentification Azure Databricks, consultez l’article Authentification.

Cet exemple de code récupère les valeurs des variables de connexion token, server_hostname et http_path à partir d’un ensemble de variables d’environnement Azure Databricks. Ces variables d’environnement ont les noms de variables d’environnement suivantes :

  • DATABRICKS_TOKEN, qui représente votre jeton d’accès personnel Azure Databricks à partir des exigences.
  • DATABRICKS_SERVER_HOSTNAME, qui représente la valeur Nom d’hôte du serveur issue des exigences.
  • DATABRICKS_HTTP_PATH, qui représente la valeur Chemin HTTP issue des exigences.

Vous pouvez utiliser d’autres approches pour récupérer ces valeurs de variable de connexion. L’utilisation de variables d’environnement n’est qu’une seule approche parmi plusieurs.

L’exemple de code suivant montre comment appeler le connecteur Databricks SQL pour Node.js afin d’exécuter une commande SQL de base sur un cluster ou un entrepôt SQL. Cette commande retourne les deux premières lignes de la table 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);
});

Sortie :

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

Sessions

Toutes les méthodes IDBSQLSession qui renvoient des objets IOperation dans la référence API ont les paramètres communs suivants qui affectent leur comportement :

  • Le réglage runAsync sur true démarre le mode asynchrone. Les méthodes IDBSQLSession mettent les opérations dans la file d’attente et reviennent le plus rapidement possible. L'état actuel de l'objet renvoyé IOperation peut varier et le client est responsable de vérifier son état avant d'utiliser l'objet renvoyé IOperation. Consultez Opérations. La définition runAsync sur false signifie que les méthodes IDBSQLSession attendent la fin des opérations. Databricks recommande de toujours définir runAsync sur true.
  • La définition de maxRows comme une valeur non nulle permet d’obtenir des résultats directs. Avec des résultats directs, le serveur essaie d'attendre la fin des opérations, puis récupère une partie des données. En fonction de la quantité de travail que le serveur a pu effectuer dans le délai défini, les objets IOperation reviennent dans un état intermédiaire plutôt que dans un état en attente. Très souvent, toutes les métadonnées et résultats de requête sont renvoyés dans une seule requête adressée au serveur. Le serveur l'utilise maxRows pour déterminer le nombre d'enregistrements qu'il peut renvoyer immédiatement. Cependant, le morceau réel peut être d’une taille différente ; voir IDBSQLSession.fetchChunk. Les résultats directs sont activés par défaut. Databricks recommande de ne pas désactiver les résultats directs.

Opérations

Comme décrit dans Sessions, IOperation les objets renvoyés par les méthodes de session IDBSQLSession dans la référence API ne sont pas entièrement renseignés. L'opération de serveur associée peut être toujours en cours, par exemple en attendant le démarrage de l'entrepôt SQL Databricks, en exécutant la requête ou en récupérant les données. La classe IOperation cache ces détails aux utilisateurs. Par exemple, des méthodes telles que fetchAll, fetchChunk et getSchema attendent en interne la fin des opérations, puis renvoient les résultats. Vous pouvez utiliser la méthode IOperation.finished() pour attendre explicitement la fin des opérations. Ces méthodes nécessitent un rappel périodiquement appelé en attendant la fin des opérations. Définir l'option progress sur true tente de demander des données de progression supplémentaires au serveur et de les transmettre à ce rappel.

Les méthodes close et cancel peuvent être appelées à tout moment. Lorsqu'ils sont appelés, ils invalident immédiatement l'objet IOperation ; tous les appels en attente tels que fetchAll, fetchChunk et getSchema sont immédiatement annulés et une erreur est renvoyée. Dans certains cas, l'opération du serveur peut être déjà terminée et la méthode cancel affecte uniquement le client.

La méthode fetchAll appelle fetchChunk en interne et collecte toutes les données dans un tableau. Bien que cela soit pratique, cela peut provoquer des erreurs de mémoire insuffisante lorsqu'il est utilisé sur de grands ensembles de données. les options fetchAll sont généralement transmises à fetchChunk.

Récupérer des morceaux de données

La récupération de blocs de données utilise le modèle de code suivant :

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

La méthode fetchChunk de la référence API traite les données en petites portions pour réduire la consommation de mémoire. fetchChunk attend d'abord que les opérations se terminent si elles ne sont pas déjà terminées, puis appelle un rappel pendant le cycle d'attente, puis récupère le bloc de données suivant.

Vous pouvez utiliser l'option maxRows pour spécifier la taille de morceau souhaitée. Cependant, le morceau renvoyé peut avoir une taille différente, plus petite ou même parfois plus grande. fetchChunk ne tente pas de pré-extraire les données en interne, afin de les découper en parties demandées. Il envoie l'option maxRows au serveur et renvoie tout ce que le serveur renvoie. Ne confondez pas cette option maxRows avec celle de IDBSQLSession. maxRows passé à fetchChunk définit la taille de chaque morceau et ne fait rien d'autre.

Gérer les fichiers dans les volumes de catalogue Unity

Databricks SQL Driver vous permet d’écrire des fichiers locaux dans des volumesdu catalogue Unity, de télécharger des fichiers à partir de volumes et de supprimer des fichiers des volumes, comme illustré dans l’exemple suivant :

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

Configuration de la journalisation

L’enregistreur d’événements fournit des informations sur les problèmes de débogage avec le connecteur. Tous les objets DBSQLClient sont instanciés avec un enregistreur d’événements qui s’imprime sur la console, mais en passant un enregistreur d’événements personnalisé, vous pouvez envoyer ces informations à un fichier. L’exemple suivant montre comment configurer un enregistreur d’événements et modifier son niveau.

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

Pour obtenir d’autres exemples, consultez le dossier Exemples dans le référentiel databricks/databricks-sql-nodejs sur GitHub.

Test

Pour tester votre code, vous pouvez utiliser des frameworks de test JavaScript tels que Jest. Pour tester votre code dans des conditions simulées sans appeler des points de terminaison d’API REST Azure Databricks ni modifier l’état de vos comptes ou espaces de travail Azure Databricks, vous pouvez utiliser les frameworks fictifs intégrés de Jest.

Par exemple, étant donné le fichier suivant nommé helpers.js contenant une fonction getDBSQLClientWithPAT qui utilise un jeton d’accès personnel Azure Databricks pour retourner une connexion à un espace de travail Azure Databricks, une fonction getAllColumnsFromTable qui utilise la connexion pour obtenir le nombre spécifié de lignes de données dans la table (par exemple, la table trips dans le schéma nyctaxi du catalogue samples) et une fonction printResults pour imprimer le contenu des lignes de données :

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

Et étant donné le fichier suivant nommé main.js qui appelle les fonctions getDBSQLClientWithPAT, getAllColumnsFromTable et 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);
  });

Le fichier suivant nommé helpers.test.js teste si la fonction getAllColumnsFromTable retourne la réponse attendue. Au lieu de créer une connexion réelle à l’espace de travail cible, ce test simule un objet DBSQLClient. Le test simule également des données qui sont conformes au schéma et aux valeurs qui se trouvent dans les données réelles. Le test renvoie les données simulées sur la connexion simulée, puis vérifie si une des valeurs des lignes de données simulées correspond à la valeur attendue.

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

Pour TypeScript, le code précédent est similaire. Pour les tests Jest avec TypeScript, utilisez ts-jest.

Ressources supplémentaires

Informations de référence sur l'API

Classes

Classe DBSQLClient

Point d’entrée principal pour interagir avec une base de données.

Méthodes
Méthode connect

Ouvre une connexion à la base de données.

Paramètres
options

Entrez : ConnectionOptions

Ensemble d’options utilisées pour se connecter à la base de données.

Les champs host, path et les autres champs obligatoires doivent être remplis. Voir Authentification.

Exemple :


const client: DBSQLClient = new DBSQLClient();

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

Retourne : Promise<IDBSQLClient>

Méthode openSession

Ouvre une session entre DBSQLClient et la base de données.

Paramètres
requête

Entrez : OpenSessionRequest

Ensemble de paramètres facultatifs pour spécifier le schéma initial et le catalogue initial

Exemple :


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

Retourne : Promise<IDBSQLSession>

Méthode getClient

Retourne l’objet TCLIService.Client interne. Doit être appelé après la connexion de DBSQLClient.

Aucun paramètre

Renvoie TCLIService.Client

Méthode close

Ferme la connexion à la base de données et libère toutes les ressources associées sur le serveur. Tous les appels supplémentaires à ce client lèveront une erreur

Aucun paramètre.

Aucune valeur renvoyée.

Classe DBSQLSession

Les DBSQLSessions sont principalement utilisées pour l’exécution d’instructions sur la base de données, ainsi que pour diverses opérations d’extraction de métadonnées.

Méthodes
Méthode executeStatement

Exécute une instruction avec les options fournies.

Paramètres
instruction

Entrez : str

L’instruction T-SQL à exécuter.
options

Entrez : ExecuteStatementOptions

Ensemble de paramètres facultatifs pour déterminer le délai d’expiration de la requête, le nombre maximal de lignes pour les résultats directs et l’exécution asynchrone de la requête. Par défaut, maxRows est défini sur 10000. Si maxRows est défini sur null, l’opération s’exécute avec la fonctionnalité de résultats directs désactivée.

Exemple :


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

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

Retourne : Promise<IOperation>

Méthode close

Ferme la session. Doit être effectué après l’utilisation de la session.

Aucun paramètre.

Aucune valeur renvoyée.

Méthode getId

Retourne le GUID de la session.

Aucun paramètre.

Retourne : str

Méthode getTypeInfo

Retourne des informations sur les types de données pris en charge.

Paramètres
requête

Entrez : TypeInfoRequest

Paramètres de la requête.

Retourne : Promise<IOperation>

Méthode getCatalogs

Obtient la liste des catalogues.

Paramètres
requête

Entrez : CatalogsRequest

Paramètres de la requête.

Retourne : Promise<IOperation>

Méthode getSchemas

Obtient la liste des schémas.

Paramètres
requête

Entrez : SchemasRequest

Paramètres de la requête. Les champs catalogName et schemaName peuvent être utilisés à des fins de filtrage.

Retourne : Promise<IOperation>

Méthode getTables

Obtient une liste de tables.

Paramètres
requête

Entrez : TablesRequest

Paramètres de la requête. Les champs catalogName et schemaName et
tableName peuvent être utilisés pour le filtrage.

Retourne : Promise<IOperation>

Méthode getFunctions

Obtient une liste de tables.

Paramètres
requête

Entrez : FunctionsRequest

Paramètres de la requête. Le champ functionName est requis.

Retourne : Promise<IOperation>

Méthode getPrimaryKeys

Obtient la liste des clés primaires.

Paramètres
requête

Entrez : PrimaryKeysRequest

Paramètres de la requête. Les champs schemaName et tableName sont obligatoires.

Retourne : Promise<IOperation>

Méthode getCrossReference

Obtient des informations sur les clés étrangères entre deux tables.

Paramètres
requête

Entrez : CrossReferenceRequest

Paramètres de la requête. Le schéma, le parent et le nom du catalogue doivent être spécifiés pour les deux tables.

Retourne : Promise<IOperation>

Classe DBSQLOperation

Les DBSQLOperations sont créées par des DBSQLSessions et peuvent être utilisées pour extraire les résultats des instructions et vérifier leur exécution. Les données sont extraites via les fonctions fetchChunk et fetchAll.

Méthodes
Méthode getId

Retourne le GUID de l’opération.

Aucun paramètre.

Retourne : str

Méthode fetchAll

Attend la fin de l’opération, puis extrait toutes les lignes de l’opération.

Paramètres : aucun

Retourne : Promise<Array<object>>

Méthode fetchChunk

Attend la fin de l’opération, puis extrait jusqu’à un nombre spécifié de lignes à partir d’une opération.

Paramètres
options

Entrez : FetchOptions

Options utilisées pour extraire. Actuellement, la seule option est maxRows, qui correspond au nombre maximal d’objets de données à retourner dans un tableau donné.

Retourne : Promise<Array<object>>

Méthode close

Ferme l’opération et libère toutes les ressources associées. Doit être effectué quand vous avez fini d’utiliser l’opération.

Aucun paramètre.

Aucune valeur renvoyée.