[Day15] Boxenn 实作 Repository & Query

Repository

source wrapperrecord mapperfactory 都完成後,在 repository 里只需要简单的归位初始化後就完成了。

# 这边以 order 做举例,primary key 为 serial_number

class Order < Boxenn::Entity
  def self.primary_keys
    [:serial_number]
  end

  # 订单编号 (identity)
  attribute :serial_number,         Types::Coercible::String
  # 状态
  attribute :status,                Types::Symbol.enum(successed: 0, refunded: 1, canceled: 2)
  # 购买日期
  attribute :puchased_at,           Types::DateTime
  # 备注
  attribute :comment,               Types::Coercible::String.optional.default(nil)
end
module Repositories
  class Order < Boxenn::Repository
    option :source_wrapper, default: -> { Wrapper::Order.new }

    option :record_mapper, default: -> { Mapper::Order.new }

    option :factory, default: -> { Factory::Order.new }
  end
end
# 实际运用

repo = Repositories::Order.new
repo.find_by_identity(serial_number: 'ABC-1234567890') # 会回传 order 的 entity
repo.destroy(serial_number: 'ABC-1234567890') # 会删除资料库中的 record
order = Order.new(
	serial_number: 'ABC-9876543210',
	status: :successed,
	puchased_at: Time.zone.now,
	comment: '测试',
)
repo.save(order) # 会根据 serial_number = 'ABC-9876543210' 来找 record,如果有找到即更新资料,没有找到则建立一笔新 record

save 可以传入多个 entity 的 array ,一次更新或新增多笔资料

Query

负责归纳复杂读取逻辑。
唯一定义的介面是 collect ,回传的资料会传入 factory 转成 entity,以ActiveRecord 为例回传为 array of models 即可。

下面范例一样以 ActiveRecord 为外部资源做示范:

require 'dry/initializer'

module Boxenn
  module Repositories
    class Query

      extend Dry::Initializer

      param :relation, default: proc { nil }

      def collect
        raise NotImplementedError
      end
    end
  end
end
# Order Query
class OrderQuery < Boxenn::Repositories::Query
	param :relation, default: -> { ::Models::Order }

  def comment_include(key_word)
    @relation = relation.where('comment LIKE ?', "%#{key_word}%")
    self
  end

  def by_status(status)
    @relation = relation.where(status: status)
    self
  end

  def collect
    relation
  end
end
# 实际运用

repo = Repositories::Order.new
query = OrderQuery.new
query.comment_include('测试')
repo.find_by_query(query)

需要注意这边 query 有储存 Active::Record::Relation, 因此不同的 method 之间可以 chain ,但如果想要新的搜寻结果就需要重新 new 一个 query

repo = Repositories::Order.new
query = OrderQuery.new
query.comment_include('测试').by_status(:refunded)
repo.find_by_query(query)

下篇会说明如何对整个 DAL 做测试。


<<:  Day 15: 范式概述、结构化设计 (待改进中... )

>>:  Day 15: GCP-Storage

[Day 15] Reactive Programming -Reactor(COLD VS HOT) -PART 2

前言 其实有一个特别的例子是just,直觉会认为just就是产生一个publisher等人来subs...

[Day 7] 初学HTML

前言 我们终於要开使进入网页世界,一开始会觉得好多标签名称要记得、时不时也会忘记放入结束标签,而出现...

[NestJS 带你飞!] DAY07 - Provider (下)

汇出自订 Provider 在介绍共享模组的时候,有提到可以透过 Module 的 exports ...

进行战略性和批判性思考

战略性和批判性思考是资安专业人员的基本技能。我认为,战略思考意味着从长期和高阶概念的角度进行思考。...

[python 爬虫] 美金_欧元 半年走势

import matplotlib.pyplot as plt import requests im...