module ComputedModel::Model
A mixin for batch-loadable compound models. This is the main API of ComputedModel
.
See {ComputedModel::Model::ClassMethods} for methods you can use in the including classes.
@example
require 'computed_model' # Consider them external sources (ActiveRecord or resources obtained via HTTP) RawUser = Struct.new(:id, :name, :title) Preference = Struct.new(:user_id, :name_public) class User include ComputedModel::Model attr_reader :id def initialize(raw_user) @id = raw_user.id @raw_user = raw_user end def self.list(ids, with:) bulk_load_and_compute(Array(with), ids: ids) end define_primary_loader :raw_user do |_subfields, ids:, **| # In ActiveRecord: # raw_users = RawUser.where(id: ids).to_a raw_users = [ RawUser.new(1, "Tanaka Taro", "Mr. "), RawUser.new(2, "Yamada Hanako", "Dr. "), ].filter { |u| ids.include?(u.id) } raw_users.map { |u| User.new(u) } end define_loader :preference, key: -> { id } do |user_ids, _subfields, **| # In ActiveRecord: # Preference.where(user_id: user_ids).index_by(&:user_id) { 1 => Preference.new(1, true), 2 => Preference.new(2, false), }.filter { |k, _v| user_ids.include?(k) } end delegate_dependency :name, to: :raw_user delegate_dependency :title, to: :raw_user delegate_dependency :name_public, to: :preference dependency :name, :name_public computed def public_name name_public ? name : "Anonymous" end dependency :public_name, :title computed def public_name_with_title "#{title}#{public_name}" end end # You can only access the field you requested ahead of time users = User.list([1, 2], with: [:public_name_with_title]) users.map(&:public_name_with_title) # => ["Mr. Tanaka Taro", "Dr. Anonymous"] users.map(&:public_name) # => error (ForbiddenDependency) users = User.list([1, 2], with: [:public_name_with_title, :public_name]) users.map(&:public_name_with_title) # => ["Mr. Tanaka Taro", "Dr. Anonymous"] users.map(&:public_name) # => ["Tanaka Taro", "Anonymous"] # In this case, preference will not be loaded. users = User.list([1, 2], with: [:title]) users.map(&:title) # => ["Mr. ", "Dr. "]
Public Instance Methods
current_deps()
click to toggle source
Returns dependency of the currently computing field, or the toplevel dependency if called outside of computed fields. @return [Set<Symbol>]
# File lib/computed_model/model.rb, line 430 def current_deps @__computed_model_stack.last.deps end
current_subfields()
click to toggle source
Returns subfield selectors passed to the currently computing field, or nil if called outside of computed fields. @return [ComputedModel::NormalizableArray, nil]
# File lib/computed_model/model.rb, line 437 def current_subfields @__computed_model_stack.last.subfields end
Private Instance Methods
__computed_model_check_availability(name)
click to toggle source
@param name [Symbol]
# File lib/computed_model/model.rb, line 442 def __computed_model_check_availability(name) return if @__computed_model_stack.last.deps.include?(name) raise ComputedModel::ForbiddenDependency, "Not a direct dependency: #{name}" end