Class: Graphiti::Scope
Instance Attribute Summary collapse
-
#object ⇒ Object
Returns the value of attribute object.
-
#pagination ⇒ Object
readonly
Returns the value of attribute pagination.
-
#unpaginated_object ⇒ Object
Returns the value of attribute unpaginated_object.
Class Method Summary collapse
- .global_thread_pool_executor ⇒ Object
- .global_thread_pool_stats ⇒ Object
-
.marking_pool_thread ⇒ Object
Restores rather than clears because :caller_runs may have run the task on a request thread.
-
.on_pool_thread? ⇒ Boolean
TODO: move to Fiber once the floor is Ruby 3.2.
-
.resolve_synchronously? ⇒ Boolean
A pool thread that waits on the pool deadlocks, since the task it waits for cannot start until the waiting thread frees its slot.
Instance Method Summary collapse
- #cache_key ⇒ Object
- #cache_key_with_version ⇒ Object
- #future_resolve(&blk) ⇒ Object
-
#initialize(object, resource, query, opts = {}) ⇒ Scope
constructor
A new instance of Scope.
- #parent_resource ⇒ Object
- #resolve(&blk) ⇒ Object
- #resolve_sideloads(results) ⇒ Object
- #updated_at ⇒ Object (also: #last_modified_at)
Constructor Details
#initialize(object, resource, query, opts = {}) ⇒ Scope
Returns a new instance of Scope.
56 57 58 59 60 61 62 63 64 65 |
# File 'lib/graphiti/scope.rb', line 56 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
#object ⇒ Object
Returns the value of attribute object.
3 4 5 |
# File 'lib/graphiti/scope.rb', line 3 def object @object end |
#pagination ⇒ Object (readonly)
Returns the value of attribute pagination.
4 5 6 |
# File 'lib/graphiti/scope.rb', line 4 def pagination @pagination end |
#unpaginated_object ⇒ Object
Returns the value of attribute unpaginated_object.
3 4 5 |
# File 'lib/graphiti/scope.rb', line 3 def unpaginated_object @unpaginated_object end |
Class Method Details
.global_thread_pool_executor ⇒ Object
24 25 26 |
# File 'lib/graphiti/scope.rb', line 24 def self.global_thread_pool_executor GLOBAL_THREAD_POOL_EXECUTOR.value! end |
.global_thread_pool_stats ⇒ Object
28 29 30 31 32 |
# File 'lib/graphiti/scope.rb', line 28 def self.global_thread_pool_stats GLOBAL_THREAD_POOL_EXECUTOR_BROADCAST_STATS.each_with_object({}) do |key, memo| memo[key] = global_thread_pool_executor.send(key) end end |
.marking_pool_thread ⇒ Object
Restores rather than clears because :caller_runs may have run the task on a request thread.
48 49 50 51 52 53 54 |
# File 'lib/graphiti/scope.rb', line 48 def self.marking_pool_thread previous = Thread.current[POOL_THREAD] Thread.current[POOL_THREAD] = true yield ensure Thread.current[POOL_THREAD] = previous end |
.on_pool_thread? ⇒ Boolean
TODO: move to Fiber once the floor is Ruby 3.2
43 44 45 |
# File 'lib/graphiti/scope.rb', line 43 def self.on_pool_thread? Thread.current[POOL_THREAD] == true end |
Instance Method Details
#cache_key ⇒ Object
106 107 108 109 110 111 112 113 114 |
# File 'lib/graphiti/scope.rb', line 106 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.(cache_keys.flatten.compact) end |
#cache_key_with_version ⇒ Object
116 117 118 119 120 121 122 123 124 |
# File 'lib/graphiti/scope.rb', line 116 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.(cache_keys.flatten.compact) end |
#future_resolve(&blk) ⇒ Object
88 89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/graphiti/scope.rb', line 88 def future_resolve(&blk) return Concurrent::Promises.fulfilled_future([], self.class.global_thread_pool_executor) if @query.zero_results? resolved = resolve_primary_data(&blk) sideloaded = @query.parents.any? close_adapter = Graphiti.config.concurrency && sideloaded if close_adapter @resource.adapter.close end future_resolve_sideloads(resolved) .then_on(self.class.global_thread_pool_executor, resolved) { resolved } end |
#parent_resource ⇒ Object
102 103 104 |
# File 'lib/graphiti/scope.rb', line 102 def parent_resource @resource end |
#resolve(&blk) ⇒ Object
67 68 69 70 71 72 73 74 75 |
# File 'lib/graphiti/scope.rb', line 67 def resolve(&blk) # The caller blocks on .value! either way, so concurrency only benefits parallel sideloads # See https://github.com/graphiti-api/graphiti/issues/505 if self.class.resolve_synchronously? || !applicable_sideloads? sync_resolve(&blk) else future_resolve(&blk).value! end end |
#resolve_sideloads(results) ⇒ Object
77 78 79 80 81 82 83 84 85 86 |
# File 'lib/graphiti/scope.rb', line 77 def resolve_sideloads(results) if self.class.resolve_synchronously? sync_resolve_sideloads(results) else future_resolve_sideloads(results).value! end # Never return the sideloads hash, a caller mutating it would mess up the cache key nil end |
#updated_at ⇒ Object Also known as: last_modified_at
126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/graphiti/scope.rb', line 126 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 |