Skip to content
This repository was archived by the owner on Oct 26, 2022. It is now read-only.

Commit dfc6701

Browse files
committed
Restore relation connection with original nodes
1 parent 9618cab commit dfc6701

File tree

6 files changed

+45
-16
lines changed

6 files changed

+45
-16
lines changed

lib/graphql/cache/resolvers/connection_resolver.rb

+32-11
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,19 @@
33
module GraphQL
44
module Cache
55
module Resolvers
6-
# Pass cache write method into GraphQL::Relay::BaseConnection
7-
# and wrap them original Connection methods
86
class ConnectionResolver < BaseResolver
9-
class ConnectionCache < Module
7+
NodesCache = Struct.new(:nodes, :paged_nodes)
8+
9+
# Pass cache write method into GraphQL::Relay::RelationConnection
10+
class RelationConnectionOverload < Module
1011
module WrappedMethods
1112
def paged_nodes
1213
cache_write = instance_variable_get(:@__cache_write)
1314

14-
cache_write.call { super }
15+
super.tap do |result|
16+
# save original relation (aka @nodes) and loaded records
17+
cache_write.call { NodesCache.new(@nodes, result) }
18+
end
1519
end
1620
end
1721

@@ -27,26 +31,43 @@ def extended(base)
2731

2832
def call(args:, field:, parent:, context:, force_cache:)
2933
if force_cache || (cached = read).nil?
30-
define_connection_cache(resolve_proc.call)
34+
define_relation_cache(resolve_proc.call)
3135
else
3236
wrap_connection(cached, args, field, parent: parent, context: context)
3337
end
3438
end
3539

3640
private
3741

38-
def wrap_connection(value, args, field, **kwargs)
39-
GraphQL::Relay::BaseConnection.connection_for_nodes(value).new(
40-
value,
42+
def wrap_connection(cached, args, field, **kwargs)
43+
nodes, paged_nodes = parse(cached)
44+
45+
GraphQL::Relay::BaseConnection.connection_for_nodes(nodes).new(
46+
nodes,
4147
args,
4248
field: field,
4349
parent: kwargs[:parent],
4450
context: kwargs[:context]
45-
)
51+
).tap do |connection|
52+
# restore cached paged_nodes
53+
connection.instance_variable_set(:@paged_nodes, paged_nodes) if paged_nodes
54+
end
55+
end
56+
57+
def define_relation_cache(connection)
58+
if connection.is_a?(GraphQL::Relay::RelationConnection)
59+
# inject cached logic into the relation connection
60+
connection.extend(RelationConnectionOverload.new(method(:write)))
61+
else
62+
# cache loaded connection (works for ArrayConnection)
63+
write { connection }
64+
end
4665
end
4766

48-
def define_connection_cache(connection)
49-
connection.extend(ConnectionCache.new(method(:write)))
67+
def parse(cached)
68+
return [cached, nil] unless cached.is_a?(NodesCache)
69+
70+
[cached.nodes, cached.paged_nodes]
5071
end
5172
end
5273
end

spec/features/connections_spec.rb

+3-3
Original file line numberDiff line numberDiff line change
@@ -101,11 +101,11 @@ def execute(query, context = {})
101101
it 'calls sql engine only one time per cached field' do
102102
5.times { execute(query) }
103103

104-
expect(sql_logger.messages).to eq(
105-
<<~SQL
104+
expect(sql_logger.messages.squish).to eq(
105+
<<~SQL.squish
106106
SELECT \"customers\".* FROM \"customers\" ORDER BY \"customers\".\"id\" DESC LIMIT ?\e[0m [[\"LIMIT\", 1]]
107107
SELECT \"customers\".* FROM \"customers\" WHERE \"customers\".\"id\" = ? LIMIT ?\e[0m [[\"id\", 1], [\"LIMIT\", 1]]
108-
SELECT \"orders\".* FROM \"orders\" WHERE \"orders\".\"customer_id\" = ?\e[0m [[\"customer_id\", 1]]
108+
SELECT \"orders\".* FROM \"orders\" WHERE \"orders\".\"customer_id\" = ? LIMIT ?\e[0m [[\"customer_id\", 1], [\"LIMIT\", 50]]
109109
SQL
110110
)
111111
end

spec/spec_helper.rb

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
require 'active_record' # should be required before graphql-ruby
1+
# ORMs should be required before graphql-ruby
2+
require 'active_record'
3+
require 'sequel'
4+
25
require 'bundler/setup'
36
require 'pry'
47

spec/support/test_cache.rb

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
class TestCache
44
def write(key, doc, opts={})
5-
# we duplicate the value to get rid of ruby object level caching
5+
# duplicate the value to get rid of ruby object level caching
6+
# and reproduce Rails.cache logic
67
cache[key] = ::Marshal.load(::Marshal.dump(doc))
78
end
89

test_schema/active_record/graphql_schema.rb

+2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ class CacheSchema < ::CacheSchema
1616
query AR::QueryType
1717
use GraphQL::Cache
1818

19+
default_max_page_size 50
20+
1921
def self.resolve_type(_type, obj, _ctx)
2022
"AR::#{obj.class.name}Type"
2123
end

test_schema/sequel/graphql_schema.rb

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ class CacheSchema < GraphQL::Schema
3131

3232
use GraphQL::Cache
3333

34+
default_max_page_size 50
35+
3436
def self.resolve_type(_type, obj, _ctx)
3537
"#{obj.class.name}Type"
3638
end

0 commit comments

Comments
 (0)