Module: JSONAPI::Realizer::Resource

Extended by:
ActiveSupport::Concern
Includes:
ActiveModel::Model
Defined in:
lib/jsonapi/realizer/resource.rb,
lib/jsonapi/realizer/resource/relation.rb,
lib/jsonapi/realizer/resource/attribute.rb,
lib/jsonapi/realizer/resource/configuration.rb

Defined Under Namespace

Classes: Attribute, Configuration, Relation

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#contextObject



201
202
203
# File 'lib/jsonapi/realizer/resource.rb', line 201

def context
  self.class.const_get(:Context).new(**@context || {})
end

#headersObject

Returns the value of attribute headers.



41
42
43
# File 'lib/jsonapi/realizer/resource.rb', line 41

def headers
  @headers
end

#intentObject



197
198
199
# File 'lib/jsonapi/realizer/resource.rb', line 197

def intent
  @intent.to_sym
end

#parametersObject

Returns the value of attribute parameters.



40
41
42
# File 'lib/jsonapi/realizer/resource.rb', line 40

def parameters
  @parameters
end

#scope=(value) ⇒ Object

Sets the attribute scope



43
44
45
# File 'lib/jsonapi/realizer/resource.rb', line 43

def scope=(value)
  @scope = value
end

Instance Method Details

#attributesObject



169
170
171
172
173
174
175
# File 'lib/jsonapi/realizer/resource.rb', line 169

def attributes
  return {} unless data["attributes"].kind_of?(Hash)
  @attributes ||= data
                  .fetch("attributes")
                  .transform_keys(&:underscore)
                  .transform_keys { |key| attribute(key).as }
end

#filtering?Boolean



107
108
109
# File 'lib/jsonapi/realizer/resource.rb', line 107

def filtering?
  parameters.key?("filter")
end

#filtersObject



111
112
113
114
115
116
117
118
# File 'lib/jsonapi/realizer/resource.rb', line 111

def filters
  @filters ||= parameters.
               # {"filter" => {"full-name" => "Abby Marquardt", "email" => "[email protected]"}}
               fetch("filter").
               # {"full-name" => "Abby Marquardt", "email" => "[email protected]"}
               transform_keys(&:underscore)
  # {"full_name" => "Abby Marquardt", "email" => "[email protected]"}
end

#include?Boolean



120
121
122
# File 'lib/jsonapi/realizer/resource.rb', line 120

def include?
  parameters.key?("include")
end

#includesObject



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/jsonapi/realizer/resource.rb', line 124

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

#initialize(**keyword_arguments) ⇒ Object



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/jsonapi/realizer/resource.rb', line 45

def initialize(**keyword_arguments)
  super(**keyword_arguments)

  context.validate!
  validate!

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

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

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

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

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

  return unless writing? && data? && relationships?

  adapter.write_relationships(object, relationships)
end

#objectObject



186
187
188
189
190
191
192
193
194
195
# File 'lib/jsonapi/realizer/resource.rb', line 186

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?Boolean



75
76
77
# File 'lib/jsonapi/realizer/resource.rb', line 75

def paginate?
  parameters.key?("page") && (parameters.fetch("page").key?("limit") || parameters.fetch("page").key?("offset"))
end

#paginationObject



79
80
81
82
83
84
# File 'lib/jsonapi/realizer/resource.rb', line 79

def pagination
  [
    parameters.fetch("page").fetch("limit", nil),
    parameters.fetch("page").fetch("offset", nil)
  ]
end

#relationshipsObject



177
178
179
180
181
182
183
184
# File 'lib/jsonapi/realizer/resource.rb', line 177

def relationships
  return {} unless data["relationships"].kind_of?(Hash)
  @relationships ||= data
                     .fetch("relationships")
                     .transform_keys(&:underscore)
                     .map(&method(:as_relationship)).to_h
                     .transform_keys { |key| relation(key).as }
end

#selectsObject



156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/jsonapi/realizer/resource.rb', line 156

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?Boolean



152
153
154
# File 'lib/jsonapi/realizer/resource.rb', line 152

def selects?
  parameters.key?("fields")
end

#sorting?Boolean



86
87
88
# File 'lib/jsonapi/realizer/resource.rb', line 86

def sorting?
  parameters.key?("sort")
end

#sortsObject



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/jsonapi/realizer/resource.rb', line 90

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|
               token.start_with?("-") ? [token.sub(/^-/, "").underscore, "-"] : [token.underscore, "+"]
             end.
             # [["name", "+"], ["age", "-"], ["accounts.created_at", "+"], ["accounts.updated_at", "-"]]
             map do |(path, direction)|
    [path.include?(".") ? path.split(".") : [self.class.configuration.type, path], direction]
  end
  # [[["accounts", "name"], "+"], [["accounts", "age"], "-"], [["accounts", "created_at"], "+"], [["accounts", "updated_at"], "-"]]
end

#to_hashObject



66
67
68
69
70
71
72
73
# File 'lib/jsonapi/realizer/resource.rb', line 66

def to_hash
  @to_hash ||= {
    pagination: (pagination if paginate?),
    selects: (selects if selects?),
    includes: (includes if include?),
    object:
  }.compact
end