module JSONAPI::Realizer::Resource

Constants

MIXIN_HOOK

Attributes

context[W]
headers[RW]
intent[W]
parameters[RW]
scope[RW]

Public Class Methods

new(**keyword_arguments) click to toggle source
Calls superclass method
# File lib/jsonapi/realizer/resource.rb, line 43
def initialize(**keyword_arguments)
  super(**keyword_arguments)

  context.validate!
  validate!

  if filtering?
    @scope = adapter.filtering(scope, filters)
  end

  if include?
    @scope = adapter.include_relationships(scope, includes)
  end

  if sorting?
    @scope = adapter.sorting(scope, sorts)
  end

  if paginate?
    @scope = adapter.paginate(scope, *pagination)
  end

  if writing? && data?
    adapter.write_attributes(object, attributes)
    adapter.write_relationships(object, relationships)
  end
end

Public Instance Methods

attributes() click to toggle source
# File lib/jsonapi/realizer/resource.rb, line 192
def attributes
  return unless data.key?("attributes")

  @attributes ||= data.
    fetch("attributes").
    transform_keys(&:underscore).
    transform_keys{|key| attribute(key).as}
end
configuration() click to toggle source
# File lib/jsonapi/realizer/resource.rb, line 313
def configuration
  @configuration ||= Configuration.new({
    :owner => self,
    :type => @type,
    :model_class => @model_class,
    :adapter => @adapter,
    :attributes => @attributes,
    :relations => @relations
  })
end
context() click to toggle source
# File lib/jsonapi/realizer/resource.rb, line 258
def context
  self.class.const_get("Context").new(**@context || {})
end
filtering?() click to toggle source
# File lib/jsonapi/realizer/resource.rb, line 116
def filtering?
  parameters.key?("filter")
end
filters() click to toggle source
# File lib/jsonapi/realizer/resource.rb, line 120
def filters
  @filters ||= parameters.
    # {"filter" => {"full-name" => "Abby Marquardt", "email" => "amado@goldner.com"}}
    fetch("filter").
    # {"full-name" => "Abby Marquardt", "email" => "amado@goldner.com"}
    transform_keys(&:underscore)
    # {"full_name" => "Abby Marquardt", "email" => "amado@goldner.com"}
end
has(name, as: name) click to toggle source
# File lib/jsonapi/realizer/resource.rb, line 281
def has(name, as: name)
  @attributes[name] ||= Attribute.new(
    :name => name,
    :as => as,
    :owner => self
  )
end
has_many(name, as: name, class_name:) click to toggle source
# File lib/jsonapi/realizer/resource.rb, line 299
def has_many(name, as: name, class_name:)
  @relations[name] ||= Relation.new(
    :owner => self,
    :type => :many,
    :name => name,
    :as => as,
    :realizer_class_name => class_name
  )
end
has_one(name, as: name, class_name:) click to toggle source
# File lib/jsonapi/realizer/resource.rb, line 289
def has_one(name, as: name, class_name:)
  @relations[name] ||= Relation.new(
    :owner => self,
    :type => :one,
    :name => name,
    :as => as,
    :realizer_class_name => class_name
  )
end
identifier(value) click to toggle source
# File lib/jsonapi/realizer/resource.rb, line 271
def identifier(value)
  @identifier ||= value.to_sym
end
include?() click to toggle source
# File lib/jsonapi/realizer/resource.rb, line 129
def include?
  parameters.key?("include")
end
includes() click to toggle source
# File lib/jsonapi/realizer/resource.rb, line 133
def includes
  @includes ||= parameters.
    # {"include" => "active-photographer.photographs,comments,comments.author"}
    fetch("include").
    # "active-photographer.photographs,comments,comments.author"
    split(/\s*,\s*/).
    # ["active-photographer.photographs", "comments", "comments.author"]
    map {|chain| chain.split(".")}.
    # [["active-photographer", "photographs"], ["comments"], ["comments", "author"]]
    map {|list| list.map(&:underscore)}.
    # [["active_photographer", "photographs"], ["comments"], ["comments", "author"]]
    map do |relationship_chain|
      # This walks down the path of relationships and normalizes thenm to
      # their defined "as", which lets us expose AccountRealizer#name, but that actually
      # references Account#full_name.
      relationship_chain.reduce([[], self.class]) do |(normalized_relationship_chain, realizer_class), relationship_link|
        [
          [
            *normalized_relationship_chain,
            realizer_class.relation(relationship_link).as
          ],
          realizer_class.relation(relationship_link).realizer_class
        ]
      end.first
    end
    # [["account", "photographs"], ["comments"], ["comments", "account"]]
end
inherited(object) click to toggle source
# File lib/jsonapi/realizer/resource.rb, line 267
def inherited(object)
  object.class_eval(&MIXIN_HOOK) unless object.instance_variable_defined?(:@abstract_class)
end
intent() click to toggle source
# File lib/jsonapi/realizer/resource.rb, line 226
def intent
  @intent.to_sym
end
object() click to toggle source
# File lib/jsonapi/realizer/resource.rb, line 215
def object
  @object ||= case intent
  when :create
    scope.new
  when :show, :update, :destroy
    adapter.find_one(scope, parameters.fetch("id"))
  else
    scope
  end
end
paginate?() click to toggle source
# File lib/jsonapi/realizer/resource.rb, line 84
def paginate?
  parameters.key?("page") && (parameters.fetch("page").key?("limit") || parameters.fetch("page").key?("offset"))
end
pagination() click to toggle source
# File lib/jsonapi/realizer/resource.rb, line 88
def pagination
  [
    parameters.fetch("page").fetch("limit", nil),
    parameters.fetch("page").fetch("offset", nil)
  ]
end
relationships() click to toggle source
# File lib/jsonapi/realizer/resource.rb, line 201
def relationships
  return unless data.key?("relationships")

  @relationships ||= data.
    fetch("relationships").
    transform_keys(&:underscore).
    map(&method(:as_relationship)).to_h.
    transform_keys{|key| relation(key).as}
end
selects() click to toggle source
# File lib/jsonapi/realizer/resource.rb, line 165
def selects
  @selects ||= parameters.
    # {"fields" => {"articles" => "title,body,sub-text", "people" => "name"}}
    fetch("fields").
    # {"articles" => "title,body,sub-text", "people" => "name"}
    transform_keys(&:underscore).
    # {"articles" => "title,body,sub-text", "people" => "name"}
    transform_values {|value| value.split(/\s*,\s*/)}.
    # {"articles" => ["title", "body", "sub-text"], "people" => ["name"]}
    transform_values {|value| value.map(&:underscore)}
    # {"articles" => ["title", "body", "sub_text"], "people" => ["name"]}
end
selects?() click to toggle source
# File lib/jsonapi/realizer/resource.rb, line 161
def selects?
  parameters.key?("fields")
end
sorting?() click to toggle source
# File lib/jsonapi/realizer/resource.rb, line 95
def sorting?
  parameters.key?("sort")
end
sorts() click to toggle source
# File lib/jsonapi/realizer/resource.rb, line 99
def sorts
  @sorts ||= parameters.
    # {sort: "name,-age,accounts.created_at,-accounts.updated_at"}
    fetch("sort").
    # "name,-age,accounts.created_at,-accounts.updated_at"
    split(",").
    # ["name", "-age", "accounts.created_at", "-accounts.updated_at"]
    map do |token|
      if token.start_with?("-") then [token.sub(/^-/, "").underscore, "-"] else [token.underscore, "+"] end
    end.
    # [["name", "+"], ["age", "-"], ["accounts.created_at", "+"], ["accounts.updated_at", "-"]]
    map do |(path, direction)|
      [if path.include?(".") then path.split(".") else [self.class.configuration.type, path] end, direction]
    end
    # [[["accounts", "name"], "+"], [["accounts", "age"], "-"], [["accounts", "created_at"], "+"], [["accounts", "updated_at"], "-"]]
end
to_hash() click to toggle source
# File lib/jsonapi/realizer/resource.rb, line 71
def to_hash
  @native ||= {
    :pagination => if paginate? then pagination end,
    :selects => if selects? then selects end,
    :includes => if include? then includes end,
    :object => object
  }.compact
end

Private Instance Methods

adapter() click to toggle source
# File lib/jsonapi/realizer/resource.rb, line 250
        def adapter
  self.class.configuration.adapter
end
as_relationship(name, value) click to toggle source
# File lib/jsonapi/realizer/resource.rb, line 230
        def as_relationship(name, value)
  data = value.fetch("data")

  relation_configuration = relation(name).realizer_class.configuration

  if data.is_a?(Array)
    [name, relation_configuration.adapter.find_many(relation_configuration.model_class, {id: data.map {|value| value.fetch("id")}})]
  else
    [name, relation_configuration.adapter.find_one(relation_configuration.model_class, data.fetch("id"))]
  end
end
attribute(name) click to toggle source
# File lib/jsonapi/realizer/resource.rb, line 242
        def attribute(name)
  self.class.attribute(name)
end
data() click to toggle source
# File lib/jsonapi/realizer/resource.rb, line 182
        def data
  @data ||= parameters.fetch("data")
end
data?() click to toggle source
# File lib/jsonapi/realizer/resource.rb, line 178
        def data?
  parameters.key?("data")
end
model_class() click to toggle source
# File lib/jsonapi/realizer/resource.rb, line 254
        def model_class
  self.class.configuration.model_class
end
relation(name) click to toggle source
# File lib/jsonapi/realizer/resource.rb, line 246
        def relation(name)
  self.class.relation(name)
end
type() click to toggle source
# File lib/jsonapi/realizer/resource.rb, line 186
        def type
  return unless data.key?("type")

  @type ||= data.fetch("type")
end
writing?() click to toggle source
# File lib/jsonapi/realizer/resource.rb, line 80
        def writing?
  [:create, :update].include?(intent)
end