Class: Graphiti::Scope

Inherits:
Object show all
Defined in:
lib/graphiti/scope.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(object, resource, query, opts = {}) ⇒ Scope

Returns a new instance of Scope.



5
6
7
8
9
10
11
12
13
14
# File 'lib/graphiti/scope.rb', line 5

def initialize(object, resource, query, opts = {})
  @object = object
  @resource = resource
  @query = query
  @opts = opts

  @object = @resource.around_scoping(@object, @query.hash) { |scope|
    apply_scoping(scope, opts)
  }
end

Instance Attribute Details

#objectObject

Returns the value of attribute object.



3
4
5
# File 'lib/graphiti/scope.rb', line 3

def object
  @object
end

#paginationObject (readonly)

Returns the value of attribute pagination.



4
5
6
# File 'lib/graphiti/scope.rb', line 4

def pagination
  @pagination
end

#unpaginated_objectObject

Returns the value of attribute unpaginated_object.



3
4
5
# File 'lib/graphiti/scope.rb', line 3

def unpaginated_object
  @unpaginated_object
end

Instance Method Details

#cache_keyObject



74
75
76
77
78
79
80
81
82
# File 'lib/graphiti/scope.rb', line 74

def cache_key
  # This is the combined cache key for the base query and the query for all sideloads
  # Changing the query will yield a different cache key

  cache_keys = sideload_resource_proxies.map { |proxy| proxy.try(:cache_key) }

  cache_keys << @object.try(:cache_key) # this is what calls into the ORM (ActiveRecord, most likely)
  ActiveSupport::Cache.expand_cache_key(cache_keys.flatten.compact)
end

#cache_key_with_versionObject



84
85
86
87
88
89
90
91
92
# File 'lib/graphiti/scope.rb', line 84

def cache_key_with_version
  # This is the combined and versioned cache key for the base query and the query for all sideloads
  # If any returned model's updated_at changes, this key will change

  cache_keys = sideload_resource_proxies.map { |proxy| proxy.try(:cache_key_with_version) }

  cache_keys << @object.try(:cache_key_with_version) # this is what calls into ORM (ActiveRecord, most likely)
  ActiveSupport::Cache.expand_cache_key(cache_keys.flatten.compact)
end

#parent_resourceObject



70
71
72
# File 'lib/graphiti/scope.rb', line 70

def parent_resource
  @resource
end

#resolveObject



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/graphiti/scope.rb', line 16

def resolve
  if @query.zero_results?
    []
  else
    resolved = broadcast_data { |payload|
      @object = @resource.before_resolve(@object, @query)
      payload[:results] = @resource.resolve(@object)
      payload[:results]
    }
    resolved.compact!
    assign_serializer(resolved)
    yield resolved if block_given?
    @opts[:after_resolve]&.call(resolved)
    resolve_sideloads(resolved) unless @query.sideloads.empty?
    resolved
  end
end

#resolve_sideloads(results) ⇒ Object



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/graphiti/scope.rb', line 34

def resolve_sideloads(results)
  return if results == []

  concurrent = Graphiti.config.concurrency
  promises = []

  @query.sideloads.each_pair do |name, q|
    sideload = @resource.class.sideload(name)
    next if sideload.nil? || sideload.shared_remote?
    parent_resource = @resource
    graphiti_context = Graphiti.context
    resolve_sideload = -> {
      Graphiti.config.before_sideload&.call(graphiti_context)
      Graphiti.context = graphiti_context
      sideload.resolve(results, q, parent_resource)
      @resource.adapter.close if concurrent
    }
    if concurrent
      promises << Concurrent::Promise.execute(&resolve_sideload)
    else
      resolve_sideload.call
    end
  end

  if concurrent
    # Wait for all promises to finish
    sleep 0.01 until promises.all? { |p| p.fulfilled? || p.rejected? }
    # Re-raise the error with correct stacktrace
    # OPTION** to avoid failing here?? if so need serializable patch
    # to avoid loading data when association not loaded
    if (rejected = promises.find(&:rejected?))
      raise rejected.reason
    end
  end
end

#updated_atObject Also known as: last_modified_at



94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/graphiti/scope.rb', line 94

def updated_at
  updated_time = nil
  begin
    updated_ats = sideload_resource_proxies.map(&:updated_at)
    updated_ats << @object.maximum(:updated_at)
    updated_time = updated_ats.compact.max
  rescue => e
    Graphiti.log(["error calculating last_modified_at for #{@resource.class}", :red])
    Graphiti.log(e)
  end

  updated_time || Time.now
end