Ruby 如何重构Hanami中的查询链?

Ruby 如何重构Hanami中的查询链?,ruby,hanami,hanami-model,Ruby,Hanami,Hanami Model,如何重构#过滤的方法 在Hanami中,无法以ActiveRecord样式生成查询链(过滤器)。我想得到一个类似ActiveRecord过滤器的方法 现在:documents.filtered(类型:“新闻”,最小发布时间:from,最大发布时间:to,跳过:30) 我想要的:documents.with_体裁('news')。在(from,to)之间发布。skip(30) class DocumentRepository

如何重构
#过滤的
方法

在Hanami中,无法以ActiveRecord样式生成查询链(过滤器)。我想得到一个类似ActiveRecord过滤器的方法

现在:
documents.filtered(类型:“新闻”,最小发布时间:from,最大发布时间:to,跳过:30)

我想要的:
documents.with_体裁('news')。在(from,to)之间发布。skip(30)

class DocumentRepository
沿着这些思路做一些事情可能会奏效,但不确定链接这些东西会对性能或结果产生怎样的不良影响,但您可以尝试一下,它可能会引导您找到您想要的答案

更新 如果你真的想链接,这是接近你想要的

class DocumentRepository < Hanami::Repository
  GENRES = DbSchema.current_schema.enum(:document_genre).values.map(&:to_s)
  DOCUMENTS_PER_PAGE = 30

  associations do
    has_many :boxes
    has_many :urls
  end

  attr_accessor :data

  def initialize
    @data = []
    super  
  end

  def data 
    @data.flatten!.uniq!
  end

  def with_genre(key)
    @data << documents.where(genre: key) 
    self
  end

  def published_between(arr)
    from, to = arr 
    @data << documents.where(created_at: [from..to])
    self
  end

  def skip(num)
    @data << documents.offset(num)
    self
  end

end
通过在每个实例方法中返回
self
,您可以链接实例上的调用

原始答案 这种方式有效,但在当前调用中使用类似的语法

class DocumentRepository < Hanami::Repository
  GENRES = DbSchema.current_schema.enum(:document_genre).values.map(&:to_s)
  DOCUMENTS_PER_PAGE = 30

  associations do
    has_many :boxes
    has_many :urls
  end

  def hack_where(opts={})
    data = []
    opts.each do |i|
      data << self.send(i[0],i[1]).call
    end
    data.flatten!.uniq!
  end

  def with_genre(key)
    lambda { |key| documents.where(genre: key) }
  end

  def published_between(arr)
    from = arr[0]
    to = arr[1]
    lambda { |from, to| documents.where(created_at: [from..to]) }
  end

  def skip(num)
    lambda { documents.offset(num) }
  end

end

介绍查询对象:

class FilterDocuments
  DOCUMENTS_PER_PAGE = 30

  def initialize(documents)
    @documents = documents
  end

  def filter(params = {})
    result = apply_ordering(documents)
    result = apply_limit_and_offset(result, params)
    result = filter_by_genre(result, params)
    result = filter_by_created_at(result, params)
    result = filter_by_published_at(result, params)

    result
  end

private
  attr_reader :documents

  def apply_ordering(documents)
    documents.order { created_at.desc }
  end

  def apply_limit_and_offset(documents, params)
    if params.key?(:skip)
      documents.offset(params[:skip])
    else
      documents
    end.limit(DOCUMENTS_PER_PAGE)
  end

  def filter_by_genre(documents, params)
    if params.key?(:genre)
      documents.where(genre: params[:genre])
    else
      documents
    end
  end

  def filter_by_created_at(documents, params)
    if params.key?(:min_created_at) && params.key?(:max_created_at)
      range = params[:min_created_at]..params[:max_created_at]
      documents.where(created_at: range)
    else
      documents
    end
  end

  def filter_by_published_at(documents, params)
    if params.key?(:min_published_at) && params.key?(:max_published_at)
      range = params[:min_published_at]..params[:max_published_at]
      documents.where(published_at: range)
    else
      documents
    end
  end
end
如何使用:

    def query
      FilterDocuments.new(DocumentRepository.new.documents)
    end

    filtered_documents = query.filter(params)

tbh,我发现它写得很好:D.你不知道的是什么;我不喜欢你看着它?
hack_where({with_genre: 'news', published_between: [from,to], skip: 30})
class FilterDocuments
  DOCUMENTS_PER_PAGE = 30

  def initialize(documents)
    @documents = documents
  end

  def filter(params = {})
    result = apply_ordering(documents)
    result = apply_limit_and_offset(result, params)
    result = filter_by_genre(result, params)
    result = filter_by_created_at(result, params)
    result = filter_by_published_at(result, params)

    result
  end

private
  attr_reader :documents

  def apply_ordering(documents)
    documents.order { created_at.desc }
  end

  def apply_limit_and_offset(documents, params)
    if params.key?(:skip)
      documents.offset(params[:skip])
    else
      documents
    end.limit(DOCUMENTS_PER_PAGE)
  end

  def filter_by_genre(documents, params)
    if params.key?(:genre)
      documents.where(genre: params[:genre])
    else
      documents
    end
  end

  def filter_by_created_at(documents, params)
    if params.key?(:min_created_at) && params.key?(:max_created_at)
      range = params[:min_created_at]..params[:max_created_at]
      documents.where(created_at: range)
    else
      documents
    end
  end

  def filter_by_published_at(documents, params)
    if params.key?(:min_published_at) && params.key?(:max_published_at)
      range = params[:min_published_at]..params[:max_published_at]
      documents.where(published_at: range)
    else
      documents
    end
  end
end
    def query
      FilterDocuments.new(DocumentRepository.new.documents)
    end

    filtered_documents = query.filter(params)