Skip to content

Commit d3e09c2

Browse files
authored
fix: Re-use resource class for remote sideloads to avoid memory leak (#421)
1 parent 91c4210 commit d3e09c2

File tree

3 files changed

+29
-7
lines changed

3 files changed

+29
-7
lines changed

lib/graphiti.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,6 @@ def self.setup!
137137
require "graphiti/request_validator"
138138
require "graphiti/request_validators/validator"
139139
require "graphiti/request_validators/update_validator"
140-
require "graphiti/query"
141140
require "graphiti/scope"
142141
require "graphiti/deserializer"
143142
require "graphiti/renderer"
@@ -176,6 +175,7 @@ def self.setup!
176175
require "graphiti/extensions/boolean_attribute"
177176
require "graphiti/extensions/temp_id"
178177
require "graphiti/serializer"
178+
require "graphiti/query"
179179
require "graphiti/debugger"
180180

181181
if defined?(ActiveRecord)

lib/graphiti/query.rb

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,14 @@ def sideload_hash
7676
end
7777
end
7878

79+
class RemoteSideloadResource < ::Graphiti::Resource
80+
self.remote = "_remote_sideload_".freeze
81+
self.abstract_class = true # exclude from schema
82+
end
83+
7984
def resource_for_sideload(sideload)
8085
if @resource.remote?
81-
Class.new(Graphiti::Resource) {
82-
self.remote = "_remote_sideload_"
83-
}.new
86+
RemoteSideloadResource.new
8487
else
8588
sideload.resource
8689
end

spec/query_spec.rb

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
before do
1212
employee_resource.has_many :positions,
1313
resource: position_resource
14+
employee_resource.belongs_to :remote, remote: true
1415
position_resource.belongs_to :department,
1516
resource: department_resource
1617
employee_resource.attribute :name, :string
@@ -986,11 +987,29 @@
986987
end
987988

988989
describe "sideloads" do
989-
before { params[:include] = "positions" }
990990
subject(:sideloads) { instance.sideloads }
991991

992-
it "does not cascate the action" do
993-
expect(sideloads.values.map(&:action)).to eq([:all])
992+
context "when including an has_many resource" do
993+
before { params[:include] = "positions" }
994+
995+
it "does not cascate the action" do
996+
expect(sideloads.values.map(&:action)).to eq([:all])
997+
end
998+
end
999+
1000+
context "when including a resource from a remote resource" do
1001+
before { params[:include] = "remote.resource" }
1002+
1003+
let(:sideloads_of_another_query) { described_class.new(resource, params).sideloads }
1004+
1005+
def resource_class_of_remote_sideload(sideloads)
1006+
sideloads.fetch(:remote).sideloads.fetch(:resource).resource.class
1007+
end
1008+
1009+
it "re-uses resource class across multiple queries (avoid memory leak)" do
1010+
expect(resource_class_of_remote_sideload(sideloads))
1011+
.to eq(resource_class_of_remote_sideload(sideloads_of_another_query))
1012+
end
9941013
end
9951014
end
9961015
end

0 commit comments

Comments
 (0)