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



207
208
209
# File 'lib/jsonapi/realizer/resource.rb', line 207

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



203
204
205
# File 'lib/jsonapi/realizer/resource.rb', line 203

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

Parameters:

  • value

    the value to set the attribute scope to.



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

def scope=(value)
  @scope = value
end

Instance Method Details

#attributesObject



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

def attributes
  @attributes ||= data
                  .fetch("attributes")
                  .transform_keys(&:underscore)
                  .transform_keys { |key| attribute(key).as }
end

#filtering?Boolean

Returns:

  • (Boolean)


115
116
117
# File 'lib/jsonapi/realizer/resource.rb', line 115

def filtering?
  parameters.key?("filter") && parameters.fetch("filter").respond_to?(:transform_keys)
end

#filtersObject



119
120
121
122
123
124
125
126
# File 'lib/jsonapi/realizer/resource.rb', line 119

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

Returns:

  • (Boolean)


128
129
130
# File 'lib/jsonapi/realizer/resource.rb', line 128

def include?
  parameters.key?("include") && parameters.fetch("include").respond_to?(:split) && parameters.fetch("include").split(/\s*,\s*/).any?
end

#includesObject



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/jsonapi/realizer/resource.rb', line 132

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



192
193
194
195
196
197
198
199
200
201
# File 'lib/jsonapi/realizer/resource.rb', line 192

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

Returns:

  • (Boolean)


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

def paginate?
  parameters.key?("page") && parameters.fetch("page").respond_to?(:fetch) && (paginate_limit? || paginate_offset?)
end

#paginationObject



87
88
89
90
91
92
# File 'lib/jsonapi/realizer/resource.rb', line 87

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

#relationshipsObject



184
185
186
187
188
189
190
# File 'lib/jsonapi/realizer/resource.rb', line 184

def relationships
  @relationships ||= data
                     .fetch("relationships")
                     .transform_keys(&:underscore)
                     .map(&method(:as_relationship)).to_h
                     .transform_keys { |key| relation(key).as }
end

#selectsObject



164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/jsonapi/realizer/resource.rb', line 164

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

Returns:

  • (Boolean)


160
161
162
# File 'lib/jsonapi/realizer/resource.rb', line 160

def selects?
  parameters.key?("fields") && parameters.fetch("fields").respond_to?(:transform_keys)
end

#sorting?Boolean

Returns:

  • (Boolean)


94
95
96
# File 'lib/jsonapi/realizer/resource.rb', line 94

def sorting?
  parameters.key?("sort") && parameters.fetch("sort").respond_to?(:split)
end

#sortsObject



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/jsonapi/realizer/resource.rb', line 98

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