見出し画像

Laravel から Redshift を使う方法

こんにちは。

adptOSという商業施設店舗の「入店数」や「どういうルートを辿って購買に至ったか」等のデータをダッシュボードで可視化する新規事業でエンジニアをやっています。

今日は少し技術的な話をしてみようと思います。

弊社が運営する adptOS では、商業施設に関する様々なデータを Amazon Redshift に保存して利用しています。

Redshift には PostgreSQL 8.0.2 に基づく API が用意されており、PostgreSQL のクライアントを使って、PostgreSQL サーバーにアクセスするのと同じようにして、利用することができます。

Laravel の Eloquent から Redshift を使う方法

Laravel から Redshift にアクセスしたい場合も、PostgreSQL 用のドライバを使います。

DB_CONNECTION=pgsql

これだけで多くのクエリは問題なく動作します。

$children = User::where('age', '<', 18)->orderBy('age')->get();

簡単ですね。

PostgreSQL だけに存在する RETURNING 句

ただ、Redshift には PostgreSQL との相違もいくつかあり、その中のひとつが、INSERT 文に付ける RETURNING 句になります。

PostgreSQL の 8.2 から実装された RETURNING 句は、INSERT や UPDATE するクエリの戻り値で、書き込まれた値を得るための構文です。RDBMS が採番した id や、NOW() などの関数を使って挿入した値など、挿入するまで決定しない値を得るのにとても便利な構文です。

postgres=# INSERT INTO "users" ("name", "created_at") VALUES ('3pey', NOW()) returning id, created_at;
 id |     created_at
----+---------------------
 1 | 2020-05-15 16:55:00
(1 row)

Laravel の ORM である Eloquent でもこの構文が使われていて、Eloquent のもっともシンプルな操作のひとつである

$user = new App\User;
$user->name = '3pay';
$user->save();

このような保存処理でも

[
 [
   "query" => "insert into "users" ("name", "updated_at", "created_at") values (?, ?, ?) returning "id"",
   "bindings" => [
     "3pay",
     "2020-05-15 16:55:00",
     "2020-05-15 16:55:00",
   ],
   "time" => 5.03,
 ],
]

id を得るために RETURNING 句が使われています。

いくら Eloquent でクエリが書けても、save() ができないと使い物になりません。INSERT 時に RETURNING 句を使わないようにはできないでしょうか?

INSERT 時に RETURNING 句を使わないようにする

結論から言えば、できます。それも簡単に。

Eloquent では、INSERT 時に DB で採番された id を、自動的に取得して自身の変数にセットするかどうかを、$incrementing というプロパティで設定できます。

/**
 * Indicates if the IDs are auto-incrementing.
 *
 * @var bool
 */
public $incrementing = true;

デフォルトでは true になってるこの値を、false に設定すれば、INSERT クエリで RETURNING 句は使われなくなります。

ソースコードでいうと、Illuminate\Database\Eloquent\Model のこの部分ですね。

if ($this->getIncrementing()) {
    $this->insertAndSetId($query, $attributes);
}

else {
    if (empty($attributes)) {
        return true;
    }

    $query->insert($attributes);
}

$this->getIncrementing() で取得した $incrementing の値によって、RETURNING 句を付ける $this->insertAndSetId() を呼ぶか、INSERT だけをする $query->insert() を呼ぶかが場合分けされています。

RETURNING 句を使わない弊害

ただ、この方法の欠点として、当たり前ですが、INSERT した後に id が取得されないので、

$user = new App\User;
$user->name = '3pay';
$user->save();

dump($user->id);  // null

インスタンスの id の値は null のままです。

id が欲しかったら何らかの方法で、自分で取得する必要があります。

$user = App\User::where('name', '3pay')->firstOrFail();

dump($user->id);  // 1

ちょっと面倒くさいですね。

COUNTERWORKS で使ってる技術

COUNTERWORKS のメインプロダクトである SHOPCOUNTER は、Ruby on Rails で作られているのですが、アプリケーションの規模が大きくなればなるほど、Rails での設計は難易度を増していきます。

そんな中、Rails のレールの外側に羽ばたくためには、他のフレームワークがどのような設計を採用しているのかを勉強した方がいいよねという話になり、ちょうどその時期入社したエンジニアが得意だった Laravel に白羽の矢が立ちました。

そうして新規事業では、Laravel + TypeScript という、今まで使ってなかった技術を使って開発され、そのノウハウは先日紹介した勉強会などを通じて共有されています。

一緒に勉強してくれる仲間を募集します!

COUNTERWORKS では、経験したことのない技術でも貪欲に勉強して、仕事に活かしていきたいという、意思のあるエンジニアを絶賛募集中です!

https://www.counterworks.jp/recruit/

この記事が参加している募集

この記事が気に入ったらサポートをしてみませんか?