DBをフロントに持てる！Vuex-ORM環境構築と動作確認

みなさんはじめまして、駆け出しエンジニアのやっしーです。

多数あるVueコンポーネントで同じデータ保持するのって面倒ですよね！そんなあなたにみたいな感じでVuexがあると思うのですが、今回はVuexのstoreに対してORM的アクセスができ、さながら、VuexをDBとして使えるプラグイン。Vuex-ORMを紹介します。

## Vuex-ORMとはなんぞや
[Vuex-ORM](https://github.com/vuex-orm)は Kia King Ishi氏によって開発されているものです。modelクラスを作成し、store.jsで登録すると、PHPの[Eloquent](https://laravel.com/docs/4.2/eloquent)やActive Recordのようなアクセスで、データのやりとりができます。

## 使い方(ざっくり)
### 環境
* mac OS Mojave 10.14.5
* npm 6.4.1
* vue 2.6.10
* vue-cli 3.7.0
* vuex 3.0.1
* vuex-orm 0.32.0

## 環境構築手順
### 1. vue-cliのインストール
```
npm install -g @vue/cli
```
ちなみに`vue-cli`よりも`@vue-cli`のパッケージの方が新しいです。詳細は[コチラ](https://qiita.com/Junpei_Takagi/items/603d44f7885bd6519de2)を見てみてください。因みに僕のこの記事執筆時点でvue-cliのバージョンは3.7.0でした。
### 2. vue-cliプロジェクトの作成
```
vue create <プロジェクト名>
```
続く下図のようにプラグイン等を設定しました
<img width="816" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448316/0186719e-da3e-14c1-57d0-1d0b0a91fa40.png">

[この記事](https://noumenon-th.net/programming/2019/02/15/vue-cli-3/)を参考にしました。

作成されたプロジェクトファイルに移動して、`npm run dev`すると、localhostで起動します。

### 3. Vuex-ORMのインストール
#### ここからメインコンテンツって感じです
```
npm install vuex-orm@core
```
インストールはこれだけ。package.jsonに追加されているはずです。

それでは、ここからは例を踏まえて解説していきます。
まず、`vue create ~`で作成したディレクトリ構造は、こうなっていると思います。

project名 
-node_modules
-public
-src
--assets
--components
--views
-.gitignore
-babel.config.js
-package-lock.json
-package.json
-README.md

#### まずは、データベースにおけるテーブルを定義するモデルを作成しましょう。lsするとsrcやpublicが見えるプロジェクトフォルダ内で、
```
mkdir ./src/model
```
で、srcフォルダ下にmodelフォルダを追加します。テーブル的構造を作りたい場合はここにjsファイルを追加していきましょう。


```javascript:src/model/Project.js
import { Model } from '@vuex-orm/core'
import Task from '../model/Task'
import moment from 'moment'

export default class Project extends Model {
  static entity = 'project'

  static fields () {
    return {
      id: this.increment(),
      name: this.string(''),
      tasks: this.hasMany(Task, 'project_id'),
      day: this.string(moment().format('YYYY/MM/DD'))
    }
  }
}


```
static fields(カラム)の型や属性を今知っている限りリストアップしておきます。

#### 型
* attr()…なんでも入る。jsのvarやletと同じ
* string()…入ってきたパラメータをstringにキャストする。integerの1は文字列の1になる。

#### 属性
* increment()…id、自動インクリメントしてくれる。多分int AUTO_INCREMENTと同じ
* hasMany(モデル名, 外部キー)…リレーション系。ネストされたデータを保存する際に使用する。たとえば、プロジェクトにタスクを登録する時、タスクに、プロジェクトIDと紐づいているなら、プロジェクトのフィールドに、

```javascript:model/Project.js
~
tasks: hasMany(Task,'project_id')
~
```
とすればいい。この場合、Taskのモデル側からどのユーザー担当かわかるよう、`project_id`というフィールドを持つようにする。

とまあ、複数のテーブルができたら、それをVuexに登録する。その際のstore.jsを下記に示す。

```javascript:/store.js
import Vue from 'vue'
import Vuex from 'vuex'
import VuexORM from '@vuex-orm/core'
import Project from './model/Project'
import Task from './model/Task'

Vue.use(Vuex)

const database = new VuexORM.Database()

database.register(Project)
database.register(Task)

const store = new Vuex.Store({
  plugins: [VuexORM.install(database)]
})

export default store
```

`const database = new VuexORM.Database()`して、
`database.register(Project)`みたいにする。そうすると、

```javascript
Project.all() //全プロジェクト取得。中のタスクはなし
Project.query().with('tasks').get() //全プロジェクト、タスクの情報も取得
Project.find(1) //ID(主キー)が1のプロジェクトを取得
Project.insert({data:{ 追加したいデータ(キー : 値) }})
Project.update({where 主キー,data:{ 編集したいデータ(キー : 値) }})
Project.delete(1) //ID(主キー)が1のプロジェクト削除
```
こんな感じの、ORM的データ取得ができる！

実際のところ、データが格納されているのはVuexの中なので、データのデバッグ等はdevtoolsでみれると思います。
<img width="772" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448316/70caca1c-fb95-a6df-100f-448527d7eda9.png">
時計マークか、その横のイベントリスナーで、vuexのentity情報が見れると思います。上の画像はcreatedフックでテスト用のシードをした時の追加処理(insert)ですね。


初めての記事投稿です。少し書きすぎた気もしますが、これからどんどんQiitaにアウトプットしていきますのでよろしくお願いします。

ソースコードはgithubに置いていますがまだ開発中のものですのであしからず
https://github.com/YaCpotato/laravueStudy

よろしければTwitterのフォローもお願いします。
コードレビューとか送ってくれたらとても喜びます。
https://twitter.com/Yasshieeee

では、良い一週間を！

ーーーーーーーーーーーーーー
Name:やっしー
大学生。新卒即戦力という矛盾を達成するため日々勉強中。2020年卒業見込み。
研究：少ないデータでの機械学習(一般物体認識、GAN等)
言語：Vuejs,Nuxt,Vuex, Django,Laravel
TwitterID: [@Yasshieeee](https://twitter.com/Yasshieeee)
githubID: [YaCpotato](https://github.com/YaCpotato)
ーーーーーーーーーーーーーー