IndexedDBの利用例としてMicrosoft To-Doを読み解く

最近趣味でIndexedDBを利用したオフライン完結型のアプリケーションを書いている。
他サイトのIndexedDBの利用例でMicrosoft To-Doで一番ちゃんと使われてた気がするので利用例としてスキーマを読み解く。

## IndexedDBの確認方法
以前から使われているLocalStorageと比べて
- （ブラウザに依るが）単純に容量がでかい
- indexを貼れる
- Objectをそのまま格納出来る
あたりがメリットになる。
このあたりは別の記事を見るとよい

Chromeで中身を確認するには、DeveloperToolsのApplicationタブ、StorageのIndexedDBを見ればよい。
各テーブルのデータを確認出来る。

<img width="756" alt="スクリーンショット 2018-04-06 11.29.27.png" src="https://qiita-image-store.s3.amazonaws.com/0/24124/a96c596d-7452-aab9-644f-cfa29981c7b1.png">

## Microsoft To-Do
Microsoftが開発しているToDo管理アプリケーション。
タスクを複数格納出来るlistがある一般的なTodo管理アプリケーションで、オフラインで動作する。

<img width="1277" alt="スクリーンショット 2018-04-06 14.33.58.png" src="https://qiita-image-store.s3.amazonaws.com/0/24124/2aa57163-301e-0e79-e444-ed633f53d0e2.png">


https://todo.microsoft.com/

## Table
2018/4/6現在は以下の6テーブル
- settings
- steps
- tasks
- members
- lists
- sync

基本的にすべてのテーブルは1つのユニークキーを持っていて、キーに対してObjectを持っている様子。

### settings
```js
{
  id: "l-5oo86"
  key: "onboarding_detail_tooltip_dismissed"
  local_id:"l-5oo86"
  remote_id: undefined
  value: true
}
```
- いわゆるkey,valueな感じのオブジェクトが保存されている。primaryKeyはkeyが設定されている。
- remote_idはtasksを見る限りサーバーサイドで持っているidが振られる様子だが、settingsに関してはremote_idが振られているレコードはないのでクライアントでのみ保存している可能性が高い

### tasks
```js
{
  ChangeKey: "XAI/lv8jBkOPt79WuS0NSwAAnP2j=="
  committed_day: undefined
  completed: false
  completed_at: undefined
  created_at: {date_time: "2017-05-04T18:22:51.500", time_zone: "UTC"}
  due_date: undefined
  id: "AQMkADAwATM0MDAAMS1hZGNiLTQzYjYtMDACLTAwCgBGAAADVFc0lFz6P0m-xARjTHHhrAcAXAI-lv8jBkOPt79WuS0NSwAAAJzsHc4AAABcAj_W-yMGQ4_3v1a5LQ1LAAAAnOwloAAAA=="
  is_ignored: undefined
  is_reminder_on: false
  list_id: "AQMkADAwATM0MDAAMS1hZGNiLTQzYjYtMDACLTAwCgAuAAADVFc0lFz6P0m-xARjTHHhrAEAXAI-lv8jBkOPt79WuS0NSwAAAJzsHc4AAA="
  local_id: "AQMkADAwATM0MDAAMS1hZGNiLTQzYjYtMDACLTAwCgBGAAADVFc0lFz6P0m-xARjTHHhrAcAXAI-lv8jBkOPt79WuS0NSwAAAJzsHc4AAABcAj_W-yMGQ4_3v1a5LQ1LAAAAnOwloAAAA=="
  note: ""
  note_updated_at: undefined
  position: 1493922090000
  postponed_day: undefined
  recurrence: undefined
  reminder: undefined
  remote_id: "AQMkADAwATM0MDAAMS1hZGNiLTQzYjYtMDACLTAwCgBGAAADVFc0lFz6P0m-xARjTHHhrAcAXAI-lv8jBkOPt79WuS0NSwAAAJzsHc4AAABcAj_W-yMGQ4_3v1a5LQ1LAAAAnOwloAAAA=="
  remote_list_id: "AQMkADAwATM0MDAAMS1hZGNiLTQzYjYtMDACLTAwCgAuAAADVFc0lFz6P0m-xARjTHHhrAEAXAI-lv8jBkOPt79WuS0NSwAAAJzsHc4AAA="
  source: undefined
  title: "タスクネーム"
  today_position: undefined
}
```
- primaryKeyはidになっている。
- remote_id, remote_list_idがおそらくサーバー側でのpkey。
- list_idはlistsのレコードに対する外部キー
- ChangeKeyを見てサーバーサイドのデータと動機を取っているように見える。

### lists
```js
{
  background: "mountains"
  id: "inbox"
  is_owner: true
  is_shared_folder: false
  local_id: "inbox"
  members: []
  position: 1493835505000
  remote_id: "AQMkADAwATM0MDAAMS1hZGNiLTQzYjYtMDACLTAwCgAuAAADVFc0lFz6P0m-xARjTHHhrAEAXAI-lv8jBkOPt79WuS0NSwAAAgESAAA"
  sharing_sync_status: "Synced"
  show_completed: false
  sort_asc: true
  sort_type: 1
  theme: "blue"
  title: "タスク"
}
```

### sync
```json
{
  id : "sync-key"
  queue : [
    {
      data : 
        committed_day : {date_time: "2018-04-06", time_zone: "Asia/Tokyo"} 
        id : "l-5hkdu"
        list_id : "inbox"
        local_id : "l-5hkdu"
        position : 1492520890000
        postponed_day : null
        remote_id : undefined
        remote_list_id : "AQMkAwATM0MDAAMS1hZGNiLTQzYjYtMDACLTAwCgAuAAADVFc0lFz6P0m-xARjTHHhrAEAXAI-lv8jBkOPt79WuS0NSwAAAgESAAAA"
        title : "aaaa"
        today_position : 1522984086542
      type : "CREATE_TASK"
    }
  ]
  length : 1
}
```
- sync-keyという1レコードのみ
- queueが合って、typeとdataがセットになったデータが入ってる。fluxのアクション的なノリ
- オンラインになると実行される

### steps, members
この2つのテーブルに保存されているデータを見たことがない
membersはタスクの共有用なんだろうなとは思ったけど、UI上で共有する方法が分からない

## おわり
- Firebase使ってアプリ書くとオンライン・オフライン対応してくれてキューとか意識しなくてよかったので、自前でやる時の参考になりそうだった。
- indexがkeyにしか振られてないので、まだlocalStorageの延長線上の使い方だなーという印象
- remote_idなどクライアントとサーバーをまたいだデータやりとりはWebエンジニアとしてはあまりやらないので、デスクトップやスマートフォン上での設計は学ぶ必要性が強くなっているように感じた。（ReactNativeとかPWAの文脈として）