re:dashでpythonを使う vol.1

[株式会社オズビジョン](http://www.oz-vision.co.jp/)の@terra_yuccoです。
現在社内のBIツールとしてre:dashを導入しておりますが、この子がただクエリ書く以外に、pythonもデータソースとして使えるらしい。
ということでC:6年/PHP:3年な初心者Pythonista、社内依頼の対応のためにPythonの道に足を踏み入れました。

あ、うちのre:dashは今のところ「2.0.0+b2990」です。びっみょーに古いです。

# vol.1 初日のチャレンジ
## そもそもpythonの文法わかんね
ググります。解決。
~~いや色々流儀が違って困ってますけどね！なんとなくrubyっぽい~~

## pythonで出力結果を作るにはどうしたらいいの
### 社内サンプルを参考にしてとりあえず足してみた
一応値はとれたものの、なぜこうなっているかがわからない。
`column`を変えればカラム名が、`value`を変えれば対象値が変化するのはわかった。それだけ。

```python
result = {}
add_result_column(result, 'column', '', 'string')
add_result_row(result, {'column' : 'value'})
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/95030/6ae6bb43-833c-fe22-48fc-d054aee42872.png)

### ドキュメンテーションがあった
大した量もない驚愕のシンプルさ。
コードがすべてを物語っている気がしますが、量も少ないのでAppendixに翻訳を付けました。
https://redash.io/help-onpremise/how-rd-works/data-source-results-format.html

### ドキュメンテーションを読んだあとで
https://github.com/getredash/redash/blob/master/redash/query_runner/python.py
以下のメソッドたちがpythonではヘルパーメソッドとして使えそうですが、ドキュメンテーションが一切ないので、実装を読まないといけなさそう。

- execute_query
- add_result_column
- add_result_row

#### execute_query

-  https://github.com/getredash/redash/blob/v2.0.0/redash/query_runner/python.py#L156-L177
- 機能サマリ
    - すごく簡単に言えば、指定したデータソースに接続し、クエリを発行するだけ
    - データソースが無かったりしたらエラーになる
    - データソースは名前でもIDでも設定可能

```python
def execute_query(data_source_name_or_id, query):
    """Run query from specific data source.
    Parameters:
    :data_source_name_or_id string|integer: Name or ID of the data source
    :query string: Query to run
    """
```

#### add_result_column
- https://github.com/getredash/redash/blob/v2.0.0/redash/query_runner/python.py#L121-L140
- 機能サマリ
    - カラムの型指定がサポートされているものかチェック
    - result["columns"][]にname, friendly_name, column_typeを設定する

```python
def add_result_column(result, column_name, friendly_name, column_type):
    """Helper function to add columns inside a Python script running in Redash in an easier way
    Parameters:
    :result dict: The result dict
    :column_name string: Name of the column, which should be consisted of lowercase latin letters or underscore.
    :friendly_name string: Name of the column for display
    :column_type string: Type of the column. Check supported data types for details.
    """
```

#### add_result_row
- https://github.com/getredash/redash/blob/v2.0.0/redash/query_runner/python.py#L143-L153
- 機能サマリ
    - result["rows"][]にvaluesをそのまま突っ込む
    - columnsの定義に合っていないと結果が出ない

```python
    def add_result_row(result, values):
        """Helper function to add one row to results set.
        Parameters:
        :result dict: The result dict
        :values dict: One row of result in dict. The key should be one of the column names. The value is the value of the column in this row.
        """
```

### それっぽい結果を作り出すコードをre:dashに書いてみた

```python
result = {}
add_result_column(result, 'id', 'id', 'integer')
add_result_column(result, 'name', 'name', 'string')
add_result_column(result, 'gender', 'gender', 'string')
add_result_column(result, 'age', 'age', 'integer')
add_result_row(result, {'id':10, 'name':'Yoshida', 'gender':'male', 'age':25})
add_result_row(result, {'id':11, 'name':'Tanaka', 'gender':'female', 'age':22})
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/95030/f82a9451-7284-65cd-b64c-3e4d1188e2ca.png)

(∩´∀｀)∩

## おわりに
とりあえずなんとかそれっぽいものできました！
次は実際のDBにクエリを投げて値を加工したいと…おもって…ます。

また次のエントリでお会いしましょう。
おしまい。

----
# Appendix
https://redash.io/help-onpremise/how-rd-works/data-source-results-format.html
## データソース結果のフォーマットについて
使えるのは以下の型

- integer
- float
- boolean
- string
- datetime
- date

re:dash内の全てのデータソースは以下に示す結果をJSON形式で返します。

```
{
    "columns" : [
        {
           // 必須: 結果内で重複しないカラム名を付ける
           "name" : "COLUMN_NAME",
           // 必須: カラムのフレンドリ名。現在は未使用なのでnameと一緒で大丈夫
           "friendly_name" : "FRIENDLY_NAME",
           // サポートされてる型はinteger, float, boolean, string (デフォルト), datetime (ISO-8601形式)
           // 型が不明ならstringを使うこと 
           "type" : "VALUE_TYPE"
        },
        ...
    ],
    "rows" : [
        {
            // nameにはカラム定義に含まれているnameを使う
            // VALUEはJSONとして有効な値を使う。日付型はISO-8601形式の文字列で。
            "name" : VALUE,
            "name2" : VALUE2
        },
        ...
    ]
}
```
例:

```
{
  "columns": [
    {
      "name": "date",
      "type": "date",
      "friendly_name": "date"
    },
    {
      "name": "day_number",
      "type": "integer",
      "friendly_name": "day_number"
    },
    {
      "name": "value",
      "type": "integer",
      "friendly_name": "value"
    },
    {
      "name": "total",
      "type": "integer",
      "friendly_name": "total"
    }
  ],
  "rows": [
    {
      "value": 40832,
      "total": 53141,
      "day_number": 0,
      "date": "2014-01-30"
    },
    {
      "value": 27296,
      "total": 53141,
      "day_number": 1,
      "date": "2014-01-30"
    },
    {
      "value": 22982,
      "total": 53141,
      "day_number": 2,
      "date": "2014-01-30"
    }
  ]
}
```