Fusion Tables×Google Apps Script（Webアプリケーション作成編2）

前回はFusion TablesのAPIを利用して、自前のWebアプリケーションからFusion Tablesへデータを追加したり、参照できるようにしました。
今回はそこから拡張して、操作の対象となるテーブルを選択できるようにしたり、テーブル自体を削除できるように実装していきます。

#実装内容
今回は全て説明していると長くなってしまうので、Fusion Tables APIの利用における部分を中心に、コードを元に説明していきます。


##fusionTableAPI.gs（サーバサイドの処理）

```lang:fusionTableAPI.gs
var tableId;

function doGet() {
  var output = HtmlService.createTemplateFromFile('index');
  return output.evaluate().setSandboxMode(HtmlService.SandboxMode.IFRAME);
}

function getInsertPage(setTableId){
  tableId = setTableId;
  return getPageHtml('insert');
}

function getSelecPage(setTableId){
  tableId = setTableId;
  return getPageHtml('select');
}

function getPageHtml(page){
  var output = HtmlService.createTemplateFromFile(page);
  return output.evaluate().getContent();
}

//テーブルの一覧を取得する
function getTableList() {
  //（１）
  var opts = {
  'maxResults': 50,
  };
  //（２）
  var tableList = FusionTables.Table.list(opts);
  
  return tableList.items;
}

function select(){
  var columns = getColumns();
  
  if(columns.length > 0) {
    var sql = 'SELECT ';
    
    for(var index in columns){
      sql += '\'' +columns[index].name + '\','
    }
    
    sql = sql.slice(0, -1);
    sql += ' FROM ' + tableId;
    
    var res = FusionTables.Query.sql(sql).rows;
    // HTMLで表示する都合上、ヘッダー（カラム名）を一番最初にする
    res.unshift(getHeaderList());
    
    return res;
  }
}

function insert(form){
  tableId = form.tableId;
  var datas = form.datas;
  var maxData = datas.length;
  
  var sql = 'INSERT INTO ' + tableId;
  var colums = getHeaderList();
  var maxColum = colums.length;
  
  sql += ' (';
  for(var columIndex = 0; columIndex < maxColum; columIndex++){
    if(datas[columIndex]) {
      sql += '\'' + colums[columIndex] + '\','
    }
  }
  sql = sql.slice(0, -1);
  sql += ') VALUES (';
  
  for(var dataIndex = 0; dataIndex < maxData; dataIndex++){
    if(datas[dataIndex]) {
      sql += '\'' + datas[dataIndex] + '\','
    }
  }
  sql = sql.slice(0, -1);
  sql += ')';
  
  Logger.log(sql);
  
  var res = FusionTables.Query.sql(sql);
  
  return 'データを追加しました'
}

//テーブルを1件削除
function deleteTable(tableId) {
  //（３）
  FusionTables.Table.remove(tableId);
  return 'テーブルを削除しました'
}

function getHeaderList() {
  var columns = getColumns();
  var headerArray = new Array();
  
  if(columns.length > 0) {
    for(var index in columns){
      headerArray.push(columns[index].name);
    }
  }
  
  return headerArray;
}

//Fusion Tablesからカラムのデータを取得
function getColumns() {
  //（４）
  var columns = FusionTables.Column.list(tableId).items;
  return columns;
}

function getTables(){
  var tables = FusionTables.Table.list();
  var retTables = new Array();
  
  if (tables.items) {
    for (var index = 0; index < tables.items.length; index++) {
      retTables.push([tables.items[index].name, tables.items[tableIndex].tableId]);
    }
  } else {
    Logger.log('No tables found.');
  }
  
  return retTables;
}

function getTableId() {
  return tableId;
}
```

##実装補足

（１）デフォルトでは取得するテーブルは25件（Fusion Tablesのリファレンスではデフォルトは5件とあったのですが、実際にやってみると25件取れていました）までなので、取得する件数を50件にしています。
コード内では"maxResults"パラメータのみ指定していますが、他には"pageToken"パラメータが存在しています。"pageToken"はテーブルの一覧を取得したときのインデックスのような役割を持っており、例えばテーブルの一覧を複数ページで表示させたいときに利用できそうです。

（２）Fusion Tables APIでテーブルの一覧を取得しています。取得できるテーブルは「自分が作成しているテーブル」か、「共有されているテーブル」に限定されます。

（３）テーブルの削除はテーブルIDを指定するだけで1行で行えます。ただし、削除用のメソッドの型はvoidとして定義されているので、本当に削除されたかは他の方法で確認するしかありません。

（４）Fusion Tablesで登録している1テーブルからカラムとデータを取得しています。Fusion Tablesはテーブルに関する情報はJSON構文で保持しているようで、"FusionTables.Column.list(tableId)"でテーブルIDで指定したテーブルのJSON構文のデータを取得し、以降のパラメータで取得したいデータを絞り込んでいきます。
コード内では"FusionTables.Column.list(tableId).items"としていますが、これでカラム名とデータを一覧で取得することができます。


#画面のHTMLファイル（参考まで）
##index.html（最初にテーブル一覧を表示する画面）
```lang:index.html
<script>
function transitionPage(html) {
    var outputDiv = document.getElementById('html');
    outputDiv.innerHTML = html;
}
  
function onSuccess(message){
    alert(message);
}
</script>

<div id="html">
<h2>テーブル一覧</h2>
<form>
<table border=1>
<?
  var tableList = getTableList();
  for(var index in tableList){
    output.append('<tr><td>' + tableList[index].name + '</td>');
    output.append('<td><input type="button" value="データ追加" onclick="google.script.run.withSuccessHandler(transitionPage).getInsertPage(\'' + tableList[index].tableId +'\')"></p></td>');
　　output.append('<td><input type="button" value="参照" onclick="google.script.run.withSuccessHandler(transitionPage).getSelecPage(\'' + tableList[index].tableId +'\')"></p></td>');
    output.append('<td><input type="button" value="削除" onclick="google.script.run.withSuccessHandler(onSuccess).deleteTable(\'' + tableList[index].tableId +'\')"></p></td></tr>');
}
?>
</table>
</form>

</div>
```

##select.html（選択されたテーブルのデータ参照画面）
```lang:select.html
<div id="html">
<h2>データ一覧</h2>
<form>
<table border=1>
<?
  var datas = select();
  var maxData = datas.length;
  var maxColumn = datas[0].length;
  
  output.append('<tr>');
  for(var index = 0; index < maxColumn; index++){
    output.append('<th>' + datas[0][index] + '</th>');
  }
  output.append('</tr>');
  
  for(var data = 1; data < maxData; data++){
    output.append('<tr>');
    for(var index = 0; index < maxColumn; index++){
      output.append('<td>' + datas[data][index] + '</td>');
    }
    output.append('</tr>');
  }
?>
</table>
  <input type="button" value="テーブル一覧へ戻る" onclick="google.script.run.withSuccessHandler(transitionPage).getPageHtml('index')">
</form>

</div>
```

##insert.html（選択されたテーブルのデータ追加画面）

```lang:insert.html
<div id="html">

<h2>データ追加</h2>

<form>

  <table border=1>

    <?

      var tableId = getTableId();

      output.append('<input type="hidden" name="tableId" value="' + tableId + '">');

      

      var headerList = getHeaderList();

      var maxHeader = headerList.length;

      for(var index = 0; index < maxHeader; index++){

        output.append('<tr><td>' + headerList[index] +'</td><td><input type="text" name="datas"></td></tr>');

      }
    ?>
  </table>
  <input type="button" value="データ追加" onclick="google.script.run.withSuccessHandler(onSuccess).insert(this.parentNode)">
  <input type="button" value="テーブル一覧へ戻る" onclick="google.script.run.withSuccessHandler(transitionPage).getPageHtml('index')">
</form>
</div>
```


（注）テーブルIDに対してセキュリティ面を考慮していません。
もし参考にするようなことがあれば、その点はご一考ください。



#アプリケーション画面
ここからはWebアプリケーションの画面や、操作についてです。

##テーブル一覧画面
まずはテーブル一覧の画面から。
![01.png](https://qiita-image-store.s3.amazonaws.com/0/82305/736ed215-e3b8-a17b-cb85-996c53cd29d0.png)


画像では途切れていますが、社員マスタテーブルの下にも同じようにテーブル名と各ボタンが並んでいます。
ここからテーブルごとの操作を行っていきます。
この画面から社員マスタテーブルの一覧データ参照ボタンをクリックし、社員マスタテーブルのデータを見てみます。

![02.png](https://qiita-image-store.s3.amazonaws.com/0/82305/4c50f248-8bd4-7f0f-cd22-e135c5c2f595.png)


あらかじめ登録しておいたデータが表示されました。

##データ追加
では、一度テーブル一覧へ戻り、社員マスタテーブルにデータを追加してみます。

![03.png](https://qiita-image-store.s3.amazonaws.com/0/82305/1a93dac2-1548-27b3-fde1-dd9106bc8ac3.png)


私の社員情報をカラムごとのテキストボックスに入力して、データ追加実行ボタンをクリックします。
登録が完了すると、次のような通知が出てきます。

![04.png](https://qiita-image-store.s3.amazonaws.com/0/82305/640075f6-d8dc-9662-b269-215a45b40199.png)


それでは、本当にデータが追加されているか、再度社員マスタテーブルのデータを参照してみます。

![05.png](https://qiita-image-store.s3.amazonaws.com/0/82305/c5499f0b-b316-0e76-8e64-d0130e888c82.png)


確かに私の社員情報がテーブルに登録されています。


##テーブル削除
最後に、テーブルを削除してみます。
テーブル一覧画面で一番上に表示されていた"アクセス履歴"テーブルの削除ボタンをクリックすると、次のような通知が出てきます。

![06.png](https://qiita-image-store.s3.amazonaws.com/0/82305/d29b5990-4a7d-fa64-3356-d4015fee71dd.png)


通知が出た後にページを更新すると、"アクセス履歴"テーブルが削除されています。

![07.png](https://qiita-image-store.s3.amazonaws.com/0/82305/9623c7f0-2d7f-9b81-1fb6-8851ee63c578.png)


#最後に
これで、テーブル単位でもFusion Tables APIを利用して操作することができるようになりました。

次は、Fusion Tablesの特徴である「マッピング」を取り上げることを考えています。