GraphQL-Houtou
view release on metacpan or search on metacpan
lib/GraphQL/Houtou/Runtime/NativeRuntime.pm view on Meta::CPAN
$native_program,
$root_value,
$context_value,
$variables || {},
);
}
my $prepared_variables = GraphQL::Houtou::Runtime::InputCoercion::prepare_variables(
$self->runtime_schema,
$native_program,
$variables || {},
);
my $specialized = $self->_cached_specialized_program(
$native_program,
$prepared_variables,
);
return $self->execute_compact_program($specialized, %opts, variables => $prepared_variables);
}
if (!$has_root_value && !$has_context_value && !$has_variables) {
return GraphQL::Houtou::XS::VM::execute_native_program_auto_simple_xs(
$runtime_handle,
$native_program,
);
}
return GraphQL::Houtou::XS::VM::execute_native_program_auto_xs(
$runtime_handle,
$native_program,
$root_value,
$context_value,
$variables,
);
}
sub execute_compact_program {
my ($self, $program, %opts) = @_;
my $native_program = _require_native_program($program);
return GraphQL::Houtou::XS::VM::execute_native_program_handle_xs(
$self->_native_runtime_handle,
$native_program,
$opts{root_value},
$opts{context},
$opts{variables},
);
}
# Drive a possibly-pending async result to completion using the caller's
# on_stall callback. This is the core batching contract: execution runs
# until every field either completed or is waiting on a promise ("stall"),
# then on_stall is invoked and must make progress (return a true dispatch
# count) by resolving promises - typically by flushing data loaders. Each
# resolution runs its continuations synchronously, advancing the scheduler
# to the next stall. No progress while promises remain pending is reported
# as a deadlock.
sub _settle_result {
my ($self, $result, $on_stall) = @_;
return $result
if !GraphQL::Houtou::XS::VM::runtime_value_is_async_xs(
$self->_native_runtime_handle, $result,
);
my ($settled, $value) = (0, undef);
# Keep the derived chain alive until settlement; Future-style adapters may
# otherwise discard it before its callbacks run.
my $chain;
eval {
$chain = GraphQL::Houtou::XS::VM::runtime_then_async_xs(
$self->_native_runtime_handle,
$result,
sub { ($settled, $value) = (1, $_[0]) },
sub { ($settled, $value) = (-1, $_[0]) },
);
1;
} or do {
my $error = $@;
GraphQL::Houtou::XS::VM::cancel_pending_response_xs($result);
die $error;
};
while (!$settled) {
my $progressed = $on_stall->();
if (!$settled && !$progressed) {
# The request is being abandoned while promises are pending; cancel
# it so the pending machinery (a reference cycle while armed) is
# torn down instead of leaking with the abandoned frames.
GraphQL::Houtou::XS::VM::cancel_pending_response_xs($result);
die "GraphQL execution stalled: promises are pending but on_stall made no progress"
. " (a resolver returned a promise that no registered loader will resolve)\n";
}
}
if ($settled < 0) {
die $value if ref $value || ($value // '') ne '';
die "GraphQL execution failed with an unknown async rejection\n";
}
return $value;
}
sub execute_bundle_descriptor {
my ($self, $descriptor, %opts) = @_;
my $bundle = $self->load_bundle_descriptor($descriptor);
return $self->execute_bundle($bundle, %opts);
}
# Request-stage checks shared by execute_document and its JSON sibling:
# depth limit and full query validation. The depth check is skipped for
# documents already in the program cache; validation is skipped only for
# documents this runtime has actually validated before (a cache entry
# stored under validate => 0 proves nothing). Returns an arrayref of
# request errors, or undef when execution may proceed. Request errors
# produce an errors-only envelope (no "data" key), per the spec's
# request-error contract.
sub _document_request_errors {
my ($self, $document, $max_depth, $max_nodes, $max_cost,
$default_list_size, $validate, $operation_name, $allow_introspection) = @_;
return undef if !defined $max_depth && !defined $max_nodes
&& !defined $max_cost && !$validate && $allow_introspection;
my $is_string = !ref($document);
my $cache_key = $is_string
? _document_cache_key($document, $operation_name)
: undef;
my $already_validated = $is_string && $self->{_validated_documents}{$cache_key};
my $already_limited = $is_string && $self->{_limit_signatures}{$cache_key}
&& $self->{_limit_signatures}{$cache_key} eq _limit_signature(
( run in 2.638 seconds using v1.01-cache-2.11-cpan-14f38c9f855 )