graphiti 1.12.0 → 1.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0ffd673e5dc4ec50d5b5aeb01abcb192894c6451cd9bfd54eca081f76bdf1d49
4
- data.tar.gz: 45ed5cf75d703bd9b573015cd7f798cdc8fe1d5606d198bbdbda09d8e9dd7383
3
+ metadata.gz: 96af714433c7faece37e74ab67dad245d5e03396ec391be80cec77622d231faf
4
+ data.tar.gz: 34ce7b027042cd3cda4cf656ba8d96a05908dc0edbe9104ee4fb3597c5970971
5
5
  SHA512:
6
- metadata.gz: 1472ab72a4ba8982a06a99d4959460ddae1e350ac6f1ce579dbe694c9c2cac6901e46d74b61532895f248e29848361aa311f39320201cb94f002874d64b34386
7
- data.tar.gz: 44d3d9fbb1f78c6ba6a1fe005dc19a9f64a7b15236075b224571d585754928352d032a5acccd7f6165695990ff5a66750868a13ebd87fec9d33e9446e599fb97
6
+ metadata.gz: 3d0c414812bbccef7567e2e8e48e6b6353582d7801aa71a893f368eb12c71906e1420a1f40dd6d18c8ad6e5d43e3585983340d409742303112dd2737810a26d1
7
+ data.tar.gz: 59774b04ced36164343ddb12a7f2aa2026d2981b0c9df1b6bb92f127abb856467403e64cf72ec15bfde012511f1fa5908bf38bbbecea1becc2527d61df346d72
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  graphiti changelog
2
2
 
3
+ ## [1.12.1](https://github.com/graphiti-api/graphiti/compare/v1.12.0...v1.12.1) (2026-07-29)
4
+
5
+
6
+ ### Performance Improvements
7
+
8
+ * skip promise machinery when concurrency is disabled ([#510](https://github.com/graphiti-api/graphiti/issues/510)) ([b2e5f37](https://github.com/graphiti-api/graphiti/commit/b2e5f37428f7628b9fadd03823bd68552e125af0)), closes [#472](https://github.com/graphiti-api/graphiti/issues/472) [#497](https://github.com/graphiti-api/graphiti/issues/497) [#505](https://github.com/graphiti-api/graphiti/issues/505)
9
+
3
10
  # [1.12.0](https://github.com/graphiti-api/graphiti/compare/v1.11.1...v1.12.0) (2026-07-29)
4
11
 
5
12
 
@@ -42,11 +42,20 @@ module Graphiti
42
42
  }
43
43
  end
44
44
 
45
- def resolve
45
+ def resolve(&blk)
46
+ # When concurrency is disabled, take a synchronous path that mirrors the
47
+ # pre-1.8 semantics. This avoids allocating Concurrent::Promises futures,
48
+ # Thread/Fiber storage snapshots, and Rails executor wrappers on every
49
+ # request purely to drive a thread pool that is intentionally synchronous.
50
+ # See https://github.com/graphiti-api/graphiti/issues/505
51
+ return sync_resolve(&blk) unless Graphiti.config.concurrency
52
+
46
53
  future_resolve.value!
47
54
  end
48
55
 
49
56
  def resolve_sideloads(results)
57
+ return sync_resolve_sideloads(results) unless Graphiti.config.concurrency
58
+
50
59
  future_resolve_sideloads(results).value!
51
60
  end
52
61
 
@@ -113,6 +122,43 @@ module Graphiti
113
122
 
114
123
  private
115
124
 
125
+ # Synchronous counterpart to #future_resolve, used when concurrency is off.
126
+ # Resolves the resource and its sideloads inline without any promise
127
+ # machinery. See #resolve.
128
+ def sync_resolve
129
+ return [] if @query.zero_results?
130
+
131
+ resolved = broadcast_data { |payload|
132
+ @object = @resource.before_resolve(@object, @query)
133
+ payload[:results] = @resource.resolve(@object)
134
+ payload[:results]
135
+ }
136
+ resolved.compact!
137
+ assign_serializer(resolved)
138
+ yield resolved if block_given?
139
+ @opts[:after_resolve]&.call(resolved)
140
+ sync_resolve_sideloads(resolved) unless @query.sideloads.empty?
141
+ resolved
142
+ end
143
+
144
+ # Synchronous counterpart to #future_resolve_sideloads, used when
145
+ # concurrency is off. Resolves each sideload inline. See #resolve_sideloads.
146
+ def sync_resolve_sideloads(results)
147
+ return if results == []
148
+
149
+ @query.sideloads.each_pair do |name, q|
150
+ sideload = @resource.class.sideload(name)
151
+ next if sideload.nil? || sideload.shared_remote?
152
+
153
+ Graphiti.config.before_sideload&.call(Graphiti.context)
154
+ sideload.resolve(results, q, @resource)
155
+ end
156
+
157
+ # Match pre-1.8 semantics: the non-concurrent resolve_sideloads returned
158
+ # nil (not the sideloads Hash). Callers don't rely on the return value.
159
+ nil
160
+ end
161
+
116
162
  def future_resolve_sideloads(results)
117
163
  return Concurrent::Promises.fulfilled_future(nil, self.class.global_thread_pool_executor) if results == []
118
164
 
@@ -108,7 +108,20 @@ class Graphiti::Sideload::PolymorphicBelongsTo < Graphiti::Sideload::BelongsTo
108
108
  end
109
109
 
110
110
  def resolve(parents, query, graph_parent)
111
- future_resolve(parents, query, graph_parent).value!
111
+ return future_resolve(parents, query, graph_parent).value! if Graphiti.config.concurrency
112
+
113
+ parents.group_by(&grouper.field_name).each_pair do |group_name, group|
114
+ next if group_name.nil? || grouper.ignore?(group_name)
115
+
116
+ match = ->(c) { c.group_name == group_name.to_sym }
117
+ if (sideload = children.values.find(&match))
118
+ duped = remove_invalid_sideloads(sideload.resource, query)
119
+ sideload.resolve(group, duped, graph_parent)
120
+ else
121
+ err = ::Graphiti::Errors::PolymorphicSideloadChildNotFound
122
+ raise err.new(self, group_name)
123
+ end
124
+ end
112
125
  end
113
126
 
114
127
  def future_resolve(parents, query, graph_parent)
@@ -240,6 +240,8 @@ module Graphiti
240
240
  end
241
241
 
242
242
  def load(parents, query, graph_parent)
243
+ return build_resource_proxy(parents, query, graph_parent).to_a unless Graphiti.config.concurrency
244
+
243
245
  future_load(parents, query, graph_parent).value!
244
246
  end
245
247
 
@@ -290,6 +292,33 @@ module Graphiti
290
292
  children.replace(associated) if track_associated
291
293
  end
292
294
 
295
+ # Synchronous counterpart to #future_resolve, used when concurrency is off.
296
+ # Mirrors #future_resolve but resolves inline via the synchronous
297
+ # Scope#resolve / #load paths (no promises). See Scope#sync_resolve_sideloads.
298
+ def resolve(parents, query, graph_parent)
299
+ return future_resolve(parents, query, graph_parent).value! if Graphiti.config.concurrency
300
+
301
+ if single? && parents.length > 1
302
+ raise Errors::SingularSideload.new(self, parents.length)
303
+ end
304
+
305
+ if self.class.scope_proc
306
+ sideload_scope = fire_scope(parents)
307
+ sideload_scope = Scope.new sideload_scope,
308
+ resource,
309
+ query,
310
+ parent: graph_parent,
311
+ sideload: self,
312
+ sideload_parent_length: parents.length,
313
+ default_paginate: false
314
+ sideload_scope.resolve do |sideload_results|
315
+ fire_assign(parents, sideload_results)
316
+ end
317
+ else
318
+ load(parents, query, graph_parent)
319
+ end
320
+ end
321
+
293
322
  def future_resolve(parents, query, graph_parent)
294
323
  if single? && parents.length > 1
295
324
  raise Errors::SingularSideload.new(self, parents.length)
@@ -1,3 +1,3 @@
1
1
  module Graphiti
2
- VERSION = "1.12.0"
2
+ VERSION = "1.12.1"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphiti
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.12.0
4
+ version: 1.12.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lee Richmond