Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Execution::Lazy) support lazy connection values #425

Merged
merged 1 commit into from
Nov 28, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions lib/graphql/compatibility/lazy_execution_specification.rb
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,34 @@ def test_it_resolves_mutation_values_eagerly
]
assert_equal expected_pushes, pushes
end

def test_it_resolves_lazy_connections
pushes = []
query_str = %|
{
pushes(values: [1,2,3]) {
edges {
node {
value
push(value: 4) {
value
}
}
}
}
}
|
res = self.class.lazy_schema.execute(query_str, context: {pushes: pushes})

expected_edges = [
{"node"=>{"value"=>1, "push"=>{"value"=>4}}},
{"node"=>{"value"=>2, "push"=>{"value"=>4}}},
{"node"=>{"value"=>3, "push"=>{"value"=>4}}},
]
assert_equal expected_edges, res["data"]["pushes"]["edges"]
assert_equal [[1, 2, 3], [4, 4, 4]], pushes

end
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,17 @@ def push
end
end

class LazyPushCollection
def initialize(ctx, values)
@ctx = ctx
@values = values
end

def push
@values.map { |v| LazyPush.new(@ctx, v) }
end
end

def self.build(execution_strategy)
lazy_push_type = GraphQL::ObjectType.define do
name "LazyPush"
Expand All @@ -46,6 +57,13 @@ def self.build(execution_strategy)
LazyPush.new(c, a[:value])
}
end

connection :pushes, lazy_push_type.connection_type do
argument :values, types[types.Int]
resolve ->(o, a, c) {
LazyPushCollection.new(c, a[:values])
}
end
end

GraphQL::Schema.define do
Expand All @@ -54,6 +72,7 @@ def self.build(execution_strategy)
query_execution_strategy(execution_strategy)
mutation_execution_strategy(execution_strategy)
lazy_resolve(LazyPush, :push)
lazy_resolve(LazyPushCollection, :push)
end
end
end
Expand Down
6 changes: 5 additions & 1 deletion lib/graphql/execution/execute.rb
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,11 @@ def resolve_field(owner, selection, parent_type, field, object, query_ctx)

lazy_method_name = query.lazy_method(raw_value)
result = if lazy_method_name
GraphQL::Execution::Lazy.new { raw_value.public_send(lazy_method_name) }.then { |inner_value|
GraphQL::Execution::Lazy.new(raw_value, lazy_method_name).then { |inner_value|
continue_resolve_field(selection, parent_type, field, inner_value, field_ctx)
}
elsif raw_value.is_a?(GraphQL::Execution::Lazy)
raw_value.then { |inner_value|
continue_resolve_field(selection, parent_type, field, inner_value, field_ctx)
}
else
Expand Down
17 changes: 14 additions & 3 deletions lib/graphql/execution/lazy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,28 @@ def self.resolve(val)
end

# Create a {Lazy} which will get its inner value by calling the block
# @param target [Object]
# @param method_name [Symbol]
# @param get_value_func [Proc] a block to get the inner value (later)
def initialize(&get_value_func)
@get_value_func = get_value_func
def initialize(target = nil, method_name = nil, &get_value_func)
if block_given?
@get_value_func = get_value_func
else
@target = target
@method_name = method_name
end
@resolved = false
end

# @return [Object] The wrapped value, calling the lazy block if necessary
def value
if !@resolved
@resolved = true
@value = @get_value_func.call
if @get_value_func
@value = @get_value_func.call
else
@value = @target.public_send(@method_name)
end
end
@value
rescue GraphQL::ExecutionError => err
Expand Down
16 changes: 15 additions & 1 deletion lib/graphql/relay/connection_resolve.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,22 @@ def initialize(field, underlying_resolve, max_page_size: nil)

def call(obj, args, ctx)
nodes = @underlying_resolve.call(obj, args, ctx)
lazy_method = ctx.query.lazy_method(nodes)
if lazy_method
GraphQL::Execution::Lazy.new do
resolved_nodes = nodes.public_send(lazy_method)
build_connection(resolved_nodes, args, obj)
end
else
build_connection(nodes, args, obj)
end
end

private

def build_connection(nodes, args, parent)
connection_class = GraphQL::Relay::BaseConnection.connection_for_nodes(nodes)
connection_class.new(nodes, args, field: @field, max_page_size: @max_page_size, parent: obj)
connection_class.new(nodes, args, field: @field, max_page_size: @max_page_size, parent: parent)
end
end
end
Expand Down