bigquery-client という gem を作った

BigQuery の API を Ruby から扱う [bigquery-client](https://github.com/ttanimichi/bigquery-client) という gem を作りました。

https://github.com/ttanimichi/bigquery-client

もともと BigQuery の gem といえば [abronte/BigQuery](https://github.com/abronte/BigQuery) があったんですが、個人的に欲しい機能がなかったのと、当時所属していたプロジェクトでは BigQuery を多用していて、もっと汎用的なものが必要だったので新しく作ることにしました。

## インストール

```
% gem install bigquery-client
```

## 基本的な使い方

```ruby
require "bigquery-client"

client = BigQuery::Client.new(
  project:                "your-project-42",
  dataset:                "your_dataset",
  email:                  "1234567890@developer.gserviceaccount.com",
  private_key_path:       "/path/to/keyfile.p12",
  private_key_passphrase: "notasecret",
  auth_method:            "private_key"
)

client.sql "SELECT * FROM publicdata:samples.wikipedia LIMIT 10"
```

## INSERT

`BigQuery::Client#insert`を使うとレコードの INSERT ができます。内部的には Streaming Insert (insertAll) を使用しています。

```ruby
client.insert("table_name", nickname: "john", age: 42)

# 配列で渡せば複数行をまとめて insert できる
rows = [
  { nickname: "foo", age: 43 },
  { nickname: "bar", age: 44 }
]
client.insert("table_name", rows)
```

## CREATE TABLE

テーブルを作成します。

```ruby
schema = [
  { name: "foo", type: "timestamp" },
  { name: "bar", type: "string"    }
]
client.create_table("new_table_name", schema)
```

## SELECT

手軽に SELECT したい場合は `BigQuery::Client#sql` を使うのが良いです。

```ruby
client.sql "SELECT * FROM dataset_name.table_name LIMIT 100"
```

BigQuery には INTEGER, STRING, BOOLEAN, FLOAT, TIMESTAMP といったデータ型がありますが、`BigQuery::Client#sql` はこれらのカラムをパースして、ハッシュの配列に詰めて結果を返します。

```
client.sql "SELECT born_alive_alive,is_male,weight_pounds FROM publicdata:samples.natality LIMIT 2"
#=> [{"born_alive_alive"=>0, "is_male"=>true, "weight_pounds"=>8.437090766739999}, {"born_alive_alive"=>2, "is_male"=>true, "weight_pounds"=>6.8122838958}]
```

## tables

データセット内にあるテーブルの一覧を返します。

```ruby
client.tables
#=> ["your_table", "your_table2", "your_table3"]
```

## fetch_schema

テーブル名を指定してスキーマを取得します。

```ruby
client.fetch_schema("table_name")
#=> [{"name"=>"nickname", "type"=>"STRING"}, {"name"=>"age", "type"=>"INTEGER"}]
```

## DELETE

テーブル名を指定してテーブルを削除します。

```ruby
client.delete_table('table_name')
```

## Datasets API

bigquery-client はデータセットを扱う API もサポートしています。データセットを扱うだけならば`:dataset`を指定する必要はありません。

```ruby
# `:dataset`は省いても OK
client = BigQuery::Client.new(
  project:                "your-project-42",
  email:                  "1234567890@developer.gserviceaccount.com",
  private_key_path:       "/path/to/keyfile.p12",
  private_key_passphrase: "notasecret",
  auth_method:            "private_key"
)

# データセットの一覧を取得
client.datasets
#=> ["your_dataset", "your_dataset2"]

# データセットを作成
client.create_dataset('dataset_name')

# データセットを削除
client.delete_dataset('dataset_name')
```

## Projects API

プロジェクトを扱う API もサポートしています。プロジェクトを扱うだけならば`:dataset`や`:project`を指定する必要はありません。

```ruby
# `:dataset`と`:project`は省いても OK
client = BigQuery::Client.new(
  email:                  "1234567890@developer.gserviceaccount.com",
  private_key_path:       "/path/to/keyfile.p12",
  private_key_passphrase: "notasecret",
  auth_method:            "private_key"
)

# プロジェクトの一覧を取得
client.projects
#=> ["your_project"]
```

## 豆知識

bigquery-client は手軽に扱えることを重視して開発しました。例えば `BigQuery::Client#datasets` は API のレスポンスに含まれる、おそらくは普通の用途では使用しないであろう情報を落として、データセット名だけをただの文字列の配列として返すようになっています。

```ruby
client.datasets #=> ["your_dataset", "your_dataset2"]
```

ですが、例えば bigquery-client を使用した gem を作る場合など、突っ込んだ用途で使用する場合には、`BigQuery::Client#datasets` が捨ててしまう一部の情報が必要になる場合もあるかと思います。そういった用途のために、bigquery-clietnt には API を叩いて素のレスポンスを返すだけのメソッドを別途用意してあります。これらのメソッドも private になってはおらず、利用できます。

```ruby
# 内部的には list_datasets を使用
def datasets
  list_datasets['datasets'].map {|dataset| dataset['datasetReference']['datasetId'] }
end

# こっちも public メソッド
def list_datasets
  access_api(
    api_method: bigquery.datasets.list
  )
end
```

ref. https://github.com/ttanimichi/bigquery-client/blob/9b24655e63d40551effacb82dceac7a3d8ba23b7/lib/bigquery-client/datasets.rb#L5-L13

## お願い: 足りない機能は Pull Request ください

BigQuery の API にはエンドポイントが数多くあり、すべてのエンドポイントをサポートしたうえで各メソッドの使い勝手を改善していくのには結構な労力を必要としています。僕は僕自身が必要としている機能を優先的に作っているので、使い方によっては機能が足りない場合があるかもしれません。そういった場合は気軽に Pull Request を送ってもらえると嬉しいです :smiley:

https://github.com/ttanimichi/bigquery-client/pulls