次の方法で共有


Databricks SQL Driver for Go

Databricks SQL Driver for Go は、Go コードを使用して Azure Databricks コンピューティング リソースで SQL コマンドを実行できる Go ライブラリです。 この記事は、Databricks SQL Driver for Go の READMEAPI リファレンスを補足するものです。

要件

Databricks SQL Driver for Go の概要

  1. Go 1.20 以上が既にインストールされ、既存の Go コード プロジェクトが既に作成されている開発マシンで、go mod init コマンドを実行して、Go コードの依存関係を追跡する go.mod ファイルを作成します。例:

    go mod init sample
    
  2. go mod edit -require コマンドを実行して、Databricks SQL Driver for Go パッケージへの依存関係を設定します。v1.5.2 は、リリースに記載されている Databricks SQL Driver for Go パッケージの最新バージョンに置き換えてください。

    go mod edit -require github.com/databricks/databricks-sql-go@v1.5.2
    

    go.mod ファイルは次のようになります。

    module sample
    
    go 1.20
    
    require github.com/databricks/databricks-sql-go v1.5.2
    
  3. プロジェクト内で、Databricks SQL Driver for Go をインポートする Go コード ファイルを作成します。 次の例では、次のコンテンツの main.go という名前のファイルで、Azure Databricks ワークスペース内のすべてのクラスターを一覧表示します。

    package main
    
    import (
      "database/sql"
      "os"
      _ "github.com/databricks/databricks-sql-go"
    )
    
    func main() {
      dsn := os.Getenv("DATABRICKS_DSN")
    
      if dsn == "" {
        panic("No connection string found. " +
         "Set the DATABRICKS_DSN environment variable, and try again.")
      }
    
      db, err := sql.Open("databricks", dsn)
      if err != nil {
        panic(err)
      }
      defer db.Close()
    
      if err := db.Ping(); err != nil {
        panic(err)
      }
    }
    
  4. go mod tidy コマンドを実行して、不足しているモジュール依存関係を追加します。

    go mod tidy
    

    Note

    エラー go: warning: "all" matched no packages が発生した場合は、Databricks SQL Driver for Go をインポートする Go コード ファイルを追加するのを忘れています。

  5. go mod vendor コマンドを実行して、main モジュール内のパッケージのビルドとテストをサポートするために必要なすべてのパッケージのコピーを作成します。

    go mod vendor
    
  6. 必要に応じて、Azure Databricks 認証のための DATABRICKS_DSN 環境変数を設定するコードを変更します。 「DSN 接続文字列を使用して接続する」も参照してください。

  7. go run コマンドを実行して、main.go という名前のファイルを想定して Go コード ファイルを実行します。

    go run main.go
    
  8. エラーが返されない場合は、Azure Databricks ワークスペースで Databricks SQL Driver for Go を正常に認証し、そのワークスペース内の実行中の Azure Databricks クラスターまたは SQL ウェアハウスに接続しています。

DSN 接続文字列を使用して接続する

クラスターと SQL ウェアハウスにアクセスするには、sql.Open() を使用して、データ ソース名 (DSN) 接続文字列を介してデータベース ハンドルを作成します。 このコード例では、DATABRICKS_DSN という名前の環境変数から DSN 接続文字列を取得します。

package main

import (
  "database/sql"
  "os"
  _ "github.com/databricks/databricks-sql-go"
)

func main() {
  dsn := os.Getenv("DATABRICKS_DSN")

  if dsn == "" {
    panic("No connection string found. " +
          "Set the DATABRICKS_DSN environment variable, and try again.")
  }

  db, err := sql.Open("databricks", dsn)
  if err != nil {
    panic(err)
  }
  defer db.Close()

  if err := db.Ping(); err != nil {
    panic(err)
  }
}

DSN 接続文字列を正しい形式で指定するには、「認証」の DSN 接続文字列の例を参照してください。 たとえば、Azure Databricks 個人用アクセス トークン認証の場合、次の構文を使用します。ここで各部分は次のとおりです。

  • <personal-access-token> は、要件の Azure Databricks 個人用アクセス トークンを表します。
  • <server-hostname> は要件のサーバー ホスト名の値です。
  • <port-number> は、要件のポートの値です。通常 443 です。
  • <http-path> は要件の HTTP パスの値です。
  • <paramX=valueX> は、この記事で後述する 1 つ以上の省略可能なパラメーターです。
token:<personal-access-token>@<server-hostname>:<port-number>/<http-path>?<param1=value1>&<param2=value2>

たとえば、クラスターの場合:

token:dapi12345678901234567890123456789012@adb-1234567890123456.7.azuredatabricks.net:443/sql/protocolv1/o/1234567890123456/1234-567890-abcdefgh

たとえば、SQL ウェアハウスの場合:

token:dapi12345678901234567890123456789012@adb-1234567890123456.7.azuredatabricks.net:443/sql/1.0/endpoints/a1b234c5678901d2

注意

セキュリティのベスト プラクティスとして、この DSN 接続文字列を Go コードにハードコーディングすることは避けてください。 代わりに、セキュリティで保護された場所からこの DSN 接続文字列を取得する必要があります。 たとえば、この記事の前半のコード例では環境変数が使用されています。

省略可能なパラメーター

  • サポートされる省略可能な接続パラメータを、<param=value> に指定できます。 よく使われるものには、次が含まれます。
    • catalog: セッションの初期カタログ名を設定します。
    • schema: セッションの初期スキーマ名を設定します。
    • maxRows: 要求ごとにフェッチされる行の最大数を設定します。 既定では、 10000です。
    • timeout: サーバー クエリ実行のタイムアウト (秒単位) を追加します。 既定では、タイムアウトはありません。
    • userAgentEntry: パートナーを識別するために使用されます。 詳細については、パートナーのドキュメントを参照してください。
  • サポートされる省略可能なセッション パラメータを、param=value に指定できます。 よく使われるものには、次が含まれます。
    • ansi_mode: ブール値の文字列。 セッション ステートメントが ANSI SQL 仕様で指定された規則に従う場合は true。 システムの既定値は false です。
    • timezone: 文字列 (例: America/Los_Angeles)。 セッションのタイムゾーンを設定します。 システムの既定値は UTC です。

たとえば、SQL ウェアハウスの場合:

token:dapi12345678901234567890123456789012@adb-1234567890123456.7.azuredatabricks.net:443/sql/1.0/endpoints/a1b234c5678901d2?catalog=hive_metastore&schema=example&maxRows=100&timeout=60&timezone=America/Sao_Paulo&ansi_mode=true

NewConnector 関数を使用して接続する

代わりに、sql.OpenDB() を使用して、dbsql.NewConnector() で作成された新しいコネクタ オブジェクトを介してデータベース ハンドルを作成します (新しいコネクタ オブジェクトを使用して Azure Databricks クラスターと SQL ウェアハウスに接続するには、v1.0.0 以上の Databricks SQL Driver for Go が必要です)。 次に例を示します。

package main

import (
  "database/sql"
  "os"
  dbsql "github.com/databricks/databricks-sql-go"
)

func main() {
  connector, err := dbsql.NewConnector(
    dbsql.WithAccessToken(os.Getenv("DATABRICKS_ACCESS_TOKEN")),
    dbsql.WithServerHostname(os.Getenv("DATABRICKS_HOST")),
    dbsql.WithPort(443),
    dbsql.WithHTTPPath(os.Getenv("DATABRICKS_HTTP_PATH")),
  )
  if err != nil {
    panic(err)
  }

  db := sql.OpenDB(connector)
  defer db.Close()

  if err := db.Ping(); err != nil {
    panic(err)
  }
}

一連の正しい NewConnector 設定を指定するには、「認証」の例を参照してください。

Note

セキュリティのベスト プラクティスとして、NewConnector 設定を Go コードにハードコーディングしないようにする必要があります。 代わりに、セキュリティで保護された場所からこれらの値を取得する必要があります。 たとえば、上記のコードでは環境変数が使用されています。

より頻繁に使用される関数オプションには、次が含まれます。

  • WithAccessToken(<access-token>): 要件の Azure Databricks 個人用アクセス トークン。 必須の string
  • WithServerHostname(<server-hostname>): 要件のサーバー ホスト名の値。 必須の string
  • WithPort(<port>): サーバーのポート番号 (通常は 443)。 必須の int
  • WithHTTPPath(<http-path>): 要件の HTTP パスの値。 必須の string
  • WithInitialNamespace(<catalog>, <schema>): セッション内のカタログとスキーマ名。 省略可能な string, string
  • WithMaxRows(<max-rows>): 要求ごとにフェッチされる行の最大数。 既定値は 10000. です。省略可能な int
  • WithSessionParams(<params-map>): "timezone" と "ansi_mode" を含むセッション パラメーター。 省略可能な map[string]string
  • WithTimeout(<timeout>). サーバー クエリ実行のタイムアウト (time.Duration 単位)。 既定では、タイムアウトはありません。 省略可能。
  • WithUserAgentEntry(<isv-name-plus-product-name>). パートナーを識別するために使用されます。 詳細については、パートナーのドキュメントを参照してください。 省略可能な string

次に例を示します。

connector, err := dbsql.NewConnector(
  dbsql.WithAccessToken(os.Getenv("DATABRICKS_ACCESS_TOKEN")),
  dbsql.WithServerHostname(os.Getenv("DATABRICKS_HOST")),
  dbsql.WithPort(443),
  dbsql.WithHTTPPath(os.Getenv("DATABRICKS_HTTP_PATH")),
  dbsql.WithInitialNamespace("samples", "nyctaxi"),
  dbsql.WithMaxRows(100),
  dbsql.SessionParams(map[string]string{"timezone": "America/Sao_Paulo", "ansi_mode": "true"}),
  dbsql.WithTimeout(time.Minute),
  dbsql.WithUserAgentEntry("example-user"),
)

認証

Databricks SQL Driver for Go は、次の Azure Databricks 認証の種類をサポートしています。

Databricks SQL Driver for Go では、次の Azure Databricks 認証の種類はまだサポートされません。

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

Databricks SQL Driver for Go を Azure Databricks 個人アクセス トークン認証で使用するには最初に Azure Databricks の個人用アクセス トークンを作成する必要があります。 この手順の詳細については、「 ワークスペース ユーザーの Azure Databricks 個人用アクセス トークンを参照してください。

DSN 接続文字列および「DSN 接続文字列を使用して接続する」のコード例を使用して Databricks SQL Driver for Go を認証するには、次の DSN 接続文字列構文を使用します。ここで各部分は次のとおりです。

  • <personal-access-token> は、要件の Azure Databricks 個人用アクセス トークンを表します。
  • <server-hostname> は要件のサーバー ホスト名の値です。
  • <port-number> は、要件のポートの値です。通常 443 です。
  • <http-path> は要件の HTTP パスの値です。

この記事で前に挙げた 1 つ以上の省略可能なパラメーターを追加することもできます。

token:<personal-access-token>@<server-hostname>:<port-number>/<http-path>

NewConnector 関数を使用して Databricks SQL Driver for Go を認証するには、次のコード スニペットおよび「NewConnector 関数を使用して接続する」のコード例を使用します。これは、次の環境変数を設定していることを想定しています。

  • DATABRICKS_SERVER_HOSTNAME が、クラスターまたは SQL ウェアハウスのサーバー ホスト名の値に設定されていること。
  • DATABRICKS_HTTP_PATH が、クラスターまたは SQL ウェアハウスの HTTP パスの値に設定されていること。
  • DATABRICKS_TOKEN が、Azure Databricks 個人用アクセス トークンに設定されていること。

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

connector, err := dbsql.NewConnector(
  dbsql.WithServerHostname(os.Getenv("DATABRICKS_SERVER_HOSTNAME")),
  dbsql.WithHTTPPath(os.Getenv("DATABRICKS_HTTP_PATH")),
  dbsql.WithPort(443),
  dbsql.WithAccessToken(os.Getenv("DATABRICKS_TOKEN")),
)

Microsoft Entra ID トークン認証

Databricks SQL Driver for Go は、Azure Databricks ユーザーまたは Microsoft Entra ID サービス プリンシパルの Microsoft Entra ID トークンをサポートします。

Microsoft Entra ID アクセス トークンを作成するには、次の操作を行います。

  • Azure Databricks ユーザーの場合は、Azure CLI を使用できます。 「Azure CLI を使用してユーザーの Microsoft Entra ID トークンを取得する」を参照してください。

    Microsoft Entra ID トークンの既定の有効期間は約 1 時間です。 新しい Microsoft Entra ID トークンを作成するには、このプロセスを繰り返します。

    DSN 接続文字列および「DSN 接続文字列を使用して接続する」のコード例を使用して Databricks SQL Driver for Go を認証するには、次の DSN 接続文字列構文を使用します。ここで各部分は次のとおりです。

    • <microsoft-entra-id-token> は、ご使用の Microsoft Entra ID トークンです。
    • <server-hostname> は要件のサーバー ホスト名の値です。
    • <port-number> は、要件のポートの値です。通常 443 です。
    • <http-path> は要件の HTTP パスの値です。

    この記事で前に挙げた 1 つ以上の省略可能なパラメーターを追加することもできます。

    token:<microsoft-entra-id-token>@<server-hostname>:<port-number>/<http-path>
    

    NewConnector 関数を使用して Databricks SQL Driver for Go を認証するには、次のコード スニペットおよび「NewConnector 関数を使用して接続する」のコード例を使用します。これは、次の環境変数を設定していることを想定しています。

    • DATABRICKS_SERVER_HOSTNAME が、クラスターまたは SQL ウェアハウスのサーバー ホスト名の値に設定されていること。
    • DATABRICKS_HTTP_PATH が、クラスターまたは SQL ウェアハウスの HTTP パスの値に設定されていること。
    • DATABRICKS_TOKEN が、Microsoft Entra ID トークンに設定されていること。

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

    connector, err := dbsql.NewConnector(
      dbsql.WithServerHostname(os.Getenv("DATABRICKS_SERVER_HOSTNAME")),
      dbsql.WithHTTPPath(os.Getenv("DATABRICKS_HTTP_PATH")),
      dbsql.WithPort(443),
      dbsql.WithAccessToken(os.Getenv("DATABRICKS_TOKEN")),
    )
    

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

Databricks SQL Driver for Go バージョン 1.5.0 以上では、OAuth ユーザー対マシン (U2M) 認証をサポートしています。

DSN 接続文字列および「DSN 接続文字列を使用して接続する」のコード例を使用して Databricks SQL Driver for Go を使用するには、次の DSN 接続文字列構文を使用します。ここで各部分は次のとおりです。

  • <server-hostname> は要件のサーバー ホスト名の値です。
  • <port-number> は、要件のポートの値です。通常 443 です。
  • <http-path> は要件の HTTP パスの値です。

この記事で前に挙げた 1 つ以上の省略可能なパラメーターを追加することもできます。

<server-hostname>:<port-number>/<http-path>?authType=OauthU2M

NewConnector 関数を使用して Databricks SQL Driver for Go を認証するには、まず import 宣言に次を追加する必要があります。

"github.com/databricks/databricks-sql-go/auth/oauth/u2m"

次に、次のコード スニペットおよび「NewConnector 関数を使用して接続する」のコード例を使用します。これは、次の環境変数を設定していることを想定しています。

  • DATABRICKS_SERVER_HOSTNAME が、クラスターまたは SQL ウェアハウスのサーバー ホスト名の値に設定されていること。
  • DATABRICKS_HTTP_PATH が、クラスターまたは SQL ウェアハウスの HTTP パスの値に設定されていること。

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

authenticator, err := u2m.NewAuthenticator(os.Getenv("DATABRICKS_SERVER_HOSTNAME"), 1*time.Minute)
if err != nil {
  panic(err)
}

connector, err := dbsql.NewConnector(
  dbsql.WithServerHostname(os.Getenv("DATABRICKS_SERVER_HOSTNAME")),
  dbsql.WithHTTPPath(os.Getenv("DATABRICKS_HTTP_PATH")),
  dbsql.WithPort(443),
  dbsql.WithAuthenticator(authenticator),
)

OAuth マシン間 (M2M) 認証

Databricks SQL Driver for Go バージョン 1.5.2 以上では、OAuth マシン対マシン (M2M) 認証をサポートしています。

OAuth M2M 認証を使用して Databricks SQL Driver for Go を使用するには、次を行う必要があります。

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

    サービスプリンシパルと OAuth シークレットを作成するには、「OAuth(OAuth M2M)を使用してサービスプリンシパルで Azure Databricks へのアクセスを認証する」を参照してください。 サービス プリンシパルの UUID またはアプリケーション ID の値と、サービス プリンシパルの OAuth シークレットのシークレットを書き留めておいてください。

  2. そのサービス プリンシパルにクラスターまたはウェアハウスへのアクセス権を付与します。

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

DSN 接続文字列および「DSN 接続文字列を使用して接続する」のコード例を使用して Databricks SQL Driver for Go を認証するには、次の DSN 接続文字列構文を使用します。ここで各部分は次のとおりです。

  • <server-hostname> は要件のサーバー ホスト名の値です。
  • <port-number> は、要件のポートの値です。通常 443 です。
  • <http-path> は要件の HTTP パスの値です。
  • <client-id> は、サービス プリンシパルの UUID またはアプリケーション ID の値です。
  • <client-secret> は、サービス プリンシパルの OAuth シークレットの [シークレット] 値です。

この記事で前に挙げた 1 つ以上の省略可能なパラメーターを追加することもできます。

<server-hostname>:<port-number>/<http-path>?authType=OAuthM2M&clientID=<client-id>&clientSecret=<client-secret>

NewConnector 関数を使用して Databricks SQL Driver for Go を認証するには、まず import 宣言に次を追加する必要があります。

"github.com/databricks/databricks-sql-go/auth/oauth/m2m"

次に、次のコード スニペットおよび「NewConnector 関数を使用して接続する」のコード例を使用します。これは、次の環境変数を設定していることを想定しています。

  • DATABRICKS_SERVER_HOSTNAME が、クラスターまたは SQL ウェアハウスのサーバー ホスト名の値に設定されていること。
  • DATABRICKS_HTTP_PATH が、クラスターまたは SQL ウェアハウスの HTTP パスの値に設定されていること。
  • DATABRICKS_CLIENT_ID。サービス プリンシパルの UUID またはアプリケーション ID の値に設定します。
  • DATABRICKS_CLIENT_SECRET が、サービス プリンシパルの OAuth シークレットの [シークレット] 値に設定されていること。

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

authenticator := m2m.NewAuthenticator(
  os.Getenv("DATABRICKS_CLIENT_ID"),
  os.Getenv("DATABRICKS_CLIENT_SECRET"),
  os.Getenv("DATABRICKS_SERVER_HOSTNAME"),
)

connector, err := dbsql.NewConnector(
  dbsql.WithServerHostname(os.Getenv("DATABRICKS_SERVER_HOSTNAME")),
  dbsql.WithHTTPPath(os.Getenv("DATABRICKS_HTTP_PATH")),
  dbsql.WithPort(443),
  dbsql.WithAuthenticator(authenticator),
)

クエリ データ

次のコード例では、Databricks SQL Driver for Go を呼び出して、Azure Databricks コンピューティング リソースで基本的な SQL クエリを実行する方法を示します。 このコマンドを使用すると、samples カタログの nyctaxi スキーマの trips テーブルから最初の 2 行が返されます。

このコード例では、DATABRICKS_DSN という名前の環境変数から DSN 接続文字列を取得します。

package main

import (
  "database/sql"
  "fmt"
  "os"
  "time"

  _ "github.com/databricks/databricks-sql-go"
)

func main() {
  dsn := os.Getenv("DATABRICKS_DSN")

  if dsn == "" {
    panic("No connection string found." +
          "Set the DATABRICKS_DSN environment variable, and try again.")
  }

  db, err := sql.Open("databricks", dsn)
  if err != nil {
    panic(err)
  }

  defer db.Close()

  var (
    tpep_pickup_datetime  time.Time
    tpep_dropoff_datetime time.Time
    trip_distance         float64
    fare_amount           float64
    pickup_zip            int
    dropoff_zip           int
  )

  rows, err := db.Query("SELECT * FROM samples.nyctaxi.trips LIMIT 2")
  if err != nil {
    panic(err)
  }

  defer rows.Close()

  fmt.Print("tpep_pickup_datetime,",
    "tpep_dropoff_datetime,",
    "trip_distance,",
    "fare_amount,",
    "pickup_zip,",
    "dropoff_zip\n")

  for rows.Next() {
    err := rows.Scan(&tpep_pickup_datetime,
      &tpep_dropoff_datetime,
      &trip_distance,
      &fare_amount,
      &pickup_zip,
      &dropoff_zip)
    if err != nil {
      panic(err)
    }

    fmt.Print(tpep_pickup_datetime, ",",
      tpep_dropoff_datetime, ",",
      trip_distance, ",",
      fare_amount, ",",
      pickup_zip, ",",
      dropoff_zip, "\n")
  }

  err = rows.Err()
  if err != nil {
    panic(err)
  }
}

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

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

package main

import (
  "context"
  "database/sql"
  "os"

  _ "github.com/databricks/databricks-sql-go"
  "github.com/databricks/databricks-sql-go/driverctx"
)

func main() {
  dsn := os.Getenv("DATABRICKS_DSN")

  if dsn == "" {
    panic("No connection string found." +
      "Set the DATABRICKS_DSN environment variable, and try again.")
  }

  db, err := sql.Open("databricks", dsn)
  if err != nil {
    panic(err)
  }
  defer db.Close()

  // For writing local files to volumes and downloading files from volumes,
  // you must first specify the path to the local folder that contains the
  // files to be written or downloaded.
  // For multiple folders, add their paths to the following string array.
  // For deleting files in volumes, this string array is ignored but must
  // still be provided, so in that case its value can be set for example
  // to an empty string.
  ctx := driverctx.NewContextWithStagingInfo(
    context.Background(),
    []string{"/tmp/"},
  )

  // Write a local file to the path in the specified volume.
  // Specify OVERWRITE to overwrite any existing file in that path.
  db.ExecContext(ctx, "PUT '/tmp/my-data.csv' INTO '/Volumes/main/default/my-volume/my-data.csv' OVERWRITE")

  // Download a file from the path in the specified volume.
  db.ExecContext(ctx, "GET '/Volumes/main/default/my-volume/my-data.csv' TO '/tmp/my-downloaded-data.csv'")

  // Delete a file from the path in the specified volume.
  db.ExecContext(ctx, "REMOVE '/Volumes/main/default/my-volume/my-data.csv'")

  db.Close()
}

ログ機能

github.com/databricks/databricks-sql-go/logger を使用し、Databricks SQL Driver for Go から出力されるメッセージをログに記録します。 次のコード例では、sql.Open() を使用し、DSN 接続文字列からデータベース ハンドルを作成します。 このコード例では、DATABRICKS_DSN という名前の環境変数から DSN 接続文字列を取得します。 debug レベル以下で出力されるすべてのログ メッセージは、results.log ファイルに書き込まれます。

package main

import (
  "database/sql"
  "io"
  "log"
  "os"

  _ "github.com/databricks/databricks-sql-go"
  dbsqllog "github.com/databricks/databricks-sql-go/logger"
)

func main() {
  dsn := os.Getenv("DATABRICKS_DSN")

  // Use the specified file for logging messages to.
  file, err := os.Create("results.log")
  if err != nil {
    log.Fatal(err)
  }
  defer file.Close()

  writer := io.Writer(file)

  // Log messages at the debug level and below.
  if err := dbsqllog.SetLogLevel("debug"); err != nil {
    log.Fatal(err)
  }

  // Log messages to the file.
  dbsqllog.SetLogOutput(writer)

  if dsn == "" {
    panic("Error: Cannot connect. No connection string found. " +
      "Set the DATABRICKS_DSN environment variable, and try again.")
  }

  db, err := sql.Open("databricks", dsn)
  if err != nil {
    panic(err)
  }
  defer db.Close()

  if err := db.Ping(); err != nil {
    panic(err)
  }
}

テスト

コードをテストするには、testing 標準ライブラリなどの Go テスト フレームワークを使用します。 Azure Databricks REST API エンドポイントを呼び出したり、Azure Databricks アカウントまたはワークスペースの状態を変更したりせずに、シミュレートされた条件下でコードをテストするには、testfify などの Go モック ライブラリを使用します。

たとえば、Azure Databricks ワークスペース接続を返す GetDBWithDSNPAT 関数、samples カタログの nyctaxi スキーマの trips テーブルからデータを返す GetNYCTaxiTrips 関数、返されたデータを出力する PrintNYCTaxiTrips を含む、helpers.go という名前の次のファイルがあるとします。

package main

import (
  "database/sql"
  "fmt"
  "strconv"
  "time"
)

func GetDBWithDSNPAT(dsn string) (*sql.DB, error) {
  db, err := sql.Open("databricks", dsn)
  if err != nil {
    return nil, err
  }
  return db, nil
}

func GetNYCTaxiTrips(db *sql.DB, numRows int) (*sql.Rows, error) {
  rows, err := db.Query("SELECT * FROM samples.nyctaxi.trips LIMIT " + strconv.Itoa(numRows))
  if err != nil {
    return nil, err
  }
  return rows, nil
}

func PrintNYCTaxiTrips(rows *sql.Rows) {
  var (
    tpep_pickup_datetime  time.Time
    tpep_dropoff_datetime time.Time
    trip_distance         float64
    fare_amount           float64
    pickup_zip            int
    dropoff_zip           int
  )

  fmt.Print(
    "tpep_pickup_datetime,",
    "tpep_dropoff_datetime,",
    "trip_distance,",
    "fare_amount,",
    "pickup_zip,",
    "dropoff_zip\n",
  )

  for rows.Next() {
    err := rows.Scan(
      &tpep_pickup_datetime,
      &tpep_dropoff_datetime,
      &trip_distance,
      &fare_amount,
      &pickup_zip,
      &dropoff_zip,
    )
    if err != nil {
      panic(err)
    }

    fmt.Print(
      tpep_pickup_datetime, ",",
      tpep_dropoff_datetime, ",",
      trip_distance, ",",
      fare_amount, ",",
      pickup_zip, ",",
      dropoff_zip, "\n",
    )
  }

  err := rows.Err()
  if err != nil {
    panic(err)
  }
}

また、これらの関数を呼び出す、main.go という名前の次のファイルがあるとします。

package main

import (
  "os"
)

func main() {
  db, err := GetDBWithDSNPAT(os.Getenv("DATABRICKS_DSN"))
  if err != nil {
    panic(err)
  }

  rows, err := GetNYCTaxiTrips(db, 2)
  if err != nil {
    panic(err)
  }

  PrintNYCTaxiTrips(rows)
}

helpers_test.go という名前の次のファイルは、GetNYCTaxiTrips 関数が、想定される応答を返すかどうかをテストします。 このテストでは、ターゲット ワークスペースへの実際の接続を作成するのではなく、sql.DB オブジェクトをモックします。 また、このテストでは、実際のデータ内にあるスキーマと値に準拠するデータをモックします。 テストでは、モックされた接続を介してモックされたデータが返され、モックされたデータ行の値のいずれかが期待値と一致するかどうかを確認します。

package main

import (
  "database/sql"
  "testing"

  "github.com/stretchr/testify/assert"
  "github.com/stretchr/testify/mock"
)

// Define an interface that contains a method with the same signature
// as the real GetNYCTaxiTrips function that you want to test.
type MockGetNYCTaxiTrips interface {
  GetNYCTaxiTrips(db *sql.DB, numRows int) (*sql.Rows, error)
}

// Define a struct that represents the receiver of the interface's method
// that you want to test.
type MockGetNYCTaxiTripsObj struct {
  mock.Mock
}

// Define the behavior of the interface's method that you want to test.
func (m *MockGetNYCTaxiTripsObj) GetNYCTaxiTrips(db *sql.DB, numRows int) (*sql.Rows, error) {
  args := m.Called(db, numRows)
  return args.Get(0).(*sql.Rows), args.Error(1)
}

func TestGetNYCTaxiTrips(t *testing.T) {
  // Instantiate the receiver.
  mockGetNYCTaxiTripsObj := new(MockGetNYCTaxiTripsObj)

  // Define how the mock function should be called and what it should return.
  // We're not concerned with whether the actual database is connected to--just
  // what is returned.
  mockGetNYCTaxiTripsObj.On("GetNYCTaxiTrips", mock.Anything, mock.AnythingOfType("int")).Return(&sql.Rows{}, nil)

  // Call the mock function that you want to test.
  rows, err := mockGetNYCTaxiTripsObj.GetNYCTaxiTrips(nil, 2)

  // Assert that the mock function was called as expected.
  mockGetNYCTaxiTripsObj.AssertExpectations(t)

  // Assert that the mock function returned what you expected.
  assert.NotNil(t, rows)
  assert.Nil(t, err)
}

GetNYCTaxiTrips 関数には SELECT ステートメントが含まれ、そのため、trips テーブルの状態が変更されないため、モックはこの例では完全に不要です。 ただし、モックの場合、ワークスペースとの実際の接続が行われるのを待つことなく、テストを速やかに実行できます。 また、モックの場合、INSERT INTOUPDATEDELETE FROM など、テーブルの状態を変更する可能性のある関数に対してシミュレーション テストを複数回実行できます。

その他のリソース