HanamiのRepositoryで作成した独自SQLクエリーのデータにアクセスする

Repositories: SQL Queries - Hanami に書かれているとおり、Repositoryに定義するだけだが、このままだとviewに渡されるまでメソッドが実行されないので、InteractorsとかControllerでクエリー結果のデータにアクセスしようと思っても、アクセスできない。

■HanamiのDBクエリー

HanamiのDBクエリーは、Ruby Object Mapper(ORM)Sequel が使われている。

以下、Hanami Guide v1.1からの引用。

Hanami queries are based on gems from ROM project, namely rom-repository and rom-sql. The gem rom-sql is itself based on Sequel project.
Learn more on how to craft queries with ROM and Sequel.

■最初から用意されているメソッドはアクセス可能

Repositories Overview #Interface - Hanami に書かれている、最初から用意されているallとかfirstなどのメソッドは、おそらくすぐにcallされているためか、データにアクセス可能。

■データにアクセスする方法

.call.collectionをつけると、クエリーを即時実行してデータにアクセスができる。

(例)
lib/gnote/repositories/message_repository.rb
-----------------------------------------------------------------
class GnoteMessageRepository < Hanami::Repository
・・・
 def most_recent_posts(most_recent_start_date)
    gnote_messages
      .where(
        created_at: most_recent_start_date..CURRENT_DATE,
        is_deleted: nil
      )
      .order{ created_at.desc }
      .call.collection
  end
・・・
end
-----------------------------------------------------------------

lib/gnote/interactors/index_messages.rb
-----------------------------------------------------------------
require 'hanami/interactor'
・・・
    def call
      @most_recent = @repository.most_recent_posts(MOST_RECENT_START_DATE) # call  lib/gnote/repositories/message_repository.rb
      Hanami.logger.debug @most_recent.inspect
    end
・・・
end
-----------------------------------------------------------------

コンソールの出力結果
-----------------------------------------------------------------
[tanebox] [DEBUG] [2018-01-05 23:02:48 +0700] [#2,
:created_at=>2018-01-05 07:51:54 UTC, :updated_at=>2018-01-05
07:51:54 UTC, :author_hash_ip=>nil, :content=>"カレー作ったえらい",
:is_deleted=>nil}>, #1,
:created_at=>2018-01-04 13:35:21 UTC, :updated_at=>2018-01-04
13:35:21 UTC, :author_hash_ip=>nil, :content=>"早起きできた!",
:is_deleted=>nil}>]
-----------------------------------------------------------------

■.call.collectionをつけない場合

コンソールの出力結果(クエリー文が出力される)
-----------------------------------------------------------------
[tanebox] [DEBUG] [2018-01-05 22:43:34 +0700] #= '2017-12-29') AND (`created_at` <= '2018-01-06') AND (`is_deleted` IS NULL)) ORDER BY `created_at` DESC">>
-----------------------------------------------------------------

■.callのみつけた場合

コンソールの出力結果(クエリー文とデータオブジェクトが出力される)
-----------------------------------------------------------------
[tanebox] [DEBUG] [2018-01-05 22:53:52 +0700] #@source
=#= '2017-12-29') AND (`created_at` <= '2018-01-06') AND (`is_deleted` IS NULL)) ORDER BY `created_at` DESC">>, @collection=[#2,
:created_at=>2018-01-05 07:51:54 UTC, :updated_at=>2018-01-05
07:51:54 UTC, :author_hash_ip=>nil, :content=>"カレー作ったえらい",
:is_deleted=>nil}>, #1,
:created_at=>2018-01-04 13:35:21 UTC, :updated_at=>2018-01-04
13:35:21 UTC, :author_hash_ip=>nil, :content=>"早起きできた!",
:is_deleted=>nil}>]>
-----------------------------------------------------------------

■.callと.collectionの意味(推測)

ROMとSequelの両方のAPIドキュメントを見たがメソッドの解説を発見できなかったので以下推測。
・call → rubyのcallメソッドと同じ意味で、メソッドを即時実行(評価)する。.callをつけるまで実行されず(遅延評価)、逆にタイミングのよいときに実行させることができる。
・collection → collectionのattributeにアクセスする。.collectionをつけないと、@source(クエリー文)と@collection(データオブジェクト)が出力される。

■.callと.collectionをつけなかった場合のクエリー実行場所(推測)

Hanamiのソースコードを読んでないのであっているかわからないが、各レイヤーでdebugした結果だと以下のとおり。

ユーザーアクセス → Routes → Controller → Interactor → Repository, Entity → Interactor → Controller → |Viewレイヤーでクエリー実行| View, Template → 画面描画

■参考ソースコード

pinfluence/lib/pinfluence/repositories/moment_repository.rb