Class: Graphiti::ResourceProxy
- Includes:
- Enumerable
- Defined in:
- lib/graphiti/resource_proxy.rb
Instance Attribute Summary collapse
-
#cache ⇒ Object
readonly
Returns the value of attribute cache.
-
#cache_expires_in ⇒ Object
readonly
Returns the value of attribute cache_expires_in.
-
#cache_tag ⇒ Object
readonly
Returns the value of attribute cache_tag.
-
#payload ⇒ Object
readonly
Returns the value of attribute payload.
-
#query ⇒ Object
readonly
Returns the value of attribute query.
-
#resource ⇒ Object
readonly
Returns the value of attribute resource.
-
#scope ⇒ Object
readonly
Returns the value of attribute scope.
Instance Method Summary collapse
- #[](val) ⇒ Object
- #as_graphql(options = {}) ⇒ Object
- #as_json(options = {}) ⇒ Object
-
#assign_attributes(params) ⇒ Object
Apply request params to the underlying model without saving it, Rails-style: the params are always passed explicitly, in the same request-params shape find/build accept.
- #cache? ⇒ Boolean (also: #cached?)
- #cache_key ⇒ Object
- #cache_key_with_version ⇒ Object
- #data ⇒ Object (also: #to_a, #resolve_data)
-
#data=(models) ⇒ Object
Records supplied directly, no scope resolution.
- #debug_requested? ⇒ Boolean
- #destroy ⇒ Object
- #each(&blk) ⇒ Object
- #errors ⇒ Object
- #etag ⇒ Object
- #extra_fields ⇒ Object
- #fields ⇒ Object
- #future_resolve_data ⇒ Object
- #include_hash ⇒ Object
-
#initialize(resource, scope, query, payload: nil, single: false, raise_on_missing: false, assign_action: nil, cache: nil, cache_expires_in: nil, cache_tag: nil) ⇒ ResourceProxy
constructor
A new instance of ResourceProxy.
- #jsonapi_render_options(opts = {}) ⇒ Object
- #meta ⇒ Object
- #pagination ⇒ Object
- #raise_on_missing? ⇒ Boolean
- #resource_cache_tag ⇒ Object
- #save(action: :create) ⇒ Object
- #single? ⇒ Boolean
- #stats ⇒ Object
- #to_graphql(options = {}) ⇒ Object
- #to_json(options = {}) ⇒ Object
- #to_jsonapi(options = {}) ⇒ Object
- #to_xml(options = {}) ⇒ Object
-
#update(params = nil) ⇒ Object
(also: #update_attributes)
Rails-style: pass params to assign and save in one call, or call with no arguments to save a payload assigned earlier (via find or #assign_attributes).
- #updated_at ⇒ Object
-
#with_context_action(action) ⇒ Object
TODO: remove this.
Constructor Details
#initialize(resource, scope, query, payload: nil, single: false, raise_on_missing: false, assign_action: nil, cache: nil, cache_expires_in: nil, cache_tag: nil) ⇒ ResourceProxy
Returns a new instance of ResourceProxy.
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
# File 'lib/graphiti/resource_proxy.rb', line 7 def initialize( resource, scope, query, payload: nil, single: false, raise_on_missing: false, assign_action: nil, cache: nil, cache_expires_in: nil, cache_tag: nil ) @resource = resource @scope = scope @query = query @payload = payload @single = single @raise_on_missing = raise_on_missing @assign_action = assign_action @cache = cache @cache_expires_in = cache_expires_in @cache_tag = cache_tag end |
Instance Attribute Details
#cache ⇒ Object (readonly)
Returns the value of attribute cache.
5 6 7 |
# File 'lib/graphiti/resource_proxy.rb', line 5 def cache @cache end |
#cache_expires_in ⇒ Object (readonly)
Returns the value of attribute cache_expires_in.
5 6 7 |
# File 'lib/graphiti/resource_proxy.rb', line 5 def cache_expires_in @cache_expires_in end |
#cache_tag ⇒ Object (readonly)
Returns the value of attribute cache_tag.
5 6 7 |
# File 'lib/graphiti/resource_proxy.rb', line 5 def cache_tag @cache_tag end |
#payload ⇒ Object (readonly)
Returns the value of attribute payload.
5 6 7 |
# File 'lib/graphiti/resource_proxy.rb', line 5 def payload @payload end |
#query ⇒ Object (readonly)
Returns the value of attribute query.
5 6 7 |
# File 'lib/graphiti/resource_proxy.rb', line 5 def query @query end |
#resource ⇒ Object (readonly)
Returns the value of attribute resource.
5 6 7 |
# File 'lib/graphiti/resource_proxy.rb', line 5 def resource @resource end |
#scope ⇒ Object (readonly)
Returns the value of attribute scope.
5 6 7 |
# File 'lib/graphiti/resource_proxy.rb', line 5 def scope @scope end |
Instance Method Details
#[](val) ⇒ Object
49 50 51 |
# File 'lib/graphiti/resource_proxy.rb', line 49 def [](val) data[val] end |
#as_graphql(options = {}) ⇒ Object
80 81 82 |
# File 'lib/graphiti/resource_proxy.rb', line 80 def as_graphql( = {}) Renderer.new(self, ).as_graphql end |
#as_json(options = {}) ⇒ Object
68 69 70 |
# File 'lib/graphiti/resource_proxy.rb', line 68 def as_json( = {}) Renderer.new(self, ).as_json end |
#assign_attributes(params) ⇒ Object
Apply request params to the underlying model without saving it, Rails-style: the params are always passed explicitly, in the same request-params shape find/build accept. They are validated, deserialized, and become the payload #save will persist.
Idempotent per params - calling again with params that normalize to the same payload is a no-op, so the attributes callbacks fire once. Different params re-assign onto the same model instance.
Note the attributes callbacks fire here, outside any transaction opened during #save - the persistence hooks wrap only the save phase, receiving this assigned model.
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
# File 'lib/graphiti/resource_proxy.rb', line 161 def assign_attributes(params) action = @assign_action || :update params = normalized_params_copy(params) add_endpoint_filter(params, action) validator = ::Graphiti::RequestValidator.new(@resource, params, action) with_context_action(action) { validator.validate! } if @assigned_model && same_write_payload?(validator.deserialized_payload) return @assigned_model end @payload = validator.deserialized_payload @assigned_model = @data = @resource.assign_with_relationships( @payload.(action: action), @payload.attributes, @payload.relationships, model_instance: @assigned_model || (data if action == :update) ) end |
#cache? ⇒ Boolean Also known as: cached?
31 32 33 |
# File 'lib/graphiti/resource_proxy.rb', line 31 def cache? !!@cache end |
#cache_key ⇒ Object
283 284 285 286 287 288 289 290 291 |
# File 'lib/graphiti/resource_proxy.rb', line 283 def cache_key ActiveSupport::Cache.( [ @scope.cache_key, @query.cache_key, resource_cache_tag ].compact_blank ) end |
#cache_key_with_version ⇒ Object
293 294 295 296 297 298 299 300 301 |
# File 'lib/graphiti/resource_proxy.rb', line 293 def cache_key_with_version ActiveSupport::Cache.( [ @scope.cache_key_with_version, @query.cache_key, resource_cache_tag ].compact_blank ) end |
#data ⇒ Object Also known as: to_a, resolve_data
90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/graphiti/resource_proxy.rb', line 90 def data return @data unless @data.nil? return assign_attributes(@payload.params) if @assign_action @data = begin records = @scope.resolve raise Graphiti::Errors::RecordNotFound if records.empty? && raise_on_missing? records = records[0] if single? records end end |
#data=(models) ⇒ Object
Records supplied directly, no scope resolution
85 86 87 88 |
# File 'lib/graphiti/resource_proxy.rb', line 85 def data=(models) @data = models [@data].flatten.compact.each { |record| @resource.decorate_record(record) } end |
#debug_requested? ⇒ Boolean
265 266 267 |
# File 'lib/graphiti/resource_proxy.rb', line 265 def debug_requested? query.debug_requested? end |
#destroy ⇒ Object
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 |
# File 'lib/graphiti/resource_proxy.rb', line 221 def destroy resolve_data transaction_response = @resource.transaction do = {method: :destroy} model = @resource.destroy(@query.filters[:id], ) model.instance_variable_set(:@__serializer_klass, @resource.serializer) @resource.after_graph_persist(model, ) validator = ::Graphiti::Util::ValidationResponse.new \ model, @payload validator.validate! @resource.before_commit(model, ) {result: validator} end @data, success = transaction_response[:result].to_a success end |
#each(&blk) ⇒ Object
119 120 121 |
# File 'lib/graphiti/resource_proxy.rb', line 119 def each(&blk) to_a.each(&blk) end |
#errors ⇒ Object
45 46 47 |
# File 'lib/graphiti/resource_proxy.rb', line 45 def errors data.errors end |
#etag ⇒ Object
273 274 275 |
# File 'lib/graphiti/resource_proxy.rb', line 273 def etag "W/#{ActiveSupport::Digest.hexdigest(cache_key_with_version.to_s)}" end |
#extra_fields ⇒ Object
261 262 263 |
# File 'lib/graphiti/resource_proxy.rb', line 261 def extra_fields query.extra_fields end |
#fields ⇒ Object
257 258 259 |
# File 'lib/graphiti/resource_proxy.rb', line 257 def fields query.fields end |
#future_resolve_data ⇒ Object
106 107 108 109 110 111 112 113 |
# File 'lib/graphiti/resource_proxy.rb', line 106 def future_resolve_data @scope.future_resolve.then do |records| raise Graphiti::Errors::RecordNotFound if records.empty? && raise_on_missing? records = records[0] if single? @data = records end end |
#include_hash ⇒ Object
250 251 252 253 254 255 |
# File 'lib/graphiti/resource_proxy.rb', line 250 def include_hash @include_hash ||= begin base = @payload ? @payload.include_hash : {} base.deep_merge(@query.include_hash) end end |
#jsonapi_render_options(opts = {}) ⇒ Object
53 54 55 56 57 |
# File 'lib/graphiti/resource_proxy.rb', line 53 def (opts = {}) opts[:expose] ||= {} opts[:expose][:context] = Graphiti.context[:object] opts end |
#meta ⇒ Object
115 116 117 |
# File 'lib/graphiti/resource_proxy.rb', line 115 def @meta ||= data.respond_to?(:meta) ? data. : {} end |
#pagination ⇒ Object
145 146 147 |
# File 'lib/graphiti/resource_proxy.rb', line 145 def pagination @pagination ||= Delegates::Pagination.new(self) end |
#raise_on_missing? ⇒ Boolean
41 42 43 |
# File 'lib/graphiti/resource_proxy.rb', line 41 def raise_on_missing? !!@raise_on_missing end |
#resource_cache_tag ⇒ Object
277 278 279 280 281 |
# File 'lib/graphiti/resource_proxy.rb', line 277 def resource_cache_tag return unless @cache_tag.present? && @resource.respond_to?(@cache_tag) @resource.try(@cache_tag) end |
#save(action: :create) ⇒ Object
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
# File 'lib/graphiti/resource_proxy.rb', line 191 def save(action: :create) validator = with_context_action(action) do # An assigned model can only come from #assign_attributes, which # validated the payload it stored - re-validating here would run the # writable guards (and their guard_model lookups) a redundant time. unless @assigned_model ::Graphiti::RequestValidator.new(@resource, @payload.params, action).validate! end persist { @resource.persist_with_relationships \ @payload.(action: action), @payload.attributes, @payload.relationships, assigned_model: @assigned_model } end @data, success = validator.to_a if success # If the context action is `update` or `create`, certain # adapters will cause N+1 validation calls, so lets explicitly # switch to a lookup context. Graphiti.with_context(Graphiti.context[:object], :show) do @scope.resolve_sideloads([@data]) end end success end |
#single? ⇒ Boolean
37 38 39 |
# File 'lib/graphiti/resource_proxy.rb', line 37 def single? !!@single end |
#stats ⇒ Object
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/graphiti/resource_proxy.rb', line 123 def stats @stats ||= if @query.hash[:stats] scope = @scope.unpaginated_object if resource.adapter.can_group? if (group = @query.hash[:stats].delete(:group_by)) # A foreign key whose values render as public ids exposes nothing, so it may group even when unreadable. flag = resource.class.public_id_source_for(group[0]) ? :filterable : :readable resource.get_attr!(group[0], flag, request: true) scope = resource.adapter.group(scope, resource.model_attribute_for(group[0])) end end payload = Stats::Payload.new @resource, @query, scope, data, group_by: group&.first payload.generate else {} end end |
#to_graphql(options = {}) ⇒ Object
76 77 78 |
# File 'lib/graphiti/resource_proxy.rb', line 76 def to_graphql( = {}) Renderer.new(self, ).to_graphql end |
#to_json(options = {}) ⇒ Object
64 65 66 |
# File 'lib/graphiti/resource_proxy.rb', line 64 def to_json( = {}) Renderer.new(self, ).to_json end |
#to_jsonapi(options = {}) ⇒ Object
59 60 61 62 |
# File 'lib/graphiti/resource_proxy.rb', line 59 def to_jsonapi( = {}) = () Renderer.new(self, ).to_jsonapi end |
#to_xml(options = {}) ⇒ Object
72 73 74 |
# File 'lib/graphiti/resource_proxy.rb', line 72 def to_xml( = {}) Renderer.new(self, ).to_xml end |
#update(params = nil) ⇒ Object Also known as: update_attributes
Rails-style: pass params to assign and save in one call, or call with no arguments to save a payload assigned earlier (via find or #assign_attributes).
242 243 244 245 246 |
# File 'lib/graphiti/resource_proxy.rb', line 242 def update(params = nil) assign_attributes(params) if params resolve_data save(action: :update) end |
#updated_at ⇒ Object
269 270 271 |
# File 'lib/graphiti/resource_proxy.rb', line 269 def updated_at @scope.updated_at end |
#with_context_action(action) ⇒ Object
TODO: remove this. Only used for persisting many-to-many with AR (see activerecord adapter)
183 184 185 186 187 188 189 |
# File 'lib/graphiti/resource_proxy.rb', line 183 def with_context_action(action) original = Graphiti.context[:action] Graphiti.context[:action] = action yield ensure Graphiti.context[:action] = original end |